Loading core/java/android/text/TextLine.java +4 −7 Original line number Diff line number Diff line Loading @@ -723,7 +723,7 @@ class TextLine { float ret = 0; int contextLen = contextEnd - contextStart; if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineCount != 0 || runIsRtl))) { if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) { int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR; if (mCharsValid) { ret = wp.getTextRunAdvances(mChars, start, runLen, Loading Loading @@ -753,7 +753,7 @@ class TextLine { wp.setColor(previousColor); } if (wp.underlineCount != 0) { if (wp.underlineColor != 0) { // kStdUnderline_Offset = 1/9, defined in SkTextFormatParams.h float underlineTop = y + wp.baselineShift + (1.0f / 9.0f) * wp.getTextSize(); Loading @@ -764,11 +764,8 @@ class TextLine { wp.setStyle(Paint.Style.FILL); wp.setAntiAlias(true); for (int i = 0; i < wp.underlineCount; i++) { wp.setColor(wp.underlineColors[i]); c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThicknesses[i], wp); } wp.setColor(wp.underlineColor); c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThickness, wp); wp.setStyle(previousStyle); wp.setColor(previousColor); Loading core/java/android/text/TextPaint.java +6 −45 Original line number Diff line number Diff line Loading @@ -24,8 +24,6 @@ import android.graphics.Paint; */ public class TextPaint extends Paint { private static final int DEFAULT_UNDERLINE_SIZE = 3; // Special value 0 means no background paint public int bgColor; public int baselineShift; Loading @@ -36,17 +34,12 @@ public class TextPaint extends Paint { * Special value 0 means no custom underline * @hide */ public int[] underlineColors; public int underlineColor = 0; /** * Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness. * @hide */ public float[] underlineThicknesses; /** * The number of underlines currently stored in the array. If 0, no underline is drawn. * @hide */ public int underlineCount; public float underlineThickness; public TextPaint() { super(); Loading @@ -72,16 +65,8 @@ public class TextPaint extends Paint { linkColor = tp.linkColor; drawableState = tp.drawableState; density = tp.density; if (tp.underlineColors != null) { if (underlineColors == null || underlineColors.length < tp.underlineCount) { underlineColors = new int[tp.underlineCount]; underlineThicknesses = new float[tp.underlineCount]; } System.arraycopy(tp.underlineColors, 0, underlineColors, 0, tp.underlineCount); System.arraycopy(tp.underlineThicknesses, 0, underlineThicknesses, 0, tp.underlineCount); } underlineCount = tp.underlineCount; underlineColor = tp.underlineColor; underlineThickness = tp.underlineThickness; } /** Loading @@ -91,31 +76,7 @@ public class TextPaint extends Paint { * @hide */ public void setUnderlineText(int color, float thickness) { if (color == 0) { // No underline return; } if (underlineCount == 0) { underlineColors = new int[DEFAULT_UNDERLINE_SIZE]; underlineThicknesses = new float[DEFAULT_UNDERLINE_SIZE]; underlineColors[underlineCount] = color; underlineThicknesses[underlineCount] = thickness; underlineCount++; } else { if (underlineCount == underlineColors.length) { int[] newColors = new int[underlineColors.length + DEFAULT_UNDERLINE_SIZE]; float[] newThickness = new float[underlineThicknesses.length + DEFAULT_UNDERLINE_SIZE]; System.arraycopy(underlineColors, 0, newColors, 0, underlineColors.length); System.arraycopy( underlineThicknesses, 0, newThickness, 0, underlineThicknesses.length); underlineColors = newColors; underlineThicknesses = newThickness; } underlineColors[underlineCount] = color; underlineThicknesses[underlineCount] = thickness; underlineCount++; } underlineColor = color; underlineThickness = thickness; } } core/java/android/text/style/SuggestionSpan.java +21 −7 Original line number Diff line number Diff line Loading @@ -108,7 +108,8 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { /** * @param context Context for the application * @param locale locale Locale of the suggestions * @param suggestions Suggestions for the string under the span * @param suggestions Suggestions for the string under the span. Only the first up to * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered. * @param flags Additional flags indicating how this span is handled in TextView * @param notificationTargetClass if not null, this class will get notified when the user * selects one of the suggestions. Loading Loading @@ -258,10 +259,16 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { @Override public void updateDrawState(TextPaint tp) { if ((mFlags & FLAG_MISSPELLED) != 0) { tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness); } else if ((mFlags & FLAG_EASY_CORRECT) != 0) { final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0; final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0; if (easy) { if (!misspelled) { tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness); } else if (tp.underlineColor == 0) { // Spans are rendered in an arbitrary order. Since misspelled is less prioritary // than just easy, do not apply misspelled if an easy (or a mispelled) has been set tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness); } } } Loading @@ -272,8 +279,15 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { */ public int getUnderlineColor() { // The order here should match what is used in updateDrawState if ((mFlags & FLAG_MISSPELLED) != 0) return mMisspelledUnderlineColor; if ((mFlags & FLAG_EASY_CORRECT) != 0) return mEasyCorrectUnderlineColor; final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0; final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0; if (easy) { if (!misspelled) { return mEasyCorrectUnderlineColor; } else { return mMisspelledUnderlineColor; } } return 0; } } core/java/android/widget/TextView.java +30 −13 Original line number Diff line number Diff line Loading @@ -9560,6 +9560,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mNumberOfSuggestions; private boolean mCursorWasVisibleBeforeSuggestions; private SuggestionAdapter mSuggestionsAdapter; private final Comparator<SuggestionSpan> mSuggestionSpanComparator; private final HashMap<SuggestionSpan, Integer> mSpansLengths; private class CustomPopupWindow extends PopupWindow { public CustomPopupWindow(Context context, int defStyle) { Loading @@ -9585,6 +9588,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public SuggestionsPopupWindow() { mCursorWasVisibleBeforeSuggestions = mCursorVisible; mSuggestionSpanComparator = new SuggestionSpanComparator(); mSpansLengths = new HashMap<SuggestionSpan, Integer>(); } @Override Loading Loading @@ -9663,6 +9668,26 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } private class SuggestionSpanComparator implements Comparator<SuggestionSpan> { public int compare(SuggestionSpan span1, SuggestionSpan span2) { final int flag1 = span1.getFlags(); final int flag2 = span2.getFlags(); if (flag1 != flag2) { // The order here should match what is used in updateDrawState final boolean easy1 = (flag1 & SuggestionSpan.FLAG_EASY_CORRECT) != 0; final boolean easy2 = (flag2 & SuggestionSpan.FLAG_EASY_CORRECT) != 0; final boolean misspelled1 = (flag1 & SuggestionSpan.FLAG_MISSPELLED) != 0; final boolean misspelled2 = (flag2 & SuggestionSpan.FLAG_MISSPELLED) != 0; if (easy1 && !misspelled1) return -1; if (easy2 && !misspelled2) return 1; if (misspelled1) return -1; if (misspelled2) return 1; } return mSpansLengths.get(span1).intValue() - mSpansLengths.get(span2).intValue(); } } /** * Returns the suggestion spans that cover the current cursor position. The suggestion * spans are sorted according to the length of text that they are attached to. Loading @@ -9672,24 +9697,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Spannable spannable = (Spannable) TextView.this.mText; SuggestionSpan[] suggestionSpans = spannable.getSpans(pos, pos, SuggestionSpan.class); // Cache the span length for performance reason. final HashMap<SuggestionSpan, Integer> spansLengths = new HashMap<SuggestionSpan, Integer>(); mSpansLengths.clear(); for (SuggestionSpan suggestionSpan : suggestionSpans) { int start = spannable.getSpanStart(suggestionSpan); int end = spannable.getSpanEnd(suggestionSpan); spansLengths.put(suggestionSpan, Integer.valueOf(end - start)); } // The suggestions are sorted according to the lenght of the text that they cover // (shorter first) Arrays.sort(suggestionSpans, new Comparator<SuggestionSpan>() { public int compare(SuggestionSpan span1, SuggestionSpan span2) { return spansLengths.get(span1).intValue() - spansLengths.get(span2).intValue(); mSpansLengths.put(suggestionSpan, Integer.valueOf(end - start)); } }); // The suggestions are sorted according to their types (easy correction first, then // misspelled) and to the length of the text that they cover (shorter first). Arrays.sort(suggestionSpans, mSuggestionSpanComparator); return suggestionSpans; } Loading Loading
core/java/android/text/TextLine.java +4 −7 Original line number Diff line number Diff line Loading @@ -723,7 +723,7 @@ class TextLine { float ret = 0; int contextLen = contextEnd - contextStart; if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineCount != 0 || runIsRtl))) { if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) { int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR; if (mCharsValid) { ret = wp.getTextRunAdvances(mChars, start, runLen, Loading Loading @@ -753,7 +753,7 @@ class TextLine { wp.setColor(previousColor); } if (wp.underlineCount != 0) { if (wp.underlineColor != 0) { // kStdUnderline_Offset = 1/9, defined in SkTextFormatParams.h float underlineTop = y + wp.baselineShift + (1.0f / 9.0f) * wp.getTextSize(); Loading @@ -764,11 +764,8 @@ class TextLine { wp.setStyle(Paint.Style.FILL); wp.setAntiAlias(true); for (int i = 0; i < wp.underlineCount; i++) { wp.setColor(wp.underlineColors[i]); c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThicknesses[i], wp); } wp.setColor(wp.underlineColor); c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThickness, wp); wp.setStyle(previousStyle); wp.setColor(previousColor); Loading
core/java/android/text/TextPaint.java +6 −45 Original line number Diff line number Diff line Loading @@ -24,8 +24,6 @@ import android.graphics.Paint; */ public class TextPaint extends Paint { private static final int DEFAULT_UNDERLINE_SIZE = 3; // Special value 0 means no background paint public int bgColor; public int baselineShift; Loading @@ -36,17 +34,12 @@ public class TextPaint extends Paint { * Special value 0 means no custom underline * @hide */ public int[] underlineColors; public int underlineColor = 0; /** * Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness. * @hide */ public float[] underlineThicknesses; /** * The number of underlines currently stored in the array. If 0, no underline is drawn. * @hide */ public int underlineCount; public float underlineThickness; public TextPaint() { super(); Loading @@ -72,16 +65,8 @@ public class TextPaint extends Paint { linkColor = tp.linkColor; drawableState = tp.drawableState; density = tp.density; if (tp.underlineColors != null) { if (underlineColors == null || underlineColors.length < tp.underlineCount) { underlineColors = new int[tp.underlineCount]; underlineThicknesses = new float[tp.underlineCount]; } System.arraycopy(tp.underlineColors, 0, underlineColors, 0, tp.underlineCount); System.arraycopy(tp.underlineThicknesses, 0, underlineThicknesses, 0, tp.underlineCount); } underlineCount = tp.underlineCount; underlineColor = tp.underlineColor; underlineThickness = tp.underlineThickness; } /** Loading @@ -91,31 +76,7 @@ public class TextPaint extends Paint { * @hide */ public void setUnderlineText(int color, float thickness) { if (color == 0) { // No underline return; } if (underlineCount == 0) { underlineColors = new int[DEFAULT_UNDERLINE_SIZE]; underlineThicknesses = new float[DEFAULT_UNDERLINE_SIZE]; underlineColors[underlineCount] = color; underlineThicknesses[underlineCount] = thickness; underlineCount++; } else { if (underlineCount == underlineColors.length) { int[] newColors = new int[underlineColors.length + DEFAULT_UNDERLINE_SIZE]; float[] newThickness = new float[underlineThicknesses.length + DEFAULT_UNDERLINE_SIZE]; System.arraycopy(underlineColors, 0, newColors, 0, underlineColors.length); System.arraycopy( underlineThicknesses, 0, newThickness, 0, underlineThicknesses.length); underlineColors = newColors; underlineThicknesses = newThickness; } underlineColors[underlineCount] = color; underlineThicknesses[underlineCount] = thickness; underlineCount++; } underlineColor = color; underlineThickness = thickness; } }
core/java/android/text/style/SuggestionSpan.java +21 −7 Original line number Diff line number Diff line Loading @@ -108,7 +108,8 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { /** * @param context Context for the application * @param locale locale Locale of the suggestions * @param suggestions Suggestions for the string under the span * @param suggestions Suggestions for the string under the span. Only the first up to * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered. * @param flags Additional flags indicating how this span is handled in TextView * @param notificationTargetClass if not null, this class will get notified when the user * selects one of the suggestions. Loading Loading @@ -258,10 +259,16 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { @Override public void updateDrawState(TextPaint tp) { if ((mFlags & FLAG_MISSPELLED) != 0) { tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness); } else if ((mFlags & FLAG_EASY_CORRECT) != 0) { final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0; final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0; if (easy) { if (!misspelled) { tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness); } else if (tp.underlineColor == 0) { // Spans are rendered in an arbitrary order. Since misspelled is less prioritary // than just easy, do not apply misspelled if an easy (or a mispelled) has been set tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness); } } } Loading @@ -272,8 +279,15 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { */ public int getUnderlineColor() { // The order here should match what is used in updateDrawState if ((mFlags & FLAG_MISSPELLED) != 0) return mMisspelledUnderlineColor; if ((mFlags & FLAG_EASY_CORRECT) != 0) return mEasyCorrectUnderlineColor; final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0; final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0; if (easy) { if (!misspelled) { return mEasyCorrectUnderlineColor; } else { return mMisspelledUnderlineColor; } } return 0; } }
core/java/android/widget/TextView.java +30 −13 Original line number Diff line number Diff line Loading @@ -9560,6 +9560,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mNumberOfSuggestions; private boolean mCursorWasVisibleBeforeSuggestions; private SuggestionAdapter mSuggestionsAdapter; private final Comparator<SuggestionSpan> mSuggestionSpanComparator; private final HashMap<SuggestionSpan, Integer> mSpansLengths; private class CustomPopupWindow extends PopupWindow { public CustomPopupWindow(Context context, int defStyle) { Loading @@ -9585,6 +9588,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public SuggestionsPopupWindow() { mCursorWasVisibleBeforeSuggestions = mCursorVisible; mSuggestionSpanComparator = new SuggestionSpanComparator(); mSpansLengths = new HashMap<SuggestionSpan, Integer>(); } @Override Loading Loading @@ -9663,6 +9668,26 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } private class SuggestionSpanComparator implements Comparator<SuggestionSpan> { public int compare(SuggestionSpan span1, SuggestionSpan span2) { final int flag1 = span1.getFlags(); final int flag2 = span2.getFlags(); if (flag1 != flag2) { // The order here should match what is used in updateDrawState final boolean easy1 = (flag1 & SuggestionSpan.FLAG_EASY_CORRECT) != 0; final boolean easy2 = (flag2 & SuggestionSpan.FLAG_EASY_CORRECT) != 0; final boolean misspelled1 = (flag1 & SuggestionSpan.FLAG_MISSPELLED) != 0; final boolean misspelled2 = (flag2 & SuggestionSpan.FLAG_MISSPELLED) != 0; if (easy1 && !misspelled1) return -1; if (easy2 && !misspelled2) return 1; if (misspelled1) return -1; if (misspelled2) return 1; } return mSpansLengths.get(span1).intValue() - mSpansLengths.get(span2).intValue(); } } /** * Returns the suggestion spans that cover the current cursor position. The suggestion * spans are sorted according to the length of text that they are attached to. Loading @@ -9672,24 +9697,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Spannable spannable = (Spannable) TextView.this.mText; SuggestionSpan[] suggestionSpans = spannable.getSpans(pos, pos, SuggestionSpan.class); // Cache the span length for performance reason. final HashMap<SuggestionSpan, Integer> spansLengths = new HashMap<SuggestionSpan, Integer>(); mSpansLengths.clear(); for (SuggestionSpan suggestionSpan : suggestionSpans) { int start = spannable.getSpanStart(suggestionSpan); int end = spannable.getSpanEnd(suggestionSpan); spansLengths.put(suggestionSpan, Integer.valueOf(end - start)); } // The suggestions are sorted according to the lenght of the text that they cover // (shorter first) Arrays.sort(suggestionSpans, new Comparator<SuggestionSpan>() { public int compare(SuggestionSpan span1, SuggestionSpan span2) { return spansLengths.get(span1).intValue() - spansLengths.get(span2).intValue(); mSpansLengths.put(suggestionSpan, Integer.valueOf(end - start)); } }); // The suggestions are sorted according to their types (easy correction first, then // misspelled) and to the length of the text that they cover (shorter first). Arrays.sort(suggestionSpans, mSuggestionSpanComparator); return suggestionSpans; } Loading