Skip to content

Commit fd5bc01

Browse files
author
Gilles Debunne
committed
Better horizontal internal scroll handling in Text.
Bug 6378843 Corrects CL 183460, which would clip text with a width greater than twice the TextView's width. Internal horizontal translation is now handled in a similar way to vertical scrolling. Internal scrolling is indeed handled by the TextView, which translates the canvas and sets the clipping bounds accordingly. When drawing the internal DL, we tighten the horizontal bounds like we did for the vertical bounds using top and bottom. As in Touch.java, we use the getHorizontallyScrolling() method to know if we indeed have to measure the actual text width. If there is no horizontal scrolling we use the TextView's width as a safe upper estimate in order to avoid an actual computation. Note that horizontal scrolling is typically only used for long single-lined text, so that the measurement loop is quick. As a result, the internal DLs represent the entire text, and there is no need to invalidate them when an internal scrolling takes place. This behavior replaces the draw-only-what-is-needed we had before, but is more consistent with what we do for long texts inside of a ScrollView with no noticeable performance change, even on very long text. Change-Id: I47c24c0ae988547d4f1e9f87d136225c93a3056d
1 parent c9ca7f3 commit fd5bc01

File tree

1 file changed

+19
-16
lines changed

1 file changed

+19
-16
lines changed

core/java/android/widget/Editor.java

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,8 +1223,6 @@ void onDraw(Canvas canvas, Layout layout, Path highlight, Paint highlightPaint,
12231223

12241224
private void drawHardwareAccelerated(Canvas canvas, Layout layout, Path highlight,
12251225
Paint highlightPaint, int cursorOffsetVertical) {
1226-
final int width = mTextView.getWidth();
1227-
12281226
final long lineRange = layout.getLineRangeForDraw(canvas);
12291227
int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
12301228
int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
@@ -1243,10 +1241,6 @@ private void drawHardwareAccelerated(Canvas canvas, Layout layout, Path highligh
12431241
int[] blockIndices = dynamicLayout.getBlockIndices();
12441242
final int numberOfBlocks = dynamicLayout.getNumberOfBlocks();
12451243

1246-
final int scrollX = mTextView.getScrollX();
1247-
final int scrollY = mTextView.getScrollY();
1248-
canvas.translate(scrollX, scrollY);
1249-
12501244
int endOfPreviousBlock = -1;
12511245
int searchStartIndex = 0;
12521246
for (int i = 0; i < numberOfBlocks; i++) {
@@ -1274,34 +1268,43 @@ private void drawHardwareAccelerated(Canvas canvas, Layout layout, Path highligh
12741268
final int blockBeginLine = endOfPreviousBlock + 1;
12751269
final int top = layout.getLineTop(blockBeginLine);
12761270
final int bottom = layout.getLineBottom(blockEndLine);
1271+
int left = 0;
1272+
int right = mTextView.getWidth();
1273+
if (mTextView.getHorizontallyScrolling()) {
1274+
float min = Float.MAX_VALUE;
1275+
float max = Float.MIN_VALUE;
1276+
for (int line = blockBeginLine; line <= blockEndLine; line++) {
1277+
min = Math.min(min, layout.getLineLeft(line));
1278+
max = Math.max(max, layout.getLineRight(line));
1279+
}
1280+
left = (int) min;
1281+
right = (int) (max + 0.5f);
1282+
}
12771283

12781284
final HardwareCanvas hardwareCanvas = blockDisplayList.start();
12791285
try {
1280-
hardwareCanvas.setViewport(width, bottom - top);
1286+
// Tighten the bounds of the viewport to the actual text size
1287+
hardwareCanvas.setViewport(right - left, bottom - top);
12811288
// The dirty rect should always be null for a display list
12821289
hardwareCanvas.onPreDraw(null);
12831290
// drawText is always relative to TextView's origin, this translation brings
1284-
// this range of text back to the top of the viewport
1285-
hardwareCanvas.translate(-scrollX, -top);
1291+
// this range of text back to the top left corner of the viewport
1292+
hardwareCanvas.translate(-left, -top);
12861293
layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine);
1287-
hardwareCanvas.translate(scrollX, top);
1294+
// No need to untranslate, previous context is popped after drawDisplayList
12881295
} finally {
12891296
hardwareCanvas.onPostDraw();
12901297
blockDisplayList.end();
1291-
blockDisplayList.setLeftTopRightBottom(0, top, width, bottom);
1298+
blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
12921299
// Same as drawDisplayList below, handled by our TextView's parent
12931300
blockDisplayList.setClipChildren(false);
12941301
}
12951302
}
12961303

1297-
// TODO When View.USE_DISPLAY_LIST_PROPERTIES is the only code path, the
1298-
// width and height parameters should be removed and the bounds set above in
1299-
// setLeftTopRightBottom should be used instead for quick rejection.
13001304
((HardwareCanvas) canvas).drawDisplayList(blockDisplayList, null,
13011305
0 /* no child clipping, our TextView parent enforces it */);
1306+
13021307
endOfPreviousBlock = blockEndLine;
1303-
1304-
canvas.translate(-scrollX, -scrollY);
13051308
}
13061309
} else {
13071310
// Boring layout is used for empty and hint text

0 commit comments

Comments
 (0)