Skip to content

Commit 8615ac9

Browse files
author
Gilles Debunne
committed
Invalidated bounds tightened in TextView
New invalidateRegion method, with better horizontal invalidate bounds in case the region is on one line. Use by SpellChecker when a new SuggestionSpan is added. Change-Id: Ide11f1d3d2b1350032b475db0641018a49c08d13
1 parent 9b518d9 commit 8615ac9

File tree

2 files changed

+48
-39
lines changed

2 files changed

+48
-39
lines changed

core/java/android/widget/SpellChecker.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,11 @@ public void onGetSuggestions(SuggestionsInfo[] results) {
258258
((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0);
259259

260260
SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j];
261+
261262
if (!isInDictionary && looksLikeTypo) {
262263
createMisspelledSuggestionSpan(editable, suggestionsInfo, spellCheckSpan);
263264
}
265+
264266
editable.removeSpan(spellCheckSpan);
265267
break;
266268
}
@@ -276,20 +278,21 @@ public void onGetSuggestions(SuggestionsInfo[] results) {
276278
}
277279
}
278280

279-
private void createMisspelledSuggestionSpan(Editable editable,
280-
SuggestionsInfo suggestionsInfo, SpellCheckSpan spellCheckSpan) {
281+
private void createMisspelledSuggestionSpan(Editable editable, SuggestionsInfo suggestionsInfo,
282+
SpellCheckSpan spellCheckSpan) {
281283
final int start = editable.getSpanStart(spellCheckSpan);
282284
final int end = editable.getSpanEnd(spellCheckSpan);
283-
if (start < 0 || end < 0) return; // span was removed in the meantime
285+
if (start < 0 || end <= start) return; // span was removed in the meantime
284286

285287
// Other suggestion spans may exist on that region, with identical suggestions, filter
286-
// them out to avoid duplicates. First, filter suggestion spans on that exact region.
288+
// them out to avoid duplicates.
287289
SuggestionSpan[] suggestionSpans = editable.getSpans(start, end, SuggestionSpan.class);
288290
final int length = suggestionSpans.length;
289291
for (int i = 0; i < length; i++) {
290292
final int spanStart = editable.getSpanStart(suggestionSpans[i]);
291293
final int spanEnd = editable.getSpanEnd(suggestionSpans[i]);
292294
if (spanStart != start || spanEnd != end) {
295+
// Nulled (to avoid new array allocation) if not on that exact same region
293296
suggestionSpans[i] = null;
294297
}
295298
}
@@ -337,8 +340,7 @@ private void createMisspelledSuggestionSpan(Editable editable,
337340
SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED);
338341
editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
339342

340-
// TODO limit to the word rectangle region
341-
mTextView.invalidate();
343+
mTextView.invalidateRegion(start, end);
342344
}
343345

344346
private class SpellParser {

core/java/android/widget/TextView.java

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4313,52 +4313,61 @@ private void invalidateCursor() {
43134313
}
43144314

43154315
private void invalidateCursor(int a, int b, int c) {
4316+
if (a >= 0 || b >= 0 || c >= 0) {
4317+
int start = Math.min(Math.min(a, b), c);
4318+
int end = Math.max(Math.max(a, b), c);
4319+
invalidateRegion(start, end);
4320+
}
4321+
}
4322+
4323+
/**
4324+
* Invalidates the region of text enclosed between the start and end text offsets.
4325+
*
4326+
* @hide
4327+
*/
4328+
void invalidateRegion(int start, int end) {
43164329
if (mLayout == null) {
43174330
invalidate();
43184331
} else {
4319-
if (a >= 0 || b >= 0 || c >= 0) {
4320-
int first = Math.min(Math.min(a, b), c);
4321-
int last = Math.max(Math.max(a, b), c);
4322-
4323-
int line = mLayout.getLineForOffset(first);
4324-
int top = mLayout.getLineTop(line);
4332+
int lineStart = mLayout.getLineForOffset(start);
4333+
int top = mLayout.getLineTop(lineStart);
43254334

43264335
// This is ridiculous, but the descent from the line above
43274336
// can hang down into the line we really want to redraw,
43284337
// so we have to invalidate part of the line above to make
43294338
// sure everything that needs to be redrawn really is.
43304339
// (But not the whole line above, because that would cause
43314340
// the same problem with the descenders on the line above it!)
4332-
if (line > 0) {
4333-
top -= mLayout.getLineDescent(line - 1);
4341+
if (lineStart > 0) {
4342+
top -= mLayout.getLineDescent(lineStart - 1);
43344343
}
43354344

4336-
int line2;
4345+
int lineEnd;
43374346

4338-
if (first == last)
4339-
line2 = line;
4347+
if (start == end)
4348+
lineEnd = lineStart;
43404349
else
4341-
line2 = mLayout.getLineForOffset(last);
4350+
lineEnd = mLayout.getLineForOffset(end);
43424351

4343-
int bottom = mLayout.getLineTop(line2 + 1);
4352+
int bottom = mLayout.getLineBottom(lineEnd);
43444353

4345-
final int horizontalPadding = getCompoundPaddingLeft();
4354+
final int compoundPaddingLeft = getCompoundPaddingLeft();
43464355
final int verticalPadding = getExtendedPaddingTop() + getVerticalOffset(true);
4347-
4348-
// If used, the cursor drawables can have an arbitrary dimension that can go beyond
4349-
// the invalidated lines specified above.
4350-
for (int i = 0; i < mCursorCount; i++) {
4351-
Rect bounds = mCursorDrawable[i].getBounds();
4352-
top = Math.min(top, bounds.top);
4353-
bottom = Math.max(bottom, bounds.bottom);
4354-
// Horizontal bounds are already full width, no need to update
4356+
4357+
int left, right;
4358+
if (lineStart == lineEnd) {
4359+
left = (int) mLayout.getPrimaryHorizontal(start);
4360+
right = (int) (mLayout.getPrimaryHorizontal(end) + 1.0);
4361+
left += compoundPaddingLeft;
4362+
right += compoundPaddingLeft;
4363+
} else {
4364+
// Rectangle bounding box when the region spans several lines
4365+
left = compoundPaddingLeft;
4366+
right = getWidth() - getCompoundPaddingRight();
43554367
}
43564368

4357-
invalidate(horizontalPadding + mScrollX, top + verticalPadding,
4358-
horizontalPadding + mScrollX + getWidth() -
4359-
getCompoundPaddingLeft() - getCompoundPaddingRight(),
4360-
bottom + verticalPadding);
4361-
}
4369+
invalidate(mScrollX + left, verticalPadding + top,
4370+
mScrollX + right, verticalPadding + bottom);
43624371
}
43634372
}
43644373

@@ -5893,10 +5902,10 @@ public void draw(Canvas canvas, int cursorOffsetVertical) {
58935902
if (cursorOffsetVertical != 0) {
58945903
canvas.translate(0, -cursorOffsetVertical);
58955904
}
5896-
invalidate(true);
5905+
invalidate(true); // TODO invalidate cursor region only
58975906
} else {
58985907
stopAnimation();
5899-
invalidate(false);
5908+
invalidate(false); // TODO invalidate cursor region only
59005909
}
59015910
}
59025911

@@ -7716,10 +7725,8 @@ void spanChange(Spanned buf, Object what, int oldStart, int newStart, int oldEnd
77167725
onSelectionChanged(newSelStart, newSelEnd);
77177726
}
77187727
}
7719-
7720-
if (what instanceof UpdateAppearance || what instanceof ParagraphStyle
7721-
|| (what instanceof SuggestionSpan && (((SuggestionSpan)what).getFlags()
7722-
& SuggestionSpan.FLAG_AUTO_CORRECTION) != 0)) {
7728+
7729+
if (what instanceof UpdateAppearance || what instanceof ParagraphStyle) {
77237730
if (ims == null || ims.mBatchEditNesting == 0) {
77247731
invalidate();
77257732
mHighlightPathBogus = true;

0 commit comments

Comments
 (0)