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 Original line Diff line number Diff line
@@ -98,7 +98,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
                if (en > end - start)
                if (en > end - start)
                    en = end - start;
                    en = end - start;


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


                if (spanStart != ost || spanEnd != oen) {
                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;
                    changed = true;
                }
                }
            }
            }
@@ -430,13 +431,8 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
                    int copySpanEnd = en - csStart + start;
                    int copySpanEnd = en - csStart + start;
                    int copySpanFlags = sp.getSpanFlags(spans[i]) | SPAN_ADDED;
                    int copySpanFlags = sp.getSpanFlags(spans[i]) | SPAN_ADDED;


                    int flagsStart = (copySpanFlags & START_MASK) >> START_SHIFT;
                    setSpan(false, spans[i], copySpanStart, copySpanEnd, copySpanFlags,
                    int flagsEnd = copySpanFlags & END_MASK;
                            false/*enforceParagraph*/);

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


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


                changed = true;
                changed = true;
                setSpan(false, Selection.SELECTION_END, selectionEnd, selectionEnd,
                setSpan(false, Selection.SELECTION_END, selectionEnd, selectionEnd,
                        Spanned.SPAN_POINT_POINT);
                        Spanned.SPAN_POINT_POINT, true/*enforceParagraph*/);
            }
            }
            if (changed) {
            if (changed) {
                restoreInvariants();
                restoreInvariants();
@@ -673,23 +669,34 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
     * inserted at the start or end of the span's range.
     * inserted at the start or end of the span's range.
     */
     */
    public void setSpan(Object what, int start, int end, int flags) {
    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
    // 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
    // invariants. If send is false and the span already exists, then this method
    // will not change the index of any spans.
    // 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);
        checkRange("setSpan", start, end);


        int flagsStart = (flags & START_MASK) >> START_SHIFT;
        int flagsStart = (flags & START_MASK) >> START_SHIFT;
        if(isInvalidParagraphStart(start, flagsStart)) {
        if (isInvalidParagraph(start, flagsStart)) {
            throw new RuntimeException("PARAGRAPH span must start at paragraph boundary");
            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;
        int flagsEnd = flags & END_MASK;
        if(isInvalidParagraphEnd(end, flagsEnd)) {
        if (isInvalidParagraph(end, flagsEnd)) {
            throw new RuntimeException("PARAGRAPH span must end at paragraph boundary");
            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
        // 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) {
    private boolean isInvalidParagraph(int index, int flag) {
        if (flagsStart == PARAGRAPH) {
        return flag == PARAGRAPH && index != 0 && index != length() && charAt(index - 1) != '\n';
            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;
    }
    }


    /**
    /**
+23 −15
Original line number Original line Diff line number Diff line
@@ -65,7 +65,7 @@ import java.lang.reflect.Array;
            if (en > end)
            if (en > end)
                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) {
    /* 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 nstart = start;
        int nend = end;
        int nend = end;


        checkRange("setSpan", start, end);
        checkRange("setSpan", start, end);


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

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


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

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