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

Commit 5b730ba2 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Emit text direction with selection rectangle"

parents 64b70b7d b92c5392
Loading
Loading
Loading
Loading
+40 −14
Original line number Diff line number Diff line
@@ -1704,7 +1704,7 @@ public abstract class Layout {
    }

    private void addSelection(int line, int start, int end,
            int top, int bottom, RectangleConsumer consumer) {
            int top, int bottom, SelectionRectangleConsumer consumer) {
        int linestart = getLineStart(line);
        int lineend = getLineEnd(line);
        Directions dirs = getLineDirections(line);
@@ -1732,7 +1732,14 @@ public abstract class Layout {
                    float left = Math.min(h1, h2);
                    float right = Math.max(h1, h2);

                    consumer.accept(left, top, right, bottom);
                    final boolean isRtl = (dirs.mDirections[i + 1] & RUN_RTL_FLAG) != 0;
                    if (isRtl) {
                        consumer.accept(left, top, right, bottom,
                                TextSelectionLayout.RIGHT_TO_LEFT);
                    } else {
                        consumer.accept(left, top, right, bottom,
                                TextSelectionLayout.LEFT_TO_RIGHT);
                    }
                }
            }
        }
@@ -1746,22 +1753,22 @@ public abstract class Layout {
     */
    public void getSelectionPath(int start, int end, Path dest) {
        dest.reset();
        getSelection(start, end, (left, top, right, bottom) ->
        getSelection(start, end, (left, top, right, bottom, textSelectionLayout) ->
                dest.addRect(left, top, right, bottom, Path.Direction.CW));
    }

    /**
     * Calculates the rectangles which should be highlighted to indicate a selection between start
     * and end and feeds them into the given {@link RectangleConsumer}.
     * and end and feeds them into the given {@link SelectionRectangleConsumer}.
     *
     * @param start    the starting index of the selection
     * @param end      the ending index of the selection
     * @param consumer the {@link RectangleConsumer} which will receive the generated rectangles. It
     *                 will be called every time a rectangle is generated.
     * @param consumer the {@link SelectionRectangleConsumer} which will receive the generated
     *                 rectangles. It will be called every time a rectangle is generated.
     * @hide
     * @see #getSelectionPath(int, int, Path)
     */
    public final void getSelection(int start, int end, final RectangleConsumer consumer) {
    public final void getSelection(int start, int end, final SelectionRectangleConsumer consumer) {
        if (start == end) {
            return;
        }
@@ -1787,15 +1794,21 @@ public abstract class Layout {
                    top, getLineBottom(startline), consumer);

            if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT) {
                consumer.accept(getLineLeft(startline), top, 0, getLineBottom(startline));
                consumer.accept(getLineLeft(startline), top, 0, getLineBottom(startline),
                        TextSelectionLayout.RIGHT_TO_LEFT);
            } else {
                consumer.accept(getLineRight(startline), top, width, getLineBottom(startline));
                consumer.accept(getLineRight(startline), top, width, getLineBottom(startline),
                        TextSelectionLayout.LEFT_TO_RIGHT);
            }

            for (int i = startline + 1; i < endline; i++) {
                top = getLineTop(i);
                bottom = getLineBottom(i);
                consumer.accept(0, top, width, bottom);
                if (getParagraphDirection(i) == DIR_RIGHT_TO_LEFT) {
                    consumer.accept(0, top, width, bottom, TextSelectionLayout.RIGHT_TO_LEFT);
                } else {
                    consumer.accept(0, top, width, bottom, TextSelectionLayout.LEFT_TO_RIGHT);
                }
            }

            top = getLineTop(endline);
@@ -1804,9 +1817,11 @@ public abstract class Layout {
            addSelection(endline, getLineStart(endline), end, top, bottom, consumer);

            if (getParagraphDirection(endline) == DIR_RIGHT_TO_LEFT) {
                consumer.accept(width, top, getLineRight(endline), bottom);
                consumer.accept(width, top, getLineRight(endline), bottom,
                        TextSelectionLayout.RIGHT_TO_LEFT);
            } else {
                consumer.accept(0, top, getLineLeft(endline), bottom);
                consumer.accept(0, top, getLineLeft(endline), bottom,
                        TextSelectionLayout.LEFT_TO_RIGHT);
            }
        }
    }
@@ -2309,9 +2324,17 @@ public abstract class Layout {
    public static final Directions DIRS_ALL_RIGHT_TO_LEFT =
        new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG });

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({TextSelectionLayout.RIGHT_TO_LEFT, TextSelectionLayout.LEFT_TO_RIGHT})
    public @interface TextSelectionLayout {
        int RIGHT_TO_LEFT = 0;
        int LEFT_TO_RIGHT = 1;
    }

    /** @hide */
    @FunctionalInterface
    public interface RectangleConsumer {
    public interface SelectionRectangleConsumer {
        /**
         * Performs this operation on the given rectangle.
         *
@@ -2319,8 +2342,11 @@ public abstract class Layout {
         * @param top    the top edge of the rectangle
         * @param right  the right edge of the rectangle
         * @param bottom the bottom edge of the rectangle
         * @param textSelectionLayout the layout (RTL or LTR) of the text covered by this
         *                            selection rectangle
         */
        void accept(float left, float top, float right, float bottom);
        void accept(float left, float top, float right, float bottom,
                @TextSelectionLayout int textSelectionLayout);
    }

}
+1 −1
Original line number Diff line number Diff line
@@ -265,7 +265,7 @@ final class SelectionActionModeHelper {
        // TODO filter out invalid rectangles
        // getSelection might give us overlapping and zero-dimension rectangles which will interfere
        // with the Smart Select animation
        layout.getSelection(start, end, (left, top, right, bottom) ->
        layout.getSelection(start, end, (left, top, right, bottom, textSelectionLayout) ->
                result.add(new RectF(left, top, right, bottom)));

        result.sort(SmartSelectSprite.RECTANGLE_COMPARATOR);
+48 −5
Original line number Diff line number Diff line
@@ -299,7 +299,8 @@ public class LayoutTest {
         */

        layout.getSelection(5 /* startIndex */, 5 /* endIndex */,
                (left, top, right, bottom) -> fail(String.format(Locale.getDefault(),
                (left, top, right, bottom, textSelectionLayout) -> fail(
                        String.format(Locale.getDefault(),
                        "Did not expect any rectangles, got a rectangle with (left: %f,"
                                + " top: %f), (right: %f, bottom: %f)",
                        left, top, right, bottom)));
@@ -313,7 +314,8 @@ public class LayoutTest {
        final List<RectF> rectangles = new ArrayList<>();

        layout.getSelection(0 /* startIndex */, 1 /* endIndex */,
                (left, top, right, bottom) -> rectangles.add(new RectF(left, top, right, bottom)));
                (left, top, right, bottom, textSelectionLayout) -> rectangles.add(
                        new RectF(left, top, right, bottom)));

        /*
         * The selection we expect will only cover the letter "a". Hence, we expect one rectangle
@@ -343,7 +345,8 @@ public class LayoutTest {
        final List<RectF> rectangles = new ArrayList<>();

        layout.getSelection(0 /* startIndex */, 2 /* endIndex */,
                (left, top, right, bottom) -> rectangles.add(new RectF(left, top, right, bottom)));
                (left, top, right, bottom, textSelectionLayout) -> rectangles.add(
                        new RectF(left, top, right, bottom)));

        /*
         * The selection that will be selected is "a\n" - the selection starts at the beginning
@@ -388,7 +391,8 @@ public class LayoutTest {
        final List<RectF> rectangles = new ArrayList<>();

        layout.getSelection(0 /* startIndex */, 3 /* endIndex */,
                (left, top, right, bottom) -> rectangles.add(new RectF(left, top, right, bottom)));
                (left, top, right, bottom, textSelectionLayout) -> rectangles.add(
                        new RectF(left, top, right, bottom)));

        /*
         * The selection that will be selected is "a\nb" - the selection starts at the beginning
@@ -430,7 +434,8 @@ public class LayoutTest {
        final List<RectF> rectangles = new ArrayList<>();

        layout.getSelection(0 /* startIndex */, 1 /* endIndex */,
                (left, top, right, bottom) -> rectangles.add(new RectF(left, top, right, bottom)));
                (left, top, right, bottom, textSelectionLayout) -> rectangles.add(
                        new RectF(left, top, right, bottom)));

        /*
         * In the single line selection case, we expect that only one rectangle covering the letter
@@ -454,6 +459,44 @@ public class LayoutTest {
        assertEquals(rectangle, pathRectangle);
    }

    @Test
    public void testGetSelection_latinTextDirection() {
        final Layout layout = new StaticLayout("abc", mTextPaint, Integer.MAX_VALUE,
                Alignment.ALIGN_LEFT, mSpacingMult, mSpacingAdd, false);

        layout.getSelection(0 /* startIndex */, 2 /* endIndex */,
                (left, top, right, bottom, textSelectionLayout) ->
                        assertEquals(Layout.TextSelectionLayout.LEFT_TO_RIGHT,
                                textSelectionLayout));
    }

    @Test
    public void testGetSelection_arabicTextDirection() {
        final Layout layout = new StaticLayout("غينيا", mTextPaint, Integer.MAX_VALUE,
                Alignment.ALIGN_LEFT, mSpacingMult, mSpacingAdd, false);

        layout.getSelection(0 /* startIndex */, 2 /* endIndex */,
                (left, top, right, bottom, textSelectionLayout) ->
                        assertEquals(Layout.TextSelectionLayout.RIGHT_TO_LEFT,
                                textSelectionLayout));
    }

    @Test
    public void testGetSelection_mixedLatinAndArabicTextDirection() {
        final Layout layout = new StaticLayout("abcغينيا", mTextPaint, Integer.MAX_VALUE,
                Alignment.ALIGN_LEFT, mSpacingMult, mSpacingAdd, false);

        final List<Integer> layouts = new ArrayList<>(2);

        layout.getSelection(0 /* startIndex */, 6 /* endIndex */,
                (left, top, right, bottom, textSelectionLayout) -> layouts.add(
                        textSelectionLayout));

        assertEquals(2, layouts.size());
        assertEquals(Layout.TextSelectionLayout.LEFT_TO_RIGHT, (long) layouts.get(0));
        assertEquals(Layout.TextSelectionLayout.RIGHT_TO_LEFT, (long) layouts.get(1));
    }

    @Test
    public void testIsSpanned() {
        MockLayout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,