Bug 5281947: add to dictionnary option promoted in suggestions.
When several SuggestionSpans are available at a given position, their content are merged, in creation time order. As a result, the IME's suggestions are picked before the spell check, and no add to dictionnary option is created. This CL modifies the comparator to make easy correction spans appear first (Voice IME), then misspelled words and then regular suggestions. Also avoids the creation of a new comparator and length hash map on every display. Change-Id: I1f9f031a6fdcbbc09f248a192b83051092765f8e
This commit is contained in:
@@ -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,
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -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) {
|
||||
tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9547,6 +9547,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) {
|
||||
@@ -9572,6 +9575,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
|
||||
public SuggestionsPopupWindow() {
|
||||
mCursorWasVisibleBeforeSuggestions = mCursorVisible;
|
||||
mSuggestionSpanComparator = new SuggestionSpanComparator();
|
||||
mSpansLengths = new HashMap<SuggestionSpan, Integer>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -9650,6 +9655,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.
|
||||
@@ -9659,24 +9684,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));
|
||||
mSpansLengths.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();
|
||||
}
|
||||
});
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user