Loading core/java/android/text/TextLine.java +48 −57 Original line number Diff line number Diff line Loading @@ -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]; Loading Loading @@ -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; Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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++) { Loading @@ -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++; } Loading Loading @@ -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. Loading @@ -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 { Loading @@ -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); } Loading Loading
core/java/android/text/TextLine.java +48 −57 Original line number Diff line number Diff line Loading @@ -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]; Loading Loading @@ -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; Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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++) { Loading @@ -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++; } Loading Loading @@ -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. Loading @@ -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 { Loading @@ -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); } Loading