Skip to content

Commit 287d6c6

Browse files
author
Gilles Debunne
committed
Bug 5250788: LatinIME slows down as amount of Text increases
Removed unnecessary CharSequenceIterator and made the WordIterator work on String instead of CharSequence Submit words to the spell checker by batches. Refactored WordIterator to make it intrinsically local. Change-Id: Ie9e30691985a130fa55cd052005ddb22a21761cb
1 parent e0f2515 commit 287d6c6

File tree

5 files changed

+276
-355
lines changed

5 files changed

+276
-355
lines changed

core/java/android/text/CharSequenceIterator.java

Lines changed: 0 additions & 100 deletions
This file was deleted.

core/java/android/text/method/ArrowKeyMovementMethod.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ private static boolean isSelecting(Spannable buffer) {
3535
(MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SELECTING) != 0));
3636
}
3737

38-
private int getCurrentLineTop(Spannable buffer, Layout layout) {
38+
private static int getCurrentLineTop(Spannable buffer, Layout layout) {
3939
return layout.getLineTop(layout.getLineForOffset(Selection.getSelectionEnd(buffer)));
4040
}
4141

42-
private int getPageHeight(TextView widget) {
42+
private static int getPageHeight(TextView widget) {
4343
// This calculation does not take into account the view transformations that
4444
// may have been applied to the child or its containers. In case of scaling or
4545
// rotation, the calculated page height may be incorrect.
@@ -196,14 +196,16 @@ protected boolean lineEnd(TextView widget, Spannable buffer) {
196196
/** {@hide} */
197197
@Override
198198
protected boolean leftWord(TextView widget, Spannable buffer) {
199-
mWordIterator.setCharSequence(buffer);
199+
final int selectionEnd = widget.getSelectionEnd();
200+
mWordIterator.setCharSequence(buffer, selectionEnd, selectionEnd);
200201
return Selection.moveToPreceding(buffer, mWordIterator, isSelecting(buffer));
201202
}
202203

203204
/** {@hide} */
204205
@Override
205206
protected boolean rightWord(TextView widget, Spannable buffer) {
206-
mWordIterator.setCharSequence(buffer);
207+
final int selectionEnd = widget.getSelectionEnd();
208+
mWordIterator.setCharSequence(buffer, selectionEnd, selectionEnd);
207209
return Selection.moveToFollowing(buffer, mWordIterator, isSelecting(buffer));
208210
}
209211

core/java/android/text/method/WordIterator.java

Lines changed: 53 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,9 @@
1717

1818
package android.text.method;
1919

20-
import android.text.CharSequenceIterator;
21-
import android.text.Editable;
2220
import android.text.Selection;
23-
import android.text.Spanned;
24-
import android.text.TextWatcher;
2521

2622
import java.text.BreakIterator;
27-
import java.text.CharacterIterator;
2823
import java.util.Locale;
2924

3025
/**
@@ -36,8 +31,11 @@
3631
* {@hide}
3732
*/
3833
public class WordIterator implements Selection.PositionIterator {
39-
private CharSequence mCurrent;
40-
private boolean mCurrentDirty = false;
34+
// Size of the window for the word iterator, should be greater than the longest word's length
35+
private static final int WINDOW_WIDTH = 50;
36+
37+
private String mString;
38+
private int mOffsetShift;
4139

4240
private BreakIterator mIterator;
4341

@@ -56,70 +54,40 @@ public WordIterator(Locale locale) {
5654
mIterator = BreakIterator.getWordInstance(locale);
5755
}
5856

59-
private final TextWatcher mWatcher = new TextWatcher() {
60-
/** {@inheritDoc} */
61-
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
62-
// ignored
63-
}
64-
65-
/** {@inheritDoc} */
66-
public void onTextChanged(CharSequence s, int start, int before, int count) {
67-
mCurrentDirty = true;
68-
}
69-
70-
/** {@inheritDoc} */
71-
public void afterTextChanged(Editable s) {
72-
// ignored
73-
}
74-
};
75-
76-
public void setCharSequence(CharSequence incoming) {
77-
// When incoming is different object, move listeners to new sequence
78-
// and mark as dirty so we reload contents.
79-
if (mCurrent != incoming) {
80-
if (mCurrent instanceof Editable) {
81-
((Editable) mCurrent).removeSpan(mWatcher);
82-
}
57+
public void setCharSequence(CharSequence charSequence, int start, int end) {
58+
mOffsetShift = Math.max(0, start - WINDOW_WIDTH);
59+
final int windowEnd = Math.min(charSequence.length(), end + WINDOW_WIDTH);
8360

84-
if (incoming instanceof Editable) {
85-
((Editable) incoming).setSpan(
86-
mWatcher, 0, incoming.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
87-
}
88-
89-
mCurrent = incoming;
90-
mCurrentDirty = true;
91-
}
92-
93-
if (mCurrentDirty) {
94-
final CharacterIterator charIterator = new CharSequenceIterator(mCurrent);
95-
mIterator.setText(charIterator);
96-
97-
mCurrentDirty = false;
98-
}
61+
mString = charSequence.toString().substring(mOffsetShift, windowEnd);
62+
mIterator.setText(mString);
9963
}
10064

10165
/** {@inheritDoc} */
10266
public int preceding(int offset) {
67+
int shiftedOffset = offset - mOffsetShift;
10368
do {
104-
offset = mIterator.preceding(offset);
105-
if (offset == BreakIterator.DONE || isOnLetterOrDigit(offset)) {
106-
break;
69+
shiftedOffset = mIterator.preceding(shiftedOffset);
70+
if (shiftedOffset == BreakIterator.DONE) {
71+
return BreakIterator.DONE;
72+
}
73+
if (isOnLetterOrDigit(shiftedOffset)) {
74+
return shiftedOffset + mOffsetShift;
10775
}
10876
} while (true);
109-
110-
return offset;
11177
}
11278

11379
/** {@inheritDoc} */
11480
public int following(int offset) {
81+
int shiftedOffset = offset - mOffsetShift;
11582
do {
116-
offset = mIterator.following(offset);
117-
if (offset == BreakIterator.DONE || isAfterLetterOrDigit(offset)) {
118-
break;
83+
shiftedOffset = mIterator.following(shiftedOffset);
84+
if (shiftedOffset == BreakIterator.DONE) {
85+
return BreakIterator.DONE;
86+
}
87+
if (isAfterLetterOrDigit(shiftedOffset)) {
88+
return shiftedOffset + mOffsetShift;
11989
}
12090
} while (true);
121-
122-
return offset;
12391
}
12492

12593
/** If <code>offset</code> is within a word, returns the index of the first character of that
@@ -135,17 +103,18 @@ public int following(int offset) {
135103
* @throws IllegalArgumentException is offset is not valid.
136104
*/
137105
public int getBeginning(int offset) {
138-
checkOffsetIsValid(offset);
106+
final int shiftedOffset = offset - mOffsetShift;
107+
checkOffsetIsValid(shiftedOffset);
139108

140-
if (isOnLetterOrDigit(offset)) {
141-
if (mIterator.isBoundary(offset)) {
142-
return offset;
109+
if (isOnLetterOrDigit(shiftedOffset)) {
110+
if (mIterator.isBoundary(shiftedOffset)) {
111+
return shiftedOffset + mOffsetShift;
143112
} else {
144-
return mIterator.preceding(offset);
113+
return mIterator.preceding(shiftedOffset) + mOffsetShift;
145114
}
146115
} else {
147-
if (isAfterLetterOrDigit(offset)) {
148-
return mIterator.preceding(offset);
116+
if (isAfterLetterOrDigit(shiftedOffset)) {
117+
return mIterator.preceding(shiftedOffset) + mOffsetShift;
149118
}
150119
}
151120
return BreakIterator.DONE;
@@ -164,58 +133,44 @@ public int getBeginning(int offset) {
164133
* @throws IllegalArgumentException is offset is not valid.
165134
*/
166135
public int getEnd(int offset) {
167-
checkOffsetIsValid(offset);
136+
final int shiftedOffset = offset - mOffsetShift;
137+
checkOffsetIsValid(shiftedOffset);
168138

169-
if (isAfterLetterOrDigit(offset)) {
170-
if (mIterator.isBoundary(offset)) {
171-
return offset;
139+
if (isAfterLetterOrDigit(shiftedOffset)) {
140+
if (mIterator.isBoundary(shiftedOffset)) {
141+
return shiftedOffset + mOffsetShift;
172142
} else {
173-
return mIterator.following(offset);
143+
return mIterator.following(shiftedOffset) + mOffsetShift;
174144
}
175145
} else {
176-
if (isOnLetterOrDigit(offset)) {
177-
return mIterator.following(offset);
146+
if (isOnLetterOrDigit(shiftedOffset)) {
147+
return mIterator.following(shiftedOffset) + mOffsetShift;
178148
}
179149
}
180150
return BreakIterator.DONE;
181151
}
182152

183-
private boolean isAfterLetterOrDigit(int offset) {
184-
if (offset - 1 >= 0) {
185-
final char previousChar = mCurrent.charAt(offset - 1);
186-
if (Character.isLetterOrDigit(previousChar)) return true;
187-
if (offset - 2 >= 0) {
188-
final char previousPreviousChar = mCurrent.charAt(offset - 2);
189-
if (Character.isSurrogatePair(previousPreviousChar, previousChar)) {
190-
final int codePoint = Character.toCodePoint(previousPreviousChar, previousChar);
191-
return Character.isLetterOrDigit(codePoint);
192-
}
193-
}
153+
private boolean isAfterLetterOrDigit(int shiftedOffset) {
154+
if (shiftedOffset >= 1 && shiftedOffset <= mString.length()) {
155+
final int codePoint = mString.codePointBefore(shiftedOffset);
156+
if (Character.isLetterOrDigit(codePoint)) return true;
194157
}
195158
return false;
196159
}
197160

198-
private boolean isOnLetterOrDigit(int offset) {
199-
final int length = mCurrent.length();
200-
if (offset < length) {
201-
final char currentChar = mCurrent.charAt(offset);
202-
if (Character.isLetterOrDigit(currentChar)) return true;
203-
if (offset + 1 < length) {
204-
final char nextChar = mCurrent.charAt(offset + 1);
205-
if (Character.isSurrogatePair(currentChar, nextChar)) {
206-
final int codePoint = Character.toCodePoint(currentChar, nextChar);
207-
return Character.isLetterOrDigit(codePoint);
208-
}
209-
}
161+
private boolean isOnLetterOrDigit(int shiftedOffset) {
162+
if (shiftedOffset >= 0 && shiftedOffset < mString.length()) {
163+
final int codePoint = mString.codePointAt(shiftedOffset);
164+
if (Character.isLetterOrDigit(codePoint)) return true;
210165
}
211166
return false;
212167
}
213168

214-
private void checkOffsetIsValid(int offset) {
215-
if (offset < 0 || offset > mCurrent.length()) {
216-
final String message = "Invalid offset: " + offset +
217-
". Valid range is [0, " + mCurrent.length() + "]";
218-
throw new IllegalArgumentException(message);
169+
private void checkOffsetIsValid(int shiftedOffset) {
170+
if (shiftedOffset < 0 || shiftedOffset > mString.length()) {
171+
throw new IllegalArgumentException("Invalid offset: " + (shiftedOffset + mOffsetShift) +
172+
". Valid range is [" + mOffsetShift + ", " + (mString.length() + mOffsetShift) +
173+
"]");
219174
}
220175
}
221176
}

0 commit comments

Comments
 (0)