Merge "TextView's sub display lists have tighten bounds"

This commit is contained in:
Gilles Debunne
2012-04-20 10:56:05 -07:00
committed by Android (Google) Code Review
3 changed files with 55 additions and 50 deletions

View File

@@ -117,7 +117,7 @@ public class DynamicLayout extends Layout
mObjects = new PackedObjectVector<Directions>(1);
mBlockEnds = new int[] { 0 };
mBlockEndLines = new int[] { 0 };
mBlockIndices = new int[] { INVALID_BLOCK_INDEX };
mNumberOfBlocks = 1;
@@ -391,23 +391,23 @@ public class DynamicLayout extends Layout
int firstBlock = -1;
int lastBlock = -1;
for (int i = 0; i < mNumberOfBlocks; i++) {
if (mBlockEnds[i] >= startLine) {
if (mBlockEndLines[i] >= startLine) {
firstBlock = i;
break;
}
}
for (int i = firstBlock; i < mNumberOfBlocks; i++) {
if (mBlockEnds[i] >= endLine) {
if (mBlockEndLines[i] >= endLine) {
lastBlock = i;
break;
}
}
final int lastBlockEndLine = mBlockEnds[lastBlock];
final int lastBlockEndLine = mBlockEndLines[lastBlock];
boolean createBlockBefore = startLine > (firstBlock == 0 ? 0 :
mBlockEnds[firstBlock - 1] + 1);
mBlockEndLines[firstBlock - 1] + 1);
boolean createBlock = newLineCount > 0;
boolean createBlockAfter = endLine < mBlockEnds[lastBlock];
boolean createBlockAfter = endLine < mBlockEndLines[lastBlock];
int numAddedBlocks = 0;
if (createBlockBefore) numAddedBlocks++;
@@ -419,27 +419,27 @@ public class DynamicLayout extends Layout
if (newNumberOfBlocks == 0) {
// Even when text is empty, there is actually one line and hence one block
mBlockEnds[0] = 0;
mBlockEndLines[0] = 0;
mBlockIndices[0] = INVALID_BLOCK_INDEX;
mNumberOfBlocks = 1;
return;
}
if (newNumberOfBlocks > mBlockEnds.length) {
if (newNumberOfBlocks > mBlockEndLines.length) {
final int newSize = ArrayUtils.idealIntArraySize(newNumberOfBlocks);
int[] blockEnds = new int[newSize];
int[] blockEndLines = new int[newSize];
int[] blockIndices = new int[newSize];
System.arraycopy(mBlockEnds, 0, blockEnds, 0, firstBlock);
System.arraycopy(mBlockEndLines, 0, blockEndLines, 0, firstBlock);
System.arraycopy(mBlockIndices, 0, blockIndices, 0, firstBlock);
System.arraycopy(mBlockEnds, lastBlock + 1,
blockEnds, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
System.arraycopy(mBlockEndLines, lastBlock + 1,
blockEndLines, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
System.arraycopy(mBlockIndices, lastBlock + 1,
blockIndices, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
mBlockEnds = blockEnds;
mBlockEndLines = blockEndLines;
mBlockIndices = blockIndices;
} else {
System.arraycopy(mBlockEnds, lastBlock + 1,
mBlockEnds, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
System.arraycopy(mBlockEndLines, lastBlock + 1,
mBlockEndLines, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
System.arraycopy(mBlockIndices, lastBlock + 1,
mBlockIndices, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1);
}
@@ -447,24 +447,24 @@ public class DynamicLayout extends Layout
mNumberOfBlocks = newNumberOfBlocks;
final int deltaLines = newLineCount - (endLine - startLine + 1);
for (int i = firstBlock + numAddedBlocks; i < mNumberOfBlocks; i++) {
mBlockEnds[i] += deltaLines;
mBlockEndLines[i] += deltaLines;
}
int blockIndex = firstBlock;
if (createBlockBefore) {
mBlockEnds[blockIndex] = startLine - 1;
mBlockEndLines[blockIndex] = startLine - 1;
mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX;
blockIndex++;
}
if (createBlock) {
mBlockEnds[blockIndex] = startLine + newLineCount - 1;
mBlockEndLines[blockIndex] = startLine + newLineCount - 1;
mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX;
blockIndex++;
}
if (createBlockAfter) {
mBlockEnds[blockIndex] = lastBlockEndLine + deltaLines;
mBlockEndLines[blockIndex] = lastBlockEndLine + deltaLines;
mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX;
}
}
@@ -473,10 +473,10 @@ public class DynamicLayout extends Layout
* This package private method is used for test purposes only
* @hide
*/
void setBlocksDataForTest(int[] blockEnds, int[] blockIndices, int numberOfBlocks) {
mBlockEnds = new int[blockEnds.length];
void setBlocksDataForTest(int[] blockEndLines, int[] blockIndices, int numberOfBlocks) {
mBlockEndLines = new int[blockEndLines.length];
mBlockIndices = new int[blockIndices.length];
System.arraycopy(blockEnds, 0, mBlockEnds, 0, blockEnds.length);
System.arraycopy(blockEndLines, 0, mBlockEndLines, 0, blockEndLines.length);
System.arraycopy(blockIndices, 0, mBlockIndices, 0, blockIndices.length);
mNumberOfBlocks = numberOfBlocks;
}
@@ -484,8 +484,8 @@ public class DynamicLayout extends Layout
/**
* @hide
*/
public int[] getBlockEnds() {
return mBlockEnds;
public int[] getBlockEndLines() {
return mBlockEndLines;
}
/**
@@ -633,8 +633,8 @@ public class DynamicLayout extends Layout
* @hide
*/
public static final int INVALID_BLOCK_INDEX = -1;
// Stores the line numbers of the last line of each block
private int[] mBlockEnds;
// Stores the line numbers of the last line of each block (inclusive)
private int[] mBlockEndLines;
// The indices of this block's display list in TextView's internal display list array or
// INVALID_BLOCK_INDEX if this block has been invalidated during an edition
private int[] mBlockIndices;

View File

@@ -1241,24 +1241,21 @@ public class Editor {
}
DynamicLayout dynamicLayout = (DynamicLayout) layout;
int[] blockEnds = dynamicLayout.getBlockEnds();
int[] blockEndLines = dynamicLayout.getBlockEndLines();
int[] blockIndices = dynamicLayout.getBlockIndices();
final int numberOfBlocks = dynamicLayout.getNumberOfBlocks();
final int mScrollX = mTextView.getScrollX();
final int mScrollY = mTextView.getScrollY();
canvas.translate(mScrollX, mScrollY);
int endOfPreviousBlock = -1;
int searchStartIndex = 0;
for (int i = 0; i < numberOfBlocks; i++) {
int blockEnd = blockEnds[i];
int blockEndLine = blockEndLines[i];
int blockIndex = blockIndices[i];
final boolean blockIsInvalid = blockIndex == DynamicLayout.INVALID_BLOCK_INDEX;
if (blockIsInvalid) {
blockIndex = getAvailableDisplayListIndex(blockIndices, numberOfBlocks,
searchStartIndex);
// Dynamic layout internal block indices structure is updated from Editor
// Note how dynamic layout's internal block indices get updated from Editor
blockIndices[i] = blockIndex;
searchStartIndex = blockIndex + 1;
}
@@ -1272,28 +1269,38 @@ public class Editor {
}
if (!blockDisplayList.isValid()) {
final int blockBeginLine = endOfPreviousBlock + 1;
final int top = layout.getLineTop(blockBeginLine);
final int bottom = layout.getLineBottom(blockEndLine);
final HardwareCanvas hardwareCanvas = blockDisplayList.start();
try {
hardwareCanvas.setViewport(width, height);
hardwareCanvas.setViewport(width, bottom - top);
// The dirty rect should always be null for a display list
hardwareCanvas.onPreDraw(null);
hardwareCanvas.translate(-mScrollX, -mScrollY);
layout.drawText(hardwareCanvas, endOfPreviousBlock + 1, blockEnd);
hardwareCanvas.translate(mScrollX, mScrollY);
// drawText is always relative to TextView's origin, this translation brings
// this range of text back to the top of the viewport
hardwareCanvas.translate(0, -top);
layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine);
hardwareCanvas.translate(0, top);
} finally {
hardwareCanvas.onPostDraw();
blockDisplayList.end();
if (View.USE_DISPLAY_LIST_PROPERTIES) {
blockDisplayList.setLeftTopRightBottom(0, 0, width, height);
blockDisplayList.setLeftTopRightBottom(0, top, width, bottom);
// Same as drawDisplayList below, handled by our TextView's parent
blockDisplayList.setClipChildren(false);
}
}
}
// TODO When View.USE_DISPLAY_LIST_PROPERTIES is the only code path, the
// width and height parameters should be removed and the bounds set above in
// setLeftTopRightBottom should be used instead for quick rejection.
((HardwareCanvas) canvas).drawDisplayList(blockDisplayList, width, height, null,
DisplayList.FLAG_CLIP_CHILDREN);
endOfPreviousBlock = blockEnd;
0 /* no child clipping, our TextView parent enforces it */);
endOfPreviousBlock = blockEndLine;
}
canvas.translate(-mScrollX, -mScrollY);
} else {
// Boring layout is used for empty and hint text
layout.drawText(canvas, firstLine, lastLine);
@@ -1572,11 +1579,9 @@ public class Editor {
}
void onScrollChanged() {
if (mPositionListener != null) {
mPositionListener.onScrollChanged();
}
// Internal scroll affects the clip boundaries
invalidateTextDisplayList();
if (mPositionListener != null) {
mPositionListener.onScrollChanged();
}
}
/**

View File

@@ -45,18 +45,18 @@ public class DynamicLayoutBlocksTest extends TestCase {
public void printBlocks(String message) {
System.out.print(message);
for (int i = 0; i < dl.getNumberOfBlocks(); i++) {
System.out.print(" " + Integer.toString(dl.getBlockEnds()[i]));
System.out.print(" " + Integer.toString(dl.getBlockEndLines()[i]));
}
System.out.println();
}
public void checkInvariants() {
assertTrue(dl.getNumberOfBlocks() > 0);
assertTrue(dl.getNumberOfBlocks() <= dl.getBlockEnds().length);
assertEquals(dl.getBlockEnds().length, dl.getBlockIndices().length);
assertTrue(dl.getNumberOfBlocks() <= dl.getBlockEndLines().length);
assertEquals(dl.getBlockEndLines().length, dl.getBlockIndices().length);
for (int i = 1; i < dl.getNumberOfBlocks(); i++) {
assertTrue(dl.getBlockEnds()[i] > dl.getBlockEnds()[i-1]);
assertTrue(dl.getBlockEndLines()[i] > dl.getBlockEndLines()[i-1]);
}
}
@@ -78,7 +78,7 @@ public class DynamicLayoutBlocksTest extends TestCase {
}
for (int i = 0; i < dl.getNumberOfBlocks(); i++) {
assertEquals(ends[i], dl.getBlockEnds()[i]);
assertEquals(ends[i], dl.getBlockEndLines()[i]);
assertEquals(indices[i], dl.getBlockIndices()[i]);
}
}