Loading core/java/android/text/DynamicLayout.java +142 −3 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import android.graphics.Paint; import android.text.style.UpdateLayout; import android.text.style.WrapTogetherSpan; import com.android.internal.util.ArrayUtils; import java.lang.ref.WeakReference; /** Loading @@ -30,8 +32,7 @@ import java.lang.ref.WeakReference; * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint) * Canvas.drawText()} directly.</p> */ public class DynamicLayout extends Layout public class DynamicLayout extends Layout { private static final int PRIORITY = 128; Loading Loading @@ -116,6 +117,10 @@ extends Layout mObjects = new PackedObjectVector<Directions>(1); mBlockEnds = new int[] { 0 }; mBlockIndices = new int[] { INVALID_BLOCK_INDEX }; mNumberOfBlocks = 1; mIncludePad = includepad; /* Loading Loading @@ -295,9 +300,9 @@ extends Layout n--; // remove affected lines from old layout mInts.deleteAt(startline, endline - startline); mObjects.deleteAt(startline, endline - startline); updateBlocks(startline, endline - 1, n); // adjust offsets in layout for new height and offsets Loading Loading @@ -363,6 +368,124 @@ extends Layout } } /** * This method is called every time the layout is reflowed after an edition. * It updates the internal block data structure. The text is split in blocks * of contiguous lines, with at least one block for the entire text. * When a range of lines is edited, new blocks (from 0 to 3 depending on the * overlap structure) will replace the set of overlapping blocks. * Blocks are listed in order and are represented by their ending line number. * An index is associated to each block (which will be used by display lists), * this class simply invalidates the index of blocks overlapping a modification. * * @param startLine the first line of the range of modified lines * @param endLine the last line of the range, possibly equal to startLine, lower * than getLineCount() * @param newLineCount the number of lines that will replace the range, possibly 0 */ private void updateBlocks(int startLine, int endLine, int newLineCount) { int firstBlock = -1; int lastBlock = -1; for (int i = 0; i < mNumberOfBlocks; i++) { if (mBlockEnds[i] >= startLine) { firstBlock = i; break; } } for (int i = firstBlock; i < mNumberOfBlocks; i++) { if (mBlockEnds[i] >= endLine) { lastBlock = i; break; } } final int lastBlockEndLine = mBlockEnds[lastBlock]; boolean createBlockBefore = startLine > (firstBlock == 0 ? 0 : mBlockEnds[firstBlock - 1] + 1); boolean createBlock = newLineCount > 0; boolean createBlockAfter = endLine < mBlockEnds[lastBlock]; int numAddedBlocks = 0; if (createBlockBefore) numAddedBlocks++; if (createBlock) numAddedBlocks++; if (createBlockAfter) numAddedBlocks++; final int numRemovedBlocks = lastBlock - firstBlock + 1; final int newNumberOfBlocks = mNumberOfBlocks + numAddedBlocks - numRemovedBlocks; if (newNumberOfBlocks == 0) { // Even when text is empty, there is actually one line and hence one block mBlockEnds[0] = 0; mBlockIndices[0] = INVALID_BLOCK_INDEX; mNumberOfBlocks = 1; return; } if (newNumberOfBlocks > mBlockEnds.length) { final int newSize = ArrayUtils.idealIntArraySize(newNumberOfBlocks); int[] blockEnds = new int[newSize]; int[] blockIndices = new int[newSize]; System.arraycopy(mBlockEnds, 0, blockEnds, 0, firstBlock); System.arraycopy(mBlockIndices, 0, blockIndices, 0, firstBlock); System.arraycopy(mBlockEnds, lastBlock + 1, blockEnds, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); System.arraycopy(mBlockIndices, lastBlock + 1, blockIndices, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); mBlockEnds = blockEnds; mBlockIndices = blockIndices; } else { System.arraycopy(mBlockEnds, lastBlock + 1, mBlockEnds, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); System.arraycopy(mBlockIndices, lastBlock + 1, mBlockIndices, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); } mNumberOfBlocks = newNumberOfBlocks; final int deltaLines = newLineCount - (endLine - startLine + 1); for (int i = firstBlock + numAddedBlocks; i < mNumberOfBlocks; i++) { mBlockEnds[i] += deltaLines; } int blockIndex = firstBlock; if (createBlockBefore) { mBlockEnds[blockIndex] = startLine - 1; mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX; blockIndex++; } if (createBlock) { mBlockEnds[blockIndex] = startLine + newLineCount - 1; mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX; blockIndex++; } if (createBlockAfter) { mBlockEnds[blockIndex] = lastBlockEndLine + deltaLines; mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX; } } /** * @hide */ public int[] getBlockEnds() { return mBlockEnds; } /** * @hide */ public int[] getBlockIndices() { return mBlockIndices; } /** * @hide */ public int getNumberOfBlocks() { return mNumberOfBlocks; } @Override public int getLineCount() { return mInts.size() - 1; Loading Loading @@ -428,6 +551,7 @@ extends Layout } public void beforeTextChanged(CharSequence s, int where, int before, int after) { // Intentionally empty } public void onTextChanged(CharSequence s, int where, int before, int after) { Loading @@ -435,6 +559,7 @@ extends Layout } public void afterTextChanged(Editable s) { // Intentionally empty } public void onSpanAdded(Spannable s, Object o, int start, int end) { Loading Loading @@ -486,6 +611,20 @@ extends Layout private PackedIntVector mInts; private PackedObjectVector<Directions> mObjects; /* * Value used in mBlockIndices when a block has been created or recycled and indicating that its * display list needs to be re-created. * @hide */ public static final int INVALID_BLOCK_INDEX = -1; // Stores the line numbers of the last line of each block private int[] mBlockEnds; // 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; // Number of items actually currently being used in the above 2 arrays private int mNumberOfBlocks; private int mTopPadding, mBottomPadding; private static StaticLayout sStaticLayout = new StaticLayout(null); Loading core/java/android/widget/TextView.java +90 −28 Original line number Diff line number Diff line Loading @@ -139,6 +139,7 @@ import android.view.textservice.TextServicesManager; import android.widget.AdapterView.OnItemClickListener; import android.widget.RemoteViews.RemoteView; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastMath; import com.android.internal.widget.EditableInputConnection; Loading Loading @@ -1214,6 +1215,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (imm != null) imm.restartInput(this); } // Will change text color if (mEditor != null) getEditor().invalidateTextDisplayList(); prepareCursorControllers(); Loading Loading @@ -2328,7 +2330,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void setHighlightColor(int color) { if (mHighlightColor != color) { mHighlightColor = color; if (mEditor != null) getEditor().invalidateTextDisplayList(); invalidate(); } } Loading @@ -2349,6 +2350,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mShadowDx = dx; mShadowDy = dy; // Will change text clip region if (mEditor != null) getEditor().invalidateTextDisplayList(); invalidate(); } Loading Loading @@ -2841,6 +2843,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } if (inval) { // Text needs to be redrawn with the new color if (mEditor != null) getEditor().invalidateTextDisplayList(); invalidate(); } Loading Loading @@ -3332,7 +3335,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener invalidate(); } // Invalidate display list if hint will be used // Invalidate display list if hint is currently used if (mEditor != null && mText.length() == 0 && mHint != null) { getEditor().invalidateTextDisplayList(); } Loading Loading @@ -8274,6 +8277,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (getEditor().mPositionListener != null) { getEditor().mPositionListener.onScrollChanged(); } // Internal scroll affects the clip boundaries getEditor().invalidateTextDisplayList(); } } Loading Loading @@ -11299,7 +11303,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener InputContentType mInputContentType; InputMethodState mInputMethodState; DisplayList mTextDisplayList; DisplayList[] mTextDisplayLists; boolean mFrozenWithFocus; boolean mSelectionMoved; Loading Loading @@ -11545,7 +11549,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener void sendOnTextChanged(int start, int after) { updateSpellCheckSpans(start, start + after, false); invalidateTextDisplayList(); // Hide the controllers as soon as text is modified (typing, procedural...) // We do not hide the span controllers, since they can be added when a new text is Loading Loading @@ -11702,36 +11705,91 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener layout.drawBackground(canvas, highlight, mHighlightPaint, cursorOffsetVertical, firstLine, lastLine); if (mTextDisplayList == null || !mTextDisplayList.isValid()) { boolean displayListCreated = false; if (mTextDisplayList == null) { mTextDisplayList = getHardwareRenderer().createDisplayList("Text"); displayListCreated = true; if (mTextDisplayLists == null) { mTextDisplayLists = new DisplayList[ArrayUtils.idealObjectArraySize(0)]; } if (! (layout instanceof DynamicLayout)) { Log.e(LOG_TAG, "Editable TextView is not using a DynamicLayout"); return; } DynamicLayout dynamicLayout = (DynamicLayout) layout; int[] blockEnds = dynamicLayout.getBlockEnds(); int[] blockIndices = dynamicLayout.getBlockIndices(); final int numberOfBlocks = dynamicLayout.getNumberOfBlocks(); canvas.translate(mScrollX, mScrollY); int endOfPreviousBlock = -1; int searchStartIndex = 0; for (int i = 0; i < numberOfBlocks; i++) { int blockEnd = blockEnds[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 blockIndices[i] = blockIndex; searchStartIndex = blockIndex + 1; } DisplayList blockDisplayList = mTextDisplayLists[blockIndex]; if (blockDisplayList == null) { blockDisplayList = mTextDisplayLists[blockIndex] = getHardwareRenderer().createDisplayList("Text " + blockIndex); } else { if (blockIsInvalid) blockDisplayList.invalidate(); } final HardwareCanvas hardwareCanvas = mTextDisplayList.start(); if (!blockDisplayList.isValid()) { final HardwareCanvas hardwareCanvas = blockDisplayList.start(); try { hardwareCanvas.setViewport(width, height); // The dirty rect should always be null for a display list hardwareCanvas.onPreDraw(null); hardwareCanvas.translate(-mScrollX, -mScrollY); layout.drawText(hardwareCanvas, firstLine, lastLine); //layout.draw(hardwareCanvas, highlight, mHighlightPaint, cursorOffsetVertical); layout.drawText(hardwareCanvas, endOfPreviousBlock + 1, blockEnd); hardwareCanvas.translate(mScrollX, mScrollY); } finally { hardwareCanvas.onPostDraw(); mTextDisplayList.end(); if (displayListCreated && USE_DISPLAY_LIST_PROPERTIES) { mTextDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); blockDisplayList.end(); if (USE_DISPLAY_LIST_PROPERTIES) { blockDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); } } } canvas.translate(mScrollX, mScrollY); ((HardwareCanvas) canvas).drawDisplayList(mTextDisplayList, width, height, null, ((HardwareCanvas) canvas).drawDisplayList(blockDisplayList, width, height, null, DisplayList.FLAG_CLIP_CHILDREN); endOfPreviousBlock = blockEnd; } canvas.translate(-mScrollX, -mScrollY); } private int getAvailableDisplayListIndex(int[] blockIndices, int numberOfBlocks, int searchStartIndex) { int length = mTextDisplayLists.length; for (int i = searchStartIndex; i < length; i++) { boolean blockIndexFound = false; for (int j = 0; j < numberOfBlocks; j++) { if (blockIndices[j] == i) { blockIndexFound = true; break; } } if (blockIndexFound) continue; return i; } // No available index found, the pool has to grow int newSize = ArrayUtils.idealIntArraySize(length + 1); DisplayList[] displayLists = new DisplayList[newSize]; System.arraycopy(mTextDisplayLists, 0, displayLists, 0, length); mTextDisplayLists = displayLists; return length; } private void drawCursor(Canvas canvas, int cursorOffsetVertical) { final boolean translate = cursorOffsetVertical != 0; if (translate) canvas.translate(0, cursorOffsetVertical); Loading @@ -11742,7 +11800,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private void invalidateTextDisplayList() { if (mTextDisplayList != null) mTextDisplayList.invalidate(); if (mTextDisplayLists != null) { for (int i = 0; i < mTextDisplayLists.length; i++) { if (mTextDisplayLists[i] != null) mTextDisplayLists[i].invalidate(); } } } private void updateCursorsPositions() { Loading Loading
core/java/android/text/DynamicLayout.java +142 −3 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import android.graphics.Paint; import android.text.style.UpdateLayout; import android.text.style.WrapTogetherSpan; import com.android.internal.util.ArrayUtils; import java.lang.ref.WeakReference; /** Loading @@ -30,8 +32,7 @@ import java.lang.ref.WeakReference; * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint) * Canvas.drawText()} directly.</p> */ public class DynamicLayout extends Layout public class DynamicLayout extends Layout { private static final int PRIORITY = 128; Loading Loading @@ -116,6 +117,10 @@ extends Layout mObjects = new PackedObjectVector<Directions>(1); mBlockEnds = new int[] { 0 }; mBlockIndices = new int[] { INVALID_BLOCK_INDEX }; mNumberOfBlocks = 1; mIncludePad = includepad; /* Loading Loading @@ -295,9 +300,9 @@ extends Layout n--; // remove affected lines from old layout mInts.deleteAt(startline, endline - startline); mObjects.deleteAt(startline, endline - startline); updateBlocks(startline, endline - 1, n); // adjust offsets in layout for new height and offsets Loading Loading @@ -363,6 +368,124 @@ extends Layout } } /** * This method is called every time the layout is reflowed after an edition. * It updates the internal block data structure. The text is split in blocks * of contiguous lines, with at least one block for the entire text. * When a range of lines is edited, new blocks (from 0 to 3 depending on the * overlap structure) will replace the set of overlapping blocks. * Blocks are listed in order and are represented by their ending line number. * An index is associated to each block (which will be used by display lists), * this class simply invalidates the index of blocks overlapping a modification. * * @param startLine the first line of the range of modified lines * @param endLine the last line of the range, possibly equal to startLine, lower * than getLineCount() * @param newLineCount the number of lines that will replace the range, possibly 0 */ private void updateBlocks(int startLine, int endLine, int newLineCount) { int firstBlock = -1; int lastBlock = -1; for (int i = 0; i < mNumberOfBlocks; i++) { if (mBlockEnds[i] >= startLine) { firstBlock = i; break; } } for (int i = firstBlock; i < mNumberOfBlocks; i++) { if (mBlockEnds[i] >= endLine) { lastBlock = i; break; } } final int lastBlockEndLine = mBlockEnds[lastBlock]; boolean createBlockBefore = startLine > (firstBlock == 0 ? 0 : mBlockEnds[firstBlock - 1] + 1); boolean createBlock = newLineCount > 0; boolean createBlockAfter = endLine < mBlockEnds[lastBlock]; int numAddedBlocks = 0; if (createBlockBefore) numAddedBlocks++; if (createBlock) numAddedBlocks++; if (createBlockAfter) numAddedBlocks++; final int numRemovedBlocks = lastBlock - firstBlock + 1; final int newNumberOfBlocks = mNumberOfBlocks + numAddedBlocks - numRemovedBlocks; if (newNumberOfBlocks == 0) { // Even when text is empty, there is actually one line and hence one block mBlockEnds[0] = 0; mBlockIndices[0] = INVALID_BLOCK_INDEX; mNumberOfBlocks = 1; return; } if (newNumberOfBlocks > mBlockEnds.length) { final int newSize = ArrayUtils.idealIntArraySize(newNumberOfBlocks); int[] blockEnds = new int[newSize]; int[] blockIndices = new int[newSize]; System.arraycopy(mBlockEnds, 0, blockEnds, 0, firstBlock); System.arraycopy(mBlockIndices, 0, blockIndices, 0, firstBlock); System.arraycopy(mBlockEnds, lastBlock + 1, blockEnds, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); System.arraycopy(mBlockIndices, lastBlock + 1, blockIndices, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); mBlockEnds = blockEnds; mBlockIndices = blockIndices; } else { System.arraycopy(mBlockEnds, lastBlock + 1, mBlockEnds, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); System.arraycopy(mBlockIndices, lastBlock + 1, mBlockIndices, firstBlock + numAddedBlocks, mNumberOfBlocks - lastBlock - 1); } mNumberOfBlocks = newNumberOfBlocks; final int deltaLines = newLineCount - (endLine - startLine + 1); for (int i = firstBlock + numAddedBlocks; i < mNumberOfBlocks; i++) { mBlockEnds[i] += deltaLines; } int blockIndex = firstBlock; if (createBlockBefore) { mBlockEnds[blockIndex] = startLine - 1; mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX; blockIndex++; } if (createBlock) { mBlockEnds[blockIndex] = startLine + newLineCount - 1; mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX; blockIndex++; } if (createBlockAfter) { mBlockEnds[blockIndex] = lastBlockEndLine + deltaLines; mBlockIndices[blockIndex] = INVALID_BLOCK_INDEX; } } /** * @hide */ public int[] getBlockEnds() { return mBlockEnds; } /** * @hide */ public int[] getBlockIndices() { return mBlockIndices; } /** * @hide */ public int getNumberOfBlocks() { return mNumberOfBlocks; } @Override public int getLineCount() { return mInts.size() - 1; Loading Loading @@ -428,6 +551,7 @@ extends Layout } public void beforeTextChanged(CharSequence s, int where, int before, int after) { // Intentionally empty } public void onTextChanged(CharSequence s, int where, int before, int after) { Loading @@ -435,6 +559,7 @@ extends Layout } public void afterTextChanged(Editable s) { // Intentionally empty } public void onSpanAdded(Spannable s, Object o, int start, int end) { Loading Loading @@ -486,6 +611,20 @@ extends Layout private PackedIntVector mInts; private PackedObjectVector<Directions> mObjects; /* * Value used in mBlockIndices when a block has been created or recycled and indicating that its * display list needs to be re-created. * @hide */ public static final int INVALID_BLOCK_INDEX = -1; // Stores the line numbers of the last line of each block private int[] mBlockEnds; // 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; // Number of items actually currently being used in the above 2 arrays private int mNumberOfBlocks; private int mTopPadding, mBottomPadding; private static StaticLayout sStaticLayout = new StaticLayout(null); Loading
core/java/android/widget/TextView.java +90 −28 Original line number Diff line number Diff line Loading @@ -139,6 +139,7 @@ import android.view.textservice.TextServicesManager; import android.widget.AdapterView.OnItemClickListener; import android.widget.RemoteViews.RemoteView; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastMath; import com.android.internal.widget.EditableInputConnection; Loading Loading @@ -1214,6 +1215,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (imm != null) imm.restartInput(this); } // Will change text color if (mEditor != null) getEditor().invalidateTextDisplayList(); prepareCursorControllers(); Loading Loading @@ -2328,7 +2330,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void setHighlightColor(int color) { if (mHighlightColor != color) { mHighlightColor = color; if (mEditor != null) getEditor().invalidateTextDisplayList(); invalidate(); } } Loading @@ -2349,6 +2350,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mShadowDx = dx; mShadowDy = dy; // Will change text clip region if (mEditor != null) getEditor().invalidateTextDisplayList(); invalidate(); } Loading Loading @@ -2841,6 +2843,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } if (inval) { // Text needs to be redrawn with the new color if (mEditor != null) getEditor().invalidateTextDisplayList(); invalidate(); } Loading Loading @@ -3332,7 +3335,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener invalidate(); } // Invalidate display list if hint will be used // Invalidate display list if hint is currently used if (mEditor != null && mText.length() == 0 && mHint != null) { getEditor().invalidateTextDisplayList(); } Loading Loading @@ -8274,6 +8277,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (getEditor().mPositionListener != null) { getEditor().mPositionListener.onScrollChanged(); } // Internal scroll affects the clip boundaries getEditor().invalidateTextDisplayList(); } } Loading Loading @@ -11299,7 +11303,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener InputContentType mInputContentType; InputMethodState mInputMethodState; DisplayList mTextDisplayList; DisplayList[] mTextDisplayLists; boolean mFrozenWithFocus; boolean mSelectionMoved; Loading Loading @@ -11545,7 +11549,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener void sendOnTextChanged(int start, int after) { updateSpellCheckSpans(start, start + after, false); invalidateTextDisplayList(); // Hide the controllers as soon as text is modified (typing, procedural...) // We do not hide the span controllers, since they can be added when a new text is Loading Loading @@ -11702,36 +11705,91 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener layout.drawBackground(canvas, highlight, mHighlightPaint, cursorOffsetVertical, firstLine, lastLine); if (mTextDisplayList == null || !mTextDisplayList.isValid()) { boolean displayListCreated = false; if (mTextDisplayList == null) { mTextDisplayList = getHardwareRenderer().createDisplayList("Text"); displayListCreated = true; if (mTextDisplayLists == null) { mTextDisplayLists = new DisplayList[ArrayUtils.idealObjectArraySize(0)]; } if (! (layout instanceof DynamicLayout)) { Log.e(LOG_TAG, "Editable TextView is not using a DynamicLayout"); return; } DynamicLayout dynamicLayout = (DynamicLayout) layout; int[] blockEnds = dynamicLayout.getBlockEnds(); int[] blockIndices = dynamicLayout.getBlockIndices(); final int numberOfBlocks = dynamicLayout.getNumberOfBlocks(); canvas.translate(mScrollX, mScrollY); int endOfPreviousBlock = -1; int searchStartIndex = 0; for (int i = 0; i < numberOfBlocks; i++) { int blockEnd = blockEnds[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 blockIndices[i] = blockIndex; searchStartIndex = blockIndex + 1; } DisplayList blockDisplayList = mTextDisplayLists[blockIndex]; if (blockDisplayList == null) { blockDisplayList = mTextDisplayLists[blockIndex] = getHardwareRenderer().createDisplayList("Text " + blockIndex); } else { if (blockIsInvalid) blockDisplayList.invalidate(); } final HardwareCanvas hardwareCanvas = mTextDisplayList.start(); if (!blockDisplayList.isValid()) { final HardwareCanvas hardwareCanvas = blockDisplayList.start(); try { hardwareCanvas.setViewport(width, height); // The dirty rect should always be null for a display list hardwareCanvas.onPreDraw(null); hardwareCanvas.translate(-mScrollX, -mScrollY); layout.drawText(hardwareCanvas, firstLine, lastLine); //layout.draw(hardwareCanvas, highlight, mHighlightPaint, cursorOffsetVertical); layout.drawText(hardwareCanvas, endOfPreviousBlock + 1, blockEnd); hardwareCanvas.translate(mScrollX, mScrollY); } finally { hardwareCanvas.onPostDraw(); mTextDisplayList.end(); if (displayListCreated && USE_DISPLAY_LIST_PROPERTIES) { mTextDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); blockDisplayList.end(); if (USE_DISPLAY_LIST_PROPERTIES) { blockDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); } } } canvas.translate(mScrollX, mScrollY); ((HardwareCanvas) canvas).drawDisplayList(mTextDisplayList, width, height, null, ((HardwareCanvas) canvas).drawDisplayList(blockDisplayList, width, height, null, DisplayList.FLAG_CLIP_CHILDREN); endOfPreviousBlock = blockEnd; } canvas.translate(-mScrollX, -mScrollY); } private int getAvailableDisplayListIndex(int[] blockIndices, int numberOfBlocks, int searchStartIndex) { int length = mTextDisplayLists.length; for (int i = searchStartIndex; i < length; i++) { boolean blockIndexFound = false; for (int j = 0; j < numberOfBlocks; j++) { if (blockIndices[j] == i) { blockIndexFound = true; break; } } if (blockIndexFound) continue; return i; } // No available index found, the pool has to grow int newSize = ArrayUtils.idealIntArraySize(length + 1); DisplayList[] displayLists = new DisplayList[newSize]; System.arraycopy(mTextDisplayLists, 0, displayLists, 0, length); mTextDisplayLists = displayLists; return length; } private void drawCursor(Canvas canvas, int cursorOffsetVertical) { final boolean translate = cursorOffsetVertical != 0; if (translate) canvas.translate(0, cursorOffsetVertical); Loading @@ -11742,7 +11800,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private void invalidateTextDisplayList() { if (mTextDisplayList != null) mTextDisplayList.invalidate(); if (mTextDisplayLists != null) { for (int i = 0; i < mTextDisplayLists.length; i++) { if (mTextDisplayLists[i] != null) mTextDisplayLists[i].invalidate(); } } } private void updateCursorsPositions() { Loading