diff --git a/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java b/apct-tests/perftests/core/src/android/text/MeasuredTextMemoryUsageTest.java similarity index 73% rename from apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java rename to apct-tests/perftests/core/src/android/text/MeasuredTextMemoryUsageTest.java index 73e17242ae785..fc6302ea93942 100644 --- a/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java +++ b/apct-tests/perftests/core/src/android/text/MeasuredTextMemoryUsageTest.java @@ -45,7 +45,7 @@ import java.util.Random; @LargeTest @RunWith(AndroidJUnit4.class) -public class PrecomputedTextMemoryUsageTest { +public class MeasuredTextMemoryUsageTest { private static final int WORD_LENGTH = 9; // Random word has 9 characters. private static final boolean NO_STYLE_TEXT = false; @@ -53,7 +53,7 @@ public class PrecomputedTextMemoryUsageTest { private static int TRIAL_COUNT = 100; - public PrecomputedTextMemoryUsageTest() {} + public MeasuredTextMemoryUsageTest() {} private TextPerfUtils mTextUtil = new TextPerfUtils(); @@ -77,16 +77,13 @@ public class PrecomputedTextMemoryUsageTest { @Test public void testMemoryUsage_NoHyphenation() { int[] memories = new int[TRIAL_COUNT]; - final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT) + // Report median of randomly generated MeasuredText. + for (int i = 0; i < TRIAL_COUNT; ++i) { + memories[i] = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) - .build(); - - // Report median of randomly generated PrecomputedText. - for (int i = 0; i < TRIAL_COUNT; ++i) { - memories[i] = PrecomputedText.create( - mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), param) - .getMemoryUsage(); + .build().getMemoryUsage(); } reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation"); } @@ -94,16 +91,13 @@ public class PrecomputedTextMemoryUsageTest { @Test public void testMemoryUsage_Hyphenation() { int[] memories = new int[TRIAL_COUNT]; - final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT) + // Report median of randomly generated MeasuredText. + for (int i = 0; i < TRIAL_COUNT; ++i) { + memories[i] = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) - .build(); - - // Report median of randomly generated PrecomputedText. - for (int i = 0; i < TRIAL_COUNT; ++i) { - memories[i] = PrecomputedText.create( - mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), param) - .getMemoryUsage(); + .build().getMemoryUsage(); } reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation"); } @@ -111,16 +105,13 @@ public class PrecomputedTextMemoryUsageTest { @Test public void testMemoryUsage_NoHyphenation_WidthOnly() { int[] memories = new int[TRIAL_COUNT]; - final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT) + // Report median of randomly generated MeasuredText. + for (int i = 0; i < TRIAL_COUNT; ++i) { + memories[i] = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) - .build(); - - // Report median of randomly generated PrecomputedText. - for (int i = 0; i < TRIAL_COUNT; ++i) { - CharSequence cs = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); - memories[i] = PrecomputedText.createWidthOnly(cs, param, 0, cs.length()) - .getMemoryUsage(); + .build(false /* width only */).getMemoryUsage(); } reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation_WidthOnly"); } @@ -128,16 +119,13 @@ public class PrecomputedTextMemoryUsageTest { @Test public void testMemoryUsage_Hyphenatation_WidthOnly() { int[] memories = new int[TRIAL_COUNT]; - final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT) + // Report median of randomly generated MeasuredText. + for (int i = 0; i < TRIAL_COUNT; ++i) { + memories[i] = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) - .build(); - - // Report median of randomly generated PrecomputedText. - for (int i = 0; i < TRIAL_COUNT; ++i) { - CharSequence cs = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); - memories[i] = PrecomputedText.createWidthOnly(cs, param, 0, cs.length()) - .getMemoryUsage(); + .build(false /* width only */).getMemoryUsage(); } reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation_WidthOnly"); } diff --git a/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/text/MeasuredTextPerfTest.java similarity index 66% rename from apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java rename to apct-tests/perftests/core/src/android/text/MeasuredTextPerfTest.java index 1cd0ae13069bb..98f2bd5e57365 100644 --- a/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/MeasuredTextPerfTest.java @@ -42,7 +42,7 @@ import java.util.Random; @LargeTest @RunWith(AndroidJUnit4.class) -public class PrecomputedTextPerfTest { +public class MeasuredTextPerfTest { private static final int WORD_LENGTH = 9; // Random word has 9 characters. private static final int WORDS_IN_LINE = 8; // Roughly, 8 words in a line. private static final boolean NO_STYLE_TEXT = false; @@ -51,7 +51,7 @@ public class PrecomputedTextPerfTest { private static TextPaint PAINT = new TextPaint(); private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize(); - public PrecomputedTextPerfTest() {} + public MeasuredTextPerfTest() {} @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); @@ -66,136 +66,120 @@ public class PrecomputedTextPerfTest { @Test public void testCreate_NoStyled_Hyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT) - .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) - .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) - .build(); - while (state.keepRunning()) { state.pauseTiming(); final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); state.resumeTiming(); - PrecomputedText.create(text, param); + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build(true /* do full layout */); } } @Test public void testCreate_NoStyled_NoHyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT) - .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) - .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) - .build(); - while (state.keepRunning()) { state.pauseTiming(); final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); state.resumeTiming(); - PrecomputedText.create(text, param); + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build(true /* do full layout */); } } @Test public void testCreate_NoStyled_Hyphenation_WidthOnly() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT) - .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) - .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) - .build(); - while (state.keepRunning()) { state.pauseTiming(); final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); state.resumeTiming(); - PrecomputedText.create(text, param); + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build(false /* width only */); } } @Test public void testCreate_NoStyled_NoHyphenation_WidthOnly() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT) - .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) - .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) - .build(); - while (state.keepRunning()) { state.pauseTiming(); final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); state.resumeTiming(); - PrecomputedText.create(text, param); + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build(false /* width only */); } } @Test public void testCreate_Styled_Hyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT) - .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) - .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) - .build(); - while (state.keepRunning()) { state.pauseTiming(); final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT); state.resumeTiming(); - PrecomputedText.create(text, param); + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build(true /* do full layout */); } } @Test public void testCreate_Styled_NoHyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT) - .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) - .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) - .build(); - while (state.keepRunning()) { state.pauseTiming(); final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT); state.resumeTiming(); - PrecomputedText.create(text, param); + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build(true /* do full layout */); } } @Test public void testCreate_Styled_Hyphenation_WidthOnly() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT) - .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) - .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) - .build(); - while (state.keepRunning()) { state.pauseTiming(); final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT); state.resumeTiming(); - PrecomputedText.create(text, param); + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build(false /* width only */); } } @Test public void testCreate_Styled_NoHyphenation_WidthOnly() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT) - .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) - .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) - .build(); - while (state.keepRunning()) { state.pauseTiming(); final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT); state.resumeTiming(); - PrecomputedText.create(text, param); + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build(false /* width only */); } } } diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java index 8823af1df3509..231aaf2ca0749 100644 --- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java @@ -63,18 +63,6 @@ public class StaticLayoutPerfTest { mTextUtil.resetRandom(0 /* seed */); } - private PrecomputedText makeMeasured(CharSequence text, TextPaint paint) { - PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint).build(); - return PrecomputedText.create(text, param); - } - - private PrecomputedText makeMeasured(CharSequence text, TextPaint paint, int strategy, - int frequency) { - PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint) - .setHyphenationFrequency(frequency).setBreakStrategy(strategy).build(); - return PrecomputedText.create(text, param); - } - @Test public void testCreate_FixedText_NoStyle_Greedy_NoHyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); @@ -163,16 +151,18 @@ public class StaticLayoutPerfTest { } @Test - public void testCreate_PrecomputedText_NoStyled_Greedy_NoHyphenation() { + public void testCreate_MeasuredText_NoStyled_Greedy_NoHyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { state.pauseTiming(); - final PrecomputedText text = makeMeasured( - mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, - Layout.BREAK_STRATEGY_SIMPLE, Layout.HYPHENATION_FREQUENCY_NONE); + final MeasuredText text = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build(); state.resumeTiming(); - StaticLayout.Builder.obtain(text, 0, text.getText().length(), PAINT, TEXT_WIDTH) + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) .build(); @@ -180,16 +170,18 @@ public class StaticLayoutPerfTest { } @Test - public void testCreate_PrecomputedText_NoStyled_Greedy_Hyphenation() { + public void testCreate_MeasuredText_NoStyled_Greedy_Hyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { state.pauseTiming(); - final PrecomputedText text = makeMeasured( - mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, - Layout.BREAK_STRATEGY_SIMPLE, Layout.HYPHENATION_FREQUENCY_NORMAL); + final MeasuredText text = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build(); state.resumeTiming(); - StaticLayout.Builder.obtain(text, 0, text.getText().length(), PAINT, TEXT_WIDTH) + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) .build(); @@ -197,16 +189,18 @@ public class StaticLayoutPerfTest { } @Test - public void testCreate_PrecomputedText_NoStyled_Balanced_NoHyphenation() { + public void testCreate_MeasuredText_NoStyled_Balanced_NoHyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { state.pauseTiming(); - final PrecomputedText text = makeMeasured( - mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, - Layout.BREAK_STRATEGY_BALANCED, Layout.HYPHENATION_FREQUENCY_NONE); + final MeasuredText text = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build(); state.resumeTiming(); - StaticLayout.Builder.obtain(text, 0, text.getText().length(), PAINT, TEXT_WIDTH) + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) .build(); @@ -214,16 +208,18 @@ public class StaticLayoutPerfTest { } @Test - public void testCreate_PrecomputedText_NoStyled_Balanced_Hyphenation() { + public void testCreate_MeasuredText_NoStyled_Balanced_Hyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { state.pauseTiming(); - final PrecomputedText text = makeMeasured( - mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, - Layout.BREAK_STRATEGY_BALANCED, Layout.HYPHENATION_FREQUENCY_NORMAL); + final MeasuredText text = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build(); state.resumeTiming(); - StaticLayout.Builder.obtain(text, 0, text.getText().length(), PAINT, TEXT_WIDTH) + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) .build(); @@ -231,16 +227,18 @@ public class StaticLayoutPerfTest { } @Test - public void testCreate_PrecomputedText_Styled_Greedy_NoHyphenation() { + public void testCreate_MeasuredText_Styled_Greedy_NoHyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { state.pauseTiming(); - final PrecomputedText text = makeMeasured( - mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT, - Layout.BREAK_STRATEGY_SIMPLE, Layout.HYPHENATION_FREQUENCY_NONE); + final MeasuredText text = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build(); state.resumeTiming(); - StaticLayout.Builder.obtain(text, 0, text.getText().length(), PAINT, TEXT_WIDTH) + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) .build(); @@ -330,16 +328,15 @@ public class StaticLayoutPerfTest { } @Test - public void testDraw_PrecomputedText_Styled() { + public void testDraw_MeasuredText_Styled() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); final RenderNode node = RenderNode.create("benchmark", null); while (state.keepRunning()) { state.pauseTiming(); - final PrecomputedText text = makeMeasured( - mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT); + final MeasuredText text = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build(); final StaticLayout layout = - StaticLayout.Builder.obtain( - text, 0, text.getText().length(), PAINT, TEXT_WIDTH).build(); + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build(); final DisplayListCanvas c = node.start(1200, 200); state.resumeTiming(); @@ -348,16 +345,15 @@ public class StaticLayoutPerfTest { } @Test - public void testDraw_PrecomputedText_NoStyled() { + public void testDraw_MeasuredText_NoStyled() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); final RenderNode node = RenderNode.create("benchmark", null); while (state.keepRunning()) { state.pauseTiming(); - final PrecomputedText text = makeMeasured( - mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT); + final MeasuredText text = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build(); final StaticLayout layout = - StaticLayout.Builder.obtain( - text, 0, text.getText().length(), PAINT, TEXT_WIDTH).build(); + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build(); final DisplayListCanvas c = node.start(1200, 200); state.resumeTiming(); @@ -366,16 +362,15 @@ public class StaticLayoutPerfTest { } @Test - public void testDraw_PrecomputedText_Styled_WithoutCache() { + public void testDraw_MeasuredText_Styled_WithoutCache() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); final RenderNode node = RenderNode.create("benchmark", null); while (state.keepRunning()) { state.pauseTiming(); - final PrecomputedText text = makeMeasured( - mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT); + final MeasuredText text = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build(); final StaticLayout layout = - StaticLayout.Builder.obtain( - text, 0, text.getText().length(), PAINT, TEXT_WIDTH).build(); + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build(); final DisplayListCanvas c = node.start(1200, 200); Canvas.freeTextLayoutCaches(); state.resumeTiming(); @@ -385,16 +380,15 @@ public class StaticLayoutPerfTest { } @Test - public void testDraw_PrecomputedText_NoStyled_WithoutCache() { + public void testDraw_MeasuredText_NoStyled_WithoutCache() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); final RenderNode node = RenderNode.create("benchmark", null); while (state.keepRunning()) { state.pauseTiming(); - final PrecomputedText text = makeMeasured( - mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT); + final MeasuredText text = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build(); final StaticLayout layout = - StaticLayout.Builder.obtain( - text, 0, text.getText().length(), PAINT, TEXT_WIDTH).build(); + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build(); final DisplayListCanvas c = node.start(1200, 200); Canvas.freeTextLayoutCaches(); state.resumeTiming(); diff --git a/api/current.txt b/api/current.txt index 3edd2c08bcf31..7150c29fe3cfb 100644 --- a/api/current.txt +++ b/api/current.txt @@ -13835,7 +13835,6 @@ package android.graphics { method public int breakText(java.lang.String, boolean, float, float[]); method public void clearShadowLayer(); method public float descent(); - method public boolean equalsForTextMeasurement(android.graphics.Paint); method public int getAlpha(); method public int getColor(); method public android.graphics.ColorFilter getColorFilter(); @@ -43225,6 +43224,36 @@ package android.text { method public boolean isAllowed(char); } + public class MeasuredText implements android.text.Spanned { + method public char charAt(int); + method public int getBreakStrategy(); + method public int getEnd(); + method public int getHyphenationFrequency(); + method public android.text.TextPaint getPaint(); + method public int getParagraphCount(); + method public int getParagraphEnd(int); + method public int getParagraphStart(int); + method public int getSpanEnd(java.lang.Object); + method public int getSpanFlags(java.lang.Object); + method public int getSpanStart(java.lang.Object); + method public T[] getSpans(int, int, java.lang.Class); + method public int getStart(); + method public java.lang.CharSequence getText(); + method public android.text.TextDirectionHeuristic getTextDir(); + method public int length(); + method public int nextSpanTransition(int, int, java.lang.Class); + method public java.lang.CharSequence subSequence(int, int); + } + + public static final class MeasuredText.Builder { + ctor public MeasuredText.Builder(java.lang.CharSequence, android.text.TextPaint); + method public android.text.MeasuredText build(); + method public android.text.MeasuredText.Builder setBreakStrategy(int); + method public android.text.MeasuredText.Builder setHyphenationFrequency(int); + method public android.text.MeasuredText.Builder setRange(int, int); + method public android.text.MeasuredText.Builder setTextDirection(android.text.TextDirectionHeuristic); + } + public abstract interface NoCopySpan { } @@ -43236,31 +43265,6 @@ package android.text { method public abstract int getSpanTypeId(); } - public class PrecomputedText { - method public static android.text.PrecomputedText create(java.lang.CharSequence, android.text.PrecomputedText.Params); - method public int getParagraphCount(); - method public int getParagraphEnd(int); - method public int getParagraphStart(int); - method public android.text.PrecomputedText.Params getParams(); - method public java.lang.CharSequence getText(); - } - - public static class PrecomputedText.Params { - method public int getBreakStrategy(); - method public int getHyphenationFrequency(); - method public android.text.TextDirectionHeuristic getTextDirection(); - method public android.text.TextPaint getTextPaint(); - method public boolean sameTextMetrics(android.text.PrecomputedText.Params); - } - - public static class PrecomputedText.Params.Builder { - ctor public PrecomputedText.Params.Builder(android.text.TextPaint); - method public android.text.PrecomputedText.Params build(); - method public android.text.PrecomputedText.Params.Builder setBreakStrategy(int); - method public android.text.PrecomputedText.Params.Builder setHyphenationFrequency(int); - method public android.text.PrecomputedText.Params.Builder setTextDirection(android.text.TextDirectionHeuristic); - } - public class Selection { method public static boolean extendDown(android.text.Spannable, android.text.Layout); method public static boolean extendLeft(android.text.Spannable, android.text.Layout); @@ -43392,7 +43396,6 @@ package android.text { public static final class StaticLayout.Builder { method public android.text.StaticLayout build(); - method public static android.text.StaticLayout.Builder obtain(android.text.PrecomputedText, int, int, android.text.TextPaint, int); method public static android.text.StaticLayout.Builder obtain(java.lang.CharSequence, int, int, android.text.TextPaint, int); method public android.text.StaticLayout.Builder setAlignment(android.text.Layout.Alignment); method public android.text.StaticLayout.Builder setBreakStrategy(int); @@ -53644,7 +53647,6 @@ package android.widget { method public final android.content.res.ColorStateList getTextColors(); method public java.util.Locale getTextLocale(); method public android.os.LocaleList getTextLocales(); - method public android.text.PrecomputedText.Params getTextMetricsParams(); method public float getTextScaleX(); method public float getTextSize(); method public int getTotalPaddingBottom(); @@ -53750,8 +53752,6 @@ package android.widget { method public final void setMovementMethod(android.text.method.MovementMethod); method public void setOnEditorActionListener(android.widget.TextView.OnEditorActionListener); method public void setPaintFlags(int); - method public void setPrecomputedTextAndParams(android.text.PrecomputedText); - method public void setPrecomputedTextOrThrow(android.text.PrecomputedText); method public void setPrivateImeOptions(java.lang.String); method public void setRawInputType(int); method public void setScroller(android.widget.Scroller); @@ -53776,7 +53776,6 @@ package android.widget { method public final void setTextKeepState(java.lang.CharSequence, android.widget.TextView.BufferType); method public void setTextLocale(java.util.Locale); method public void setTextLocales(android.os.LocaleList); - method public void setTextMetricsParams(android.text.PrecomputedText.Params); method public void setTextScaleX(float); method public void setTextSize(float); method public void setTextSize(int, float); diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java index dbe415773899b..6fa5312be5cce 100644 --- a/core/java/android/text/BoringLayout.java +++ b/core/java/android/text/BoringLayout.java @@ -322,12 +322,6 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback */ public static Metrics isBoring(CharSequence text, TextPaint paint, TextDirectionHeuristic textDir, Metrics metrics) { - return isBoring(text, null /* precomputed */, paint, textDir, metrics); - } - - /** @hide */ - public static Metrics isBoring(CharSequence text, PrecomputedText precomputed, TextPaint paint, - TextDirectionHeuristic textDir, Metrics metrics) { final int textLength = text.length(); if (hasAnyInterestingChars(text, textLength)) { return null; // There are some interesting characters. Not boring. @@ -350,17 +344,18 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback fm.reset(); } - if (precomputed != null) { + TextLine line = TextLine.obtain(); + line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT, + Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null); + if (text instanceof MeasuredText) { + MeasuredText mt = (MeasuredText) text; // Reaching here means there is only one paragraph. - MeasuredParagraph mp = precomputed.getMeasuredParagraph(0); + MeasuredParagraph mp = mt.getMeasuredParagraph(0); fm.width = (int) Math.ceil(mp.getWidth(0, mp.getTextLength())); } else { - TextLine line = TextLine.obtain(); - line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT, - Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null); fm.width = (int) Math.ceil(line.metrics(fm)); - TextLine.recycle(line); } + TextLine.recycle(line); return fm; } diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index 10444f045d6f9..18431cacbfaf3 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -363,7 +363,7 @@ public class DynamicLayout extends Layout { @JustificationMode int justificationMode, @Nullable TextUtils.TruncateAt ellipsize, @IntRange(from = 0) int ellipsizedWidth) { - super(createEllipsizer(ellipsize, display), null /* precomputed */, + super(createEllipsizer(ellipsize, display), paint, width, align, textDir, spacingmult, spacingadd); final Builder b = Builder.obtain(base, paint, width) diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index d5d35904031c0..aa97b2aba749b 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -245,13 +245,6 @@ public abstract class Layout { protected Layout(CharSequence text, TextPaint paint, int width, Alignment align, TextDirectionHeuristic textDir, float spacingMult, float spacingAdd) { - this(text, null /* precomputed */, paint, width, align, textDir, spacingMult, spacingAdd); - } - - /** @hide */ - protected Layout(CharSequence text, PrecomputedText precomputed, TextPaint paint, - int width, Alignment align, TextDirectionHeuristic textDir, - float spacingMult, float spacingAdd) { if (width < 0) throw new IllegalArgumentException("Layout: " + width + " < 0"); @@ -266,7 +259,6 @@ public abstract class Layout { } mText = text; - mPrecomputed = precomputed; mPaint = paint; mWidth = width; mAlignment = align; @@ -570,7 +562,7 @@ public abstract class Layout { // XXX: assumes there's nothing additional to be done canvas.drawText(buf, start, end, x, lbaseline, paint); } else { - tl.set(paint, buf, mPrecomputed, start, end, dir, directions, hasTab, tabStops); + tl.set(paint, buf, start, end, dir, directions, hasTab, tabStops); if (justify) { tl.justify(right - left - indentWidth); } @@ -2272,7 +2264,6 @@ public abstract class Layout { } private CharSequence mText; - private PrecomputedText mPrecomputed; private TextPaint mPaint; private TextPaint mWorkPaint = new TextPaint(); private int mWidth; diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java new file mode 100644 index 0000000000000..bb7a9e0b7906f --- /dev/null +++ b/core/java/android/text/MeasuredText.java @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.text; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.util.IntArray; + +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; + +/** + * A text which has already been measured. + */ +public class MeasuredText implements Spanned { + private static final char LINE_FEED = '\n'; + + // The original text. + private final @NonNull CharSequence mText; + + // The inclusive start offset of the measuring target. + private final @IntRange(from = 0) int mStart; + + // The exclusive end offset of the measuring target. + private final @IntRange(from = 0) int mEnd; + + // The TextPaint used for measurement. + private final @NonNull TextPaint mPaint; + + // The requested text direction. + private final @NonNull TextDirectionHeuristic mTextDir; + + // The measured paragraph texts. + private final @NonNull MeasuredParagraph[] mMeasuredParagraphs; + + // The sorted paragraph end offsets. + private final @NonNull int[] mParagraphBreakPoints; + + // The break strategy for this measured text. + private final @Layout.BreakStrategy int mBreakStrategy; + + // The hyphenation frequency for this measured text. + private final @Layout.HyphenationFrequency int mHyphenationFrequency; + + /** + * A Builder for MeasuredText + */ + public static final class Builder { + // Mandatory parameters. + private final @NonNull CharSequence mText; + private final @NonNull TextPaint mPaint; + + // Members to be updated by setters. + private @IntRange(from = 0) int mStart; + private @IntRange(from = 0) int mEnd; + private TextDirectionHeuristic mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR; + private @Layout.BreakStrategy int mBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY; + private @Layout.HyphenationFrequency int mHyphenationFrequency = + Layout.HYPHENATION_FREQUENCY_NORMAL; + + + /** + * Builder constructor + * + * @param text The text to be measured. + * @param paint The paint to be used for drawing. + */ + public Builder(@NonNull CharSequence text, @NonNull TextPaint paint) { + Preconditions.checkNotNull(text); + Preconditions.checkNotNull(paint); + + mText = text; + mPaint = paint; + mStart = 0; + mEnd = text.length(); + } + + /** + * Set the range of measuring target. + * + * @param start The measuring target start offset in the text. + * @param end The measuring target end offset in the text. + */ + public @NonNull Builder setRange(@IntRange(from = 0) int start, + @IntRange(from = 0) int end) { + Preconditions.checkArgumentInRange(start, 0, mText.length(), "start"); + Preconditions.checkArgumentInRange(end, 0, mText.length(), "end"); + Preconditions.checkArgument(start <= end, "The range is reversed."); + + mStart = start; + mEnd = end; + return this; + } + + /** + * Set the text direction heuristic + * + * The default value is {@link TextDirectionHeuristics#FIRSTSTRONG_LTR}. + * + * @param textDir The text direction heuristic for resolving bidi behavior. + * @return this builder, useful for chaining. + */ + public @NonNull Builder setTextDirection(@NonNull TextDirectionHeuristic textDir) { + Preconditions.checkNotNull(textDir); + mTextDir = textDir; + return this; + } + + /** + * Set the break strategy + * + * The default value is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}. + * + * @param breakStrategy The break strategy. + * @return this builder, useful for chaining. + */ + public @NonNull Builder setBreakStrategy(@Layout.BreakStrategy int breakStrategy) { + mBreakStrategy = breakStrategy; + return this; + } + + /** + * Set the hyphenation frequency + * + * The default value is {@link Layout#HYPHENATION_FREQUENCY_NORMAL}. + * + * @param hyphenationFrequency The hyphenation frequency. + * @return this builder, useful for chaining. + */ + public @NonNull Builder setHyphenationFrequency( + @Layout.HyphenationFrequency int hyphenationFrequency) { + mHyphenationFrequency = hyphenationFrequency; + return this; + } + + /** + * Build the measured text + * + * @return the measured text. + */ + public @NonNull MeasuredText build() { + return build(true /* build full layout result */); + } + + /** @hide */ + public @NonNull MeasuredText build(boolean computeLayout) { + final boolean needHyphenation = mBreakStrategy != Layout.BREAK_STRATEGY_SIMPLE + && mHyphenationFrequency != Layout.HYPHENATION_FREQUENCY_NONE; + + final IntArray paragraphEnds = new IntArray(); + final ArrayList measuredTexts = new ArrayList<>(); + + int paraEnd = 0; + for (int paraStart = mStart; paraStart < mEnd; paraStart = paraEnd) { + paraEnd = TextUtils.indexOf(mText, LINE_FEED, paraStart, mEnd); + if (paraEnd < 0) { + // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph + // end. + paraEnd = mEnd; + } else { + paraEnd++; // Includes LINE_FEED(U+000A) to the prev paragraph. + } + + paragraphEnds.add(paraEnd); + measuredTexts.add(MeasuredParagraph.buildForStaticLayout( + mPaint, mText, paraStart, paraEnd, mTextDir, needHyphenation, + computeLayout, null /* no recycle */)); + } + + return new MeasuredText(mText, mStart, mEnd, mPaint, mTextDir, mBreakStrategy, + mHyphenationFrequency, measuredTexts.toArray( + new MeasuredParagraph[measuredTexts.size()]), + paragraphEnds.toArray()); + } + }; + + // Use MeasuredText.Builder instead. + private MeasuredText(@NonNull CharSequence text, + @IntRange(from = 0) int start, + @IntRange(from = 0) int end, + @NonNull TextPaint paint, + @NonNull TextDirectionHeuristic textDir, + @Layout.BreakStrategy int breakStrategy, + @Layout.HyphenationFrequency int frequency, + @NonNull MeasuredParagraph[] measuredTexts, + @NonNull int[] paragraphBreakPoints) { + mText = text; + mStart = start; + mEnd = end; + // Copy the paint so that we can keep the reference of typeface in native layout result. + mPaint = new TextPaint(paint); + mMeasuredParagraphs = measuredTexts; + mParagraphBreakPoints = paragraphBreakPoints; + mTextDir = textDir; + mBreakStrategy = breakStrategy; + mHyphenationFrequency = frequency; + } + + /** + * Return the underlying text. + */ + public @NonNull CharSequence getText() { + return mText; + } + + /** + * Returns the inclusive start offset of measured region. + */ + public @IntRange(from = 0) int getStart() { + return mStart; + } + + /** + * Returns the exclusive end offset of measured region. + */ + public @IntRange(from = 0) int getEnd() { + return mEnd; + } + + /** + * Returns the text direction associated with char sequence. + */ + public @NonNull TextDirectionHeuristic getTextDir() { + return mTextDir; + } + + /** + * Returns the paint used to measure this text. + */ + public @NonNull TextPaint getPaint() { + return mPaint; + } + + /** + * Returns the length of the paragraph of this text. + */ + public @IntRange(from = 0) int getParagraphCount() { + return mParagraphBreakPoints.length; + } + + /** + * Returns the paragraph start offset of the text. + */ + public @IntRange(from = 0) int getParagraphStart(@IntRange(from = 0) int paraIndex) { + Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex"); + return paraIndex == 0 ? mStart : mParagraphBreakPoints[paraIndex - 1]; + } + + /** + * Returns the paragraph end offset of the text. + */ + public @IntRange(from = 0) int getParagraphEnd(@IntRange(from = 0) int paraIndex) { + Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex"); + return mParagraphBreakPoints[paraIndex]; + } + + /** @hide */ + public @NonNull MeasuredParagraph getMeasuredParagraph(@IntRange(from = 0) int paraIndex) { + return mMeasuredParagraphs[paraIndex]; + } + + /** + * Returns the break strategy for this text. + */ + public @Layout.BreakStrategy int getBreakStrategy() { + return mBreakStrategy; + } + + /** + * Returns the hyphenation frequency for this text. + */ + public @Layout.HyphenationFrequency int getHyphenationFrequency() { + return mHyphenationFrequency; + } + + /** + * Returns true if the given TextPaint gives the same result of text layout for this text. + * @hide + */ + public boolean canUseMeasuredResult(@NonNull TextPaint paint) { + return mPaint.getTextSize() == paint.getTextSize() + && mPaint.getTextSkewX() == paint.getTextSkewX() + && mPaint.getTextScaleX() == paint.getTextScaleX() + && mPaint.getLetterSpacing() == paint.getLetterSpacing() + && mPaint.getWordSpacing() == paint.getWordSpacing() + && mPaint.getFlags() == paint.getFlags() // Maybe not all flag affects text layout. + && mPaint.getTextLocales() == paint.getTextLocales() // need to be equals? + && mPaint.getFontVariationSettings() == paint.getFontVariationSettings() + && mPaint.getTypeface() == paint.getTypeface() + && TextUtils.equals(mPaint.getFontFeatureSettings(), paint.getFontFeatureSettings()); + } + + /** @hide */ + public int findParaIndex(@IntRange(from = 0) int pos) { + // TODO: Maybe good to remove paragraph concept from MeasuredText and add substring layout + // support to StaticLayout. + for (int i = 0; i < mParagraphBreakPoints.length; ++i) { + if (pos < mParagraphBreakPoints[i]) { + return i; + } + } + throw new IndexOutOfBoundsException( + "pos must be less than " + mParagraphBreakPoints[mParagraphBreakPoints.length - 1] + + ", gave " + pos); + } + + /** @hide */ + public float getWidth(@IntRange(from = 0) int start, @IntRange(from = 0) int end) { + final int paraIndex = findParaIndex(start); + final int paraStart = getParagraphStart(paraIndex); + final int paraEnd = getParagraphEnd(paraIndex); + if (start < paraStart || paraEnd < end) { + throw new RuntimeException("Cannot measured across the paragraph:" + + "para: (" + paraStart + ", " + paraEnd + "), " + + "request: (" + start + ", " + end + ")"); + } + return getMeasuredParagraph(paraIndex).getWidth(start - paraStart, end - paraStart); + } + + /** + * Returns the size of native MeasuredText memory usage + * + * Note that this may not be aculate. Must be used only for testing purposes. + * @hide + */ + public int getMemoryUsage() { + int r = 0; + for (int i = 0; i < getParagraphCount(); ++i) { + r += getMeasuredParagraph(i).getMemoryUsage(); + } + return r; + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // Spanned overrides + // + // Just proxy for underlying mText if appropriate. + + @Override + public T[] getSpans(int start, int end, Class type) { + if (mText instanceof Spanned) { + return ((Spanned) mText).getSpans(start, end, type); + } else { + return ArrayUtils.emptyArray(type); + } + } + + @Override + public int getSpanStart(Object tag) { + if (mText instanceof Spanned) { + return ((Spanned) mText).getSpanStart(tag); + } else { + return -1; + } + } + + @Override + public int getSpanEnd(Object tag) { + if (mText instanceof Spanned) { + return ((Spanned) mText).getSpanEnd(tag); + } else { + return -1; + } + } + + @Override + public int getSpanFlags(Object tag) { + if (mText instanceof Spanned) { + return ((Spanned) mText).getSpanFlags(tag); + } else { + return 0; + } + } + + @Override + public int nextSpanTransition(int start, int limit, Class type) { + if (mText instanceof Spanned) { + return ((Spanned) mText).nextSpanTransition(start, limit, type); + } else { + return mText.length(); + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // CharSequence overrides. + // + // Just proxy for underlying mText. + + @Override + public int length() { + return mText.length(); + } + + @Override + public char charAt(int index) { + // TODO: Should this be index + mStart ? + return mText.charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) { + // TODO: return MeasuredText. + // TODO: Should this be index + mStart, end + mStart ? + return mText.subSequence(start, end); + } + + @Override + public String toString() { + return mText.toString(); + } +} diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java deleted file mode 100644 index 39fc2bd52db47..0000000000000 --- a/core/java/android/text/PrecomputedText.java +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.text; - -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.util.IntArray; - -import com.android.internal.util.Preconditions; - -import java.util.ArrayList; - -/** - * A text which has the character metrics data - * - * This text holds a part of the text layout result. You can accelerate - * {@link android.widget.TextView} or {@link StaticLayout} by using this text. - * - *
- * Example of background measurement.
- * 
- *  void asyncSetText(final TextView textView, final String expensiveLongString, Handler handler) {
- *      final PrecomputedText.Params params = textView.getTextParams();
- *      handler.post(() -> {
- *          final PrecomputedText precomputedText
- *                  = PrecomputedText.create(expensiveLongString, params);
- *          textView.post(() -> {
- *              textView.setPrecomputedTextOrThrow(precomputedText);
- *          });
- *      });
- *  }
- * 
- * 
- * - * Note that the {@link PrecomputedText} created from different parameters of the target - * {@link android.widget.TextView} will be rejected internally and compute the text layout again - * with the current {@link android.widget.TextView} parameters. - */ -public class PrecomputedText { - private static final char LINE_FEED = '\n'; - - /** - * The information required for building {@link PrecomputedText}. - * - * Contains information required for precomputing text measurement metadata, so it can be done - * in isolation of a {@link android.widget.TextView} or {@link StaticLayout}, when final layout - * constraints are not known. - */ - public static class Params { - // The TextPaint used for measurement. - private final @NonNull TextPaint mPaint; - - // The requested text direction. - private final @NonNull TextDirectionHeuristic mTextDir; - - // The break strategy for this measured text. - private final @Layout.BreakStrategy int mBreakStrategy; - - // The hyphenation frequency for this measured text. - private final @Layout.HyphenationFrequency int mHyphenationFrequency; - - /** - * A builder for creating {@link Params}. - */ - public static class Builder { - // The TextPaint used for measurement. - private final @NonNull TextPaint mPaint; - - // The requested text direction. - private TextDirectionHeuristic mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR; - - // The break strategy for this measured text. - private @Layout.BreakStrategy int mBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY; - - // The hyphenation frequency for this measured text. - private @Layout.HyphenationFrequency int mHyphenationFrequency = - Layout.HYPHENATION_FREQUENCY_NORMAL; - - /** - * Builder constructor - * - * @param paint The paint to be used for drawing - */ - public Builder(@NonNull TextPaint paint) { - mPaint = paint; - } - - /** - * Set the line break strategy - * - * The default value is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}. - * - * @param strategy The break strategy - * @return this builder, useful for chaining - */ - public Builder setBreakStrategy(@Layout.BreakStrategy int strategy) { - mBreakStrategy = strategy; - return this; - } - - /** - * Set the hyphenation frequency - * - * The default value is {@link Layout#HYPHENATION_FREQUENCY_NORMAL}. - * - * @param frequency The hyphenation frequency - * @return this builder, useful for chaining - */ - public Builder setHyphenationFrequency(@Layout.HyphenationFrequency int frequency) { - mHyphenationFrequency = frequency; - return this; - } - - /** - * Set the text direction heuristic - * - * The default value is {@link TextDirectionHeuristics#FIRSTSTRONG_LTR}. - * - * @param textDir The text direction heuristic for resolving bidi behavior - * @return this builder, useful for chaining - */ - public Builder setTextDirection(@NonNull TextDirectionHeuristic textDir) { - mTextDir = textDir; - return this; - } - - /** - * Build the {@link Params} - * - * @return the layout parameter - */ - public @NonNull Params build() { - return new Params(mPaint, mTextDir, mBreakStrategy, mHyphenationFrequency); - } - } - - // Use Builder instead. - /** @hide */ - public Params(@NonNull TextPaint paint, @NonNull TextDirectionHeuristic textDir, - @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) { - mPaint = paint; - mTextDir = textDir; - mBreakStrategy = strategy; - mHyphenationFrequency = frequency; - } - - /** - * Returns the {@link TextPaint} for this text - * - * @return A {@link TextPaint} - */ - public @NonNull TextPaint getTextPaint() { - return mPaint; - } - - /** - * Returns the {@link TextDirectionHeuristic} for this text - * - * @return A {@link TextDirectionHeuristic} - */ - public @NonNull TextDirectionHeuristic getTextDirection() { - return mTextDir; - } - - /** - * Returns the break strategy for this text - * - * @return A line break strategy - */ - public @Layout.BreakStrategy int getBreakStrategy() { - return mBreakStrategy; - } - - /** - * Returns the hyphenation frequency for this text - * - * @return A hyphenation frequency - */ - public @Layout.HyphenationFrequency int getHyphenationFrequency() { - return mHyphenationFrequency; - } - - private boolean sameTextMetricsInternal(@NonNull TextPaint paint, - @NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy, - @Layout.HyphenationFrequency int frequency) { - return mTextDir == textDir - && mBreakStrategy == strategy - && mHyphenationFrequency == frequency - && mPaint.equalsForTextMeasurement(paint); - } - - /** - * Check if the same text layout. - * - * @return true if this and the given param result in the same text layout - */ - public boolean sameTextMetrics(@NonNull Params param) { - return sameTextMetricsInternal(param.mPaint, param.mTextDir, param.mBreakStrategy, - param.mHyphenationFrequency); - } - }; - - // The original text. - private final @NonNull CharSequence mText; - - // The inclusive start offset of the measuring target. - private final @IntRange(from = 0) int mStart; - - // The exclusive end offset of the measuring target. - private final @IntRange(from = 0) int mEnd; - - private final @NonNull Params mParams; - - // The measured paragraph texts. - private final @NonNull MeasuredParagraph[] mMeasuredParagraphs; - - // The sorted paragraph end offsets. - private final @NonNull int[] mParagraphBreakPoints; - - /** - * Create a new {@link PrecomputedText} which will pre-compute text measurement and glyph - * positioning information. - *

- * This can be expensive, so computing this on a background thread before your text will be - * presented can save work on the UI thread. - *

- * - * @param text The text to be measured - * @param param Parameters that define how text will be precomputed - * @return A {@link PrecomputedText} - */ - public static PrecomputedText create(@NonNull CharSequence text, @NonNull Params param) { - return createInternal(text, param, 0, text.length(), true /* compute full Layout */); - } - - - /** @hide */ - public static PrecomputedText createWidthOnly(@NonNull CharSequence text, @NonNull Params param, - @IntRange(from = 0) int start, @IntRange(from = 0) int end) { - return createInternal(text, param, start, end, false /* compute width only */); - } - - private static PrecomputedText createInternal(@NonNull CharSequence text, @NonNull Params param, - @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean computeLayout) { - Preconditions.checkNotNull(text); - Preconditions.checkNotNull(param); - final boolean needHyphenation = param.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE - && param.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE; - - final IntArray paragraphEnds = new IntArray(); - final ArrayList measuredTexts = new ArrayList<>(); - - int paraEnd = 0; - for (int paraStart = start; paraStart < end; paraStart = paraEnd) { - paraEnd = TextUtils.indexOf(text, LINE_FEED, paraStart, end); - if (paraEnd < 0) { - // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph - // end. - paraEnd = end; - } else { - paraEnd++; // Includes LINE_FEED(U+000A) to the prev paragraph. - } - - paragraphEnds.add(paraEnd); - measuredTexts.add(MeasuredParagraph.buildForStaticLayout( - param.getTextPaint(), text, paraStart, paraEnd, param.getTextDirection(), - needHyphenation, computeLayout, null /* no recycle */)); - } - - return new PrecomputedText(text, start, end, param, - measuredTexts.toArray(new MeasuredParagraph[measuredTexts.size()]), - paragraphEnds.toArray()); - } - - // Use PrecomputedText.create instead. - private PrecomputedText(@NonNull CharSequence text, @IntRange(from = 0) int start, - @IntRange(from = 0) int end, @NonNull Params param, - @NonNull MeasuredParagraph[] measuredTexts, @NonNull int[] paragraphBreakPoints) { - mText = TextUtils.stringOrSpannedString(text); - mStart = start; - mEnd = end; - mParams = param; - mMeasuredParagraphs = measuredTexts; - mParagraphBreakPoints = paragraphBreakPoints; - } - - /** - * Return the underlying text. - */ - public @NonNull CharSequence getText() { - return mText; - } - - /** - * Returns the inclusive start offset of measured region. - * @hide - */ - public @IntRange(from = 0) int getStart() { - return mStart; - } - - /** - * Returns the exclusive end offset of measured region. - * @hide - */ - public @IntRange(from = 0) int getEnd() { - return mEnd; - } - - /** - * Returns the layout parameters used to measure this text. - */ - public @NonNull Params getParams() { - return mParams; - } - - /** - * Returns the length of the paragraph of this text. - */ - public @IntRange(from = 0) int getParagraphCount() { - return mParagraphBreakPoints.length; - } - - /** - * Returns the paragraph start offset of the text. - */ - public @IntRange(from = 0) int getParagraphStart(@IntRange(from = 0) int paraIndex) { - Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex"); - return paraIndex == 0 ? mStart : mParagraphBreakPoints[paraIndex - 1]; - } - - /** - * Returns the paragraph end offset of the text. - */ - public @IntRange(from = 0) int getParagraphEnd(@IntRange(from = 0) int paraIndex) { - Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex"); - return mParagraphBreakPoints[paraIndex]; - } - - /** @hide */ - public @NonNull MeasuredParagraph getMeasuredParagraph(@IntRange(from = 0) int paraIndex) { - return mMeasuredParagraphs[paraIndex]; - } - - /** - * Returns true if the given TextPaint gives the same result of text layout for this text. - * @hide - */ - public boolean canUseMeasuredResult(@IntRange(from = 0) int start, @IntRange(from = 0) int end, - @NonNull TextDirectionHeuristic textDir, @NonNull TextPaint paint, - @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) { - final TextPaint mtPaint = mParams.getTextPaint(); - return mStart == start - && mEnd == end - && mParams.sameTextMetricsInternal(paint, textDir, strategy, frequency); - } - - /** @hide */ - public int findParaIndex(@IntRange(from = 0) int pos) { - // TODO: Maybe good to remove paragraph concept from PrecomputedText and add substring - // layout support to StaticLayout. - for (int i = 0; i < mParagraphBreakPoints.length; ++i) { - if (pos < mParagraphBreakPoints[i]) { - return i; - } - } - throw new IndexOutOfBoundsException( - "pos must be less than " + mParagraphBreakPoints[mParagraphBreakPoints.length - 1] - + ", gave " + pos); - } - - /** @hide */ - public float getWidth(@IntRange(from = 0) int start, @IntRange(from = 0) int end) { - final int paraIndex = findParaIndex(start); - final int paraStart = getParagraphStart(paraIndex); - final int paraEnd = getParagraphEnd(paraIndex); - if (start < paraStart || paraEnd < end) { - throw new RuntimeException("Cannot measured across the paragraph:" - + "para: (" + paraStart + ", " + paraEnd + "), " - + "request: (" + start + ", " + end + ")"); - } - return getMeasuredParagraph(paraIndex).getWidth(start - paraStart, end - paraStart); - } - - /** - * Returns the size of native PrecomputedText memory usage - * - * Note that this is not guaranteed to be accurate. Must be used only for testing purposes. - * @hide - */ - public int getMemoryUsage() { - int r = 0; - for (int i = 0; i < getParagraphCount(); ++i) { - r += getMeasuredParagraph(i).getMemoryUsage(); - } - return r; - } -} diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 5869802e74e61..e62f4216f33ac 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -75,23 +75,6 @@ public class StaticLayout extends Layout { public final static class Builder { private Builder() {} - /** - * Obtain a builder for constructing StaticLayout objects. - * - * @param source The precomputed text. - * @param start The index of the start of the text - * @param end The index + 1 of the end of the text - * @param paint The base paint used for layout - * @param width The width in pixels - * @return a builder object used for constructing the StaticLayout - */ - @NonNull - public static Builder obtain(@NonNull PrecomputedText source, @IntRange(from = 0) int start, - @IntRange(from = 0) int end, @NonNull TextPaint paint, - @IntRange(from = 0) int width) { - return obtain(source.getText(), source, start, end, paint, width); - } - /** * Obtain a builder for constructing StaticLayout objects. * @@ -106,12 +89,6 @@ public class StaticLayout extends Layout { public static Builder obtain(@NonNull CharSequence source, @IntRange(from = 0) int start, @IntRange(from = 0) int end, @NonNull TextPaint paint, @IntRange(from = 0) int width) { - return obtain(source, null, start, end, paint, width); - } - - private static Builder obtain(@NonNull CharSequence source, @Nullable PrecomputedText text, - @IntRange(from = 0) int start, @IntRange(from = 0) int end, - @NonNull TextPaint paint, @IntRange(from = 0) int width) { Builder b = sPool.acquire(); if (b == null) { b = new Builder(); @@ -119,7 +96,6 @@ public class StaticLayout extends Layout { // set default initial values b.mText = source; - b.mPrecomputed = text; b.mStart = start; b.mEnd = end; b.mPaint = paint; @@ -452,7 +428,6 @@ public class StaticLayout extends Layout { } private CharSequence mText; - private PrecomputedText mPrecomputed; private int mStart; private int mEnd; private TextPaint mPaint; @@ -515,7 +490,7 @@ public class StaticLayout extends Layout { float spacingmult, float spacingadd, boolean includepad, TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { - this(source, null /* precomputed */, bufstart, bufend, paint, outerwidth, align, + this(source, bufstart, bufend, paint, outerwidth, align, TextDirectionHeuristics.FIRSTSTRONG_LTR, spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth, Integer.MAX_VALUE); } @@ -525,16 +500,7 @@ public class StaticLayout extends Layout { * @deprecated Use {@link Builder} instead. */ @Deprecated - public StaticLayout(CharSequence source, int bufstart, int bufend, TextPaint paint, - int outerwidth, Alignment align, TextDirectionHeuristic textDir, - float spacingmult, float spacingadd, boolean includepad, - TextUtils.TruncateAt ellipsize, int ellipsizedWidth, int maxLines) { - this(source, null /* precomputed */, bufstart, bufend, paint, outerwidth, align, textDir, - spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth, maxLines); - } - - /** @hide */ - public StaticLayout(CharSequence source, PrecomputedText precomputed, int bufstart, int bufend, + public StaticLayout(CharSequence source, int bufstart, int bufend, TextPaint paint, int outerwidth, Alignment align, TextDirectionHeuristic textDir, float spacingmult, float spacingadd, @@ -545,7 +511,6 @@ public class StaticLayout extends Layout { : (source instanceof Spanned) ? new SpannedEllipsizer(source) : new Ellipsizer(source), - (ellipsize == null) ? precomputed : null, paint, outerwidth, align, textDir, spacingmult, spacingadd); Builder b = Builder.obtain(source, bufstart, bufend, paint, outerwidth) @@ -686,20 +651,43 @@ public class StaticLayout extends Layout { b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE, indents, mLeftPaddings, mRightPaddings); - PrecomputedText measured = null; - final Spanned spanned = (b.mText instanceof Spanned) ? (Spanned) b.mText : null; - if (b.mPrecomputed != null) { - if (b.mPrecomputed.canUseMeasuredResult(bufStart, bufEnd, textDir, paint, - b.mBreakStrategy, b.mHyphenationFrequency)) { - measured = b.mPrecomputed; + MeasuredText measured = null; + final Spanned spanned; + final boolean canUseMeasuredText; + if (source instanceof MeasuredText) { + measured = (MeasuredText) source; + + if (bufStart != measured.getStart() || bufEnd != measured.getEnd()) { + // The buffer position has changed. Re-measure here. + canUseMeasuredText = false; + } else if (b.mBreakStrategy != measured.getBreakStrategy() + || b.mHyphenationFrequency != measured.getHyphenationFrequency()) { + // The computed hyphenation pieces may not be able to used. Re-measure it. + canUseMeasuredText = false; + } else { + // We can use measured information. + canUseMeasuredText = true; } - } - if (measured == null) { - final PrecomputedText.Params param = new PrecomputedText.Params(paint, textDir, - b.mBreakStrategy, b.mHyphenationFrequency); - measured = PrecomputedText.createWidthOnly(source, param, bufStart, bufEnd); + } else { + canUseMeasuredText = false; } + if (!canUseMeasuredText) { + measured = new MeasuredText.Builder(source, paint) + .setRange(bufStart, bufEnd) + .setTextDirection(textDir) + .setBreakStrategy(b.mBreakStrategy) + .setHyphenationFrequency(b.mHyphenationFrequency) + .build(false /* full layout is not necessary for line breaking */); + spanned = (source instanceof Spanned) ? (Spanned) source : null; + } else { + final CharSequence original = measured.getText(); + spanned = (original instanceof Spanned) ? (Spanned) original : null; + // Overwrite with the one when measured. + // TODO: Give an option for developer not to overwrite and measure again here? + textDir = measured.getTextDir(); + paint = measured.getPaint(); + } try { for (int paraIndex = 0; paraIndex < measured.getParagraphCount(); paraIndex++) { diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index be5bb4d1809a5..55367dcce47e2 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -16,7 +16,6 @@ package android.text; -import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Canvas; @@ -61,7 +60,7 @@ public class TextLine { private char[] mChars; private boolean mCharsValid; private Spanned mSpanned; - private PrecomputedText mComputed; + private MeasuredText mMeasured; // Additional width of whitespace for justification. This value is per whitespace, thus // the line width will increase by mAddedWidth x (number of stretchable whitespaces). @@ -120,7 +119,7 @@ public class TextLine { tl.mSpanned = null; tl.mTabs = null; tl.mChars = null; - tl.mComputed = null; + tl.mMeasured = null; tl.mMetricAffectingSpanSpanSet.recycle(); tl.mCharacterStyleSpanSet.recycle(); @@ -150,31 +149,10 @@ public class TextLine { * @param tabStops the tabStops. Can be null. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public void set(TextPaint paint, CharSequence text, int start, - int limit, int dir, Directions directions, boolean hasTabs, TabStops tabStops) { - set(paint, text, null, start, limit, dir, directions, hasTabs, tabStops); - } - - /** - * Initializes a TextLine and prepares it for use. - * - * @param paint the base paint for the line - * @param text the text, can be Styled - * @param precomputed the precomputed text - * @param start the start of the line relative to the text - * @param limit the limit of the line relative to the text - * @param dir the paragraph direction of this line - * @param directions the directions information of this line - * @param hasTabs true if the line might contain tabs - * @param tabStops the tabStops. - */ - public void set(@NonNull TextPaint paint, @NonNull CharSequence text, - @Nullable PrecomputedText precomputed, @IntRange(from = 0) int start, - @IntRange(from = 0) int limit, int dir, @NonNull Directions directions, boolean hasTabs, - @Nullable TabStops tabStops) { + public void set(TextPaint paint, CharSequence text, int start, int limit, int dir, + Directions directions, boolean hasTabs, TabStops tabStops) { mPaint = paint; mText = text; - mComputed = precomputed; mStart = start; mLen = limit - start; mDir = dir; @@ -192,6 +170,14 @@ public class TextLine { hasReplacement = mReplacementSpanSpanSet.numberOfSpans > 0; } + mMeasured = null; + if (text instanceof MeasuredText) { + MeasuredText mt = (MeasuredText) text; + if (mt.canUseMeasuredResult(paint)) { + mMeasured = mt; + } + } + mCharsValid = hasReplacement || hasTabs || directions != Layout.DIRS_ALL_LEFT_TO_RIGHT; if (mCharsValid) { @@ -760,12 +746,12 @@ public class TextLine { return wp.getRunAdvance(mChars, start, end, contextStart, contextEnd, runIsRtl, offset); } else { final int delta = mStart; - if (mComputed == null) { + if (mMeasured == null) { // TODO: Enable measured getRunAdvance for ReplacementSpan and RTL text. return wp.getRunAdvance(mText, delta + start, delta + end, delta + contextStart, delta + contextEnd, runIsRtl, delta + offset); } else { - return mComputed.getWidth(start + delta, end + delta); + return mMeasured.getWidth(start + delta, end + delta); } } } diff --git a/core/java/android/view/RecordingCanvas.java b/core/java/android/view/RecordingCanvas.java index fc7d828de12ef..fbb862be54ef5 100644 --- a/core/java/android/view/RecordingCanvas.java +++ b/core/java/android/view/RecordingCanvas.java @@ -34,7 +34,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.TemporaryBuffer; import android.text.GraphicsOperations; -import android.text.PrecomputedText; +import android.text.MeasuredText; import android.text.SpannableString; import android.text.SpannedString; import android.text.TextUtils; @@ -507,8 +507,8 @@ public class RecordingCanvas extends Canvas { TextUtils.getChars(text, contextStart, contextEnd, buf, 0); long measuredTextPtr = 0; int measuredTextOffset = 0; - if (text instanceof PrecomputedText) { - PrecomputedText mt = (PrecomputedText) text; + if (text instanceof MeasuredText) { + MeasuredText mt = (MeasuredText) text; int paraIndex = mt.findParaIndex(start); if (end <= mt.getParagraphEnd(paraIndex)) { // Only support if the target is in the same paragraph. @@ -641,7 +641,7 @@ public class RecordingCanvas extends Canvas { @FastNative private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint, - long nativePrecomputedText, int measuredTextOffset); + long nativeMeasuredText, int measuredTextOffset); @FastNative private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index f6e771a9605ed..5710db3ce8e0e 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -80,8 +80,8 @@ import android.text.GraphicsOperations; import android.text.InputFilter; import android.text.InputType; import android.text.Layout; +import android.text.MeasuredText; import android.text.ParcelableSpan; -import android.text.PrecomputedText; import android.text.Selection; import android.text.SpanWatcher; import android.text.Spannable; @@ -637,7 +637,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private CharSequence mText; private CharSequence mTransformed; private BufferType mBufferType = BufferType.NORMAL; - private PrecomputedText mPrecomputed; private CharSequence mHint; private Layout mHintLayout; @@ -4085,80 +4084,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mHyphenationFrequency; } - /** - * Gets the parameters for text layout precomputation, for use with {@link PrecomputedText} - * - * @return A current {@link PrecomputedText.Params} - */ - public @NonNull PrecomputedText.Params getTextMetricsParams() { - return new PrecomputedText.Params(new TextPaint(mTextPaint), getTextDirectionHeuristic(), - mBreakStrategy, mHyphenationFrequency); - } - - /** - * Apply the text layout parameter. - */ - public void setTextMetricsParams(@NonNull PrecomputedText.Params params) { - mTextPaint.set(params.getTextPaint()); - mTextDir = params.getTextDirection(); - mBreakStrategy = params.getBreakStrategy(); - mHyphenationFrequency = params.getHyphenationFrequency(); - if (mLayout != null) { - nullLayouts(); - requestLayout(); - invalidate(); - } - } - - /** - * Sets the precomputed text. - * - * If the parameters for the precomputed text is different from current text view parameters, - * apply the parameteres to the text view too. - * - * @param text A precomputed text. - */ - public void setPrecomputedTextAndParams(@NonNull PrecomputedText text) { - Preconditions.checkNotNull(text); - final PrecomputedText.Params params = text.getParams(); - if (!params.sameTextMetrics(getTextMetricsParams())) { - setTextMetricsParams(params); - } - setText(text.getText()); - if (mTransformed != text.getText()) { - // setText modified given text for some reasons, selection, transformation, etc. - // Can't use computed result. - return; - } else { - mPrecomputed = text; - } - } - - /** - * Sets the precomputed text. - * - * If the parameters for the precomputed text is different from current text view parameters, - * throws {@link IllegalArgumentException}. - * - * @param text A precomputed text. - */ - public void setPrecomputedTextOrThrow(@NonNull PrecomputedText text) { - Preconditions.checkNotNull(text); - final PrecomputedText.Params params = text.getParams(); - if (!params.sameTextMetrics(getTextMetricsParams())) { - throw new IllegalArgumentException( - "The precomputed configuration is different from this TextView."); - } - setText(text.getText()); - if (mTransformed != text.getText()) { - // setText modified given text for some reasons, selection, transformation, etc. - // Can't use computed result. - // TODO: Do we throw an exception here too? - } else { - mPrecomputed = text; - } - } - /** * Set justification mode. The default value is {@link Layout#JUSTIFICATION_MODE_NONE}. If the * last line is too short for justification, the last line will be displayed with the @@ -5594,7 +5519,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private void setText(CharSequence text, BufferType type, boolean notifyBefore, int oldlen) { - mPrecomputed = null; mTextSetFromXmlOrResourceId = false; if (text == null) { text = ""; @@ -5653,7 +5577,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (imm != null) imm.restartInput(this); } else if (type == BufferType.SPANNABLE || mMovement != null) { text = mSpannableFactory.newSpannable(text); - } else if (!(text instanceof CharWrapper)) { + } else if (!(text instanceof MeasuredText || text instanceof CharWrapper)) { text = TextUtils.stringOrSpannedString(text); } @@ -8320,8 +8244,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener result = builder.build(); } else { if (boring == UNKNOWN_BORING) { - boring = BoringLayout.isBoring(mTransformed, mPrecomputed, mTextPaint, mTextDir, - mBoring); + boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring); if (boring != null) { mBoring = boring; } @@ -8359,15 +8282,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } if (result == null) { - StaticLayout.Builder builder; - if (mPrecomputed != null) { - builder = StaticLayout.Builder.obtain(mPrecomputed, 0, - mPrecomputed.getText().length(), mTextPaint, wantWidth); - } else { - builder = StaticLayout.Builder.obtain(mTransformed, 0, mTransformed.length(), - mTextPaint, wantWidth); - } - builder.setAlignment(alignment) + StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed, + 0, mTransformed.length(), mTextPaint, wantWidth) + .setAlignment(alignment) .setTextDirection(mTextDir) .setLineSpacing(mSpacingAdd, mSpacingMult) .setIncludePad(mIncludePad) @@ -8494,8 +8411,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if (des < 0) { - boring = BoringLayout.isBoring(mTransformed, mPrecomputed, mTextPaint, mTextDir, - mBoring); + boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring); if (boring != null) { mBoring = boring; } @@ -11780,9 +11696,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Returns the current {@link TextDirectionHeuristic} - * - * @return A {@link TextDirectionHeuristic}. * @hide */ protected TextDirectionHeuristic getTextDirectionHeuristic() { diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 2c05d0b976fc8..482d028a67f35 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -1008,23 +1008,6 @@ namespace PaintGlue { return paint->getLooper() && paint->getLooper()->asABlurShadow(nullptr); } - static jboolean equalsForTextMeasurement(jlong lPaint, jlong rPaint) { - if (lPaint == rPaint) { - return true; - } - Paint* leftPaint = reinterpret_cast(lPaint); - Paint* rightPaint = reinterpret_cast(rPaint); - - const Typeface* leftTypeface = Typeface::resolveDefault(leftPaint->getAndroidTypeface()); - const Typeface* rightTypeface = Typeface::resolveDefault(rightPaint->getAndroidTypeface()); - minikin::MinikinPaint leftMinikinPaint - = MinikinUtils::prepareMinikinPaint(leftPaint, leftTypeface); - minikin::MinikinPaint rightMinikinPaint - = MinikinUtils::prepareMinikinPaint(rightPaint, rightTypeface); - - return leftMinikinPaint == rightMinikinPaint; - } - }; // namespace PaintGlue static const JNINativeMethod methods[] = { @@ -1124,8 +1107,7 @@ static const JNINativeMethod methods[] = { {"nGetStrikeThruPosition","(J)F", (void*) PaintGlue::getStrikeThruPosition}, {"nGetStrikeThruThickness","(J)F", (void*) PaintGlue::getStrikeThruThickness}, {"nSetShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer}, - {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer}, - {"nEqualsForTextMeasurement", "(JJ)Z", (void*)PaintGlue::equalsForTextMeasurement}, + {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer} }; int register_android_graphics_Paint(JNIEnv* env) { diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java index 07df0454362cb..eacb727099ed6 100644 --- a/graphics/java/android/graphics/BaseCanvas.java +++ b/graphics/java/android/graphics/BaseCanvas.java @@ -22,7 +22,7 @@ import android.annotation.Nullable; import android.annotation.Size; import android.graphics.Canvas.VertexMode; import android.text.GraphicsOperations; -import android.text.PrecomputedText; +import android.text.MeasuredText; import android.text.SpannableString; import android.text.SpannedString; import android.text.TextUtils; @@ -487,8 +487,8 @@ public abstract class BaseCanvas { TextUtils.getChars(text, contextStart, contextEnd, buf, 0); long measuredTextPtr = 0; int measuredTextOffset = 0; - if (text instanceof PrecomputedText) { - PrecomputedText mt = (PrecomputedText) text; + if (text instanceof MeasuredText) { + MeasuredText mt = (MeasuredText) text; int paraIndex = mt.findParaIndex(start); if (end <= mt.getParagraphEnd(paraIndex)) { // Only suppor the same paragraph. @@ -647,7 +647,7 @@ public abstract class BaseCanvas { private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint, - long nativePrecomputedText, int measuredTextOffset); + long nativeMeasuredText, int measuredTextOffset); private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count, long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint); diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 42dac38affba1..ed147e9e2ec7b 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -2835,16 +2835,6 @@ public class Paint { return result; } - /** - * Returns true of the passed {@link Paint} will have the same effect on text measurement - * - * @param other A {@link Paint} object. - * @return true if the other {@link Paint} has the same effect on text measurement. - */ - public boolean equalsForTextMeasurement(@NonNull Paint other) { - return nEqualsForTextMeasurement(mNativePaint, other.mNativePaint); - } - // regular JNI private static native long nGetNativeFinalizer(); private static native long nInit(); @@ -3012,6 +3002,4 @@ public class Paint { private static native float nGetStrikeThruThickness(long paintPtr); @CriticalNative private static native void nSetTextSize(long paintPtr, float textSize); - @CriticalNative - private static native boolean nEqualsForTextMeasurement(long leftPaintPtr, long rightPaintPtr); }