Skip to content

Commit 157aafc

Browse files
author
Gilles Debunne
committed
TextView's sub display lists have tighten bounds
An editable TextView caches text rendering inside an adaptive number of sub display lists. The bounds of these use to be those of the entire View. This CL creates block display lists with tighten bounds, so that (a still-to-be-implemented) quick rejection can occur. Also cleaned-up the contradictory translations that were used to handle the TextView's internal scroll and removed the invalidation of display lists in that case. TODO: When internal scroll sets a tighter clipping rect, quick reject the creation and display of the clipped display lists. Also renamed blockEnds to a more explicit blockEndLines. Change-Id: I7d79bea78d06d19b6935aef75ff7aa7df2594050
1 parent d7f256d commit 157aafc

File tree

3 files changed

+55
-50
lines changed

3 files changed

+55
-50
lines changed

core/java/android/text/DynamicLayout.java

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public DynamicLayout(CharSequence base, CharSequence display,
117117

118118
mObjects = new PackedObjectVector<Directions>(1);
119119

120-
mBlockEnds = new int[] { 0 };
120+
mBlockEndLines = new int[] { 0 };
121121
mBlockIndices = new int[] { INVALID_BLOCK_INDEX };
122122
mNumberOfBlocks = 1;
123123

@@ -391,23 +391,23 @@ void updateBlocks(int startLine, int endLine, int newLineCount) {
391391
int firstBlock = -1;
392392
int lastBlock = -1;
393393
for (int i = 0; i < mNumberOfBlocks; i++) {
394-
if (mBlockEnds[i] >= startLine) {
394+
if (mBlockEndLines[i] >= startLine) {
395395
firstBlock = i;
396396
break;
397397
}
398398
}
399399
for (int i = firstBlock; i < mNumberOfBlocks; i++) {
400-
if (mBlockEnds[i] >= endLine) {
400+
if (mBlockEndLines[i] >= endLine) {
401401
lastBlock = i;
402402
break;
403403
}
404404
}
405-
final int lastBlockEndLine = mBlockEnds[lastBlock];
405+
final int lastBlockEndLine = mBlockEndLines[lastBlock];
406406

407407
boolean createBlockBefore = startLine > (firstBlock == 0 ? 0 :
408-
mBlockEnds[firstBlock - 1] + 1);
408+
mBlockEndLines[firstBlock - 1] + 1);
409409
boolean createBlock = newLineCount > 0;
410-
boolean createBlockAfter = endLine < mBlockEnds[lastBlock];
410+
boolean createBlockAfter = endLine < mBlockEndLines[lastBlock];
411411

412412
int numAddedBlocks = 0;
413413
if (createBlockBefore) numAddedBlocks++;
@@ -419,52 +419,52 @@ void updateBlocks(int startLine, int endLine, int newLineCount) {
419419

420420
if (newNumberOfBlocks == 0) {
421421
// Even when text is empty, there is actually one line and hence one block
422-
mBlockEnds[0] = 0;
422+
mBlockEndLines[0] = 0;
423423
mBlockIndices[0] = INVALID_BLOCK_INDEX;
424424
mNumberOfBlocks = 1;
425425
return;
426426
}
427427

428-
if (newNumberOfBlocks > mBlockEnds.length) {
428+
if (newNumberOfBlocks > mBlockEndLines.length) {
429429
final int newSize = ArrayUtils.idealIntArraySize(newNumberOfBlocks);
430-
int[] blockEnds = new int[newSize];
430+
int[] blockEndLines = new int[newSize];
431431
int[] blockIndices = new int[newSize];
432-
System.arraycopy(mBlockEnds, 0, blockEnds, 0, firstBlock);
432+
System.arraycopy(mBlockEndLines, 0, blockEndLines, 0, firstBlock);
433433
System.arraycopy(mBlockIndices, 0, blockIndices, 0, firstBlock);
434-
System.arraycopy(mBlockEnds, lastBlock + 1,
435-
blockEnds, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
434+
System.arraycopy(mBlockEndLines, lastBlock + 1,
435+
blockEndLines, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
436436
System.arraycopy(mBlockIndices, lastBlock + 1,
437437
blockIndices, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
438-
mBlockEnds = blockEnds;
438+
mBlockEndLines = blockEndLines;
439439
mBlockIndices = blockIndices;
440440
} else {
441-
System.arraycopy(mBlockEnds, lastBlock + 1,
442-
mBlockEnds, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
441+
System.arraycopy(mBlockEndLines, lastBlock + 1,
442+
mBlockEndLines, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
443443
System.arraycopy(mBlockIndices, lastBlock + 1,
444444
mBlockIndices, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
445445
}
446446

447447
mNumberOfBlocks = newNumberOfBlocks;
448448
final int deltaLines = newLineCount - (endLine - startLine + 1);
449449
for (int i = firstBlock + numAddedBlocks; i < mNumberOfBlocks; i++) {
450-
mBlockEnds[i] += deltaLines;
450+
mBlockEndLines[i] += deltaLines;
451451
}
452452

453453
int blockIndex = firstBlock;
454454
if (createBlockBefore) {
455-
mBlockEnds[blockIndex] = startLine - 1;
455+
mBlockEndLines[blockIndex] = startLine - 1;
456456
mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX;
457457
blockIndex++;
458458
}
459459

460460
if (createBlock) {
461-
mBlockEnds[blockIndex] = startLine + newLineCount - 1;
461+
mBlockEndLines[blockIndex] = startLine + newLineCount - 1;
462462
mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX;
463463
blockIndex++;
464464
}
465465

466466
if (createBlockAfter) {
467-
mBlockEnds[blockIndex] = lastBlockEndLine + deltaLines;
467+
mBlockEndLines[blockIndex] = lastBlockEndLine + deltaLines;
468468
mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX;
469469
}
470470
}
@@ -473,19 +473,19 @@ void updateBlocks(int startLine, int endLine, int newLineCount) {
473473
* This package private method is used for test purposes only
474474
* @hide
475475
*/
476-
void setBlocksDataForTest(int[] blockEnds, int[] blockIndices, int numberOfBlocks) {
477-
mBlockEnds = new int[blockEnds.length];
476+
void setBlocksDataForTest(int[] blockEndLines, int[] blockIndices, int numberOfBlocks) {
477+
mBlockEndLines = new int[blockEndLines.length];
478478
mBlockIndices = new int[blockIndices.length];
479-
System.arraycopy(blockEnds, 0, mBlockEnds, 0, blockEnds.length);
479+
System.arraycopy(blockEndLines, 0, mBlockEndLines, 0, blockEndLines.length);
480480
System.arraycopy(blockIndices, 0, mBlockIndices, 0, blockIndices.length);
481481
mNumberOfBlocks = numberOfBlocks;
482482
}
483483

484484
/**
485485
* @hide
486486
*/
487-
public int[] getBlockEnds() {
488-
return mBlockEnds;
487+
public int[] getBlockEndLines() {
488+
return mBlockEndLines;
489489
}
490490

491491
/**
@@ -633,8 +633,8 @@ public int getEllipsisCount(int line) {
633633
* @hide
634634
*/
635635
public static final int INVALID_BLOCK_INDEX = -1;
636-
// Stores the line numbers of the last line of each block
637-
private int[] mBlockEnds;
636+
// Stores the line numbers of the last line of each block (inclusive)
637+
private int[] mBlockEndLines;
638638
// The indices of this block's display list in TextView's internal display list array or
639639
// INVALID_BLOCK_INDEX if this block has been invalidated during an edition
640640
private int[] mBlockIndices;

core/java/android/widget/Editor.java

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,24 +1241,21 @@ private void drawHardwareAccelerated(Canvas canvas, Layout layout, Path highligh
12411241
}
12421242

12431243
DynamicLayout dynamicLayout = (DynamicLayout) layout;
1244-
int[] blockEnds = dynamicLayout.getBlockEnds();
1244+
int[] blockEndLines = dynamicLayout.getBlockEndLines();
12451245
int[] blockIndices = dynamicLayout.getBlockIndices();
12461246
final int numberOfBlocks = dynamicLayout.getNumberOfBlocks();
12471247

1248-
final int mScrollX = mTextView.getScrollX();
1249-
final int mScrollY = mTextView.getScrollY();
1250-
canvas.translate(mScrollX, mScrollY);
12511248
int endOfPreviousBlock = -1;
12521249
int searchStartIndex = 0;
12531250
for (int i = 0; i < numberOfBlocks; i++) {
1254-
int blockEnd = blockEnds[i];
1251+
int blockEndLine = blockEndLines[i];
12551252
int blockIndex = blockIndices[i];
12561253

12571254
final boolean blockIsInvalid = blockIndex == DynamicLayout.INVALID_BLOCK_INDEX;
12581255
if (blockIsInvalid) {
12591256
blockIndex = getAvailableDisplayListIndex(blockIndices, numberOfBlocks,
12601257
searchStartIndex);
1261-
// Dynamic layout internal block indices structure is updated from Editor
1258+
// Note how dynamic layout's internal block indices get updated from Editor
12621259
blockIndices[i] = blockIndex;
12631260
searchStartIndex = blockIndex + 1;
12641261
}
@@ -1272,28 +1269,38 @@ private void drawHardwareAccelerated(Canvas canvas, Layout layout, Path highligh
12721269
}
12731270

12741271
if (!blockDisplayList.isValid()) {
1272+
final int blockBeginLine = endOfPreviousBlock + 1;
1273+
final int top = layout.getLineTop(blockBeginLine);
1274+
final int bottom = layout.getLineBottom(blockEndLine);
1275+
12751276
final HardwareCanvas hardwareCanvas = blockDisplayList.start();
12761277
try {
1277-
hardwareCanvas.setViewport(width, height);
1278+
hardwareCanvas.setViewport(width, bottom - top);
12781279
// The dirty rect should always be null for a display list
12791280
hardwareCanvas.onPreDraw(null);
1280-
hardwareCanvas.translate(-mScrollX, -mScrollY);
1281-
layout.drawText(hardwareCanvas, endOfPreviousBlock + 1, blockEnd);
1282-
hardwareCanvas.translate(mScrollX, mScrollY);
1281+
// drawText is always relative to TextView's origin, this translation brings
1282+
// this range of text back to the top of the viewport
1283+
hardwareCanvas.translate(0, -top);
1284+
layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine);
1285+
hardwareCanvas.translate(0, top);
12831286
} finally {
12841287
hardwareCanvas.onPostDraw();
12851288
blockDisplayList.end();
12861289
if (View.USE_DISPLAY_LIST_PROPERTIES) {
1287-
blockDisplayList.setLeftTopRightBottom(0, 0, width, height);
1290+
blockDisplayList.setLeftTopRightBottom(0, top, width, bottom);
1291+
// Same as drawDisplayList below, handled by our TextView's parent
1292+
blockDisplayList.setClipChildren(false);
12881293
}
12891294
}
12901295
}
12911296

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.
12921300
((HardwareCanvas) canvas).drawDisplayList(blockDisplayList, width, height, null,
1293-
DisplayList.FLAG_CLIP_CHILDREN);
1294-
endOfPreviousBlock = blockEnd;
1301+
0 /* no child clipping, our TextView parent enforces it */);
1302+
endOfPreviousBlock = blockEndLine;
12951303
}
1296-
canvas.translate(-mScrollX, -mScrollY);
12971304
} else {
12981305
// Boring layout is used for empty and hint text
12991306
layout.drawText(canvas, firstLine, lastLine);
@@ -1572,11 +1579,9 @@ boolean areSuggestionsShown() {
15721579
}
15731580

15741581
void onScrollChanged() {
1575-
if (mPositionListener != null) {
1576-
mPositionListener.onScrollChanged();
1577-
}
1578-
// Internal scroll affects the clip boundaries
1579-
invalidateTextDisplayList();
1582+
if (mPositionListener != null) {
1583+
mPositionListener.onScrollChanged();
1584+
}
15801585
}
15811586

15821587
/**

core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,18 @@ private void defineInitialState(int[] ends, int[] indices) {
4545
public void printBlocks(String message) {
4646
System.out.print(message);
4747
for (int i = 0; i < dl.getNumberOfBlocks(); i++) {
48-
System.out.print(" " + Integer.toString(dl.getBlockEnds()[i]));
48+
System.out.print(" " + Integer.toString(dl.getBlockEndLines()[i]));
4949
}
5050
System.out.println();
5151
}
5252

5353
public void checkInvariants() {
5454
assertTrue(dl.getNumberOfBlocks() > 0);
55-
assertTrue(dl.getNumberOfBlocks() <= dl.getBlockEnds().length);
56-
assertEquals(dl.getBlockEnds().length, dl.getBlockIndices().length);
55+
assertTrue(dl.getNumberOfBlocks() <= dl.getBlockEndLines().length);
56+
assertEquals(dl.getBlockEndLines().length, dl.getBlockIndices().length);
5757

5858
for (int i = 1; i < dl.getNumberOfBlocks(); i++) {
59-
assertTrue(dl.getBlockEnds()[i] > dl.getBlockEnds()[i-1]);
59+
assertTrue(dl.getBlockEndLines()[i] > dl.getBlockEndLines()[i-1]);
6060
}
6161
}
6262

@@ -78,7 +78,7 @@ private void assertState(int[] sizes, int[] indices) {
7878
}
7979

8080
for (int i = 0; i < dl.getNumberOfBlocks(); i++) {
81-
assertEquals(ends[i], dl.getBlockEnds()[i]);
81+
assertEquals(ends[i], dl.getBlockEndLines()[i]);
8282
assertEquals(indices[i], dl.getBlockIndices()[i]);
8383
}
8484
}

0 commit comments

Comments
 (0)