diff options
| -rw-r--r-- | core/java/android/text/DynamicLayout.java | 26 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/text/DynamicLayoutTest.java | 22 |
2 files changed, 39 insertions, 9 deletions
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index fba358cf4c1b..71e039a1e0ef 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -492,7 +492,9 @@ public class DynamicLayout extends Layout } } - private void reflow(CharSequence s, int where, int before, int after) { + /** @hide */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void reflow(CharSequence s, int where, int before, int after) { if (s != mBase) return; @@ -805,8 +807,8 @@ public class DynamicLayout extends Layout return; } - int firstBlock = -1; - int lastBlock = -1; + /*final*/ int firstBlock = -1; + /*final*/ int lastBlock = -1; for (int i = 0; i < mNumberOfBlocks; i++) { if (mBlockEndLines[i] >= startLine) { firstBlock = i; @@ -821,10 +823,10 @@ public class DynamicLayout extends Layout } final int lastBlockEndLine = mBlockEndLines[lastBlock]; - boolean createBlockBefore = startLine > (firstBlock == 0 ? 0 : + final boolean createBlockBefore = startLine > (firstBlock == 0 ? 0 : mBlockEndLines[firstBlock - 1] + 1); - boolean createBlock = newLineCount > 0; - boolean createBlockAfter = endLine < mBlockEndLines[lastBlock]; + final boolean createBlock = newLineCount > 0; + final boolean createBlockAfter = endLine < mBlockEndLines[lastBlock]; int numAddedBlocks = 0; if (createBlockBefore) numAddedBlocks++; @@ -863,12 +865,18 @@ public class DynamicLayout extends Layout if (numAddedBlocks + numRemovedBlocks != 0 && mBlocksAlwaysNeedToBeRedrawn != null) { final ArraySet<Integer> set = new ArraySet<>(); + final int changedBlockCount = numAddedBlocks - numRemovedBlocks; for (int i = 0; i < mBlocksAlwaysNeedToBeRedrawn.size(); i++) { Integer block = mBlocksAlwaysNeedToBeRedrawn.valueAt(i); - if (block > firstBlock) { - block += numAddedBlocks - numRemovedBlocks; + if (block < firstBlock) { + // block index is before firstBlock add it since it did not change + set.add(block); + } + if (block > lastBlock) { + // block index is after lastBlock, the index reduced to += changedBlockCount + block += changedBlockCount; + set.add(block); } - set.add(block); } mBlocksAlwaysNeedToBeRedrawn = set; } diff --git a/core/tests/coretests/src/android/text/DynamicLayoutTest.java b/core/tests/coretests/src/android/text/DynamicLayoutTest.java index aa9aed8e2fcc..ea954f65476d 100644 --- a/core/tests/coretests/src/android/text/DynamicLayoutTest.java +++ b/core/tests/coretests/src/android/text/DynamicLayoutTest.java @@ -30,6 +30,7 @@ import android.platform.test.annotations.Presubmit; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.text.style.ReplacementSpan; +import android.util.ArraySet; import org.junit.Test; import org.junit.runner.RunWith; @@ -190,6 +191,27 @@ public class DynamicLayoutTest { } @Test + public void testReflow_afterSpannableEdit() { + final String text = "a\nb:\uD83C\uDF1A c \n\uD83C\uDF1A"; + final int length = text.length(); + final SpannableStringBuilder spannable = new SpannableStringBuilder(text); + spannable.setSpan(new MockReplacementSpan(), 4, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + spannable.setSpan(new MockReplacementSpan(), 10, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + final DynamicLayout layout = new DynamicLayout(spannable, new TextPaint(), WIDTH, + ALIGN_NORMAL, 1.0f /*spacingMultiplier*/, 0f /*spacingAdd*/, false /*includepad*/); + + spannable.delete(8, 9); + spannable.replace(7, 8, "ch"); + + layout.reflow(spannable, 0, length, length); + final ArraySet<Integer> blocks = layout.getBlocksAlwaysNeedToBeRedrawn(); + for (Integer value : blocks) { + assertTrue("Block index should not be negative", value >= 0); + } + } + + @Test public void testFallbackLineSpacing() { // All glyphs in the fonts are 1em wide. final String[] testFontFiles = { |