@@ -59,6 +59,12 @@ class TextLine {
5959 private boolean mCharsValid ;
6060 private Spanned mSpanned ;
6161 private final TextPaint mWorkPaint = new TextPaint ();
62+ private final SpanSet <MetricAffectingSpan > mMetricAffectingSpanSpanSet =
63+ new SpanSet <MetricAffectingSpan >(MetricAffectingSpan .class );
64+ private final SpanSet <CharacterStyle > mCharacterStyleSpanSet =
65+ new SpanSet <CharacterStyle >(CharacterStyle .class );
66+ private final SpanSet <ReplacementSpan > mReplacementSpanSpanSet =
67+ new SpanSet <ReplacementSpan >(ReplacementSpan .class );
6268
6369 private static final TextLine [] sCached = new TextLine [3 ];
6470
@@ -119,7 +125,6 @@ static TextLine recycle(TextLine tl) {
119125 * @param hasTabs true if the line might contain tabs or emoji
120126 * @param tabStops the tabStops. Can be null.
121127 */
122- @ SuppressWarnings ("null" )
123128 void set (TextPaint paint , CharSequence text , int start , int limit , int dir ,
124129 Directions directions , boolean hasTabs , TabStops tabStops ) {
125130 mPaint = paint ;
@@ -135,12 +140,10 @@ void set(TextPaint paint, CharSequence text, int start, int limit, int dir,
135140 mSpanned = null ;
136141
137142 boolean hasReplacement = false ;
138- SpanSet <ReplacementSpan > replacementSpans = null ;
139143 if (text instanceof Spanned ) {
140144 mSpanned = (Spanned ) text ;
141- replacementSpans = new SpanSet <ReplacementSpan >(mSpanned , start , limit ,
142- ReplacementSpan .class );
143- hasReplacement = replacementSpans .numberOfSpans > 0 ;
145+ mReplacementSpanSpanSet .init (mSpanned , start , limit );
146+ hasReplacement = mReplacementSpanSpanSet .numberOfSpans > 0 ;
144147 }
145148
146149 mCharsValid = hasReplacement || hasTabs || directions != Layout .DIRS_ALL_LEFT_TO_RIGHT ;
@@ -158,9 +161,8 @@ void set(TextPaint paint, CharSequence text, int start, int limit, int dir,
158161 // zero-width characters.
159162 char [] chars = mChars ;
160163 for (int i = start , inext ; i < limit ; i = inext ) {
161- // replacementSpans cannot be null if hasReplacement is true
162- inext = replacementSpans .getNextTransition (i , limit );
163- if (replacementSpans .hasSpansIntersecting (i , inext )) {
164+ inext = mReplacementSpanSpanSet .getNextTransition (i , limit );
165+ if (mReplacementSpanSpanSet .hasSpansIntersecting (i , inext )) {
164166 // transition into a span
165167 chars [i - start ] = '\ufffc' ;
166168 for (int j = i - start + 1 , e = inext - start ; j < e ; ++j ) {
@@ -854,21 +856,30 @@ private float handleReplacement(ReplacementSpan replacement, TextPaint wp,
854856 }
855857
856858 private static class SpanSet <E > {
857- final int numberOfSpans ;
858- final E [] spans ;
859- final int [] spanStarts ;
860- final int [] spanEnds ;
861- final int [] spanFlags ;
859+ int numberOfSpans ;
860+ E [] spans ;
861+ int [] spanStarts ;
862+ int [] spanEnds ;
863+ int [] spanFlags ;
864+ final Class <? extends E > classType ;
865+
866+ SpanSet (Class <? extends E > type ) {
867+ classType = type ;
868+ numberOfSpans = 0 ;
869+ }
862870
863871 @ SuppressWarnings ("unchecked" )
864- SpanSet (Spanned spanned , int start , int limit , Class <? extends E > type ) {
865- final E [] allSpans = spanned .getSpans (start , limit , type );
872+ public void init (Spanned spanned , int start , int limit ) {
873+ final E [] allSpans = spanned .getSpans (start , limit , classType );
866874 final int length = allSpans .length ;
867- // These arrays may end up being too large because of empty spans
868- spans = (E []) Array .newInstance (type , length );
869- spanStarts = new int [length ];
870- spanEnds = new int [length ];
871- spanFlags = new int [length ];
875+
876+ if (length > 0 && (spans == null || spans .length < length )) {
877+ // These arrays may end up being too large because of empty spans
878+ spans = (E []) Array .newInstance (classType , length );
879+ spanStarts = new int [length ];
880+ spanEnds = new int [length ];
881+ spanFlags = new int [length ];
882+ }
872883
873884 int count = 0 ;
874885 for (int i = 0 ; i < length ; i ++) {
@@ -879,30 +890,11 @@ private static class SpanSet<E> {
879890 if (spanStart == spanEnd ) continue ;
880891
881892 final int spanFlag = spanned .getSpanFlags (span );
882- final int priority = spanFlag & Spanned .SPAN_PRIORITY ;
883- if (priority != 0 && count != 0 ) {
884- int j ;
885-
886- for (j = 0 ; j < count ; j ++) {
887- final int otherPriority = spanFlags [j ] & Spanned .SPAN_PRIORITY ;
888- if (priority > otherPriority ) break ;
889- }
890-
891- System .arraycopy (spans , j , spans , j + 1 , count - j );
892- System .arraycopy (spanStarts , j , spanStarts , j + 1 , count - j );
893- System .arraycopy (spanEnds , j , spanEnds , j + 1 , count - j );
894- System .arraycopy (spanFlags , j , spanFlags , j + 1 , count - j );
895893
896- spans [j ] = span ;
897- spanStarts [j ] = spanStart ;
898- spanEnds [j ] = spanEnd ;
899- spanFlags [j ] = spanFlag ;
900- } else {
901- spans [i ] = span ;
902- spanStarts [i ] = spanStart ;
903- spanEnds [i ] = spanEnd ;
904- spanFlags [i ] = spanFlag ;
905- }
894+ spans [i ] = span ;
895+ spanStarts [i ] = spanStart ;
896+ spanEnds [i ] = spanEnd ;
897+ spanFlags [i ] = spanFlag ;
906898
907899 count ++;
908900 }
@@ -970,10 +962,8 @@ private float handleRun(int start, int measureLimit,
970962 y , bottom , fmi , needWidth || mlimit < measureLimit );
971963 }
972964
973- final SpanSet <MetricAffectingSpan > metricAffectingSpans = new SpanSet <MetricAffectingSpan >(
974- mSpanned , mStart + start , mStart + limit , MetricAffectingSpan .class );
975- final SpanSet <CharacterStyle > characterStyleSpans = new SpanSet <CharacterStyle >(
976- mSpanned , mStart + start , mStart + limit , CharacterStyle .class );
965+ mMetricAffectingSpanSpanSet .init (mSpanned , mStart + start , mStart + limit );
966+ mCharacterStyleSpanSet .init (mSpanned , mStart + start , mStart + limit );
977967
978968 // Shaping needs to take into account context up to metric boundaries,
979969 // but rendering needs to take into account character style boundaries.
@@ -985,17 +975,18 @@ private float handleRun(int start, int measureLimit,
985975 TextPaint wp = mWorkPaint ;
986976 wp .set (mPaint );
987977
988- inext = metricAffectingSpans .getNextTransition (mStart + i , mStart + limit ) - mStart ;
978+ inext = mMetricAffectingSpanSpanSet .getNextTransition (mStart + i , mStart + limit ) -
979+ mStart ;
989980 int mlimit = Math .min (inext , measureLimit );
990981
991982 ReplacementSpan replacement = null ;
992983
993- for (int j = 0 ; j < metricAffectingSpans .numberOfSpans ; j ++) {
984+ for (int j = 0 ; j < mMetricAffectingSpanSpanSet .numberOfSpans ; j ++) {
994985 // Both intervals [spanStarts..spanEnds] and [mStart + i..mStart + mlimit] are NOT
995986 // empty by construction. This special case in getSpans() explains the >= & <= tests
996- if ((metricAffectingSpans .spanStarts [j ] >= mStart + mlimit ) ||
997- (metricAffectingSpans .spanEnds [j ] <= mStart + i )) continue ;
998- MetricAffectingSpan span = metricAffectingSpans .spans [j ];
987+ if ((mMetricAffectingSpanSpanSet .spanStarts [j ] >= mStart + mlimit ) ||
988+ (mMetricAffectingSpanSpanSet .spanEnds [j ] <= mStart + i )) continue ;
989+ MetricAffectingSpan span = mMetricAffectingSpanSpanSet .spans [j ];
999990 if (span instanceof ReplacementSpan ) {
1000991 replacement = (ReplacementSpan )span ;
1001992 } else {
@@ -1016,16 +1007,16 @@ private float handleRun(int start, int measureLimit,
10161007 y , bottom , fmi , needWidth || mlimit < measureLimit );
10171008 } else {
10181009 for (int j = i , jnext ; j < mlimit ; j = jnext ) {
1019- jnext = characterStyleSpans .getNextTransition (mStart + j , mStart + mlimit ) -
1010+ jnext = mCharacterStyleSpanSet .getNextTransition (mStart + j , mStart + mlimit ) -
10201011 mStart ;
10211012
10221013 wp .set (mPaint );
1023- for (int k = 0 ; k < characterStyleSpans .numberOfSpans ; k ++) {
1014+ for (int k = 0 ; k < mCharacterStyleSpanSet .numberOfSpans ; k ++) {
10241015 // Intentionally using >= and <= as explained above
1025- if ((characterStyleSpans .spanStarts [k ] >= mStart + jnext ) ||
1026- (characterStyleSpans .spanEnds [k ] <= mStart + j )) continue ;
1016+ if ((mCharacterStyleSpanSet .spanStarts [k ] >= mStart + jnext ) ||
1017+ (mCharacterStyleSpanSet .spanEnds [k ] <= mStart + j )) continue ;
10271018
1028- CharacterStyle span = characterStyleSpans .spans [k ];
1019+ CharacterStyle span = mCharacterStyleSpanSet .spans [k ];
10291020 span .updateDrawState (wp );
10301021 }
10311022
0 commit comments