summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
authorKeisuke Kuroyanagi <ksk@google.com>2015-04-24 18:55:56 +0900
committerKeisuke Kuroyanagi <ksk@google.com>2015-04-28 20:46:08 +0900
commit9c68b29c22a95270879f1552dec4182e8e118411 (patch)
tree6d5845415feac6ccfa18d92cea9e65d5891b7c6f /core/java
parente48cca2a20668951254e980ac9284cd3492280ba (diff)
downloadframeworks_base-9c68b29c22a95270879f1552dec4182e8e118411.zip
frameworks_base-9c68b29c22a95270879f1552dec4182e8e118411.tar.gz
frameworks_base-9c68b29c22a95270879f1552dec4182e8e118411.tar.bz2
Fix: A part of grapheme cluster can be selected.
Previously, when a selection handle is about to pass the other handle, the offset of the handle was computed with +1 or -1 to the offset, without considering UTF-16 surrogate pairs or grapheme clusters. This patch consistently uses grapheme clusters to compute the new offset in such cases. Bug: 20112392 Change-Id: I2b5e206d20886ca7ceb9f4375ee0d66f2328f99d
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/widget/Editor.java38
1 files changed, 17 insertions, 21 deletions
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 39b9907..848b556 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -813,7 +813,7 @@ public class Editor {
if (selectionStart == BreakIterator.DONE || selectionEnd == BreakIterator.DONE ||
selectionStart == selectionEnd) {
// Possible when the word iterator does not properly handle the text's language
- long range = getCharRange(minOffset);
+ long range = getCharClusterRange(minOffset);
selectionStart = TextUtils.unpackRangeStartFromLong(range);
selectionEnd = TextUtils.unpackRangeEndFromLong(range);
}
@@ -856,29 +856,25 @@ public class Editor {
return mWordIteratorWithText;
}
- private long getCharRange(int offset) {
+ private int getNextCursorOffset(int offset, boolean findAfterGivenOffset) {
+ final Layout layout = mTextView.getLayout();
+ if (layout == null) return offset;
+ final CharSequence text = mTextView.getText();
+ final int nextOffset = layout.getPaint().getTextRunCursor(text, 0, text.length(),
+ layout.isRtlCharAt(offset) ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR,
+ offset, findAfterGivenOffset ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE);
+ return nextOffset == -1 ? offset : nextOffset;
+ }
+
+ private long getCharClusterRange(int offset) {
final int textLength = mTextView.getText().length();
- if (offset + 1 < textLength) {
- final char currentChar = mTextView.getText().charAt(offset);
- final char nextChar = mTextView.getText().charAt(offset + 1);
- if (Character.isSurrogatePair(currentChar, nextChar)) {
- return TextUtils.packRangeInLong(offset, offset + 2);
- }
- }
if (offset < textLength) {
- return TextUtils.packRangeInLong(offset, offset + 1);
- }
- if (offset - 2 >= 0) {
- final char previousChar = mTextView.getText().charAt(offset - 1);
- final char previousPreviousChar = mTextView.getText().charAt(offset - 2);
- if (Character.isSurrogatePair(previousPreviousChar, previousChar)) {
- return TextUtils.packRangeInLong(offset - 2, offset);
- }
+ return TextUtils.packRangeInLong(offset, getNextCursorOffset(offset, true));
}
if (offset - 1 >= 0) {
- return TextUtils.packRangeInLong(offset - 1, offset);
+ return TextUtils.packRangeInLong(getNextCursorOffset(offset, false), offset);
}
- return TextUtils.packRangeInLong(offset, offset);
+ return TextUtils.packRangeInLong(offset, offset);
}
private boolean touchPositionIsInSelection() {
@@ -3972,7 +3968,7 @@ public class Editor {
int alteredOffset = mTextView.getOffsetAtCoordinate(mPrevLine, x);
if (alteredOffset >= selectionEnd) {
// Can't pass the other drag handle.
- offset = Math.max(0, selectionEnd - 1);
+ offset = getNextCursorOffset(selectionEnd, false);
} else {
offset = alteredOffset;
}
@@ -4075,7 +4071,7 @@ public class Editor {
int length = mTextView.getText().length();
if (alteredOffset <= selectionStart) {
// Can't pass the other drag handle.
- offset = Math.min(selectionStart + 1, length);
+ offset = getNextCursorOffset(selectionStart, true);
} else {
offset = Math.min(alteredOffset, length);
}