Merge "Optimize drawHardwareAccelerated method in Editor class"
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index d909362..122f8a1 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -503,8 +503,15 @@
mNumberOfBlocks = newNumberOfBlocks;
final int deltaLines = newLineCount - (endLine - startLine + 1);
- for (int i = firstBlock + numAddedBlocks; i < mNumberOfBlocks; i++) {
- mBlockEndLines[i] += deltaLines;
+ if (deltaLines != 0) {
+ // Display list whose index is >= mIndexFirstChangedBlock is valid
+ // but it needs to update its drawing location.
+ mIndexFirstChangedBlock = firstBlock + numAddedBlocks;
+ for (int i = mIndexFirstChangedBlock; i < mNumberOfBlocks; i++) {
+ mBlockEndLines[i] += deltaLines;
+ }
+ } else {
+ mIndexFirstChangedBlock = mNumberOfBlocks;
}
int blockIndex = firstBlock;
@@ -559,6 +566,20 @@
return mNumberOfBlocks;
}
+ /**
+ * @hide
+ */
+ public int getIndexFirstChangedBlock() {
+ return mIndexFirstChangedBlock;
+ }
+
+ /**
+ * @hide
+ */
+ public void setIndexFirstChangedBlock(int i) {
+ mIndexFirstChangedBlock = i;
+ }
+
@Override
public int getLineCount() {
return mInts.size() - 1;
@@ -697,6 +718,8 @@
private int[] mBlockIndices;
// Number of items actually currently being used in the above 2 arrays
private int mNumberOfBlocks;
+ // The first index of the blocks whose locations are changed
+ private int mIndexFirstChangedBlock;
private int mTopPadding, mBottomPadding;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 41d6033..4eaa78a 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -124,7 +124,6 @@
InputMethodState mInputMethodState;
DisplayList[] mTextDisplayLists;
- int mLastLayoutHeight;
boolean mFrozenWithFocus;
boolean mSelectionMoved;
@@ -1289,20 +1288,11 @@
mTextDisplayLists = new DisplayList[ArrayUtils.idealObjectArraySize(0)];
}
- // If the height of the layout changes (usually when inserting or deleting a line,
- // but could be changes within a span), invalidate everything. We could optimize
- // more aggressively (for example, adding offsets to blocks) but it would be more
- // complex and we would only get the benefit in some cases.
- int layoutHeight = layout.getHeight();
- if (mLastLayoutHeight != layoutHeight) {
- invalidateTextDisplayList();
- mLastLayoutHeight = layoutHeight;
- }
-
DynamicLayout dynamicLayout = (DynamicLayout) layout;
int[] blockEndLines = dynamicLayout.getBlockEndLines();
int[] blockIndices = dynamicLayout.getBlockIndices();
final int numberOfBlocks = dynamicLayout.getNumberOfBlocks();
+ final int indexFirstChangedBlock = dynamicLayout.getIndexFirstChangedBlock();
int endOfPreviousBlock = -1;
int searchStartIndex = 0;
@@ -1327,7 +1317,8 @@
if (blockIsInvalid) blockDisplayList.invalidate();
}
- if (!blockDisplayList.isValid()) {
+ final boolean blockDisplayListIsInvalid = !blockDisplayList.isValid();
+ if (i >= indexFirstChangedBlock || blockDisplayListIsInvalid) {
final int blockBeginLine = endOfPreviousBlock + 1;
final int top = layout.getLineTop(blockBeginLine);
final int bottom = layout.getLineBottom(blockEndLine);
@@ -1344,24 +1335,30 @@
right = (int) (max + 0.5f);
}
- final HardwareCanvas hardwareCanvas = blockDisplayList.start();
- try {
- // Tighten the bounds of the viewport to the actual text size
- hardwareCanvas.setViewport(right - left, bottom - top);
- // The dirty rect should always be null for a display list
- hardwareCanvas.onPreDraw(null);
- // drawText is always relative to TextView's origin, this translation brings
- // this range of text back to the top left corner of the viewport
- hardwareCanvas.translate(-left, -top);
- layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine);
- // No need to untranslate, previous context is popped after drawDisplayList
- } finally {
- hardwareCanvas.onPostDraw();
- blockDisplayList.end();
- blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
- // Same as drawDisplayList below, handled by our TextView's parent
- blockDisplayList.setClipChildren(false);
+ // Rebuild display list if it is invalid
+ if (blockDisplayListIsInvalid) {
+ final HardwareCanvas hardwareCanvas = blockDisplayList.start();
+ try {
+ // Tighten the bounds of the viewport to the actual text size
+ hardwareCanvas.setViewport(right - left, bottom - top);
+ // The dirty rect should always be null for a display list
+ hardwareCanvas.onPreDraw(null);
+ // drawText is always relative to TextView's origin, this translation brings
+ // this range of text back to the top left corner of the viewport
+ hardwareCanvas.translate(-left, -top);
+ layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine);
+ // No need to untranslate, previous context is popped after drawDisplayList
+ } finally {
+ hardwareCanvas.onPostDraw();
+ blockDisplayList.end();
+ // Same as drawDisplayList below, handled by our TextView's parent
+ blockDisplayList.setClipChildren(false);
+ }
}
+
+ // Valid disply list whose index is >= indexFirstChangedBlock
+ // only needs to update its drawing location.
+ blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
}
((HardwareCanvas) canvas).drawDisplayList(blockDisplayList, null,
@@ -1369,6 +1366,8 @@
endOfPreviousBlock = blockEndLine;
}
+
+ dynamicLayout.setIndexFirstChangedBlock(numberOfBlocks);
} else {
// Boring layout is used for empty and hint text
layout.drawText(canvas, firstLine, lastLine);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d635de6..f8db622 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6459,7 +6459,6 @@
mDeferScroll = -1;
bringPointIntoView(Math.min(curs, mText.length()));
}
- if (changed && mEditor != null) mEditor.invalidateTextDisplayList();
}
private boolean isShowingHint() {