diff options
author | Keisuke Kuroyanagi <ksk@google.com> | 2015-04-24 18:55:56 +0900 |
---|---|---|
committer | Keisuke Kuroyanagi <ksk@google.com> | 2015-04-28 20:46:08 +0900 |
commit | 9c68b29c22a95270879f1552dec4182e8e118411 (patch) | |
tree | 6d5845415feac6ccfa18d92cea9e65d5891b7c6f /core/java | |
parent | e48cca2a20668951254e980ac9284cd3492280ba (diff) | |
download | frameworks_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.java | 38 |
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); } |