Loading core/api/current.txt +18 −0 Original line number Diff line number Diff line Loading @@ -949,6 +949,7 @@ package android { field public static final int left = 16843181; // 0x10101ad field public static final int letterSpacing = 16843958; // 0x10104b6 field public static final int level = 16844032; // 0x1010500 field public static final int lineBreakStyle = 16844365; // 0x101064d field public static final int lineHeight = 16844159; // 0x101057f field public static final int lineSpacingExtra = 16843287; // 0x1010217 field public static final int lineSpacingMultiplier = 16843288; // 0x1010218 Loading Loading @@ -17576,6 +17577,17 @@ package android.graphics.pdf { package android.graphics.text { public final class LineBreakConfig { ctor public LineBreakConfig(); method public int getLineBreakStyle(); method public void set(@Nullable android.graphics.text.LineBreakConfig); method public void setLineBreakStyle(int); field public static final int LINE_BREAK_STYLE_LOOSE = 1; // 0x1 field public static final int LINE_BREAK_STYLE_NONE = 0; // 0x0 field public static final int LINE_BREAK_STYLE_NORMAL = 2; // 0x2 field public static final int LINE_BREAK_STYLE_STRICT = 3; // 0x3 } public class LineBreaker { method @NonNull public android.graphics.text.LineBreaker.Result computeLineBreaks(@NonNull android.graphics.text.MeasuredText, @NonNull android.graphics.text.LineBreaker.ParagraphConstraints, @IntRange(from=0) int); field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2 Loading Loading @@ -17631,6 +17643,7 @@ package android.graphics.text { ctor public MeasuredText.Builder(@NonNull android.graphics.text.MeasuredText); method @NonNull public android.graphics.text.MeasuredText.Builder appendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) @Px float); method @NonNull public android.graphics.text.MeasuredText.Builder appendStyleRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, boolean); method @NonNull public android.graphics.text.MeasuredText.Builder appendStyleRun(@NonNull android.graphics.Paint, @Nullable android.graphics.text.LineBreakConfig, @IntRange(from=0) int, boolean); method @NonNull public android.graphics.text.MeasuredText build(); method @Deprecated @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean); method @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(int); Loading Loading @@ -45434,6 +45447,7 @@ package android.text { public static final class PrecomputedText.Params { method public int getBreakStrategy(); method public int getHyphenationFrequency(); method @Nullable public android.graphics.text.LineBreakConfig getLineBreakConfig(); method @NonNull public android.text.TextDirectionHeuristic getTextDirection(); method @NonNull public android.text.TextPaint getTextPaint(); } Loading @@ -45444,6 +45458,7 @@ package android.text { method @NonNull 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 @NonNull public android.text.PrecomputedText.Params.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig); method public android.text.PrecomputedText.Params.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic); } Loading Loading @@ -45604,6 +45619,7 @@ package android.text { method @NonNull public android.text.StaticLayout.Builder setIncludePad(boolean); method @NonNull public android.text.StaticLayout.Builder setIndents(@Nullable int[], @Nullable int[]); method @NonNull public android.text.StaticLayout.Builder setJustificationMode(int); method @NonNull public android.text.StaticLayout.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig); method @NonNull public android.text.StaticLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float); method @NonNull public android.text.StaticLayout.Builder setMaxLines(@IntRange(from=0) int); method public android.text.StaticLayout.Builder setText(CharSequence); Loading Loading @@ -57682,6 +57698,7 @@ package android.widget { method public final android.text.Layout getLayout(); method public float getLetterSpacing(); method public int getLineBounds(int, android.graphics.Rect); method @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig(); method public int getLineCount(); method public int getLineHeight(); method public float getLineSpacingExtra(); Loading Loading @@ -57809,6 +57826,7 @@ package android.widget { method public void setKeyListener(android.text.method.KeyListener); method public void setLastBaselineToBottomHeight(@IntRange(from=0) @Px int); method public void setLetterSpacing(float); method public void setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig); method public void setLineHeight(@IntRange(from=0) @Px int); method public void setLineSpacing(float, float); method public void setLines(int); core/java/android/text/MeasuredParagraph.java +27 −13 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.text.LineBreakConfig; import android.graphics.text.MeasuredText; import android.text.AutoGrowArray.ByteArray; import android.text.AutoGrowArray.FloatArray; Loading Loading @@ -124,7 +125,7 @@ public class MeasuredParagraph { // The native MeasuredParagraph. private @Nullable MeasuredText mMeasuredText; // Following two objects are for avoiding object allocation. // Following three objects are for avoiding object allocation. private @NonNull TextPaint mCachedPaint = new TextPaint(); private @Nullable Paint.FontMetricsInt mCachedFm; Loading Loading @@ -350,7 +351,8 @@ public class MeasuredParagraph { if (mt.mSpanned == null) { // No style change by MetricsAffectingSpan. Just measure all text. mt.applyMetricsAffectingSpan( paint, null /* spans */, start, end, null /* native builder ptr */); paint, null /* lineBreakConfig */, null /* spans */, start, end, null /* native builder ptr */); } else { // There may be a MetricsAffectingSpan. Split into span transitions and apply styles. int spanEnd; Loading @@ -360,7 +362,8 @@ public class MeasuredParagraph { MetricAffectingSpan.class); spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class); mt.applyMetricsAffectingSpan( paint, spans, spanStart, spanEnd, null /* native builder ptr */); paint, null /* line break config */, spans, spanStart, spanEnd, null /* native builder ptr */); } } return mt; Loading @@ -373,6 +376,7 @@ public class MeasuredParagraph { * result to recycle and returns recycle. * * @param paint the paint to be used for rendering the text. * @param lineBreakConfig the line break configuration for text wrapping. * @param text the character sequence to be measured * @param start the inclusive start offset of the target region in the text * @param end the exclusive end offset of the target region in the text Loading @@ -386,6 +390,7 @@ public class MeasuredParagraph { */ public static @NonNull MeasuredParagraph buildForStaticLayout( @NonNull TextPaint paint, @Nullable LineBreakConfig lineBreakConfig, @NonNull CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, Loading @@ -411,7 +416,8 @@ public class MeasuredParagraph { } else { if (mt.mSpanned == null) { // No style change by MetricsAffectingSpan. Just measure all text. mt.applyMetricsAffectingSpan(paint, null /* spans */, start, end, builder); mt.applyMetricsAffectingSpan(paint, lineBreakConfig, null /* spans */, start, end, builder); mt.mSpanEndCache.append(end); } else { // There may be a MetricsAffectingSpan. Split into span transitions and apply Loading @@ -424,7 +430,9 @@ public class MeasuredParagraph { MetricAffectingSpan.class); spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class); mt.applyMetricsAffectingSpan(paint, spans, spanStart, spanEnd, builder); // TODO: Update line break config with spans. mt.applyMetricsAffectingSpan(paint, lineBreakConfig, spans, spanStart, spanEnd, builder); mt.mSpanEndCache.append(spanEnd); } } Loading Loading @@ -500,12 +508,13 @@ public class MeasuredParagraph { private void applyReplacementRun(@NonNull ReplacementSpan replacement, @IntRange(from = 0) int start, // inclusive, in copied buffer @IntRange(from = 0) int end, // exclusive, in copied buffer @NonNull TextPaint paint, @Nullable MeasuredText.Builder builder) { // Use original text. Shouldn't matter. // TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for // backward compatibility? or Should we initialize them for getFontMetricsInt? final float width = replacement.getSize( mCachedPaint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm); paint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm); if (builder == null) { // Assigns all width to the first character. This is the same behavior as minikin. mWidths.set(start, width); Loading @@ -514,22 +523,24 @@ public class MeasuredParagraph { } mWholeWidth += width; } else { builder.appendReplacementRun(mCachedPaint, end - start, width); builder.appendReplacementRun(paint, end - start, width); } } private void applyStyleRun(@IntRange(from = 0) int start, // inclusive, in copied buffer @IntRange(from = 0) int end, // exclusive, in copied buffer @NonNull TextPaint paint, @Nullable LineBreakConfig config, @Nullable MeasuredText.Builder builder) { if (mLtrWithoutBidi) { // If the whole text is LTR direction, just apply whole region. if (builder == null) { mWholeWidth += mCachedPaint.getTextRunAdvances( mWholeWidth += paint.getTextRunAdvances( mCopiedBuffer, start, end - start, start, end - start, false /* isRtl */, mWidths.getRawArray(), start); } else { builder.appendStyleRun(mCachedPaint, end - start, false /* isRtl */); builder.appendStyleRun(paint, config, end - start, false /* isRtl */); } } else { // If there is multiple bidi levels, split into individual bidi level and apply style. Loading @@ -541,11 +552,11 @@ public class MeasuredParagraph { final boolean isRtl = (level & 0x1) != 0; if (builder == null) { final int levelLength = levelEnd - levelStart; mWholeWidth += mCachedPaint.getTextRunAdvances( mWholeWidth += paint.getTextRunAdvances( mCopiedBuffer, levelStart, levelLength, levelStart, levelLength, isRtl, mWidths.getRawArray(), levelStart); } else { builder.appendStyleRun(mCachedPaint, levelEnd - levelStart, isRtl); builder.appendStyleRun(paint, config, levelEnd - levelStart, isRtl); } if (levelEnd == end) { break; Loading @@ -559,6 +570,7 @@ public class MeasuredParagraph { private void applyMetricsAffectingSpan( @NonNull TextPaint paint, @Nullable LineBreakConfig lineBreakConfig, @Nullable MetricAffectingSpan[] spans, @IntRange(from = 0) int start, // inclusive, in original text buffer @IntRange(from = 0) int end, // exclusive, in original text buffer Loading Loading @@ -595,9 +607,11 @@ public class MeasuredParagraph { } if (replacement != null) { applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer, builder); applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer, mCachedPaint, builder); } else { applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, builder); applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, mCachedPaint, lineBreakConfig, builder); } if (needFontMetrics) { Loading core/java/android/text/PrecomputedText.java +79 −14 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Rect; import android.graphics.text.LineBreakConfig; import android.graphics.text.MeasuredText; import android.text.style.MetricAffectingSpan; Loading Loading @@ -96,6 +97,9 @@ public class PrecomputedText implements Spannable { // The hyphenation frequency for this measured text. private final @Layout.HyphenationFrequency int mHyphenationFrequency; // The line break configuration for calculating text wrapping. private final @Nullable LineBreakConfig mLineBreakConfig; /** * A builder for creating {@link Params}. */ Loading @@ -113,6 +117,9 @@ public class PrecomputedText implements Spannable { private @Layout.HyphenationFrequency int mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NORMAL; // The line break configuration for calculating text wrapping. private @Nullable LineBreakConfig mLineBreakConfig; /** * Builder constructor. * Loading @@ -130,6 +137,7 @@ public class PrecomputedText implements Spannable { mTextDir = params.mTextDir; mBreakStrategy = params.mBreakStrategy; mHyphenationFrequency = params.mHyphenationFrequency; mLineBreakConfig = params.mLineBreakConfig; } /** Loading Loading @@ -176,25 +184,42 @@ public class PrecomputedText implements Spannable { return this; } /** * Set the line break config for the text wrapping. * * @param lineBreakConfig the newly line break configuration. * @return this builder, useful for chaining. * @see StaticLayout.Builder#setLineBreakConfig */ public @NonNull Builder setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) { mLineBreakConfig = lineBreakConfig; return this; } /** * Build the {@link Params}. * * @return the layout parameter */ public @NonNull Params build() { return new Params(mPaint, mTextDir, mBreakStrategy, mHyphenationFrequency); return new Params(mPaint, mLineBreakConfig, mTextDir, mBreakStrategy, mHyphenationFrequency); } } // This is public hidden for internal use. // For the external developers, use Builder instead. /** @hide */ public Params(@NonNull TextPaint paint, @NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) { public Params(@NonNull TextPaint paint, @Nullable LineBreakConfig lineBreakConfig, @NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) { mPaint = paint; mTextDir = textDir; mBreakStrategy = strategy; mHyphenationFrequency = frequency; mLineBreakConfig = lineBreakConfig; } /** Loading Loading @@ -233,6 +258,15 @@ public class PrecomputedText implements Spannable { return mHyphenationFrequency; } /** * Return the line break configuration for this text. * * @return the current line break configuration, null if no line break configuration is set. */ public @Nullable LineBreakConfig getLineBreakConfig() { return mLineBreakConfig; } /** @hide */ @IntDef(value = { UNUSABLE, NEED_RECOMPUTE, USABLE }) @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -262,8 +296,9 @@ public class PrecomputedText implements Spannable { /** @hide */ public @CheckResultUsableResult int checkResultUsable(@NonNull TextPaint paint, @NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) { @Layout.HyphenationFrequency int frequency, @Nullable LineBreakConfig lbConfig) { if (mBreakStrategy == strategy && mHyphenationFrequency == frequency && isLineBreakEquals(mLineBreakConfig, lbConfig) && mPaint.equalsForTextMeasurement(paint)) { return mTextDir == textDir ? USABLE : NEED_RECOMPUTE; } else { Loading @@ -271,6 +306,29 @@ public class PrecomputedText implements Spannable { } } /** * Check the two LineBreakConfig instances are equal. * This method assumes they are equal if one parameter is null and the other parameter has * a LineBreakStyle value of LineBreakConfig.LINE_BREAK_STYLE_NONE. * * @param o1 the first LineBreakConfig instance. * @param o2 the second LineBreakConfig instance. * @return true if the two LineBreakConfig instances are equal. */ private boolean isLineBreakEquals(LineBreakConfig o1, LineBreakConfig o2) { if (Objects.equals(o1, o2)) { return true; } if (o1 == null && (o2 != null && o2.getLineBreakStyle() == LineBreakConfig.LINE_BREAK_STYLE_NONE)) { return true; } else if (o2 == null && (o1 != null && o1.getLineBreakStyle() == LineBreakConfig.LINE_BREAK_STYLE_NONE)) { return true; } return false; } /** * Check if the same text layout. * Loading @@ -286,21 +344,25 @@ public class PrecomputedText implements Spannable { } Params param = (Params) o; return checkResultUsable(param.mPaint, param.mTextDir, param.mBreakStrategy, param.mHyphenationFrequency) == Params.USABLE; param.mHyphenationFrequency, param.mLineBreakConfig) == Params.USABLE; } @Override public int hashCode() { // TODO: implement MinikinPaint::hashCode and use it to keep consistency with equals. int lineBreakStyle = (mLineBreakConfig != null) ? mLineBreakConfig.getLineBreakStyle() : LineBreakConfig.LINE_BREAK_STYLE_NONE; return Objects.hash(mPaint.getTextSize(), mPaint.getTextScaleX(), mPaint.getTextSkewX(), mPaint.getLetterSpacing(), mPaint.getWordSpacing(), mPaint.getFlags(), mPaint.getTextLocales(), mPaint.getTypeface(), mPaint.getFontVariationSettings(), mPaint.isElegantTextHeight(), mTextDir, mBreakStrategy, mHyphenationFrequency); mBreakStrategy, mHyphenationFrequency, lineBreakStyle); } @Override public String toString() { int lineBreakStyle = (mLineBreakConfig != null) ? mLineBreakConfig.getLineBreakStyle() : LineBreakConfig.LINE_BREAK_STYLE_NONE; return "{" + "textSize=" + mPaint.getTextSize() + ", textScaleX=" + mPaint.getTextScaleX() Loading @@ -313,6 +375,7 @@ public class PrecomputedText implements Spannable { + ", textDir=" + mTextDir + ", breakStrategy=" + mBreakStrategy + ", hyphenationFrequency=" + mHyphenationFrequency + ", lineBreakStyle=" + lineBreakStyle + "}"; } }; Loading Loading @@ -369,7 +432,8 @@ public class PrecomputedText implements Spannable { final PrecomputedText.Params hintParams = hintPct.getParams(); final @Params.CheckResultUsableResult int checkResult = hintParams.checkResultUsable(params.mPaint, params.mTextDir, params.mBreakStrategy, params.mHyphenationFrequency); params.mBreakStrategy, params.mHyphenationFrequency, params.mLineBreakConfig); switch (checkResult) { case Params.USABLE: return hintPct; Loading Loading @@ -418,9 +482,9 @@ public class PrecomputedText implements Spannable { final int paraStart = pct.getParagraphStart(i); final int paraEnd = pct.getParagraphEnd(i); result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout( params.getTextPaint(), pct, paraStart, paraEnd, params.getTextDirection(), hyphenationMode, computeLayout, pct.getMeasuredParagraph(i), null /* no recycle */))); params.getTextPaint(), params.getLineBreakConfig(), pct, paraStart, paraEnd, params.getTextDirection(), hyphenationMode, computeLayout, pct.getMeasuredParagraph(i), null /* no recycle */))); } return result.toArray(new ParagraphInfo[result.size()]); } Loading Loading @@ -456,8 +520,9 @@ public class PrecomputedText implements Spannable { } result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout( params.getTextPaint(), text, paraStart, paraEnd, params.getTextDirection(), hyphenationMode, computeLayout, null /* no hint */, null /* no recycle */))); params.getTextPaint(), params.getLineBreakConfig(), text, paraStart, paraEnd, params.getTextDirection(), hyphenationMode, computeLayout, null /* no hint */, null /* no recycle */))); } return result.toArray(new ParagraphInfo[result.size()]); } Loading Loading @@ -544,11 +609,11 @@ public class PrecomputedText implements Spannable { public @Params.CheckResultUsableResult int checkResultUsable(@IntRange(from = 0) int start, @IntRange(from = 0) int end, @NonNull TextDirectionHeuristic textDir, @NonNull TextPaint paint, @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) { @Layout.HyphenationFrequency int frequency, @NonNull LineBreakConfig lbConfig) { if (mStart != start || mEnd != end) { return Params.UNUSABLE; } else { return mParams.checkResultUsable(paint, textDir, strategy, frequency); return mParams.checkResultUsable(paint, textDir, strategy, frequency, lbConfig); } } Loading core/java/android/text/StaticLayout.java +21 −3 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Paint; import android.graphics.text.LineBreakConfig; import android.graphics.text.LineBreaker; import android.os.Build; import android.text.style.LeadingMarginSpan; Loading Loading @@ -402,6 +403,21 @@ public class StaticLayout extends Layout { return this; } /** * Set the line break configuration. The line break will be passed to native used for * calculating the text wrapping. The default value of the line break style is * {@link LineBreakConfig#LINE_BREAK_STYLE_NONE} * * @param lineBreakConfig the line break configuration for text wrapping. * @return this builder, useful for chaining. * @see android.widget.TextView#setLineBreakConfig */ @NonNull public Builder setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) { mLineBreakConfig = lineBreakConfig; return this; } /** * Build the {@link StaticLayout} after options have been set. * Loading Loading @@ -438,6 +454,7 @@ public class StaticLayout extends Layout { @Nullable private int[] mRightIndents; private int mJustificationMode; private boolean mAddLastLineLineSpacing; private LineBreakConfig mLineBreakConfig; private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt(); Loading Loading @@ -670,7 +687,7 @@ public class StaticLayout extends Layout { PrecomputedText precomputed = (PrecomputedText) source; final @PrecomputedText.Params.CheckResultUsableResult int checkResult = precomputed.checkResultUsable(bufStart, bufEnd, textDir, paint, b.mBreakStrategy, b.mHyphenationFrequency); b.mBreakStrategy, b.mHyphenationFrequency, b.mLineBreakConfig); switch (checkResult) { case PrecomputedText.Params.UNUSABLE: break; Loading @@ -680,6 +697,7 @@ public class StaticLayout extends Layout { .setBreakStrategy(b.mBreakStrategy) .setHyphenationFrequency(b.mHyphenationFrequency) .setTextDirection(textDir) .setLineBreakConfig(b.mLineBreakConfig) .build(); precomputed = PrecomputedText.create(precomputed, newParams); paragraphInfo = precomputed.getParagraphInfo(); Loading @@ -692,8 +710,8 @@ public class StaticLayout extends Layout { } if (paragraphInfo == null) { final PrecomputedText.Params param = new PrecomputedText.Params(paint, textDir, b.mBreakStrategy, b.mHyphenationFrequency); final PrecomputedText.Params param = new PrecomputedText.Params(paint, b.mLineBreakConfig, textDir, b.mBreakStrategy, b.mHyphenationFrequency); paragraphInfo = PrecomputedText.createMeasuredParagraphs(source, param, bufStart, bufEnd, false /* computeLayout */); } Loading core/java/android/widget/TextView.java +54 −5 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/api/current.txt +18 −0 Original line number Diff line number Diff line Loading @@ -949,6 +949,7 @@ package android { field public static final int left = 16843181; // 0x10101ad field public static final int letterSpacing = 16843958; // 0x10104b6 field public static final int level = 16844032; // 0x1010500 field public static final int lineBreakStyle = 16844365; // 0x101064d field public static final int lineHeight = 16844159; // 0x101057f field public static final int lineSpacingExtra = 16843287; // 0x1010217 field public static final int lineSpacingMultiplier = 16843288; // 0x1010218 Loading Loading @@ -17576,6 +17577,17 @@ package android.graphics.pdf { package android.graphics.text { public final class LineBreakConfig { ctor public LineBreakConfig(); method public int getLineBreakStyle(); method public void set(@Nullable android.graphics.text.LineBreakConfig); method public void setLineBreakStyle(int); field public static final int LINE_BREAK_STYLE_LOOSE = 1; // 0x1 field public static final int LINE_BREAK_STYLE_NONE = 0; // 0x0 field public static final int LINE_BREAK_STYLE_NORMAL = 2; // 0x2 field public static final int LINE_BREAK_STYLE_STRICT = 3; // 0x3 } public class LineBreaker { method @NonNull public android.graphics.text.LineBreaker.Result computeLineBreaks(@NonNull android.graphics.text.MeasuredText, @NonNull android.graphics.text.LineBreaker.ParagraphConstraints, @IntRange(from=0) int); field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2 Loading Loading @@ -17631,6 +17643,7 @@ package android.graphics.text { ctor public MeasuredText.Builder(@NonNull android.graphics.text.MeasuredText); method @NonNull public android.graphics.text.MeasuredText.Builder appendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) @Px float); method @NonNull public android.graphics.text.MeasuredText.Builder appendStyleRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, boolean); method @NonNull public android.graphics.text.MeasuredText.Builder appendStyleRun(@NonNull android.graphics.Paint, @Nullable android.graphics.text.LineBreakConfig, @IntRange(from=0) int, boolean); method @NonNull public android.graphics.text.MeasuredText build(); method @Deprecated @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean); method @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(int); Loading Loading @@ -45434,6 +45447,7 @@ package android.text { public static final class PrecomputedText.Params { method public int getBreakStrategy(); method public int getHyphenationFrequency(); method @Nullable public android.graphics.text.LineBreakConfig getLineBreakConfig(); method @NonNull public android.text.TextDirectionHeuristic getTextDirection(); method @NonNull public android.text.TextPaint getTextPaint(); } Loading @@ -45444,6 +45458,7 @@ package android.text { method @NonNull 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 @NonNull public android.text.PrecomputedText.Params.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig); method public android.text.PrecomputedText.Params.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic); } Loading Loading @@ -45604,6 +45619,7 @@ package android.text { method @NonNull public android.text.StaticLayout.Builder setIncludePad(boolean); method @NonNull public android.text.StaticLayout.Builder setIndents(@Nullable int[], @Nullable int[]); method @NonNull public android.text.StaticLayout.Builder setJustificationMode(int); method @NonNull public android.text.StaticLayout.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig); method @NonNull public android.text.StaticLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float); method @NonNull public android.text.StaticLayout.Builder setMaxLines(@IntRange(from=0) int); method public android.text.StaticLayout.Builder setText(CharSequence); Loading Loading @@ -57682,6 +57698,7 @@ package android.widget { method public final android.text.Layout getLayout(); method public float getLetterSpacing(); method public int getLineBounds(int, android.graphics.Rect); method @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig(); method public int getLineCount(); method public int getLineHeight(); method public float getLineSpacingExtra(); Loading Loading @@ -57809,6 +57826,7 @@ package android.widget { method public void setKeyListener(android.text.method.KeyListener); method public void setLastBaselineToBottomHeight(@IntRange(from=0) @Px int); method public void setLetterSpacing(float); method public void setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig); method public void setLineHeight(@IntRange(from=0) @Px int); method public void setLineSpacing(float, float); method public void setLines(int);
core/java/android/text/MeasuredParagraph.java +27 −13 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.text.LineBreakConfig; import android.graphics.text.MeasuredText; import android.text.AutoGrowArray.ByteArray; import android.text.AutoGrowArray.FloatArray; Loading Loading @@ -124,7 +125,7 @@ public class MeasuredParagraph { // The native MeasuredParagraph. private @Nullable MeasuredText mMeasuredText; // Following two objects are for avoiding object allocation. // Following three objects are for avoiding object allocation. private @NonNull TextPaint mCachedPaint = new TextPaint(); private @Nullable Paint.FontMetricsInt mCachedFm; Loading Loading @@ -350,7 +351,8 @@ public class MeasuredParagraph { if (mt.mSpanned == null) { // No style change by MetricsAffectingSpan. Just measure all text. mt.applyMetricsAffectingSpan( paint, null /* spans */, start, end, null /* native builder ptr */); paint, null /* lineBreakConfig */, null /* spans */, start, end, null /* native builder ptr */); } else { // There may be a MetricsAffectingSpan. Split into span transitions and apply styles. int spanEnd; Loading @@ -360,7 +362,8 @@ public class MeasuredParagraph { MetricAffectingSpan.class); spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class); mt.applyMetricsAffectingSpan( paint, spans, spanStart, spanEnd, null /* native builder ptr */); paint, null /* line break config */, spans, spanStart, spanEnd, null /* native builder ptr */); } } return mt; Loading @@ -373,6 +376,7 @@ public class MeasuredParagraph { * result to recycle and returns recycle. * * @param paint the paint to be used for rendering the text. * @param lineBreakConfig the line break configuration for text wrapping. * @param text the character sequence to be measured * @param start the inclusive start offset of the target region in the text * @param end the exclusive end offset of the target region in the text Loading @@ -386,6 +390,7 @@ public class MeasuredParagraph { */ public static @NonNull MeasuredParagraph buildForStaticLayout( @NonNull TextPaint paint, @Nullable LineBreakConfig lineBreakConfig, @NonNull CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, Loading @@ -411,7 +416,8 @@ public class MeasuredParagraph { } else { if (mt.mSpanned == null) { // No style change by MetricsAffectingSpan. Just measure all text. mt.applyMetricsAffectingSpan(paint, null /* spans */, start, end, builder); mt.applyMetricsAffectingSpan(paint, lineBreakConfig, null /* spans */, start, end, builder); mt.mSpanEndCache.append(end); } else { // There may be a MetricsAffectingSpan. Split into span transitions and apply Loading @@ -424,7 +430,9 @@ public class MeasuredParagraph { MetricAffectingSpan.class); spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class); mt.applyMetricsAffectingSpan(paint, spans, spanStart, spanEnd, builder); // TODO: Update line break config with spans. mt.applyMetricsAffectingSpan(paint, lineBreakConfig, spans, spanStart, spanEnd, builder); mt.mSpanEndCache.append(spanEnd); } } Loading Loading @@ -500,12 +508,13 @@ public class MeasuredParagraph { private void applyReplacementRun(@NonNull ReplacementSpan replacement, @IntRange(from = 0) int start, // inclusive, in copied buffer @IntRange(from = 0) int end, // exclusive, in copied buffer @NonNull TextPaint paint, @Nullable MeasuredText.Builder builder) { // Use original text. Shouldn't matter. // TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for // backward compatibility? or Should we initialize them for getFontMetricsInt? final float width = replacement.getSize( mCachedPaint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm); paint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm); if (builder == null) { // Assigns all width to the first character. This is the same behavior as minikin. mWidths.set(start, width); Loading @@ -514,22 +523,24 @@ public class MeasuredParagraph { } mWholeWidth += width; } else { builder.appendReplacementRun(mCachedPaint, end - start, width); builder.appendReplacementRun(paint, end - start, width); } } private void applyStyleRun(@IntRange(from = 0) int start, // inclusive, in copied buffer @IntRange(from = 0) int end, // exclusive, in copied buffer @NonNull TextPaint paint, @Nullable LineBreakConfig config, @Nullable MeasuredText.Builder builder) { if (mLtrWithoutBidi) { // If the whole text is LTR direction, just apply whole region. if (builder == null) { mWholeWidth += mCachedPaint.getTextRunAdvances( mWholeWidth += paint.getTextRunAdvances( mCopiedBuffer, start, end - start, start, end - start, false /* isRtl */, mWidths.getRawArray(), start); } else { builder.appendStyleRun(mCachedPaint, end - start, false /* isRtl */); builder.appendStyleRun(paint, config, end - start, false /* isRtl */); } } else { // If there is multiple bidi levels, split into individual bidi level and apply style. Loading @@ -541,11 +552,11 @@ public class MeasuredParagraph { final boolean isRtl = (level & 0x1) != 0; if (builder == null) { final int levelLength = levelEnd - levelStart; mWholeWidth += mCachedPaint.getTextRunAdvances( mWholeWidth += paint.getTextRunAdvances( mCopiedBuffer, levelStart, levelLength, levelStart, levelLength, isRtl, mWidths.getRawArray(), levelStart); } else { builder.appendStyleRun(mCachedPaint, levelEnd - levelStart, isRtl); builder.appendStyleRun(paint, config, levelEnd - levelStart, isRtl); } if (levelEnd == end) { break; Loading @@ -559,6 +570,7 @@ public class MeasuredParagraph { private void applyMetricsAffectingSpan( @NonNull TextPaint paint, @Nullable LineBreakConfig lineBreakConfig, @Nullable MetricAffectingSpan[] spans, @IntRange(from = 0) int start, // inclusive, in original text buffer @IntRange(from = 0) int end, // exclusive, in original text buffer Loading Loading @@ -595,9 +607,11 @@ public class MeasuredParagraph { } if (replacement != null) { applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer, builder); applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer, mCachedPaint, builder); } else { applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, builder); applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, mCachedPaint, lineBreakConfig, builder); } if (needFontMetrics) { Loading
core/java/android/text/PrecomputedText.java +79 −14 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Rect; import android.graphics.text.LineBreakConfig; import android.graphics.text.MeasuredText; import android.text.style.MetricAffectingSpan; Loading Loading @@ -96,6 +97,9 @@ public class PrecomputedText implements Spannable { // The hyphenation frequency for this measured text. private final @Layout.HyphenationFrequency int mHyphenationFrequency; // The line break configuration for calculating text wrapping. private final @Nullable LineBreakConfig mLineBreakConfig; /** * A builder for creating {@link Params}. */ Loading @@ -113,6 +117,9 @@ public class PrecomputedText implements Spannable { private @Layout.HyphenationFrequency int mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NORMAL; // The line break configuration for calculating text wrapping. private @Nullable LineBreakConfig mLineBreakConfig; /** * Builder constructor. * Loading @@ -130,6 +137,7 @@ public class PrecomputedText implements Spannable { mTextDir = params.mTextDir; mBreakStrategy = params.mBreakStrategy; mHyphenationFrequency = params.mHyphenationFrequency; mLineBreakConfig = params.mLineBreakConfig; } /** Loading Loading @@ -176,25 +184,42 @@ public class PrecomputedText implements Spannable { return this; } /** * Set the line break config for the text wrapping. * * @param lineBreakConfig the newly line break configuration. * @return this builder, useful for chaining. * @see StaticLayout.Builder#setLineBreakConfig */ public @NonNull Builder setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) { mLineBreakConfig = lineBreakConfig; return this; } /** * Build the {@link Params}. * * @return the layout parameter */ public @NonNull Params build() { return new Params(mPaint, mTextDir, mBreakStrategy, mHyphenationFrequency); return new Params(mPaint, mLineBreakConfig, mTextDir, mBreakStrategy, mHyphenationFrequency); } } // This is public hidden for internal use. // For the external developers, use Builder instead. /** @hide */ public Params(@NonNull TextPaint paint, @NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) { public Params(@NonNull TextPaint paint, @Nullable LineBreakConfig lineBreakConfig, @NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) { mPaint = paint; mTextDir = textDir; mBreakStrategy = strategy; mHyphenationFrequency = frequency; mLineBreakConfig = lineBreakConfig; } /** Loading Loading @@ -233,6 +258,15 @@ public class PrecomputedText implements Spannable { return mHyphenationFrequency; } /** * Return the line break configuration for this text. * * @return the current line break configuration, null if no line break configuration is set. */ public @Nullable LineBreakConfig getLineBreakConfig() { return mLineBreakConfig; } /** @hide */ @IntDef(value = { UNUSABLE, NEED_RECOMPUTE, USABLE }) @Retention(RetentionPolicy.SOURCE) Loading Loading @@ -262,8 +296,9 @@ public class PrecomputedText implements Spannable { /** @hide */ public @CheckResultUsableResult int checkResultUsable(@NonNull TextPaint paint, @NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) { @Layout.HyphenationFrequency int frequency, @Nullable LineBreakConfig lbConfig) { if (mBreakStrategy == strategy && mHyphenationFrequency == frequency && isLineBreakEquals(mLineBreakConfig, lbConfig) && mPaint.equalsForTextMeasurement(paint)) { return mTextDir == textDir ? USABLE : NEED_RECOMPUTE; } else { Loading @@ -271,6 +306,29 @@ public class PrecomputedText implements Spannable { } } /** * Check the two LineBreakConfig instances are equal. * This method assumes they are equal if one parameter is null and the other parameter has * a LineBreakStyle value of LineBreakConfig.LINE_BREAK_STYLE_NONE. * * @param o1 the first LineBreakConfig instance. * @param o2 the second LineBreakConfig instance. * @return true if the two LineBreakConfig instances are equal. */ private boolean isLineBreakEquals(LineBreakConfig o1, LineBreakConfig o2) { if (Objects.equals(o1, o2)) { return true; } if (o1 == null && (o2 != null && o2.getLineBreakStyle() == LineBreakConfig.LINE_BREAK_STYLE_NONE)) { return true; } else if (o2 == null && (o1 != null && o1.getLineBreakStyle() == LineBreakConfig.LINE_BREAK_STYLE_NONE)) { return true; } return false; } /** * Check if the same text layout. * Loading @@ -286,21 +344,25 @@ public class PrecomputedText implements Spannable { } Params param = (Params) o; return checkResultUsable(param.mPaint, param.mTextDir, param.mBreakStrategy, param.mHyphenationFrequency) == Params.USABLE; param.mHyphenationFrequency, param.mLineBreakConfig) == Params.USABLE; } @Override public int hashCode() { // TODO: implement MinikinPaint::hashCode and use it to keep consistency with equals. int lineBreakStyle = (mLineBreakConfig != null) ? mLineBreakConfig.getLineBreakStyle() : LineBreakConfig.LINE_BREAK_STYLE_NONE; return Objects.hash(mPaint.getTextSize(), mPaint.getTextScaleX(), mPaint.getTextSkewX(), mPaint.getLetterSpacing(), mPaint.getWordSpacing(), mPaint.getFlags(), mPaint.getTextLocales(), mPaint.getTypeface(), mPaint.getFontVariationSettings(), mPaint.isElegantTextHeight(), mTextDir, mBreakStrategy, mHyphenationFrequency); mBreakStrategy, mHyphenationFrequency, lineBreakStyle); } @Override public String toString() { int lineBreakStyle = (mLineBreakConfig != null) ? mLineBreakConfig.getLineBreakStyle() : LineBreakConfig.LINE_BREAK_STYLE_NONE; return "{" + "textSize=" + mPaint.getTextSize() + ", textScaleX=" + mPaint.getTextScaleX() Loading @@ -313,6 +375,7 @@ public class PrecomputedText implements Spannable { + ", textDir=" + mTextDir + ", breakStrategy=" + mBreakStrategy + ", hyphenationFrequency=" + mHyphenationFrequency + ", lineBreakStyle=" + lineBreakStyle + "}"; } }; Loading Loading @@ -369,7 +432,8 @@ public class PrecomputedText implements Spannable { final PrecomputedText.Params hintParams = hintPct.getParams(); final @Params.CheckResultUsableResult int checkResult = hintParams.checkResultUsable(params.mPaint, params.mTextDir, params.mBreakStrategy, params.mHyphenationFrequency); params.mBreakStrategy, params.mHyphenationFrequency, params.mLineBreakConfig); switch (checkResult) { case Params.USABLE: return hintPct; Loading Loading @@ -418,9 +482,9 @@ public class PrecomputedText implements Spannable { final int paraStart = pct.getParagraphStart(i); final int paraEnd = pct.getParagraphEnd(i); result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout( params.getTextPaint(), pct, paraStart, paraEnd, params.getTextDirection(), hyphenationMode, computeLayout, pct.getMeasuredParagraph(i), null /* no recycle */))); params.getTextPaint(), params.getLineBreakConfig(), pct, paraStart, paraEnd, params.getTextDirection(), hyphenationMode, computeLayout, pct.getMeasuredParagraph(i), null /* no recycle */))); } return result.toArray(new ParagraphInfo[result.size()]); } Loading Loading @@ -456,8 +520,9 @@ public class PrecomputedText implements Spannable { } result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout( params.getTextPaint(), text, paraStart, paraEnd, params.getTextDirection(), hyphenationMode, computeLayout, null /* no hint */, null /* no recycle */))); params.getTextPaint(), params.getLineBreakConfig(), text, paraStart, paraEnd, params.getTextDirection(), hyphenationMode, computeLayout, null /* no hint */, null /* no recycle */))); } return result.toArray(new ParagraphInfo[result.size()]); } Loading Loading @@ -544,11 +609,11 @@ public class PrecomputedText implements Spannable { public @Params.CheckResultUsableResult int checkResultUsable(@IntRange(from = 0) int start, @IntRange(from = 0) int end, @NonNull TextDirectionHeuristic textDir, @NonNull TextPaint paint, @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) { @Layout.HyphenationFrequency int frequency, @NonNull LineBreakConfig lbConfig) { if (mStart != start || mEnd != end) { return Params.UNUSABLE; } else { return mParams.checkResultUsable(paint, textDir, strategy, frequency); return mParams.checkResultUsable(paint, textDir, strategy, frequency, lbConfig); } } Loading
core/java/android/text/StaticLayout.java +21 −3 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Paint; import android.graphics.text.LineBreakConfig; import android.graphics.text.LineBreaker; import android.os.Build; import android.text.style.LeadingMarginSpan; Loading Loading @@ -402,6 +403,21 @@ public class StaticLayout extends Layout { return this; } /** * Set the line break configuration. The line break will be passed to native used for * calculating the text wrapping. The default value of the line break style is * {@link LineBreakConfig#LINE_BREAK_STYLE_NONE} * * @param lineBreakConfig the line break configuration for text wrapping. * @return this builder, useful for chaining. * @see android.widget.TextView#setLineBreakConfig */ @NonNull public Builder setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) { mLineBreakConfig = lineBreakConfig; return this; } /** * Build the {@link StaticLayout} after options have been set. * Loading Loading @@ -438,6 +454,7 @@ public class StaticLayout extends Layout { @Nullable private int[] mRightIndents; private int mJustificationMode; private boolean mAddLastLineLineSpacing; private LineBreakConfig mLineBreakConfig; private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt(); Loading Loading @@ -670,7 +687,7 @@ public class StaticLayout extends Layout { PrecomputedText precomputed = (PrecomputedText) source; final @PrecomputedText.Params.CheckResultUsableResult int checkResult = precomputed.checkResultUsable(bufStart, bufEnd, textDir, paint, b.mBreakStrategy, b.mHyphenationFrequency); b.mBreakStrategy, b.mHyphenationFrequency, b.mLineBreakConfig); switch (checkResult) { case PrecomputedText.Params.UNUSABLE: break; Loading @@ -680,6 +697,7 @@ public class StaticLayout extends Layout { .setBreakStrategy(b.mBreakStrategy) .setHyphenationFrequency(b.mHyphenationFrequency) .setTextDirection(textDir) .setLineBreakConfig(b.mLineBreakConfig) .build(); precomputed = PrecomputedText.create(precomputed, newParams); paragraphInfo = precomputed.getParagraphInfo(); Loading @@ -692,8 +710,8 @@ public class StaticLayout extends Layout { } if (paragraphInfo == null) { final PrecomputedText.Params param = new PrecomputedText.Params(paint, textDir, b.mBreakStrategy, b.mHyphenationFrequency); final PrecomputedText.Params param = new PrecomputedText.Params(paint, b.mLineBreakConfig, textDir, b.mBreakStrategy, b.mHyphenationFrequency); paragraphInfo = PrecomputedText.createMeasuredParagraphs(source, param, bufStart, bufEnd, false /* computeLayout */); } Loading
core/java/android/widget/TextView.java +54 −5 File changed.Preview size limit exceeded, changes collapsed. Show changes