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:
Gilles Debunne
2011-09-09 09:20:12 -07:00
parent 5132273273
commit c9fd978da6
4 changed files with 61 additions and 72 deletions

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}