Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 259ee0e2 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add LineBreakSpan and merge method"

parents 85e95f50 e4ea1c10
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -17533,17 +17533,21 @@ package android.graphics.text {
  public final class LineBreakConfig {
    method public int getLineBreakStyle();
    method public int getLineBreakWordStyle();
    method @NonNull public android.graphics.text.LineBreakConfig merge(@NonNull android.graphics.text.LineBreakConfig);
    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
    field public static final int LINE_BREAK_STYLE_UNSPECIFIED = -1; // 0xffffffff
    field public static final int LINE_BREAK_WORD_STYLE_NONE = 0; // 0x0
    field public static final int LINE_BREAK_WORD_STYLE_PHRASE = 1; // 0x1
    field public static final int LINE_BREAK_WORD_STYLE_UNSPECIFIED = -1; // 0xffffffff
  }
  public static final class LineBreakConfig.Builder {
    ctor public LineBreakConfig.Builder();
    method @NonNull public android.graphics.text.LineBreakConfig build();
    method @NonNull public android.graphics.text.LineBreakConfig.Builder merge(@NonNull android.graphics.text.LineBreakConfig);
    method @NonNull public android.graphics.text.LineBreakConfig.Builder setLineBreakStyle(int);
    method @NonNull public android.graphics.text.LineBreakConfig.Builder setLineBreakWordStyle(int);
  }
@@ -48402,6 +48406,11 @@ package android.text.style {
    method public void writeToParcel(@NonNull android.os.Parcel, int);
  }
  public class LineBreakConfigSpan {
    ctor public LineBreakConfigSpan(@NonNull android.graphics.text.LineBreakConfig);
    method @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig();
  }
  public interface LineHeightSpan extends android.text.style.ParagraphStyle android.text.style.WrapTogetherSpan {
    method public void chooseHeight(CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt);
  }
+9 −0
Original line number Diff line number Diff line
@@ -3335,6 +3335,15 @@ package android.text {
    field @NonNull public static final android.os.Parcelable.Creator<android.text.FontConfig.NamedFamilyList> CREATOR;
  }

  public class MeasuredParagraph {
    method @NonNull public static android.text.MeasuredParagraph buildForStaticLayoutTest(@NonNull android.text.TextPaint, @Nullable android.graphics.text.LineBreakConfig, @NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.text.TextDirectionHeuristic, int, boolean, @Nullable android.text.MeasuredParagraph.StyleRunCallback);
  }

  public static interface MeasuredParagraph.StyleRunCallback {
    method public void onAppendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) @Px float);
    method public void onAppendStyleRun(@NonNull android.graphics.Paint, @Nullable android.graphics.text.LineBreakConfig, @IntRange(from=0) int, boolean);
  }

  public static final class Selection.MemoryTextWatcher implements android.text.TextWatcher {
    ctor public Selection.MemoryTextWatcher();
    method public void afterTextChanged(android.text.Editable);
+149 −17
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@ import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Px;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.text.LineBreakConfig;
@@ -28,6 +31,7 @@ import android.text.AutoGrowArray.ByteArray;
import android.text.AutoGrowArray.FloatArray;
import android.text.AutoGrowArray.IntArray;
import android.text.Layout.Directions;
import android.text.style.LineBreakConfigSpan;
import android.text.style.MetricAffectingSpan;
import android.text.style.ReplacementSpan;
import android.util.Pools.SynchronizedPool;
@@ -57,6 +61,7 @@ import java.util.Arrays;
 * MeasuredParagraph is NOT a thread safe object.
 * @hide
 */
@TestApi
public class MeasuredParagraph {
    private static final char OBJECT_REPLACEMENT_CHARACTER = '\uFFFC';

@@ -73,6 +78,7 @@ public class MeasuredParagraph {
     * Recycle the MeasuredParagraph.
     *
     * Do not call any methods after you call this method.
     * @hide
     */
    public void recycle() {
        release();
@@ -126,11 +132,14 @@ public class MeasuredParagraph {
    private @Nullable MeasuredText mMeasuredText;

    // Following three objects are for avoiding object allocation.
    private @NonNull TextPaint mCachedPaint = new TextPaint();
    private final @NonNull TextPaint mCachedPaint = new TextPaint();
    private @Nullable Paint.FontMetricsInt mCachedFm;
    private final @NonNull LineBreakConfig.Builder mLineBreakConfigBuilder =
            new LineBreakConfig.Builder();

    /**
     * Releases internal buffers.
     * @hide
     */
    public void release() {
        reset();
@@ -158,6 +167,7 @@ public class MeasuredParagraph {
     * Returns the length of the paragraph.
     *
     * This is always available.
     * @hide
     */
    public int getTextLength() {
        return mTextLength;
@@ -167,6 +177,7 @@ public class MeasuredParagraph {
     * Returns the characters to be measured.
     *
     * This is always available.
     * @hide
     */
    public @NonNull char[] getChars() {
        return mCopiedBuffer;
@@ -176,6 +187,7 @@ public class MeasuredParagraph {
     * Returns the paragraph direction.
     *
     * This is always available.
     * @hide
     */
    public @Layout.Direction int getParagraphDir() {
        return mParaDir;
@@ -185,6 +197,7 @@ public class MeasuredParagraph {
     * Returns the directions.
     *
     * This is always available.
     * @hide
     */
    public Directions getDirections(@IntRange(from = 0) int start,  // inclusive
                                    @IntRange(from = 0) int end) {  // exclusive
@@ -202,6 +215,7 @@ public class MeasuredParagraph {
     *
     * This is available only if the MeasuredParagraph is computed with buildForMeasurement.
     * Returns 0 in other cases.
     * @hide
     */
    public @FloatRange(from = 0.0f) float getWholeWidth() {
        return mWholeWidth;
@@ -212,6 +226,7 @@ public class MeasuredParagraph {
     *
     * This is available only if the MeasuredParagraph is computed with buildForMeasurement.
     * Returns empty array in other cases.
     * @hide
     */
    public @NonNull FloatArray getWidths() {
        return mWidths;
@@ -224,6 +239,7 @@ public class MeasuredParagraph {
     *
     * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
     * Returns empty array in other cases.
     * @hide
     */
    public @NonNull IntArray getSpanEndCache() {
        return mSpanEndCache;
@@ -236,6 +252,7 @@ public class MeasuredParagraph {
     *
     * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
     * Returns empty array in other cases.
     * @hide
     */
    public @NonNull IntArray getFontMetrics() {
        return mFontMetrics;
@@ -246,6 +263,7 @@ public class MeasuredParagraph {
     *
     * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
     * Returns null in other cases.
     * @hide
     */
    public MeasuredText getMeasuredText() {
        return mMeasuredText;
@@ -259,6 +277,7 @@ public class MeasuredParagraph {
     *
     * @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
     * @hide
     */
    public float getWidth(int start, int end) {
        if (mMeasuredText == null) {
@@ -280,6 +299,7 @@ public class MeasuredParagraph {
     * at (0, 0).
     *
     * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
     * @hide
     */
    public void getBounds(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
            @NonNull Rect bounds) {
@@ -290,6 +310,7 @@ public class MeasuredParagraph {
     * Retrieves the font metrics for the given range.
     *
     * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
     * @hide
     */
    public void getFontMetricsInt(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
            @NonNull Paint.FontMetricsInt fmi) {
@@ -300,6 +321,7 @@ public class MeasuredParagraph {
     * Returns a width of the character at the offset.
     *
     * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
     * @hide
     */
    public float getCharWidthAt(@IntRange(from = 0) int offset) {
        return mMeasuredText.getCharWidthAt(offset);
@@ -318,6 +340,7 @@ public class MeasuredParagraph {
     * @param recycle pass existing MeasuredParagraph if you want to recycle it.
     *
     * @return measured text
     * @hide
     */
    public static @NonNull MeasuredParagraph buildForBidi(@NonNull CharSequence text,
                                                     @IntRange(from = 0) int start,
@@ -343,6 +366,7 @@ public class MeasuredParagraph {
     * @param recycle pass existing MeasuredParagraph if you want to recycle it.
     *
     * @return measured text
     * @hide
     */
    public static @NonNull MeasuredParagraph buildForMeasurement(@NonNull TextPaint paint,
                                                            @NonNull CharSequence text,
@@ -361,24 +385,52 @@ public class MeasuredParagraph {
        if (mt.mSpanned == null) {
            // No style change by MetricsAffectingSpan. Just measure all text.
            mt.applyMetricsAffectingSpan(
                    paint, null /* lineBreakConfig */, null /* spans */, start, end,
                    null /* native builder ptr */);
                    paint, null /* lineBreakConfig */, null /* spans */, null /* lbcSpans */,
                    start, end, null /* native builder ptr */, null);
        } else {
            // There may be a MetricsAffectingSpan. Split into span transitions and apply styles.
            int spanEnd;
            for (int spanStart = start; spanStart < end; spanStart = spanEnd) {
                spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end, MetricAffectingSpan.class);
                int maSpanEnd = mt.mSpanned.nextSpanTransition(spanStart, end,
                        MetricAffectingSpan.class);
                int lbcSpanEnd = mt.mSpanned.nextSpanTransition(spanStart, end,
                        LineBreakConfigSpan.class);
                spanEnd = Math.min(maSpanEnd, lbcSpanEnd);
                MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd,
                        MetricAffectingSpan.class);
                LineBreakConfigSpan[] lbcSpans = mt.mSpanned.getSpans(spanStart, spanEnd,
                        LineBreakConfigSpan.class);
                spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class);
                lbcSpans = TextUtils.removeEmptySpans(lbcSpans, mt.mSpanned,
                        LineBreakConfigSpan.class);
                mt.applyMetricsAffectingSpan(
                        paint, null /* line break config */, spans, spanStart, spanEnd,
                        null /* native builder ptr */);
                        paint, null /* line break config */, spans, lbcSpans, spanStart, spanEnd,
                        null /* native builder ptr */, null);
            }
        }
        return mt;
    }

    /**
     * A test interface for observing the style run calculation.
     * @hide
     */
    @TestApi
    public interface StyleRunCallback {
        /**
         * Called when a single style run is identified.
         */
        void onAppendStyleRun(@NonNull Paint paint,
                @Nullable LineBreakConfig lineBreakConfig, @IntRange(from = 0) int length,
                boolean isRtl);

        /**
         * Called when a single replacement run is identified.
         */
        void onAppendReplacementRun(@NonNull Paint paint,
                @IntRange(from = 0) int length, @Px @FloatRange(from = 0) float width);
    }

    /**
     * Generates new MeasuredParagraph for StaticLayout.
     *
@@ -397,6 +449,7 @@ public class MeasuredParagraph {
     * @param recycle pass existing MeasuredParagraph if you want to recycle it.
     *
     * @return measured text
     * @hide
     */
    public static @NonNull MeasuredParagraph buildForStaticLayout(
            @NonNull TextPaint paint,
@@ -409,6 +462,57 @@ public class MeasuredParagraph {
            boolean computeLayout,
            @Nullable MeasuredParagraph hint,
            @Nullable MeasuredParagraph recycle) {
        return buildForStaticLayoutInternal(paint, lineBreakConfig, text, start, end, textDir,
                hyphenationMode, computeLayout, hint, recycle, null);
    }

    /**
     * Generates new MeasuredParagraph for StaticLayout.
     *
     * If recycle is null, this returns new instance. If recycle is not null, this fills computed
     * 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
     * @param textDir the text direction
     * @param hyphenationMode a hyphenation mode
     * @param computeLayout true if need to compute full layout, otherwise false.
     *
     * @return measured text
     * @hide
     */
    @SuppressLint("ExecutorRegistration")
    @TestApi
    @NonNull
    public static MeasuredParagraph buildForStaticLayoutTest(
            @NonNull TextPaint paint,
            @Nullable LineBreakConfig lineBreakConfig,
            @NonNull CharSequence text,
            @IntRange(from = 0) int start,
            @IntRange(from = 0) int end,
            @NonNull TextDirectionHeuristic textDir,
            int hyphenationMode,
            boolean computeLayout,
            @Nullable StyleRunCallback testCallback) {
        return buildForStaticLayoutInternal(paint, lineBreakConfig, text, start, end, textDir,
                hyphenationMode, computeLayout, null, null, testCallback);
    }

    private static @NonNull MeasuredParagraph buildForStaticLayoutInternal(
            @NonNull TextPaint paint,
            @Nullable LineBreakConfig lineBreakConfig,
            @NonNull CharSequence text,
            @IntRange(from = 0) int start,
            @IntRange(from = 0) int end,
            @NonNull TextDirectionHeuristic textDir,
            int hyphenationMode,
            boolean computeLayout,
            @Nullable MeasuredParagraph hint,
            @Nullable MeasuredParagraph recycle,
            @Nullable StyleRunCallback testCallback) {
        final MeasuredParagraph mt = recycle == null ? obtain() : recycle;
        mt.resetAndAnalyzeBidi(text, start, end, textDir);
        final MeasuredText.Builder builder;
@@ -426,23 +530,29 @@ public class MeasuredParagraph {
        } else {
            if (mt.mSpanned == null) {
                // No style change by MetricsAffectingSpan. Just measure all text.
                mt.applyMetricsAffectingSpan(paint, lineBreakConfig, null /* spans */, start, end,
                        builder);
                mt.applyMetricsAffectingSpan(paint, lineBreakConfig, null /* spans */, null,
                        start, end, builder, testCallback);
                mt.mSpanEndCache.append(end);
            } else {
                // There may be a MetricsAffectingSpan. Split into span transitions and apply
                // styles.
                int spanEnd;
                for (int spanStart = start; spanStart < end; spanStart = spanEnd) {
                    spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end,
                    int maSpanEnd = mt.mSpanned.nextSpanTransition(spanStart, end,
                                                             MetricAffectingSpan.class);
                    int lbcSpanEnd = mt.mSpanned.nextSpanTransition(spanStart, end,
                            LineBreakConfigSpan.class);
                    spanEnd = Math.min(maSpanEnd, lbcSpanEnd);
                    MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd,
                            MetricAffectingSpan.class);
                    LineBreakConfigSpan[] lbcSpans = mt.mSpanned.getSpans(spanStart, spanEnd,
                            LineBreakConfigSpan.class);
                    spans = TextUtils.removeEmptySpans(spans, mt.mSpanned,
                                                       MetricAffectingSpan.class);
                    // TODO: Update line break config with spans.
                    mt.applyMetricsAffectingSpan(paint, lineBreakConfig, spans, spanStart, spanEnd,
                            builder);
                    lbcSpans = TextUtils.removeEmptySpans(lbcSpans, mt.mSpanned,
                                                       LineBreakConfigSpan.class);
                    mt.applyMetricsAffectingSpan(paint, lineBreakConfig, spans, lbcSpans, spanStart,
                            spanEnd, builder, testCallback);
                    mt.mSpanEndCache.append(spanEnd);
                }
            }
@@ -519,7 +629,8 @@ public class MeasuredParagraph {
                                     @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) {
                                     @Nullable MeasuredText.Builder builder,
                                     @Nullable StyleRunCallback testCallback) {
        // 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?
@@ -535,13 +646,17 @@ public class MeasuredParagraph {
        } else {
            builder.appendReplacementRun(paint, end - start, width);
        }
        if (testCallback != null) {
            testCallback.onAppendReplacementRun(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) {
                               @Nullable MeasuredText.Builder builder,
                               @Nullable StyleRunCallback testCallback) {

        if (mLtrWithoutBidi) {
            // If the whole text is LTR direction, just apply whole region.
@@ -552,6 +667,9 @@ public class MeasuredParagraph {
            } else {
                builder.appendStyleRun(paint, config, end - start, false /* isRtl */);
            }
            if (testCallback != null) {
                testCallback.onAppendStyleRun(paint, config, end - start, false);
            }
        } else {
            // If there is multiple bidi levels, split into individual bidi level and apply style.
            byte level = mLevels.get(start);
@@ -568,6 +686,9 @@ public class MeasuredParagraph {
                    } else {
                        builder.appendStyleRun(paint, config, levelEnd - levelStart, isRtl);
                    }
                    if (testCallback != null) {
                        testCallback.onAppendStyleRun(paint, config, levelEnd - levelStart, isRtl);
                    }
                    if (levelEnd == end) {
                        break;
                    }
@@ -582,9 +703,11 @@ public class MeasuredParagraph {
            @NonNull TextPaint paint,
            @Nullable LineBreakConfig lineBreakConfig,
            @Nullable MetricAffectingSpan[] spans,
            @Nullable LineBreakConfigSpan[] lbcSpans,
            @IntRange(from = 0) int start,  // inclusive, in original text buffer
            @IntRange(from = 0) int end,  // exclusive, in original text buffer
            @Nullable MeasuredText.Builder builder) {
            @Nullable MeasuredText.Builder builder,
            @Nullable StyleRunCallback testCallback) {
        mCachedPaint.set(paint);
        // XXX paint should not have a baseline shift, but...
        mCachedPaint.baselineShift = 0;
@@ -609,6 +732,14 @@ public class MeasuredParagraph {
            }
        }

        if (lbcSpans != null) {
            mLineBreakConfigBuilder.reset(lineBreakConfig);
            for (LineBreakConfigSpan lbcSpan : lbcSpans) {
                mLineBreakConfigBuilder.merge(lbcSpan.getLineBreakConfig());
            }
            lineBreakConfig = mLineBreakConfigBuilder.build();
        }

        final int startInCopiedBuffer = start - mTextStart;
        final int endInCopiedBuffer = end - mTextStart;

@@ -618,10 +749,10 @@ public class MeasuredParagraph {

        if (replacement != null) {
            applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer, mCachedPaint,
                    builder);
                    builder, testCallback);
        } else {
            applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, mCachedPaint,
                    lineBreakConfig, builder);
                    lineBreakConfig, builder, testCallback);
        }

        if (needFontMetrics) {
@@ -690,6 +821,7 @@ public class MeasuredParagraph {

    /**
     * This only works if the MeasuredParagraph is computed with buildForStaticLayout.
     * @hide
     */
    public @IntRange(from = 0) int getMemoryUsage() {
        return mMeasuredText.getMemoryUsage();
+6 −10
Original line number Diff line number Diff line
@@ -329,22 +329,17 @@ public class PrecomputedText implements Spannable {
        @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, lineBreakStyle);
                    mBreakStrategy, mHyphenationFrequency,
                    LineBreakConfig.getResolvedLineBreakStyle(mLineBreakConfig),
                    LineBreakConfig.getResolvedLineBreakWordStyle(mLineBreakConfig));
        }

        @Override
        public String toString() {
            int lineBreakStyle = (mLineBreakConfig != null)
                    ? mLineBreakConfig.getLineBreakStyle() : LineBreakConfig.LINE_BREAK_STYLE_NONE;
            int lineBreakWordStyle = (mLineBreakConfig != null)
                    ? mLineBreakConfig.getLineBreakWordStyle()
                            : LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE;
            return "{"
                + "textSize=" + mPaint.getTextSize()
                + ", textScaleX=" + mPaint.getTextScaleX()
@@ -357,8 +352,9 @@ public class PrecomputedText implements Spannable {
                + ", textDir=" + mTextDir
                + ", breakStrategy=" + mBreakStrategy
                + ", hyphenationFrequency=" + mHyphenationFrequency
                + ", lineBreakStyle=" + lineBreakStyle
                + ", lineBreakWordStyle=" + lineBreakWordStyle
                + ", lineBreakStyle=" + LineBreakConfig.getResolvedLineBreakStyle(mLineBreakConfig)
                + ", lineBreakWordStyle="
                    + LineBreakConfig.getResolvedLineBreakWordStyle(mLineBreakConfig)
                + "}";
        }
    };
+1 −1
Original line number Diff line number Diff line
@@ -448,7 +448,7 @@ public class StaticLayout extends Layout {

        private void reviseLineBreakConfig() {
            boolean autoPhraseBreaking = mLineBreakConfig.getAutoPhraseBreaking();
            int wordStyle = mLineBreakConfig.getLineBreakWordStyle();
            int wordStyle = LineBreakConfig.getResolvedLineBreakWordStyle(mLineBreakConfig);
            if (autoPhraseBreaking) {
                if (wordStyle != LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE) {
                    if (shouldEnablePhraseBreaking()) {
Loading