summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorGilles Debunne <debunne@google.com>2011-09-28 18:51:23 -0700
committerGilles Debunne <debunne@google.com>2011-09-28 19:04:30 -0700
commitd5ea0a1bc2fae7c6084b0c5cc9b68a925a0f50f6 (patch)
tree16dd95503193a82e267a4af83b2483fcf2844381 /core
parentb062e81e3a16af43db3619d721aa522c137d1aa9 (diff)
downloadframeworks_base-d5ea0a1bc2fae7c6084b0c5cc9b68a925a0f50f6.zip
frameworks_base-d5ea0a1bc2fae7c6084b0c5cc9b68a925a0f50f6.tar.gz
frameworks_base-d5ea0a1bc2fae7c6084b0c5cc9b68a925a0f50f6.tar.bz2
Bug 5250788: EditText gets slower has the entered text gets longer
Profiling showed that the bottle neck was in the word iterator. Now initializing the word iteerator to only a window around the region of interest to reduce the text analysis. Change-Id: Ibfa4952cbf52a1b36726f965143ac7a6dc63673e
Diffstat (limited to 'core')
-rw-r--r--core/java/android/text/method/WordIterator.java4
-rw-r--r--core/java/android/widget/TextView.java60
2 files changed, 32 insertions, 32 deletions
diff --git a/core/java/android/text/method/WordIterator.java b/core/java/android/text/method/WordIterator.java
index 0433ec4..af524ee 100644
--- a/core/java/android/text/method/WordIterator.java
+++ b/core/java/android/text/method/WordIterator.java
@@ -73,10 +73,6 @@ public class WordIterator implements Selection.PositionIterator {
}
};
- public void forceUpdate() {
- mCurrentDirty = true;
- }
-
public void setCharSequence(CharSequence incoming) {
// When incoming is different object, move listeners to new sequence
// and mark as dirty so we reload contents.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 8af22dc..1c5ad0e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7609,9 +7609,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
sendOnTextChanged(buffer, start, before, after);
onTextChanged(buffer, start, before, after);
- // The WordIterator text change listener may be called after this one.
- // Make sure this changed text is rescanned before the iterator is used on it.
- getWordIterator().forceUpdate();
updateSpellCheckSpans(start, start + after);
// Hide the controllers if the amount of content changed
@@ -7745,21 +7742,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private void updateSpellCheckSpans(int start, int end) {
if (!isTextEditable() || !isSuggestionsEnabled() || !getSpellChecker().isSessionActive())
return;
-
Editable text = (Editable) mText;
- WordIterator wordIterator = getWordIterator();
- wordIterator.setCharSequence(text);
+
+ final int shift = prepareWordIterator(start, end);
+ final int shiftedStart = start - shift;
+ final int shiftedEnd = end - shift;
// Move back to the beginning of the current word, if any
- int wordStart = wordIterator.preceding(start);
+ int wordStart = mWordIterator.preceding(shiftedStart);
int wordEnd;
if (wordStart == BreakIterator.DONE) {
- wordEnd = wordIterator.following(start);
+ wordEnd = mWordIterator.following(shiftedStart);
if (wordEnd != BreakIterator.DONE) {
- wordStart = wordIterator.getBeginning(wordEnd);
+ wordStart = mWordIterator.getBeginning(wordEnd);
}
} else {
- wordEnd = wordIterator.getEnd(wordStart);
+ wordEnd = mWordIterator.getEnd(wordStart);
}
if (wordEnd == BreakIterator.DONE) {
return;
@@ -7772,22 +7770,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int numberOfSpellCheckSpans = spellCheckSpans.length;
// Iterate over the newly added text and schedule new SpellCheckSpans
- while (wordStart <= end) {
- if (wordEnd >= start) {
+ while (wordStart <= shiftedEnd) {
+ if (wordEnd >= shiftedStart) {
// A new word has been created across the interval boundaries. Remove previous spans
- if (wordStart < start && wordEnd > start) {
+ if (wordStart < shiftedStart && wordEnd > shiftedStart) {
removeSpansAt(start, spellCheckSpans, text);
removeSpansAt(start, suggestionSpans, text);
}
- if (wordStart < end && wordEnd > end) {
+ if (wordStart < shiftedEnd && wordEnd > shiftedEnd) {
removeSpansAt(end, spellCheckSpans, text);
removeSpansAt(end, suggestionSpans, text);
}
// Do not create new boundary spans if they already exist
boolean createSpellCheckSpan = true;
- if (wordEnd == start) {
+ if (wordEnd == shiftedStart) {
for (int i = 0; i < numberOfSpellCheckSpans; i++) {
final int spanEnd = text.getSpanEnd(spellCheckSpans[i]);
if (spanEnd == start) {
@@ -7797,9 +7795,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- if (wordStart == end) {
+ if (wordStart == shiftedEnd) {
for (int i = 0; i < numberOfSpellCheckSpans; i++) {
- final int spanStart = text.getSpanEnd(spellCheckSpans[i]);
+ final int spanStart = text.getSpanStart(spellCheckSpans[i]);
if (spanStart == end) {
createSpellCheckSpan = false;
break;
@@ -7808,16 +7806,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
if (createSpellCheckSpan) {
- mSpellChecker.addSpellCheckSpan(wordStart, wordEnd);
+ mSpellChecker.addSpellCheckSpan(wordStart + shift, wordEnd + shift);
}
}
// iterate word by word
- wordEnd = wordIterator.following(wordEnd);
+ wordEnd = mWordIterator.following(wordEnd);
if (wordEnd == BreakIterator.DONE) break;
- wordStart = wordIterator.getBeginning(wordEnd);
+ wordStart = mWordIterator.getBeginning(wordEnd);
if (wordStart == BreakIterator.DONE) {
- Log.e(LOG_TAG, "Unable to find word beginning from " + wordEnd + "in " + mText);
+ Log.e(LOG_TAG, "No word beginning from " + (wordEnd + shift) + "in " + mText);
break;
}
}
@@ -8941,26 +8939,32 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
selectionStart = ((Spanned) mText).getSpanStart(url);
selectionEnd = ((Spanned) mText).getSpanEnd(url);
} else {
- WordIterator wordIterator = getWordIterator();
- // WordIterator handles text changes, this is a no-op if text in unchanged.
- wordIterator.setCharSequence(mText);
+ final int shift = prepareWordIterator(minOffset, maxOffset);
- selectionStart = wordIterator.getBeginning(minOffset);
+ selectionStart = mWordIterator.getBeginning(minOffset - shift);
if (selectionStart == BreakIterator.DONE) return false;
+ selectionStart += shift;
- selectionEnd = wordIterator.getEnd(maxOffset);
+ selectionEnd = mWordIterator.getEnd(maxOffset - shift);
if (selectionEnd == BreakIterator.DONE) return false;
+ selectionEnd += shift;
}
Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
return true;
}
- WordIterator getWordIterator() {
+ int prepareWordIterator(int start, int end) {
if (mWordIterator == null) {
mWordIterator = new WordIterator();
}
- return mWordIterator;
+
+ final int TEXT_WINDOW_WIDTH = 50; // Should be larger than the longest word's length
+ final int windowStart = Math.max(0, start - TEXT_WINDOW_WIDTH);
+ final int windowEnd = Math.min(mText.length(), end + TEXT_WINDOW_WIDTH);
+ mWordIterator.setCharSequence(mText.subSequence(windowStart, windowEnd));
+
+ return windowStart;
}
private SpellChecker getSpellChecker() {