Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6284a20 authored by Siyamed Sinir's avatar Siyamed Sinir
Browse files

Do not enforce paragraph constraint for copy ctr

Update SpannableStringBuilder, SpannedString and SpannableString classes
so that they don’t enforce paragraph constraint for copy constructors.
If a paragraph constraint is not satisfied for a span, that span is not
copied. Before this change it would throw an exception.

Test: New tests added for SpannableStringBuilder and SpannableString
      cts-tradefed run cts -m CtsTextTestCases
Bug: 36511794

Change-Id: I62abf08a8d4fe7e342ed97b8e8c3a577a9397e39
parent 7a6df3b7
Loading
Loading
Loading
Loading
+26 −37
Original line number Diff line number Diff line
@@ -98,7 +98,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
                if (en > end - start)
                    en = end - start;

                setSpan(false, spans[i], st, en, fl);
                setSpan(false, spans[i], st, en, fl, false/*enforceParagraph*/);
            }
            restoreInvariants();
        }
@@ -355,7 +355,8 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
                }

                if (spanStart != ost || spanEnd != oen) {
                    setSpan(false, mSpans[i], spanStart, spanEnd, mSpanFlags[i]);
                    setSpan(false, mSpans[i], spanStart, spanEnd, mSpanFlags[i],
                            true/*enforceParagraph*/);
                    changed = true;
                }
            }
@@ -430,13 +431,8 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
                    int copySpanEnd = en - csStart + start;
                    int copySpanFlags = sp.getSpanFlags(spans[i]) | SPAN_ADDED;

                    int flagsStart = (copySpanFlags & START_MASK) >> START_SHIFT;
                    int flagsEnd = copySpanFlags & END_MASK;

                    if(!isInvalidParagraphStart(copySpanStart, flagsStart) &&
                            !isInvalidParagraphEnd(copySpanEnd, flagsEnd)) {
                        setSpan(false, spans[i], copySpanStart, copySpanEnd, copySpanFlags);
                    }
                    setSpan(false, spans[i], copySpanStart, copySpanEnd, copySpanFlags,
                            false/*enforceParagraph*/);
                }
            }
            restoreInvariants();
@@ -558,7 +554,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable

                changed = true;
                setSpan(false, Selection.SELECTION_START, selectionStart, selectionStart,
                        Spanned.SPAN_POINT_POINT);
                        Spanned.SPAN_POINT_POINT, true/*enforceParagraph*/);
            }
            if (selectionEnd > start && selectionEnd < end) {
                final long diff = selectionEnd - start;
@@ -567,7 +563,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable

                changed = true;
                setSpan(false, Selection.SELECTION_END, selectionEnd, selectionEnd,
                        Spanned.SPAN_POINT_POINT);
                        Spanned.SPAN_POINT_POINT, true/*enforceParagraph*/);
            }
            if (changed) {
                restoreInvariants();
@@ -673,23 +669,34 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
     * inserted at the start or end of the span's range.
     */
    public void setSpan(Object what, int start, int end, int flags) {
        setSpan(true, what, start, end, flags);
        setSpan(true, what, start, end, flags, true/*enforceParagraph*/);
    }

    // Note: if send is false, then it is the caller's responsibility to restore
    // invariants. If send is false and the span already exists, then this method
    // will not change the index of any spans.
    private void setSpan(boolean send, Object what, int start, int end, int flags) {
    private void setSpan(boolean send, Object what, int start, int end, int flags,
            boolean enforceParagraph) {
        checkRange("setSpan", start, end);

        int flagsStart = (flags & START_MASK) >> START_SHIFT;
        if(isInvalidParagraphStart(start, flagsStart)) {
            throw new RuntimeException("PARAGRAPH span must start at paragraph boundary");
        if (isInvalidParagraph(start, flagsStart)) {
            if (!enforceParagraph) {
                // do not set the span
                return;
            }
            throw new RuntimeException("PARAGRAPH span must start at paragraph boundary"
                    + " (" + start + " follows " + charAt(start - 1) + ")");
        }

        int flagsEnd = flags & END_MASK;
        if(isInvalidParagraphEnd(end, flagsEnd)) {
            throw new RuntimeException("PARAGRAPH span must end at paragraph boundary");
        if (isInvalidParagraph(end, flagsEnd)) {
            if (!enforceParagraph) {
                // do not set the span
                return;
            }
            throw new RuntimeException("PARAGRAPH span must end at paragraph boundary"
                    + " (" + end + " follows " + charAt(end - 1) + ")");
        }

        // 0-length Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
@@ -767,26 +774,8 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
        }
    }

    private final boolean isInvalidParagraphStart(int start, int flagsStart) {
        if (flagsStart == PARAGRAPH) {
            if (start != 0 && start != length()) {
                char c = charAt(start - 1);

                if (c != '\n') return true;
            }
        }
        return false;
    }

    private final boolean isInvalidParagraphEnd(int end, int flagsEnd) {
        if (flagsEnd == PARAGRAPH) {
            if (end != 0 && end != length()) {
                char c = charAt(end - 1);

                if (c != '\n') return true;
            }
        }
        return false;
    private boolean isInvalidParagraph(int index, int flag) {
        return flag == PARAGRAPH && index != 0 && index != length() && charAt(index - 1) != '\n';
    }

    /**
+23 −15
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ import java.lang.reflect.Array;
            if (en > end)
                en = end;

            setSpan(spans[i], st - start, en - start, fl);
            setSpan(spans[i], st - start, en - start, fl, false/*enforceParagraph*/);
        }
    }

@@ -149,28 +149,36 @@ import java.lang.reflect.Array;
    }

    /* package */ void setSpan(Object what, int start, int end, int flags) {
        setSpan(what, start, end, flags, true/*enforceParagraph*/);
    }

    private boolean isIndexFollowsNextLine(int index) {
        return index != 0 && index != length() && charAt(index - 1) != '\n';
    }

    private void setSpan(Object what, int start, int end, int flags, boolean enforceParagraph) {
        int nstart = start;
        int nend = end;

        checkRange("setSpan", start, end);

        if ((flags & Spannable.SPAN_PARAGRAPH) == Spannable.SPAN_PARAGRAPH) {
            if (start != 0 && start != length()) {
                char c = charAt(start - 1);

                if (c != '\n')
                    throw new RuntimeException(
                            "PARAGRAPH span must start at paragraph boundary" +
                            " (" + start + " follows " + c + ")");
            if (isIndexFollowsNextLine(start)) {
                if (!enforceParagraph) {
                    // do not set the span
                    return;
                }
                throw new RuntimeException("PARAGRAPH span must start at paragraph boundary"
                        + " (" + start + " follows " + charAt(start - 1) + ")");
            }

            if (end != 0 && end != length()) {
                char c = charAt(end - 1);

                if (c != '\n')
                    throw new RuntimeException(
                            "PARAGRAPH span must end at paragraph boundary" +
                            " (" + end + " follows " + c + ")");
            if (isIndexFollowsNextLine(end)) {
                if (!enforceParagraph) {
                    // do not set the span
                    return;
                }
                throw new RuntimeException("PARAGRAPH span must end at paragraph boundary"
                        + " (" + end + " follows " + charAt(end - 1) + ")");
            }
        }