Skip to content

Commit 71afc39

Browse files
author
Gilles Debunne
committed
Cut long text into multiple DL at start
Bug 5763685 To improve performance, preventively cut the the into display list of 3-10 lines of text. Further updates to small parts of the text (such as adding an underline on a word) will only invalidate and redraw the affected sub display list. DLs are aligned with paragraphs, just like they will be during text edition. Change-Id: I0d60debc7fdaea8b29080a6eacb2d60205e7d547
1 parent c2e393f commit 71afc39

File tree

1 file changed

+65
-8
lines changed

1 file changed

+65
-8
lines changed

core/java/android/text/DynamicLayout.java

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
public class DynamicLayout extends Layout
3636
{
3737
private static final int PRIORITY = 128;
38+
private static final int BLOCK_MINIMUM_CHARACTER_LENGTH = 400;
3839

3940
/**
4041
* Make a layout for the specified text that will be updated as
@@ -117,10 +118,6 @@ public DynamicLayout(CharSequence base, CharSequence display,
117118

118119
mObjects = new PackedObjectVector<Directions>(1);
119120

120-
mBlockEndLines = new int[] { 0 };
121-
mBlockIndices = new int[] { INVALID_BLOCK_INDEX };
122-
mNumberOfBlocks = 1;
123-
124121
mIncludePad = includepad;
125122

126123
/*
@@ -170,7 +167,6 @@ public DynamicLayout(CharSequence base, CharSequence display,
170167
mObjects.insertAt(0, dirs);
171168

172169
// Update from 0 characters to whatever the real text is
173-
174170
reflow(base, 0, 0, base.length());
175171

176172
if (base instanceof Spannable) {
@@ -295,14 +291,12 @@ private void reflow(CharSequence s, int where, int before, int after) {
295291
// the very end of the buffer, then we already have a line that
296292
// starts there, so disregard the blank line.
297293

298-
if (where + after != len &&
299-
reflowed.getLineStart(n - 1) == where + after)
294+
if (where + after != len && reflowed.getLineStart(n - 1) == where + after)
300295
n--;
301296

302297
// remove affected lines from old layout
303298
mInts.deleteAt(startline, endline - startline);
304299
mObjects.deleteAt(startline, endline - startline);
305-
updateBlocks(startline, endline - 1, n);
306300

307301
// adjust offsets in layout for new height and offsets
308302

@@ -362,12 +356,70 @@ private void reflow(CharSequence s, int where, int before, int after) {
362356
mObjects.insertAt(startline + i, objects);
363357
}
364358

359+
updateBlocks(startline, endline - 1, n);
360+
365361
synchronized (sLock) {
366362
sStaticLayout = reflowed;
367363
reflowed.finish();
368364
}
369365
}
370366

367+
/**
368+
* Create the initial block structure, cutting the text into blocks of at least
369+
* BLOCK_MINIMUM_CHARACTER_SIZE characters, aligned on the ends of paragraphs.
370+
*/
371+
private void createBlocks() {
372+
int offset = BLOCK_MINIMUM_CHARACTER_LENGTH;
373+
mNumberOfBlocks = 0;
374+
final CharSequence text = mDisplay;
375+
376+
while (true) {
377+
offset = TextUtils.indexOf(text, '\n', offset);
378+
if (offset < 0) {
379+
addBlockAtOffset(text.length());
380+
break;
381+
} else {
382+
addBlockAtOffset(offset);
383+
offset += BLOCK_MINIMUM_CHARACTER_LENGTH;
384+
}
385+
}
386+
387+
// mBlockIndices and mBlockEndLines should have the same length
388+
mBlockIndices = new int[mBlockEndLines.length];
389+
for (int i = 0; i < mBlockEndLines.length; i++) {
390+
mBlockIndices[i] = INVALID_BLOCK_INDEX;
391+
}
392+
}
393+
394+
/**
395+
* Create a new block, ending at the specified character offset.
396+
* A block will actually be created only if has at least one line, i.e. this offset is
397+
* not on the end line of the previous block.
398+
*/
399+
private void addBlockAtOffset(int offset) {
400+
final int line = getLineForOffset(offset);
401+
402+
if (mBlockEndLines == null) {
403+
// Initial creation of the array, no test on previous block ending line
404+
mBlockEndLines = new int[ArrayUtils.idealIntArraySize(1)];
405+
mBlockEndLines[mNumberOfBlocks] = line;
406+
mNumberOfBlocks++;
407+
return;
408+
}
409+
410+
final int previousBlockEndLine = mBlockEndLines[mNumberOfBlocks - 1];
411+
if (line > previousBlockEndLine) {
412+
if (mNumberOfBlocks == mBlockEndLines.length) {
413+
// Grow the array if needed
414+
int[] blockEndLines = new int[ArrayUtils.idealIntArraySize(mNumberOfBlocks + 1)];
415+
System.arraycopy(mBlockEndLines, 0, blockEndLines, 0, mNumberOfBlocks);
416+
mBlockEndLines = blockEndLines;
417+
}
418+
mBlockEndLines[mNumberOfBlocks] = line;
419+
mNumberOfBlocks++;
420+
}
421+
}
422+
371423
/**
372424
* This method is called every time the layout is reflowed after an edition.
373425
* It updates the internal block data structure. The text is split in blocks
@@ -388,6 +440,11 @@ private void reflow(CharSequence s, int where, int before, int after) {
388440
* @hide
389441
*/
390442
void updateBlocks(int startLine, int endLine, int newLineCount) {
443+
if (mBlockEndLines == null) {
444+
createBlocks();
445+
return;
446+
}
447+
391448
int firstBlock = -1;
392449
int lastBlock = -1;
393450
for (int i = 0; i < mNumberOfBlocks; i++) {

0 commit comments

Comments
 (0)