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

Commit 6de35cc4 authored by Seigo Nonaka's avatar Seigo Nonaka Committed by Android (Google) Code Review
Browse files

Merge "Add trace point for the text measurement/draw" into main

parents b58670e1 f0f74bba
Loading
Loading
Loading
Loading
+47 −36
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.text.LineBreakConfig;
import android.os.Trace;
import android.text.style.ParagraphStyle;

/**
@@ -567,6 +568,11 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
    public static @Nullable Metrics isBoring(@NonNull CharSequence text, @NonNull TextPaint paint,
            @NonNull TextDirectionHeuristic textDir, boolean useFallbackLineSpacing,
            @Nullable Paint.FontMetrics minimumFontMetrics, @Nullable Metrics metrics) {
        if (TRACE_LAYOUT) {
            Trace.beginSection("BoringLayout#isBoring");
            Trace.setCounter("BoringLayout#textLength", text.length());
        }
        try {
            final int textLength = text.length();
            if (hasAnyInterestingChars(text, textLength)) {
                return null;  // There are some interesting characters. Not boring.
@@ -592,9 +598,9 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
            if (ClientFlags.fixLineHeightForLocale()) {
                if (minimumFontMetrics != null) {
                    fm.set(minimumFontMetrics);
                // Because the font metrics is provided by public APIs, adjust the top/bottom with
                // ascent/descent: top must be smaller than ascent, bottom must be larger than
                // descent.
                    // Because the font metrics is provided by public APIs, adjust the top/bottom
                    // with ascent/descent: top must be smaller than ascent, bottom must be larger
                    // than descent.
                    fm.top = Math.min(fm.top, fm.ascent);
                    fm.bottom = Math.max(fm.bottom, fm.descent);
                }
@@ -610,6 +616,11 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
            TextLine.recycle(line);

            return fm;
        } finally {
            if (TRACE_LAYOUT) {
                Trace.endSection();
            }
        }
    }

    @Override
+180 −162
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.text.LineBreakConfig;
import android.os.Build;
import android.os.Trace;
import android.text.method.OffsetMapping;
import android.text.style.ReplacementSpan;
import android.text.style.UpdateLayout;
@@ -636,8 +637,13 @@ public class DynamicLayout extends Layout {
    /** @hide */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public void reflow(CharSequence s, int where, int before, int after) {
        if (s != mBase)
        if (TRACE_LAYOUT) {
            Trace.beginSection("DynamicLayout#reflow");
        }
        try {
            if (s != mBase) {
                return;
            }

            CharSequence text = mDisplay;
            int len = text.length();
@@ -645,10 +651,11 @@ public class DynamicLayout extends Layout {
            // seek back to the start of the paragraph

            int find = TextUtils.lastIndexOf(text, '\n', where - 1);
        if (find < 0)
            if (find < 0) {
                find = 0;
        else
            } else {
                find = find + 1;
            }

            {
                int diff = where - find;
@@ -660,10 +667,11 @@ public class DynamicLayout extends Layout {
            // seek forward to the end of the paragraph

            int look = TextUtils.indexOf(text, '\n', where + after);
        if (look < 0)
            if (look < 0) {
                look = len;
        else
            } else {
                look++; // we want the index after the \n
            }

            int change = look - (where + after);
            before += change;
@@ -711,8 +719,9 @@ public class DynamicLayout extends Layout {
            int startv = getLineTop(startline);

            int endline = getLineForOffset(where + before);
        if (where + after == len)
            if (where + after == len) {
                endline = getLineCount();
            }
            int endv = getLineTop(endline);
            boolean islast = (endline == getLineCount());

@@ -751,14 +760,16 @@ public class DynamicLayout extends Layout {
                    .setMinimumFontMetrics(mMinimumFontMetrics)
                    .setCalculateBounds(true);

        reflowed = b.buildPartialStaticLayoutForDynamicLayout(true /* trackpadding */, reflowed);
            reflowed = b.buildPartialStaticLayoutForDynamicLayout(true /* trackpadding */,
                    reflowed);
            int n = reflowed.getLineCount();
            // If the new layout has a blank line at the end, but it is not
            // the very end of the buffer, then we already have a line that
            // starts there, so disregard the blank line.

        if (where + after != len && reflowed.getLineStart(n - 1) == where + after)
            if (where + after != len && reflowed.getLineStart(n - 1) == where + after) {
                n--;
            }

            // remove affected lines from old layout
            mInts.deleteAt(startline, endline - startline);
@@ -803,13 +814,15 @@ public class DynamicLayout extends Layout {
                ints[TAB] |= reflowed.getLineContainsTab(i) ? TAB_MASK : 0;

                int top = reflowed.getLineTop(i) + startv;
            if (i > 0)
                if (i > 0) {
                    top -= toppad;
                }
                ints[TOP] = top;

                int desc = reflowed.getLineDescent(i);
            if (i == n - 1)
                if (i == n - 1) {
                    desc += botpad;
                }

                ints[DESCENT] = desc;
                ints[EXTRA] = reflowed.getLineExtra(i);
@@ -819,8 +832,8 @@ public class DynamicLayout extends Layout {
                ints[HYPHEN] = StaticLayout.packHyphenEdit(
                        reflowed.getStartHyphenEdit(i), reflowed.getEndHyphenEdit(i));
                ints[MAY_PROTRUDE_FROM_TOP_OR_BOTTOM] |=
                    contentMayProtrudeFromLineTopOrBottom(text, start, end) ?
                            MAY_PROTRUDE_FROM_TOP_OR_BOTTOM_MASK : 0;
                        contentMayProtrudeFromLineTopOrBottom(text, start, end)
                                ? MAY_PROTRUDE_FROM_TOP_OR_BOTTOM_MASK : 0;

                if (mEllipsize) {
                    ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i);
@@ -838,6 +851,11 @@ public class DynamicLayout extends Layout {
                sStaticLayout = reflowed;
                sBuilder = b;
            }
        } finally {
            if (TRACE_LAYOUT) {
                Trace.endSection();
            }
        }
    }

    private boolean contentMayProtrudeFromLineTopOrBottom(CharSequence text, int start, int end) {
+46 −29
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.graphics.RectF;
import android.graphics.text.LineBreakConfig;
import android.graphics.text.LineBreaker;
import android.os.Build;
import android.os.Trace;
import android.text.method.TextKeyListener;
import android.text.style.AlignmentSpan;
import android.text.style.LeadingMarginSpan;
@@ -70,6 +71,11 @@ import java.util.Locale;
 * For text that will not change, use a {@link StaticLayout}.
 */
public abstract class Layout {

    /** @hide */
    protected static final boolean TRACE_LAYOUT = Build.isDebuggable();


    /** @hide */
    @IntDef(prefix = { "BREAK_STRATEGY_" }, value = {
            LineBreaker.BREAK_STRATEGY_SIMPLE,
@@ -472,6 +478,10 @@ public abstract class Layout {
            @Nullable Path selectionPath,
            @Nullable Paint selectionPaint,
            int cursorOffsetVertical) {
        if (TRACE_LAYOUT) {
            Trace.beginSection("Layout#draw");
        }
        try {
            float leftShift = 0;
            if (mUseBoundsForWidth && mShiftDrawingOffsetForStartOverhang) {
                RectF drawingRect = computeDrawingBoundingBox();
@@ -488,17 +498,19 @@ public abstract class Layout {
            if (shouldDrawHighlightsOnTop(canvas)) {
                drawBackground(canvas, firstLine, lastLine);
            } else {
            drawWithoutText(canvas, highlightPaths, highlightPaints, selectionPath, selectionPaint,
                drawWithoutText(canvas, highlightPaths, highlightPaints, selectionPath,
                        selectionPaint,
                        cursorOffsetVertical, firstLine, lastLine);
            }

            drawText(canvas, firstLine, lastLine);

        // Since high contrast text draws a solid rectangle background behind the text, it covers up
        // the highlights and selections. In this case we draw over the top of the text with a
        // blend mode that ensures the text stays high-contrast.
            // Since high contrast text draws a solid rectangle background behind the text, it
            // covers up the highlights and selections. In this case we draw over the top of the
            // text with a blend mode that ensures the text stays high-contrast.
            if (shouldDrawHighlightsOnTop(canvas)) {
            drawHighlights(canvas, highlightPaths, highlightPaints, selectionPath, selectionPaint,
                drawHighlights(canvas, highlightPaths, highlightPaints, selectionPath,
                        selectionPaint,
                        cursorOffsetVertical, firstLine, lastLine);
            }

@@ -507,6 +519,11 @@ public abstract class Layout {
                // save/restore disappears the toggle switch drawables.
                canvas.translate(-leftShift, 0);
            }
        } finally {
            if (TRACE_LAYOUT) {
                Trace.endSection();
            }
        }
    }

    private static boolean shouldDrawHighlightsOnTop(Canvas canvas) {
+94 −66
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.text.LineBreakConfig;
import android.graphics.text.MeasuredText;
import android.os.Build;
import android.os.Trace;
import android.text.style.MetricAffectingSpan;

import com.android.internal.util.Preconditions;
@@ -78,6 +80,8 @@ import java.util.Objects;
public class PrecomputedText implements Spannable {
    private static final char LINE_FEED = '\n';

    private static final boolean TRACE_PCT = Build.isDebuggable();

    /**
     * The information required for building {@link PrecomputedText}.
     *
@@ -447,8 +451,15 @@ public class PrecomputedText implements Spannable {

    private static ParagraphInfo[] createMeasuredParagraphsFromPrecomputedText(
            @NonNull PrecomputedText pct, @NonNull Params params, boolean computeLayout) {
        final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
                && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE;
        if (TRACE_PCT) {
            Trace.beginSection("PrecomputedText#createMeasuredParagraphsFromPrecomputedText");
            Trace.setCounter("PrecomputedText#textCharCount", pct.length());
        }
        try {
            final boolean needHyphenation =
                    params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
                            && params.getHyphenationFrequency()
                            != Layout.HYPHENATION_FREQUENCY_NONE;
            final int hyphenationMode;
            if (needHyphenation) {
                hyphenationMode = isFastHyphenation(params.getHyphenationFrequency())
@@ -476,6 +487,11 @@ public class PrecomputedText implements Spannable {
                        pct.getMeasuredParagraph(i), null /* no recycle */)));
            }
            return result.toArray(new ParagraphInfo[result.size()]);
        } finally {
            if (TRACE_PCT) {
                Trace.endSection();
            }
        }
    }

    /** @hide */
@@ -483,12 +499,19 @@ public class PrecomputedText implements Spannable {
            @NonNull CharSequence text, @NonNull Params params,
            @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean computeLayout,
            boolean computeBounds) {
        if (TRACE_PCT) {
            Trace.beginSection("PrecomputedText#createMeasuredParagraphs");
            Trace.setCounter("PrecomputedText#textCharCount", text.length());
        }
        try {
            ArrayList<ParagraphInfo> result = new ArrayList<>();

            Preconditions.checkNotNull(text);
            Preconditions.checkNotNull(params);
        final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
                && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE;
            final boolean needHyphenation =
                    params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
                            && params.getHyphenationFrequency()
                            != Layout.HYPHENATION_FREQUENCY_NONE;
            final int hyphenationMode;
            if (needHyphenation) {
                hyphenationMode = isFastHyphenation(params.getHyphenationFrequency())
@@ -530,6 +553,11 @@ public class PrecomputedText implements Spannable {
                        null /* no recycle */)));
            }
            return result.toArray(new ParagraphInfo[result.size()]);
        } finally {
            if (TRACE_PCT) {
                Trace.endSection();
            }
        }
    }

    // Use PrecomputedText.create instead.
+275 −218
Original line number Diff line number Diff line
@@ -542,10 +542,20 @@ public class StaticLayout extends Layout {
         */
        @NonNull
        public StaticLayout build() {
            if (TRACE_LAYOUT) {
                Trace.beginSection("StaticLayout#build");
                Trace.setCounter("StaticLayout#textLength", mText.length());
            }
            try {
                StaticLayout result = new StaticLayout(this, mIncludePad, mEllipsize != null
                        ? COLUMNS_ELLIPSIZE : COLUMNS_NORMAL);
                Builder.recycle(this);
                return result;
            } finally {
                if (TRACE_LAYOUT) {
                    Trace.endSection();
                }
            }
        }

        /**
@@ -562,16 +572,21 @@ public class StaticLayout extends Layout {
         */
        /* package */ @NonNull StaticLayout buildPartialStaticLayoutForDynamicLayout(
                boolean trackpadding, StaticLayout recycle) {
            if (TRACE_LAYOUT) {
                Trace.beginSection("StaticLayout#forDynamicLayout");
                Trace.setCounter("StaticLayout#textLength", mText.length());
            }
            try {
                if (recycle == null) {
                    recycle = new StaticLayout();
                }
            Trace.beginSection("Generating StaticLayout For DynamicLayout");
            try {
                recycle.generate(this, mIncludePad, trackpadding);
                return recycle;
            } finally {
                if (TRACE_LAYOUT) {
                    Trace.endSection();
                }
            return recycle;
            }
        }

        private CharSequence mText;
@@ -727,12 +742,7 @@ public class StaticLayout extends Layout {
        mLeftIndents = b.mLeftIndents;
        mRightIndents = b.mRightIndents;

        Trace.beginSection("Constructing StaticLayout");
        try {
        generate(b, b.mIncludePad, trackPadding);
        } finally {
            Trace.endSection();
        }
    }

    private static int getBaseHyphenationFrequency(int frequency) {
@@ -842,6 +852,10 @@ public class StaticLayout extends Layout {
                case PrecomputedText.Params.UNUSABLE:
                    break;
                case PrecomputedText.Params.NEED_RECOMPUTE:
                    if (TRACE_LAYOUT) {
                        Trace.beginSection("StaticLayout#recomputePct");
                    }
                    try {
                        final PrecomputedText.Params newParams =
                                new PrecomputedText.Params.Builder(paint)
                                    .setBreakStrategy(b.mBreakStrategy)
@@ -850,6 +864,11 @@ public class StaticLayout extends Layout {
                                    .setLineBreakConfig(b.mLineBreakConfig)
                                    .build();
                        precomputed = PrecomputedText.create(precomputed, newParams);
                    } finally {
                        if (TRACE_LAYOUT) {
                            Trace.endSection();
                        }
                    }
                    paragraphInfo = precomputed.getParagraphInfo();
                    break;
                case PrecomputedText.Params.USABLE:
@@ -860,13 +879,27 @@ public class StaticLayout extends Layout {
        }

        if (paragraphInfo == null) {
            if (TRACE_LAYOUT) {
                Trace.beginSection("StaticLayout#computePct");
            }
            try {
                final PrecomputedText.Params param = new PrecomputedText.Params(paint,
                        b.mLineBreakConfig, textDir, b.mBreakStrategy, b.mHyphenationFrequency);
                paragraphInfo = PrecomputedText.createMeasuredParagraphs(source, param, bufStart,
                        bufEnd, false /* computeLayout */, b.mCalculateBounds);
            } finally {
                if (TRACE_LAYOUT) {
                    Trace.endSection();
                }
            }
        }

        for (int paraIndex = 0; paraIndex < paragraphInfo.length; paraIndex++) {
            if (TRACE_LAYOUT) {
                Trace.beginSection("StaticLayout#processParagraph");
                Trace.setCounter("StaticLayout#paragraph", paraIndex);
            }
            try {
                final int paraStart = paraIndex == 0
                        ? bufStart : paragraphInfo[paraIndex - 1].paragraphEnd;
                final int paraEnd = paragraphInfo[paraIndex].paragraphEnd;
@@ -942,8 +975,18 @@ public class StaticLayout extends Layout {
                constraints.setIndent(firstWidth, firstWidthLineCount);
                constraints.setTabStops(variableTabStops, TAB_INCREMENT);

            LineBreaker.Result res = lineBreaker.computeLineBreaks(
                if (TRACE_LAYOUT) {
                    Trace.beginSection("LineBreaker#computeLineBreaks");
                }
                LineBreaker.Result res;
                try {
                    res = lineBreaker.computeLineBreaks(
                            measuredPara.getMeasuredText(), constraints, mLineCount);
                } finally {
                    if (TRACE_LAYOUT) {
                        Trace.endSection();
                    }
                }
                int breakCount = res.getLineCount();
                if (lineBreakCapacity < breakCount) {
                    lineBreakCapacity = breakCount;
@@ -1045,9 +1088,9 @@ public class StaticLayout extends Layout {
                                ? Math.max(fmDescent, Math.round(descents[breakIndex]))
                                : fmDescent;

                    // The fallback ascent/descent may be larger than top/bottom of the default font
                    // metrics. Adjust top/bottom with ascent/descent for avoiding unexpected
                    // clipping.
                        // The fallback ascent/descent may be larger than top/bottom of the default
                        // font metrics. Adjust top/bottom with ascent/descent for avoiding
                        // unexpected clipping.
                        if (isFallbackLineSpacing) {
                            if (ascent < fmTop) {
                                fmTop = ascent;
@@ -1087,6 +1130,11 @@ public class StaticLayout extends Layout {
                if (paraEnd == bufEnd) {
                    break;
                }
            } finally {
                if (TRACE_LAYOUT) {
                    Trace.endSection();
                }
            }
        }

        if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE)
@@ -1179,9 +1227,18 @@ public class StaticLayout extends Layout {
                    (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) &&
                            ellipsize == TextUtils.TruncateAt.END);
            if (doEllipsis) {
                if (TRACE_LAYOUT) {
                    Trace.beginSection("StaticLayout#calculateEllipsis");
                }
                try {
                    calculateEllipsis(start, end, measured, widthStart,
                            ellipsisWidth, ellipsize, j,
                            textWidth, paint, forceEllipsis);
                } finally {
                    if (TRACE_LAYOUT) {
                        Trace.endSection();
                    }
                }
            } else {
                mLines[mColumns * j + ELLIPSIS_START] = 0;
                mLines[mColumns * j + ELLIPSIS_COUNT] = 0;
Loading