Loading core/java/android/text/Layout.java +52 −20 Original line number Original line Diff line number Diff line Loading @@ -1694,20 +1694,22 @@ public abstract class Layout { } } private void addSelection(int line, int start, int end, private void addSelection(int line, int start, int end, int top, int bottom, Path dest) { int top, int bottom, RectangleConsumer consumer) { int linestart = getLineStart(line); int linestart = getLineStart(line); int lineend = getLineEnd(line); int lineend = getLineEnd(line); Directions dirs = getLineDirections(line); Directions dirs = getLineDirections(line); if (lineend > linestart && mText.charAt(lineend - 1) == '\n') if (lineend > linestart && mText.charAt(lineend - 1) == '\n') { lineend--; lineend--; } for (int i = 0; i < dirs.mDirections.length; i += 2) { for (int i = 0; i < dirs.mDirections.length; i += 2) { int here = linestart + dirs.mDirections[i]; int here = linestart + dirs.mDirections[i]; int there = here + (dirs.mDirections[i + 1] & RUN_LENGTH_MASK); int there = here + (dirs.mDirections[i + 1] & RUN_LENGTH_MASK); if (there > lineend) if (there > lineend) { there = lineend; there = lineend; } if (start <= there && end >= here) { if (start <= there && end >= here) { int st = Math.max(start, here); int st = Math.max(start, here); Loading @@ -1720,7 +1722,7 @@ public abstract class Layout { float left = Math.min(h1, h2); float left = Math.min(h1, h2); float right = Math.max(h1, h2); float right = Math.max(h1, h2); dest.addRect(left, top, right, bottom, Path.Direction.CW); consumer.accept(left, top, right, bottom); } } } } } } Loading @@ -1734,9 +1736,25 @@ public abstract class Layout { */ */ public void getSelectionPath(int start, int end, Path dest) { public void getSelectionPath(int start, int end, Path dest) { dest.reset(); dest.reset(); getSelection(start, end, (left, top, right, bottom) -> dest.addRect(left, top, right, bottom, Path.Direction.CW)); } if (start == end) /** * Calculates the rectangles which should be highlighted to indicate a selection between start * and end and feeds them into the given {@link RectangleConsumer}. * * @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. * @hide * @see #getSelectionPath(int, int, Path) */ public final void getSelection(int start, int end, final RectangleConsumer consumer) { if (start == end) { return; return; } if (end < start) { if (end < start) { int temp = end; int temp = end; Loading @@ -1751,35 +1769,35 @@ public abstract class Layout { int bottom = getLineBottomWithoutSpacing(endline); int bottom = getLineBottomWithoutSpacing(endline); if (startline == endline) { if (startline == endline) { addSelection(startline, start, end, top, bottom, dest); addSelection(startline, start, end, top, bottom, consumer); } else { } else { final float width = mWidth; final float width = mWidth; addSelection(startline, start, getLineEnd(startline), addSelection(startline, start, getLineEnd(startline), top, getLineBottom(startline), dest); top, getLineBottom(startline), consumer); if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT) if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT) { dest.addRect(getLineLeft(startline), top, consumer.accept(getLineLeft(startline), top, 0, getLineBottom(startline)); 0, getLineBottom(startline), Path.Direction.CW); } else { else consumer.accept(getLineRight(startline), top, width, getLineBottom(startline)); dest.addRect(getLineRight(startline), top, } width, getLineBottom(startline), Path.Direction.CW); for (int i = startline + 1; i < endline; i++) { for (int i = startline + 1; i < endline; i++) { top = getLineTop(i); top = getLineTop(i); bottom = getLineBottom(i); bottom = getLineBottom(i); dest.addRect(0, top, width, bottom, Path.Direction.CW); consumer.accept(0, top, width, bottom); } } top = getLineTop(endline); top = getLineTop(endline); bottom = getLineBottomWithoutSpacing(endline); bottom = getLineBottomWithoutSpacing(endline); addSelection(endline, getLineStart(endline), end, top, bottom, dest); addSelection(endline, getLineStart(endline), end, top, bottom, consumer); if (getParagraphDirection(endline) == DIR_RIGHT_TO_LEFT) if (getParagraphDirection(endline) == DIR_RIGHT_TO_LEFT) { dest.addRect(width, top, getLineRight(endline), bottom, Path.Direction.CW); consumer.accept(width, top, getLineRight(endline), bottom); else } else { dest.addRect(0, top, getLineLeft(endline), bottom, Path.Direction.CW); consumer.accept(0, top, getLineLeft(endline), bottom); } } } } } Loading Loading @@ -2281,4 +2299,18 @@ public abstract class Layout { public static final Directions DIRS_ALL_RIGHT_TO_LEFT = public static final Directions DIRS_ALL_RIGHT_TO_LEFT = new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG }); new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG }); /** @hide */ @FunctionalInterface public interface RectangleConsumer { /** * Performs this operation on the given rectangle. * * @param left the left edge of the rectangle * @param top the top edge of the rectangle * @param right the right edge of the rectangle * @param bottom the bottom edge of the rectangle */ void accept(float left, float top, float right, float bottom); } } } Loading
core/java/android/text/Layout.java +52 −20 Original line number Original line Diff line number Diff line Loading @@ -1694,20 +1694,22 @@ public abstract class Layout { } } private void addSelection(int line, int start, int end, private void addSelection(int line, int start, int end, int top, int bottom, Path dest) { int top, int bottom, RectangleConsumer consumer) { int linestart = getLineStart(line); int linestart = getLineStart(line); int lineend = getLineEnd(line); int lineend = getLineEnd(line); Directions dirs = getLineDirections(line); Directions dirs = getLineDirections(line); if (lineend > linestart && mText.charAt(lineend - 1) == '\n') if (lineend > linestart && mText.charAt(lineend - 1) == '\n') { lineend--; lineend--; } for (int i = 0; i < dirs.mDirections.length; i += 2) { for (int i = 0; i < dirs.mDirections.length; i += 2) { int here = linestart + dirs.mDirections[i]; int here = linestart + dirs.mDirections[i]; int there = here + (dirs.mDirections[i + 1] & RUN_LENGTH_MASK); int there = here + (dirs.mDirections[i + 1] & RUN_LENGTH_MASK); if (there > lineend) if (there > lineend) { there = lineend; there = lineend; } if (start <= there && end >= here) { if (start <= there && end >= here) { int st = Math.max(start, here); int st = Math.max(start, here); Loading @@ -1720,7 +1722,7 @@ public abstract class Layout { float left = Math.min(h1, h2); float left = Math.min(h1, h2); float right = Math.max(h1, h2); float right = Math.max(h1, h2); dest.addRect(left, top, right, bottom, Path.Direction.CW); consumer.accept(left, top, right, bottom); } } } } } } Loading @@ -1734,9 +1736,25 @@ public abstract class Layout { */ */ public void getSelectionPath(int start, int end, Path dest) { public void getSelectionPath(int start, int end, Path dest) { dest.reset(); dest.reset(); getSelection(start, end, (left, top, right, bottom) -> dest.addRect(left, top, right, bottom, Path.Direction.CW)); } if (start == end) /** * Calculates the rectangles which should be highlighted to indicate a selection between start * and end and feeds them into the given {@link RectangleConsumer}. * * @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. * @hide * @see #getSelectionPath(int, int, Path) */ public final void getSelection(int start, int end, final RectangleConsumer consumer) { if (start == end) { return; return; } if (end < start) { if (end < start) { int temp = end; int temp = end; Loading @@ -1751,35 +1769,35 @@ public abstract class Layout { int bottom = getLineBottomWithoutSpacing(endline); int bottom = getLineBottomWithoutSpacing(endline); if (startline == endline) { if (startline == endline) { addSelection(startline, start, end, top, bottom, dest); addSelection(startline, start, end, top, bottom, consumer); } else { } else { final float width = mWidth; final float width = mWidth; addSelection(startline, start, getLineEnd(startline), addSelection(startline, start, getLineEnd(startline), top, getLineBottom(startline), dest); top, getLineBottom(startline), consumer); if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT) if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT) { dest.addRect(getLineLeft(startline), top, consumer.accept(getLineLeft(startline), top, 0, getLineBottom(startline)); 0, getLineBottom(startline), Path.Direction.CW); } else { else consumer.accept(getLineRight(startline), top, width, getLineBottom(startline)); dest.addRect(getLineRight(startline), top, } width, getLineBottom(startline), Path.Direction.CW); for (int i = startline + 1; i < endline; i++) { for (int i = startline + 1; i < endline; i++) { top = getLineTop(i); top = getLineTop(i); bottom = getLineBottom(i); bottom = getLineBottom(i); dest.addRect(0, top, width, bottom, Path.Direction.CW); consumer.accept(0, top, width, bottom); } } top = getLineTop(endline); top = getLineTop(endline); bottom = getLineBottomWithoutSpacing(endline); bottom = getLineBottomWithoutSpacing(endline); addSelection(endline, getLineStart(endline), end, top, bottom, dest); addSelection(endline, getLineStart(endline), end, top, bottom, consumer); if (getParagraphDirection(endline) == DIR_RIGHT_TO_LEFT) if (getParagraphDirection(endline) == DIR_RIGHT_TO_LEFT) { dest.addRect(width, top, getLineRight(endline), bottom, Path.Direction.CW); consumer.accept(width, top, getLineRight(endline), bottom); else } else { dest.addRect(0, top, getLineLeft(endline), bottom, Path.Direction.CW); consumer.accept(0, top, getLineLeft(endline), bottom); } } } } } Loading Loading @@ -2281,4 +2299,18 @@ public abstract class Layout { public static final Directions DIRS_ALL_RIGHT_TO_LEFT = public static final Directions DIRS_ALL_RIGHT_TO_LEFT = new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG }); new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG }); /** @hide */ @FunctionalInterface public interface RectangleConsumer { /** * Performs this operation on the given rectangle. * * @param left the left edge of the rectangle * @param top the top edge of the rectangle * @param right the right edge of the rectangle * @param bottom the bottom edge of the rectangle */ void accept(float left, float top, float right, float bottom); } } }