Loading apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java +12 −4 Original line number Diff line number Diff line Loading @@ -119,8 +119,12 @@ public class PrecomputedTextMemoryUsageTest { // 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(); PrecomputedText.ParagraphInfo[] paragraphInfo = PrecomputedText.createMeasuredParagraphs(cs, param, 0, cs.length(), false); memories[i] = 0; for (PrecomputedText.ParagraphInfo info : paragraphInfo) { memories[i] += info.measured.getMemoryUsage(); } } reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation_WidthOnly"); } Loading @@ -136,8 +140,12 @@ public class PrecomputedTextMemoryUsageTest { // 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(); PrecomputedText.ParagraphInfo[] paragraphInfo = PrecomputedText.createMeasuredParagraphs(cs, param, 0, cs.length(), false); memories[i] = 0; for (PrecomputedText.ParagraphInfo info : paragraphInfo) { memories[i] += info.measured.getMemoryUsage(); } } reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation_WidthOnly"); } Loading core/java/android/text/MeasuredParagraph.java +1 −1 Original line number Diff line number Diff line Loading @@ -675,7 +675,7 @@ public class MeasuredParagraph { /** * This only works if the MeasuredParagraph is computed with buildForStaticLayout. */ @IntRange(from = 0) int getMemoryUsage() { public @IntRange(from = 0) int getMemoryUsage() { return nGetMemoryUsage(mNativePtr); } Loading core/java/android/text/PrecomputedText.java +50 −41 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package android.text; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.IntArray; import com.android.internal.util.Preconditions; Loading Loading @@ -267,6 +266,22 @@ public class PrecomputedText implements Spanned { } }; /** @hide */ public static class ParagraphInfo { public final @IntRange(from = 0) int paragraphEnd; public final @NonNull MeasuredParagraph measured; /** * @param paraEnd the end offset of this paragraph * @param measured a measured paragraph */ public ParagraphInfo(@IntRange(from = 0) int paraEnd, @NonNull MeasuredParagraph measured) { this.paragraphEnd = paraEnd; this.measured = measured; } }; // The original text. private final @NonNull SpannedString mText; Loading @@ -278,11 +293,8 @@ public class PrecomputedText implements Spanned { private final @NonNull Params mParams; // The measured paragraph texts. private final @NonNull MeasuredParagraph[] mMeasuredParagraphs; // The sorted paragraph end offsets. private final @NonNull int[] mParagraphBreakPoints; // The list of measured paragraph info. private final @NonNull ParagraphInfo[] mParagraphInfo; /** * Create a new {@link PrecomputedText} which will pre-compute text measurement and glyph Loading @@ -293,28 +305,25 @@ public class PrecomputedText implements Spanned { * </p> * * @param text the text to be measured * @param param parameters that define how text will be precomputed * @param params 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 */); public static PrecomputedText create(@NonNull CharSequence text, @NonNull Params params) { ParagraphInfo[] paraInfo = createMeasuredParagraphs( text, params, 0, text.length(), true /* computeLayout */); return new PrecomputedText(text, 0, text.length(), params, paraInfo); } /** @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, public static ParagraphInfo[] createMeasuredParagraphs( @NonNull CharSequence text, @NonNull Params params, @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; ArrayList<ParagraphInfo> result = new ArrayList<>(); final IntArray paragraphEnds = new IntArray(); final ArrayList<MeasuredParagraph> measuredTexts = new ArrayList<>(); Preconditions.checkNotNull(text); Preconditions.checkNotNull(params); final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE; int paraEnd = 0; for (int paraStart = start; paraStart < end; paraStart = paraEnd) { Loading @@ -327,27 +336,22 @@ public class PrecomputedText implements Spanned { 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 */)); result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout( params.getTextPaint(), text, paraStart, paraEnd, params.getTextDirection(), needHyphenation, computeLayout, null /* no recycle */))); } return new PrecomputedText(text, start, end, param, measuredTexts.toArray(new MeasuredParagraph[measuredTexts.size()]), paragraphEnds.toArray()); return result.toArray(new ParagraphInfo[result.size()]); } // 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) { @IntRange(from = 0) int end, @NonNull Params params, @NonNull ParagraphInfo[] paraInfo) { mText = new SpannedString(text); mStart = start; mEnd = end; mParams = param; mMeasuredParagraphs = measuredTexts; mParagraphBreakPoints = paragraphBreakPoints; mParams = params; mParagraphInfo = paraInfo; } /** Loading Loading @@ -384,7 +388,7 @@ public class PrecomputedText implements Spanned { * Returns the count of paragraphs. */ public @IntRange(from = 0) int getParagraphCount() { return mParagraphBreakPoints.length; return mParagraphInfo.length; } /** Loading @@ -392,7 +396,7 @@ public class PrecomputedText implements Spanned { */ public @IntRange(from = 0) int getParagraphStart(@IntRange(from = 0) int paraIndex) { Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex"); return paraIndex == 0 ? mStart : mParagraphBreakPoints[paraIndex - 1]; return paraIndex == 0 ? mStart : getParagraphEnd(paraIndex - 1); } /** Loading @@ -400,12 +404,17 @@ public class PrecomputedText implements Spanned { */ public @IntRange(from = 0) int getParagraphEnd(@IntRange(from = 0) int paraIndex) { Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex"); return mParagraphBreakPoints[paraIndex]; return mParagraphInfo[paraIndex].paragraphEnd; } /** @hide */ public @NonNull MeasuredParagraph getMeasuredParagraph(@IntRange(from = 0) int paraIndex) { return mMeasuredParagraphs[paraIndex]; return mParagraphInfo[paraIndex].measured; } /** @hide */ public @NonNull ParagraphInfo[] getParagraphInfo() { return mParagraphInfo; } /** Loading @@ -425,13 +434,13 @@ public class PrecomputedText implements Spanned { 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]) { for (int i = 0; i < mParagraphInfo.length; ++i) { if (pos < mParagraphInfo[i].paragraphEnd) { return i; } } throw new IndexOutOfBoundsException( "pos must be less than " + mParagraphBreakPoints[mParagraphBreakPoints.length - 1] "pos must be less than " + mParagraphInfo[mParagraphInfo.length - 1].paragraphEnd + ", gave " + pos); } Loading core/java/android/text/StaticLayout.java +14 −16 Original line number Diff line number Diff line Loading @@ -651,31 +651,29 @@ public class StaticLayout extends Layout { b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE, indents, mLeftPaddings, mRightPaddings); PrecomputedText measured = null; final Spanned spanned; PrecomputedText.ParagraphInfo[] paragraphInfo = null; final Spanned spanned = (source instanceof Spanned) ? (Spanned) source : null; if (source instanceof PrecomputedText) { measured = (PrecomputedText) source; if (!measured.canUseMeasuredResult(bufStart, bufEnd, textDir, paint, b.mBreakStrategy, b.mHyphenationFrequency)) { PrecomputedText precomputed = (PrecomputedText) source; if (precomputed.canUseMeasuredResult(bufStart, bufEnd, textDir, paint, b.mBreakStrategy, b.mHyphenationFrequency)) { // Some parameters are different from the ones when measured text is created. measured = null; paragraphInfo = precomputed.getParagraphInfo(); } } if (measured == null) { if (paragraphInfo == null) { final PrecomputedText.Params param = new PrecomputedText.Params(paint, textDir, b.mBreakStrategy, b.mHyphenationFrequency); measured = PrecomputedText.createWidthOnly(source, param, bufStart, bufEnd); spanned = (source instanceof Spanned) ? (Spanned) source : null; } else { final CharSequence original = measured.getText(); spanned = (original instanceof Spanned) ? (Spanned) original : null; paragraphInfo = PrecomputedText.createMeasuredParagraphs(source, param, bufStart, bufEnd, false /* computeLayout */); } try { for (int paraIndex = 0; paraIndex < measured.getParagraphCount(); paraIndex++) { final int paraStart = measured.getParagraphStart(paraIndex); final int paraEnd = measured.getParagraphEnd(paraIndex); for (int paraIndex = 0; paraIndex < paragraphInfo.length; paraIndex++) { final int paraStart = paraIndex == 0 ? bufStart : paragraphInfo[paraIndex - 1].paragraphEnd; final int paraEnd = paragraphInfo[paraIndex].paragraphEnd; int firstWidthLineCount = 1; int firstWidth = outerWidth; Loading Loading @@ -741,7 +739,7 @@ public class StaticLayout extends Layout { } } final MeasuredParagraph measuredPara = measured.getMeasuredParagraph(paraIndex); final MeasuredParagraph measuredPara = paragraphInfo[paraIndex].measured; final char[] chs = measuredPara.getChars(); final int[] spanEndCache = measuredPara.getSpanEndCache().getRawArray(); final int[] fmCache = measuredPara.getFontMetrics().getRawArray(); Loading Loading
apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java +12 −4 Original line number Diff line number Diff line Loading @@ -119,8 +119,12 @@ public class PrecomputedTextMemoryUsageTest { // 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(); PrecomputedText.ParagraphInfo[] paragraphInfo = PrecomputedText.createMeasuredParagraphs(cs, param, 0, cs.length(), false); memories[i] = 0; for (PrecomputedText.ParagraphInfo info : paragraphInfo) { memories[i] += info.measured.getMemoryUsage(); } } reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation_WidthOnly"); } Loading @@ -136,8 +140,12 @@ public class PrecomputedTextMemoryUsageTest { // 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(); PrecomputedText.ParagraphInfo[] paragraphInfo = PrecomputedText.createMeasuredParagraphs(cs, param, 0, cs.length(), false); memories[i] = 0; for (PrecomputedText.ParagraphInfo info : paragraphInfo) { memories[i] += info.measured.getMemoryUsage(); } } reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation_WidthOnly"); } Loading
core/java/android/text/MeasuredParagraph.java +1 −1 Original line number Diff line number Diff line Loading @@ -675,7 +675,7 @@ public class MeasuredParagraph { /** * This only works if the MeasuredParagraph is computed with buildForStaticLayout. */ @IntRange(from = 0) int getMemoryUsage() { public @IntRange(from = 0) int getMemoryUsage() { return nGetMemoryUsage(mNativePtr); } Loading
core/java/android/text/PrecomputedText.java +50 −41 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package android.text; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.IntArray; import com.android.internal.util.Preconditions; Loading Loading @@ -267,6 +266,22 @@ public class PrecomputedText implements Spanned { } }; /** @hide */ public static class ParagraphInfo { public final @IntRange(from = 0) int paragraphEnd; public final @NonNull MeasuredParagraph measured; /** * @param paraEnd the end offset of this paragraph * @param measured a measured paragraph */ public ParagraphInfo(@IntRange(from = 0) int paraEnd, @NonNull MeasuredParagraph measured) { this.paragraphEnd = paraEnd; this.measured = measured; } }; // The original text. private final @NonNull SpannedString mText; Loading @@ -278,11 +293,8 @@ public class PrecomputedText implements Spanned { private final @NonNull Params mParams; // The measured paragraph texts. private final @NonNull MeasuredParagraph[] mMeasuredParagraphs; // The sorted paragraph end offsets. private final @NonNull int[] mParagraphBreakPoints; // The list of measured paragraph info. private final @NonNull ParagraphInfo[] mParagraphInfo; /** * Create a new {@link PrecomputedText} which will pre-compute text measurement and glyph Loading @@ -293,28 +305,25 @@ public class PrecomputedText implements Spanned { * </p> * * @param text the text to be measured * @param param parameters that define how text will be precomputed * @param params 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 */); public static PrecomputedText create(@NonNull CharSequence text, @NonNull Params params) { ParagraphInfo[] paraInfo = createMeasuredParagraphs( text, params, 0, text.length(), true /* computeLayout */); return new PrecomputedText(text, 0, text.length(), params, paraInfo); } /** @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, public static ParagraphInfo[] createMeasuredParagraphs( @NonNull CharSequence text, @NonNull Params params, @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; ArrayList<ParagraphInfo> result = new ArrayList<>(); final IntArray paragraphEnds = new IntArray(); final ArrayList<MeasuredParagraph> measuredTexts = new ArrayList<>(); Preconditions.checkNotNull(text); Preconditions.checkNotNull(params); final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE; int paraEnd = 0; for (int paraStart = start; paraStart < end; paraStart = paraEnd) { Loading @@ -327,27 +336,22 @@ public class PrecomputedText implements Spanned { 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 */)); result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout( params.getTextPaint(), text, paraStart, paraEnd, params.getTextDirection(), needHyphenation, computeLayout, null /* no recycle */))); } return new PrecomputedText(text, start, end, param, measuredTexts.toArray(new MeasuredParagraph[measuredTexts.size()]), paragraphEnds.toArray()); return result.toArray(new ParagraphInfo[result.size()]); } // 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) { @IntRange(from = 0) int end, @NonNull Params params, @NonNull ParagraphInfo[] paraInfo) { mText = new SpannedString(text); mStart = start; mEnd = end; mParams = param; mMeasuredParagraphs = measuredTexts; mParagraphBreakPoints = paragraphBreakPoints; mParams = params; mParagraphInfo = paraInfo; } /** Loading Loading @@ -384,7 +388,7 @@ public class PrecomputedText implements Spanned { * Returns the count of paragraphs. */ public @IntRange(from = 0) int getParagraphCount() { return mParagraphBreakPoints.length; return mParagraphInfo.length; } /** Loading @@ -392,7 +396,7 @@ public class PrecomputedText implements Spanned { */ public @IntRange(from = 0) int getParagraphStart(@IntRange(from = 0) int paraIndex) { Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex"); return paraIndex == 0 ? mStart : mParagraphBreakPoints[paraIndex - 1]; return paraIndex == 0 ? mStart : getParagraphEnd(paraIndex - 1); } /** Loading @@ -400,12 +404,17 @@ public class PrecomputedText implements Spanned { */ public @IntRange(from = 0) int getParagraphEnd(@IntRange(from = 0) int paraIndex) { Preconditions.checkArgumentInRange(paraIndex, 0, getParagraphCount(), "paraIndex"); return mParagraphBreakPoints[paraIndex]; return mParagraphInfo[paraIndex].paragraphEnd; } /** @hide */ public @NonNull MeasuredParagraph getMeasuredParagraph(@IntRange(from = 0) int paraIndex) { return mMeasuredParagraphs[paraIndex]; return mParagraphInfo[paraIndex].measured; } /** @hide */ public @NonNull ParagraphInfo[] getParagraphInfo() { return mParagraphInfo; } /** Loading @@ -425,13 +434,13 @@ public class PrecomputedText implements Spanned { 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]) { for (int i = 0; i < mParagraphInfo.length; ++i) { if (pos < mParagraphInfo[i].paragraphEnd) { return i; } } throw new IndexOutOfBoundsException( "pos must be less than " + mParagraphBreakPoints[mParagraphBreakPoints.length - 1] "pos must be less than " + mParagraphInfo[mParagraphInfo.length - 1].paragraphEnd + ", gave " + pos); } Loading
core/java/android/text/StaticLayout.java +14 −16 Original line number Diff line number Diff line Loading @@ -651,31 +651,29 @@ public class StaticLayout extends Layout { b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE, indents, mLeftPaddings, mRightPaddings); PrecomputedText measured = null; final Spanned spanned; PrecomputedText.ParagraphInfo[] paragraphInfo = null; final Spanned spanned = (source instanceof Spanned) ? (Spanned) source : null; if (source instanceof PrecomputedText) { measured = (PrecomputedText) source; if (!measured.canUseMeasuredResult(bufStart, bufEnd, textDir, paint, b.mBreakStrategy, b.mHyphenationFrequency)) { PrecomputedText precomputed = (PrecomputedText) source; if (precomputed.canUseMeasuredResult(bufStart, bufEnd, textDir, paint, b.mBreakStrategy, b.mHyphenationFrequency)) { // Some parameters are different from the ones when measured text is created. measured = null; paragraphInfo = precomputed.getParagraphInfo(); } } if (measured == null) { if (paragraphInfo == null) { final PrecomputedText.Params param = new PrecomputedText.Params(paint, textDir, b.mBreakStrategy, b.mHyphenationFrequency); measured = PrecomputedText.createWidthOnly(source, param, bufStart, bufEnd); spanned = (source instanceof Spanned) ? (Spanned) source : null; } else { final CharSequence original = measured.getText(); spanned = (original instanceof Spanned) ? (Spanned) original : null; paragraphInfo = PrecomputedText.createMeasuredParagraphs(source, param, bufStart, bufEnd, false /* computeLayout */); } try { for (int paraIndex = 0; paraIndex < measured.getParagraphCount(); paraIndex++) { final int paraStart = measured.getParagraphStart(paraIndex); final int paraEnd = measured.getParagraphEnd(paraIndex); for (int paraIndex = 0; paraIndex < paragraphInfo.length; paraIndex++) { final int paraStart = paraIndex == 0 ? bufStart : paragraphInfo[paraIndex - 1].paragraphEnd; final int paraEnd = paragraphInfo[paraIndex].paragraphEnd; int firstWidthLineCount = 1; int firstWidth = outerWidth; Loading Loading @@ -741,7 +739,7 @@ public class StaticLayout extends Layout { } } final MeasuredParagraph measuredPara = measured.getMeasuredParagraph(paraIndex); final MeasuredParagraph measuredPara = paragraphInfo[paraIndex].measured; final char[] chs = measuredPara.getChars(); final int[] spanEndCache = measuredPara.getSpanEndCache().getRawArray(); final int[] fmCache = measuredPara.getFontMetrics().getRawArray(); Loading