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

Commit ebd9a238 authored by Gilles Debunne's avatar Gilles Debunne
Browse files

Faster and simpler replace in SSB

The original method was adding a suspicious space that was eventually
removed with a series of 3 calls to change.

This should not be necessary. I have tested this with various gap
positions and lengths, for all replace cases I could think of.

The test can not be added to the CTS as it would need to expose the
internal resizeFor and moveGapTo methods.

Change-Id: I194457fbcfd758fa69a7f380665cfd5ae4d3f1d4
parent 75cf9e19
Loading
Loading
Loading
Loading
+21 −46
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
    public SpannableStringBuilder(CharSequence text, int start, int end) {
        int srclen = end - start;

        if (srclen < 0) throw new StringIndexOutOfBoundsException();

        int len = ArrayUtils.idealCharArraySize(srclen + 1);
        mText = new char[len];
        mGapStart = srclen;
@@ -153,7 +155,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
        if (where == mGapStart)
            return;

        boolean atend = (where == length());
        boolean atEnd = (where == length());

        if (where < mGapStart) {
            int overlap = mGapStart - where;
@@ -179,7 +181,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
            else if (start == where) {
                int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;

                if (flag == POINT || (atend && flag == PARAGRAPH))
                if (flag == POINT || (atEnd && flag == PARAGRAPH))
                    start += mGapLength;
            }

@@ -190,7 +192,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
            else if (end == where) {
                int flag = (mSpanFlags[i] & END_MASK);

                if (flag == POINT || (atend && flag == PARAGRAPH))
                if (flag == POINT || (atEnd && flag == PARAGRAPH))
                    end += mGapLength;
            }

@@ -419,53 +421,26 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
        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);
            int selend = Selection.getSelectionEnd(this);

            // XXX just make the span fixups in change() do the right thing
            // instead of this madness!

            checkRange("replace", start, end);
            moveGapTo(end);

            if (mGapLength < 2)
                resizeFor(length() + 1);

            for (int i = mSpanCount - 1; i >= 0; i--) {
                if (mSpanStarts[i] == mGapStart)
                    mSpanStarts[i]++;

                if (mSpanEnds[i] == mGapStart)
                    mSpanEnds[i]++;
        // Try to keep the cursor / selection at the same relative position during
        // a text replacement. If replaced or replacement text length is zero, this
        // is already taken care of.
        boolean adjustSelection = origLen != 0 && newLen != 0;
        int selstart = 0;
        int selend = 0;
        if (adjustSelection) {
            selstart = Selection.getSelectionStart(this);
            selend = Selection.getSelectionEnd(this);
        }

            mText[mGapStart] = ' ';
            mGapStart++;
            mGapLength--;

            if (mGapLength < 1) {
                new Exception("mGapLength < 1").printStackTrace();
            }
        checkRange("replace", start, end);

            change(start + 1, start + 1, tb, tbstart, tbend);
            change(start, start + 1, "", 0, 0);
            change(start + newLen, start + newLen + origLen, "", 0, 0);
        change(start, end, tb, tbstart, tbend);

            /*
             * Special case to keep the cursor in the same position
             * if it was somewhere in the middle of the replaced region.
             * If it was at the start or the end or crossing the whole
             * replacement, it should already be where it belongs.
             * TODO: Is there some more general mechanism that could
             * accomplish this?
             */
        if (adjustSelection) {
            if (selstart > start && selstart < end) {
                long off = selstart - start;

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

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

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

                setSpan(false, Selection.SELECTION_END, selend, selend, Spanned.SPAN_POINT_POINT);