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

Commit e912a16b authored by Gilles Debunne's avatar Gilles Debunne Committed by Android Git Automerger
Browse files

am 316ca505: Merge "Re-use SpanSets in TextLine" into ics-mr1

* commit '316ca505':
  Re-use SpanSets in TextLine
parents 8e94d912 316ca505
Loading
Loading
Loading
Loading
+48 −57
Original line number Diff line number Diff line
@@ -59,6 +59,12 @@ class TextLine {
    private boolean mCharsValid;
    private Spanned mSpanned;
    private final TextPaint mWorkPaint = new TextPaint();
    private final SpanSet<MetricAffectingSpan> mMetricAffectingSpanSpanSet =
            new SpanSet<MetricAffectingSpan>(MetricAffectingSpan.class);
    private final SpanSet<CharacterStyle> mCharacterStyleSpanSet =
            new SpanSet<CharacterStyle>(CharacterStyle.class);
    private final SpanSet<ReplacementSpan> mReplacementSpanSpanSet =
            new SpanSet<ReplacementSpan>(ReplacementSpan.class);

    private static final TextLine[] sCached = new TextLine[3];

@@ -119,7 +125,6 @@ class TextLine {
     * @param hasTabs true if the line might contain tabs or emoji
     * @param tabStops the tabStops. Can be null.
     */
    @SuppressWarnings("null")
    void set(TextPaint paint, CharSequence text, int start, int limit, int dir,
            Directions directions, boolean hasTabs, TabStops tabStops) {
        mPaint = paint;
@@ -135,12 +140,10 @@ class TextLine {
        mSpanned = null;

        boolean hasReplacement = false;
        SpanSet<ReplacementSpan> replacementSpans = null;
        if (text instanceof Spanned) {
            mSpanned = (Spanned) text;
            replacementSpans = new SpanSet<ReplacementSpan>(mSpanned, start, limit,
                    ReplacementSpan.class);
            hasReplacement = replacementSpans.numberOfSpans > 0;
            mReplacementSpanSpanSet.init(mSpanned, start, limit);
            hasReplacement = mReplacementSpanSpanSet.numberOfSpans > 0;
        }

        mCharsValid = hasReplacement || hasTabs || directions != Layout.DIRS_ALL_LEFT_TO_RIGHT;
@@ -158,9 +161,8 @@ class TextLine {
                // zero-width characters.
                char[] chars = mChars;
                for (int i = start, inext; i < limit; i = inext) {
                    // replacementSpans cannot be null if hasReplacement is true
                    inext = replacementSpans.getNextTransition(i, limit);
                    if (replacementSpans.hasSpansIntersecting(i, inext)) {
                    inext = mReplacementSpanSpanSet.getNextTransition(i, limit);
                    if (mReplacementSpanSpanSet.hasSpansIntersecting(i, inext)) {
                        // transition into a span
                        chars[i - start] = '\ufffc';
                        for (int j = i - start + 1, e = inext - start; j < e; ++j) {
@@ -854,21 +856,30 @@ class TextLine {
    }

    private static class SpanSet<E> {
        final int numberOfSpans;
        final E[] spans;
        final int[] spanStarts;
        final int[] spanEnds;
        final int[] spanFlags;
        int numberOfSpans;
        E[] spans;
        int[] spanStarts;
        int[] spanEnds;
        int[] spanFlags;
        final Class<? extends E> classType;

        SpanSet(Class<? extends E> type) {
            classType = type;
            numberOfSpans = 0;
        }

        @SuppressWarnings("unchecked")
        SpanSet(Spanned spanned, int start, int limit, Class<? extends E> type) {
            final E[] allSpans = spanned.getSpans(start, limit, type);
        public void init(Spanned spanned, int start, int limit) {
            final E[] allSpans = spanned.getSpans(start, limit, classType);
            final int length = allSpans.length;

            if (length > 0 && (spans == null || spans.length < length)) {
                // These arrays may end up being too large because of empty spans
            spans = (E[]) Array.newInstance(type, length);
                spans = (E[]) Array.newInstance(classType, length);
                spanStarts = new int[length];
                spanEnds = new int[length];
                spanFlags = new int[length];
            }

            int count = 0;
            for (int i = 0; i < length; i++) {
@@ -879,30 +890,11 @@ class TextLine {
                if (spanStart == spanEnd) continue;

                final int spanFlag = spanned.getSpanFlags(span);
                final int priority = spanFlag & Spanned.SPAN_PRIORITY;
                if (priority != 0 && count != 0) {
                    int j;

                    for (j = 0; j < count; j++) {
                        final int otherPriority = spanFlags[j] & Spanned.SPAN_PRIORITY;
                        if (priority > otherPriority) break;
                    }

                    System.arraycopy(spans, j, spans, j + 1, count - j);
                    System.arraycopy(spanStarts, j, spanStarts, j + 1, count - j);
                    System.arraycopy(spanEnds, j, spanEnds, j + 1, count - j);
                    System.arraycopy(spanFlags, j, spanFlags, j + 1, count - j);

                    spans[j] = span;
                    spanStarts[j] = spanStart;
                    spanEnds[j] = spanEnd;
                    spanFlags[j] = spanFlag;
                } else {
                spans[i] = span;
                spanStarts[i] = spanStart;
                spanEnds[i] = spanEnd;
                spanFlags[i] = spanFlag;
                }

                count++;
            }
@@ -970,10 +962,8 @@ class TextLine {
                    y, bottom, fmi, needWidth || mlimit < measureLimit);
        }

        final SpanSet<MetricAffectingSpan> metricAffectingSpans = new SpanSet<MetricAffectingSpan>(
                mSpanned, mStart + start, mStart + limit, MetricAffectingSpan.class);
        final SpanSet<CharacterStyle> characterStyleSpans = new SpanSet<CharacterStyle>(
                    mSpanned, mStart + start, mStart + limit, CharacterStyle.class);
        mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit);
        mCharacterStyleSpanSet.init(mSpanned, mStart + start, mStart + limit);

        // Shaping needs to take into account context up to metric boundaries,
        // but rendering needs to take into account character style boundaries.
@@ -985,17 +975,18 @@ class TextLine {
            TextPaint wp = mWorkPaint;
            wp.set(mPaint);

            inext = metricAffectingSpans.getNextTransition(mStart + i, mStart + limit) - mStart;
            inext = mMetricAffectingSpanSpanSet.getNextTransition(mStart + i, mStart + limit) -
                    mStart;
            int mlimit = Math.min(inext, measureLimit);

            ReplacementSpan replacement = null;

            for (int j = 0; j < metricAffectingSpans.numberOfSpans; j++) {
            for (int j = 0; j < mMetricAffectingSpanSpanSet.numberOfSpans; j++) {
                // Both intervals [spanStarts..spanEnds] and [mStart + i..mStart + mlimit] are NOT
                // empty by construction. This special case in getSpans() explains the >= & <= tests
                if ((metricAffectingSpans.spanStarts[j] >= mStart + mlimit) ||
                        (metricAffectingSpans.spanEnds[j] <= mStart + i)) continue;
                MetricAffectingSpan span = metricAffectingSpans.spans[j];
                if ((mMetricAffectingSpanSpanSet.spanStarts[j] >= mStart + mlimit) ||
                        (mMetricAffectingSpanSpanSet.spanEnds[j] <= mStart + i)) continue;
                MetricAffectingSpan span = mMetricAffectingSpanSpanSet.spans[j];
                if (span instanceof ReplacementSpan) {
                    replacement = (ReplacementSpan)span;
                } else {
@@ -1016,16 +1007,16 @@ class TextLine {
                        y, bottom, fmi, needWidth || mlimit < measureLimit);
            } else {
                for (int j = i, jnext; j < mlimit; j = jnext) {
                    jnext = characterStyleSpans.getNextTransition(mStart + j, mStart + mlimit) -
                    jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + mlimit) -
                            mStart;

                    wp.set(mPaint);
                    for (int k = 0; k < characterStyleSpans.numberOfSpans; k++) {
                    for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) {
                        // Intentionally using >= and <= as explained above
                        if ((characterStyleSpans.spanStarts[k] >= mStart + jnext) ||
                                (characterStyleSpans.spanEnds[k] <= mStart + j)) continue;
                        if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + jnext) ||
                                (mCharacterStyleSpanSet.spanEnds[k] <= mStart + j)) continue;

                        CharacterStyle span = characterStyleSpans.spans[k];
                        CharacterStyle span = mCharacterStyleSpanSet.spans[k];
                        span.updateDrawState(wp);
                    }