Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c68b29c authored by Keisuke Kuroyanagi's avatar Keisuke Kuroyanagi
Browse files

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
parent e48cca2a
Loading
Loading
Loading
Loading
+17 −21
Original line number Original line Diff line number Diff line
@@ -813,7 +813,7 @@ public class Editor {
            if (selectionStart == BreakIterator.DONE || selectionEnd == BreakIterator.DONE ||
            if (selectionStart == BreakIterator.DONE || selectionEnd == BreakIterator.DONE ||
                    selectionStart == selectionEnd) {
                    selectionStart == selectionEnd) {
                // Possible when the word iterator does not properly handle the text's language
                // 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);
                selectionStart = TextUtils.unpackRangeStartFromLong(range);
                selectionEnd = TextUtils.unpackRangeEndFromLong(range);
                selectionEnd = TextUtils.unpackRangeEndFromLong(range);
            }
            }
@@ -856,27 +856,23 @@ public class Editor {
        return mWordIteratorWithText;
        return mWordIteratorWithText;
    }
    }


    private long getCharRange(int offset) {
    private int getNextCursorOffset(int offset, boolean findAfterGivenOffset) {
        final int textLength = mTextView.getText().length();
        final Layout layout = mTextView.getLayout();
        if (offset + 1 < textLength) {
        if (layout == null) return offset;
            final char currentChar = mTextView.getText().charAt(offset);
        final CharSequence text = mTextView.getText();
            final char nextChar = mTextView.getText().charAt(offset + 1);
        final int nextOffset = layout.getPaint().getTextRunCursor(text, 0, text.length(),
            if (Character.isSurrogatePair(currentChar, nextChar)) {
                layout.isRtlCharAt(offset) ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR,
                return TextUtils.packRangeInLong(offset,  offset + 2);
                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 < textLength) {
        if (offset < textLength) {
            return TextUtils.packRangeInLong(offset,  offset + 1);
            return TextUtils.packRangeInLong(offset, getNextCursorOffset(offset, true));
        }
        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);
            }
        }
        }
        if (offset - 1 >= 0) {
        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);
    }
    }
@@ -3972,7 +3968,7 @@ public class Editor {
                    int alteredOffset = mTextView.getOffsetAtCoordinate(mPrevLine, x);
                    int alteredOffset = mTextView.getOffsetAtCoordinate(mPrevLine, x);
                    if (alteredOffset >= selectionEnd) {
                    if (alteredOffset >= selectionEnd) {
                        // Can't pass the other drag handle.
                        // Can't pass the other drag handle.
                        offset = Math.max(0, selectionEnd - 1);
                        offset = getNextCursorOffset(selectionEnd, false);
                    } else {
                    } else {
                        offset = alteredOffset;
                        offset = alteredOffset;
                    }
                    }
@@ -4075,7 +4071,7 @@ public class Editor {
                    int length = mTextView.getText().length();
                    int length = mTextView.getText().length();
                    if (alteredOffset <= selectionStart) {
                    if (alteredOffset <= selectionStart) {
                        // Can't pass the other drag handle.
                        // Can't pass the other drag handle.
                        offset = Math.min(selectionStart + 1, length);
                        offset = getNextCursorOffset(selectionStart, true);
                    } else {
                    } else {
                        offset = Math.min(alteredOffset, length);
                        offset = Math.min(alteredOffset, length);
                    }
                    }