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

Commit 7afe571b authored by Siyamed Sinir's avatar Siyamed Sinir Committed by Android (Google) Code Review
Browse files

Merge "Make SpannableStringBuilder.getSpans thread-safe"

parents a393ff7d 1bcdcebf
Loading
Loading
Loading
Loading
+67 −16
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.graphics.BaseCanvas;
import android.graphics.Paint;
import android.util.Log;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;

@@ -73,8 +74,6 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
        mSpanFlags = EmptyArray.INT;
        mSpanMax = EmptyArray.INT;
        mSpanOrder = EmptyArray.INT;
        mPrioSortBuffer = EmptyArray.INT;
        mOrderSortBuffer = EmptyArray.INT;

        if (text instanceof Spanned) {
            Spanned sp = (Spanned) text;
@@ -856,14 +855,14 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
     * @param queryStart Start index.
     * @param queryEnd End index.
     * @param kind Class type to search for.
     * @param sort If true the results are sorted by the insertion order.
     * @param sortByInsertionOrder If true the results are sorted by the insertion order.
     * @param <T>
     * @return Array of the spans. Empty array if no results are found.
     *
     * @hide
     */
    public <T> T[] getSpans(int queryStart, int queryEnd, @Nullable Class<T> kind,
                                 boolean sort) {
            boolean sortByInsertionOrder) {
        if (kind == null) return (T[]) ArrayUtils.emptyArray(Object.class);
        if (mSpanCount == 0) return ArrayUtils.emptyArray(kind);
        int count = countSpans(queryStart, queryEnd, kind, treeRoot());
@@ -873,13 +872,15 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable

        // Safe conversion, but requires a suppressWarning
        T[] ret = (T[]) Array.newInstance(kind, count);
        if (sort) {
            mPrioSortBuffer = checkSortBuffer(mPrioSortBuffer, count);
            mOrderSortBuffer = checkSortBuffer(mOrderSortBuffer, count);
        final int[] prioSortBuffer = sortByInsertionOrder ? obtain(count) : EmptyArray.INT;
        final int[] orderSortBuffer = sortByInsertionOrder ? obtain(count) : EmptyArray.INT;
        getSpansRec(queryStart, queryEnd, kind, treeRoot(), ret, prioSortBuffer,
                orderSortBuffer, 0, sortByInsertionOrder);
        if (sortByInsertionOrder) {
            sort(ret, prioSortBuffer, orderSortBuffer);
            recycle(prioSortBuffer);
            recycle(orderSortBuffer);
        }
        getSpansRec(queryStart, queryEnd, kind, treeRoot(), ret, mPrioSortBuffer,
                mOrderSortBuffer, 0, sort);
        if (sort) sort(ret, mPrioSortBuffer, mOrderSortBuffer);
        return ret;
    }

@@ -991,16 +992,64 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
        return count;
    }

    /**
     * Obtain a temporary sort buffer.
     *
     * @param elementCount the size of the int[] to be returned
     * @return an int[] with elementCount length
     */
    private static int[] obtain(final int elementCount) {
        int[] result = null;
        synchronized (sCachedIntBuffer) {
            // try finding a tmp buffer with length of at least elementCount
            // if not get the first available one
            int candidateIndex = -1;
            for (int i = sCachedIntBuffer.length - 1; i >= 0; i--) {
                if (sCachedIntBuffer[i] != null) {
                    if (sCachedIntBuffer[i].length >= elementCount) {
                        candidateIndex = i;
                        break;
                    } else if (candidateIndex == -1) {
                        candidateIndex = i;
                    }
                }
            }

            if (candidateIndex != -1) {
                result = sCachedIntBuffer[candidateIndex];
                sCachedIntBuffer[candidateIndex] = null;
            }
        }
        result = checkSortBuffer(result, elementCount);
        return result;
    }

    /**
     * Recycle sort buffer.
     *
     * @param buffer buffer to be recycled
     */
    private static void recycle(int[] buffer) {
        synchronized (sCachedIntBuffer) {
            for (int i = 0; i < sCachedIntBuffer.length; i++) {
                if (sCachedIntBuffer[i] == null || buffer.length > sCachedIntBuffer[i].length) {
                    sCachedIntBuffer[i] = buffer;
                    break;
                }
            }
        }
    }

    /**
     * Check the size of the buffer and grow if required.
     *
     * @param buffer Buffer to be checked.
     * @param size Required size.
     * @param buffer buffer to be checked.
     * @param size   required size.
     * @return Same buffer instance if the current size is greater than required size. Otherwise a
     * new instance is created and returned.
     */
    private final int[] checkSortBuffer(int[] buffer, int size) {
        if(size > buffer.length) {
    private static int[] checkSortBuffer(int[] buffer, int size) {
        if (buffer == null || size > buffer.length) {
            return ArrayUtils.newUnpaddedIntArray(GrowingArrayUtils.growSize(size));
        }
        return buffer;
@@ -1704,6 +1753,10 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
    }

    private static final InputFilter[] NO_FILTERS = new InputFilter[0];

    @GuardedBy("sCachedIntBuffer")
    private static final int[][] sCachedIntBuffer = new int[6][0];

    private InputFilter[] mFilters = NO_FILTERS;

    private char[] mText;
@@ -1717,8 +1770,6 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
    private int[] mSpanFlags;
    private int[] mSpanOrder;  // store the order of span insertion
    private int mSpanInsertCount;  // counter for the span insertion
    private int[] mPrioSortBuffer;  // buffer used to sort getSpans result
    private int[] mOrderSortBuffer;  // buffer used to sort getSpans result

    private int mSpanCount;
    private IdentityHashMap<Object, Integer> mIndexOfSpan;