summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2017-09-07 13:02:22 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2017-09-07 13:02:22 +0000
commit5b730ba2a01ca0068952ebf7003367857d8bf2b6 (patch)
treea22e01b3fc1da80541d8d50641c6b5bd9c960cb2
parent64b70b7dc7f4b7056c2f020907a9de99bdebad5e (diff)
parentb92c539232900537d5005bcf7cbc8950ff7f42d9 (diff)
Merge "Emit text direction with selection rectangle"
-rw-r--r--core/java/android/text/Layout.java54
-rw-r--r--core/java/android/widget/SelectionActionModeHelper.java2
-rw-r--r--core/tests/coretests/src/android/text/LayoutTest.java53
3 files changed, 89 insertions, 20 deletions
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 62bd6e04bbe0..97b6f4961a62 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -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);
}
}
}
@@ -2310,8 +2325,16 @@ public abstract class Layout {
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);
}
}
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 57a3468724a3..041b515f7e47 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -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);
diff --git a/core/tests/coretests/src/android/text/LayoutTest.java b/core/tests/coretests/src/android/text/LayoutTest.java
index 0cc41ba0a36b..b3c67947f43b 100644
--- a/core/tests/coretests/src/android/text/LayoutTest.java
+++ b/core/tests/coretests/src/android/text/LayoutTest.java
@@ -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
@@ -455,6 +460,44 @@ public class LayoutTest {
}
@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,
mAlign, mSpacingMult, mSpacingAdd);