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

Commit 646a404d authored by Gilles Debunne's avatar Gilles Debunne Committed by Android (Google) Code Review
Browse files

Merge "Refactoring SpannableStringBuilder"

parents 5a7a1db4 b51036f7
Loading
Loading
Loading
Loading
+52 −80
Original line number Diff line number Diff line
@@ -262,19 +262,8 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
        return append(String.valueOf(text));
    }

    private int change(int start, int end, CharSequence tb, int tbstart, int tbend) {
        return change(true, start, end, tb, tbstart, tbend);
    }

    private int change(boolean notify, int start, int end,
                       CharSequence tb, int tbstart, int tbend) {
    private void change(int start, int end, CharSequence tb, int tbstart, int tbend) {
        checkRange("replace", start, end);
        int ret = tbend - tbstart;
        TextWatcher[] recipients = null;

        if (notify) {
            recipients = sendTextWillChange(start, end - start, tbend - tbstart);
        }

        for (int i = mSpanCount - 1; i >= 0; i--) {
            if ((mSpanFlags[i] & SPAN_PARAGRAPH) == SPAN_PARAGRAPH) {
@@ -338,7 +327,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
                    en = tbend;

                if (getSpanStart(spans[i]) < 0) {
                    setSpan(true, spans[i],
                    setSpan(false, spans[i],
                            st - tbstart + start,
                            en - tbstart + start,
                            sp.getSpanFlags(spans[i]));
@@ -346,24 +335,16 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
            }
        }

        if (end > start) {
            // no need for span fixup on pure insertion
        if (tbend > tbstart && end - start == 0) {
            if (notify) {
                sendTextChange(recipients, start, end - start, tbend - tbstart);
                sendTextHasChanged(recipients);
            }

            return ret;
        }

        boolean atend = (mGapStart + mGapLength == mText.length);
            boolean atEnd = (mGapStart + mGapLength == mText.length);

            for (int i = mSpanCount - 1; i >= 0; i--) {
                if (mSpanStarts[i] >= start &&
                        mSpanStarts[i] < mGapStart + mGapLength) {
                    int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;

                if (flag == POINT || (flag == PARAGRAPH && atend))
                if (flag == POINT || (flag == PARAGRAPH && atEnd))
                    mSpanStarts[i] = mGapStart + mGapLength;
                else
                    mSpanStarts[i] = start;
@@ -373,7 +354,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
                        mSpanEnds[i] < mGapStart + mGapLength) {
                    int flag = (mSpanFlags[i] & END_MASK);

                if (flag == POINT || (flag == PARAGRAPH && atend))
                    if (flag == POINT || (flag == PARAGRAPH && atEnd))
                        mSpanEnds[i] = mGapStart + mGapLength;
                    else
                        mSpanEnds[i] = start;
@@ -384,13 +365,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
                    removeSpan(i);
                }
            }

        if (notify) {
            sendTextChange(recipients, start, end - start, tbend - tbstart);
            sendTextHasChanged(recipients);
        }

        return ret;
    }

    private void removeSpan(int i) {
@@ -425,8 +400,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
                        CharSequence tb, int tbstart, int tbend) {
        int filtercount = mFilters.length;
        for (int i = 0; i < filtercount; i++) {
            CharSequence repl = mFilters[i].filter(tb, tbstart, tbend,
                                                   this, start, end);
            CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);

            if (repl != null) {
                tb = repl;
@@ -435,11 +409,17 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
            }
        }

        if (end == start && tbstart == tbend) {
        final int origLen = end - start;
        final int newLen = tbend - tbstart;

        if (origLen == 0 && newLen == 0) {
            return this;
        }

        if (end == start || tbstart == tbend) {
        TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class);
        sendBeforeTextChanged(textWatchers, start, origLen, newLen);

        if (origLen == 0 || newLen == 0) {
            change(start, end, tb, tbstart, tbend);
        } else {
            int selstart = Selection.getSelectionStart(this);
@@ -450,11 +430,6 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable

            checkRange("replace", start, end);
            moveGapTo(end);
            TextWatcher[] recipients;

            int origlen = end - start;

            recipients = sendTextWillChange(start, origlen, tbend - tbstart);

            if (mGapLength < 2)
                resizeFor(length() + 1);
@@ -475,9 +450,9 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
                new Exception("mGapLength < 1").printStackTrace();
            }

            int inserted = change(false, start + 1, start + 1, tb, tbstart, tbend);
            change(false, start, start + 1, "", 0, 0);
            change(false, start + inserted, start + inserted + origlen, "", 0, 0);
            change(start + 1, start + 1, tb, tbstart, tbend);
            change(start, start + 1, "", 0, 0);
            change(start + newLen, start + newLen + origLen, "", 0, 0);

            /*
             * Special case to keep the cursor in the same position
@@ -490,7 +465,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
            if (selstart > start && selstart < end) {
                long off = selstart - start;

                off = off * inserted / (end - start);
                off = off * newLen / (end - start);
                selstart = (int) off + start;

                setSpan(false, Selection.SELECTION_START, selstart, selstart,
@@ -499,15 +474,16 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
            if (selend > start && selend < end) {
                long off = selend - start;

                off = off * inserted / (end - start);
                off = off * newLen / (end - start);
                selend = (int) off + start;

                setSpan(false, Selection.SELECTION_END, selend, selend, Spanned.SPAN_POINT_POINT);
            }
            sendTextChange(recipients, start, origlen, inserted);
            sendTextHasChanged(recipients);
        }

        sendTextChanged(textWatchers, start, origLen, newLen);
        sendAfterTextChanged(textWatchers);

        return this; 
    }

@@ -872,30 +848,27 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
        return new String(buf);
    }

    private TextWatcher[] sendTextWillChange(int start, int before, int after) {
        TextWatcher[] recip = getSpans(start, start + before, TextWatcher.class);
        int n = recip.length;
    private void sendBeforeTextChanged(TextWatcher[] watchers, int start, int before, int after) {
        int n = watchers.length;

        for (int i = 0; i < n; i++) {
            recip[i].beforeTextChanged(this, start, before, after);
            watchers[i].beforeTextChanged(this, start, before, after);
        }

        return recip;
    }

    private void sendTextChange(TextWatcher[] recip, int start, int before, int after) {
        int n = recip.length;
    private void sendTextChanged(TextWatcher[] watchers, int start, int before, int after) {
        int n = watchers.length;

        for (int i = 0; i < n; i++) {
            recip[i].onTextChanged(this, start, before, after);
            watchers[i].onTextChanged(this, start, before, after);
        }
    }

    private void sendTextHasChanged(TextWatcher[] recip) {
        int n = recip.length;
    private void sendAfterTextChanged(TextWatcher[] watchers) {
        int n = watchers.length;

        for (int i = 0; i < n; i++) {
            recip[i].afterTextChanged(this);
            watchers[i].afterTextChanged(this);
        }
    }

@@ -1037,8 +1010,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
     * Don't call this yourself -- exists for Canvas to use internally.
     * {@hide}
     */
    public void drawText(Canvas c, int start, int end,
                         float x, float y, Paint p) {
    public void drawText(Canvas c, int start, int end, float x, float y, Paint p) {
        checkRange("drawText", start, end);

        if (end <= mGapStart) {
@@ -1059,8 +1031,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
     * Don't call this yourself -- exists for Canvas to use internally.
     * {@hide}
     */
    public void drawTextRun(Canvas c, int start, int end,
            int contextStart, int contextEnd,
    public void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
            float x, float y, int flags, Paint p) {
        checkRange("drawTextRun", start, end);

@@ -1262,6 +1233,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
    private int[] mSpanFlags;
    private int mSpanCount;

    // TODO These value are tightly related to the public SPAN_MARK/POINT values in {@link Spanned}
    private static final int POINT = 2;
    private static final int PARAGRAPH = 3;