Merge "Revert "Add trace point for the text measurement/draw"" into main
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index e95b216..9db8aa1 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -28,7 +28,6 @@
 import android.graphics.Path;
 import android.graphics.RectF;
 import android.graphics.text.LineBreakConfig;
-import android.os.Trace;
 import android.text.style.ParagraphStyle;
 
 /**
@@ -568,59 +567,49 @@
     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());
+        final int textLength = text.length();
+        if (hasAnyInterestingChars(text, textLength)) {
+           return null;  // There are some interesting characters. Not boring.
         }
-        try {
-            final int textLength = text.length();
-            if (hasAnyInterestingChars(text, textLength)) {
-                return null;  // There are some interesting characters. Not boring.
-            }
-            if (textDir != null && textDir.isRtl(text, 0, textLength)) {
-                return null;  // The heuristic considers the whole text RTL. Not boring.
-            }
-            if (text instanceof Spanned) {
-                Spanned sp = (Spanned) text;
-                Object[] styles = sp.getSpans(0, textLength, ParagraphStyle.class);
-                if (styles.length > 0) {
-                    return null;  // There are some ParagraphStyle spans. Not boring.
-                }
-            }
-
-            Metrics fm = metrics;
-            if (fm == null) {
-                fm = new Metrics();
-            } else {
-                fm.reset();
-            }
-
-            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.
-                    fm.top = Math.min(fm.top, fm.ascent);
-                    fm.bottom = Math.max(fm.bottom, fm.descent);
-                }
-            }
-
-            TextLine line = TextLine.obtain();
-            line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT,
-                    Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null,
-                    0 /* ellipsisStart, 0 since text has not been ellipsized at this point */,
-                    0 /* ellipsisEnd, 0 since text has not been ellipsized at this point */,
-                    useFallbackLineSpacing);
-            fm.width = (int) Math.ceil(line.metrics(fm, fm.mDrawingBounds, false, null));
-            TextLine.recycle(line);
-
-            return fm;
-        } finally {
-            if (TRACE_LAYOUT) {
-                Trace.endSection();
+        if (textDir != null && textDir.isRtl(text, 0, textLength)) {
+           return null;  // The heuristic considers the whole text RTL. Not boring.
+        }
+        if (text instanceof Spanned) {
+            Spanned sp = (Spanned) text;
+            Object[] styles = sp.getSpans(0, textLength, ParagraphStyle.class);
+            if (styles.length > 0) {
+                return null;  // There are some ParagraphStyle spans. Not boring.
             }
         }
+
+        Metrics fm = metrics;
+        if (fm == null) {
+            fm = new Metrics();
+        } else {
+            fm.reset();
+        }
+
+        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.
+                fm.top = Math.min(fm.top, fm.ascent);
+                fm.bottom = Math.max(fm.bottom, fm.descent);
+            }
+        }
+
+        TextLine line = TextLine.obtain();
+        line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT,
+                Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null,
+                0 /* ellipsisStart, 0 since text has not been ellipsized at this point */,
+                0 /* ellipsisEnd, 0 since text has not been ellipsized at this point */,
+                useFallbackLineSpacing);
+        fm.width = (int) Math.ceil(line.metrics(fm, fm.mDrawingBounds, false, null));
+        TextLine.recycle(line);
+
+        return fm;
     }
 
     @Override
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 99ce0ef..cce4f7b 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -31,7 +31,6 @@
 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;
@@ -637,224 +636,207 @@
     /** @hide */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     public void reflow(CharSequence s, int where, int before, int after) {
-        if (TRACE_LAYOUT) {
-            Trace.beginSection("DynamicLayout#reflow");
+        if (s != mBase)
+            return;
+
+        CharSequence text = mDisplay;
+        int len = text.length();
+
+        // seek back to the start of the paragraph
+
+        int find = TextUtils.lastIndexOf(text, '\n', where - 1);
+        if (find < 0)
+            find = 0;
+        else
+            find = find + 1;
+
+        {
+            int diff = where - find;
+            before += diff;
+            after += diff;
+            where -= diff;
         }
-        try {
-            if (s != mBase) {
-                return;
-            }
 
-            CharSequence text = mDisplay;
-            int len = text.length();
+        // seek forward to the end of the paragraph
 
-            // seek back to the start of the paragraph
+        int look = TextUtils.indexOf(text, '\n', where + after);
+        if (look < 0)
+            look = len;
+        else
+            look++; // we want the index after the \n
 
-            int find = TextUtils.lastIndexOf(text, '\n', where - 1);
-            if (find < 0) {
-                find = 0;
-            } else {
-                find = find + 1;
-            }
+        int change = look - (where + after);
+        before += change;
+        after += change;
 
-            {
-                int diff = where - find;
-                before += diff;
-                after += diff;
-                where -= diff;
-            }
+        // seek further out to cover anything that is forced to wrap together
 
-            // seek forward to the end of the paragraph
+        if (text instanceof Spanned) {
+            Spanned sp = (Spanned) text;
+            boolean again;
 
-            int look = TextUtils.indexOf(text, '\n', where + after);
-            if (look < 0) {
-                look = len;
-            } else {
-                look++; // we want the index after the \n
-            }
+            do {
+                again = false;
 
-            int change = look - (where + after);
-            before += change;
-            after += change;
+                Object[] force = sp.getSpans(where, where + after,
+                                             WrapTogetherSpan.class);
 
-            // seek further out to cover anything that is forced to wrap together
+                for (int i = 0; i < force.length; i++) {
+                    int st = sp.getSpanStart(force[i]);
+                    int en = sp.getSpanEnd(force[i]);
 
-            if (text instanceof Spanned) {
-                Spanned sp = (Spanned) text;
-                boolean again;
+                    if (st < where) {
+                        again = true;
 
-                do {
-                    again = false;
-
-                    Object[] force = sp.getSpans(where, where + after,
-                            WrapTogetherSpan.class);
-
-                    for (int i = 0; i < force.length; i++) {
-                        int st = sp.getSpanStart(force[i]);
-                        int en = sp.getSpanEnd(force[i]);
-
-                        if (st < where) {
-                            again = true;
-
-                            int diff = where - st;
-                            before += diff;
-                            after += diff;
-                            where -= diff;
-                        }
-
-                        if (en > where + after) {
-                            again = true;
-
-                            int diff = en - (where + after);
-                            before += diff;
-                            after += diff;
-                        }
+                        int diff = where - st;
+                        before += diff;
+                        after += diff;
+                        where -= diff;
                     }
-                } while (again);
-            }
 
-            // find affected region of old layout
+                    if (en > where + after) {
+                        again = true;
 
-            int startline = getLineForOffset(where);
-            int startv = getLineTop(startline);
+                        int diff = en - (where + after);
+                        before += diff;
+                        after += diff;
+                    }
+                }
+            } while (again);
+        }
 
-            int endline = getLineForOffset(where + before);
-            if (where + after == len) {
-                endline = getLineCount();
-            }
-            int endv = getLineTop(endline);
-            boolean islast = (endline == getLineCount());
+        // find affected region of old layout
 
-            // generate new layout for affected text
+        int startline = getLineForOffset(where);
+        int startv = getLineTop(startline);
 
-            StaticLayout reflowed;
-            StaticLayout.Builder b;
+        int endline = getLineForOffset(where + before);
+        if (where + after == len)
+            endline = getLineCount();
+        int endv = getLineTop(endline);
+        boolean islast = (endline == getLineCount());
 
-            synchronized (sLock) {
-                reflowed = sStaticLayout;
-                b = sBuilder;
-                sStaticLayout = null;
-                sBuilder = null;
-            }
+        // generate new layout for affected text
 
-            if (b == null) {
-                b = StaticLayout.Builder.obtain(text, where, where + after, getPaint(), getWidth());
-            }
+        StaticLayout reflowed;
+        StaticLayout.Builder b;
 
-            b.setText(text, where, where + after)
-                    .setPaint(getPaint())
-                    .setWidth(getWidth())
-                    .setTextDirection(getTextDirectionHeuristic())
-                    .setLineSpacing(getSpacingAdd(), getSpacingMultiplier())
-                    .setUseLineSpacingFromFallbacks(mFallbackLineSpacing)
-                    .setEllipsizedWidth(mEllipsizedWidth)
-                    .setEllipsize(mEllipsizeAt)
-                    .setBreakStrategy(mBreakStrategy)
-                    .setHyphenationFrequency(mHyphenationFrequency)
-                    .setJustificationMode(mJustificationMode)
-                    .setLineBreakConfig(mLineBreakConfig)
-                    .setAddLastLineLineSpacing(!islast)
-                    .setIncludePad(false)
-                    .setUseBoundsForWidth(mUseBoundsForWidth)
-                    .setShiftDrawingOffsetForStartOverhang(mShiftDrawingOffsetForStartOverhang)
-                    .setMinimumFontMetrics(mMinimumFontMetrics)
-                    .setCalculateBounds(true);
+        synchronized (sLock) {
+            reflowed = sStaticLayout;
+            b = sBuilder;
+            sStaticLayout = null;
+            sBuilder = null;
+        }
 
-            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 (b == null) {
+            b = StaticLayout.Builder.obtain(text, where, where + after, getPaint(), getWidth());
+        }
 
-            if (where + after != len && reflowed.getLineStart(n - 1) == where + after) {
-                n--;
-            }
+        b.setText(text, where, where + after)
+                .setPaint(getPaint())
+                .setWidth(getWidth())
+                .setTextDirection(getTextDirectionHeuristic())
+                .setLineSpacing(getSpacingAdd(), getSpacingMultiplier())
+                .setUseLineSpacingFromFallbacks(mFallbackLineSpacing)
+                .setEllipsizedWidth(mEllipsizedWidth)
+                .setEllipsize(mEllipsizeAt)
+                .setBreakStrategy(mBreakStrategy)
+                .setHyphenationFrequency(mHyphenationFrequency)
+                .setJustificationMode(mJustificationMode)
+                .setLineBreakConfig(mLineBreakConfig)
+                .setAddLastLineLineSpacing(!islast)
+                .setIncludePad(false)
+                .setUseBoundsForWidth(mUseBoundsForWidth)
+                .setShiftDrawingOffsetForStartOverhang(mShiftDrawingOffsetForStartOverhang)
+                .setMinimumFontMetrics(mMinimumFontMetrics)
+                .setCalculateBounds(true);
 
-            // remove affected lines from old layout
-            mInts.deleteAt(startline, endline - startline);
-            mObjects.deleteAt(startline, endline - startline);
+        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.
 
-            // adjust offsets in layout for new height and offsets
+        if (where + after != len && reflowed.getLineStart(n - 1) == where + after)
+            n--;
 
-            int ht = reflowed.getLineTop(n);
-            int toppad = 0, botpad = 0;
+        // remove affected lines from old layout
+        mInts.deleteAt(startline, endline - startline);
+        mObjects.deleteAt(startline, endline - startline);
 
-            if (mIncludePad && startline == 0) {
-                toppad = reflowed.getTopPadding();
-                mTopPadding = toppad;
-                ht -= toppad;
-            }
-            if (mIncludePad && islast) {
-                botpad = reflowed.getBottomPadding();
-                mBottomPadding = botpad;
-                ht += botpad;
-            }
+        // adjust offsets in layout for new height and offsets
 
-            mInts.adjustValuesBelow(startline, START, after - before);
-            mInts.adjustValuesBelow(startline, TOP, startv - endv + ht);
+        int ht = reflowed.getLineTop(n);
+        int toppad = 0, botpad = 0;
 
-            // insert new layout
+        if (mIncludePad && startline == 0) {
+            toppad = reflowed.getTopPadding();
+            mTopPadding = toppad;
+            ht -= toppad;
+        }
+        if (mIncludePad && islast) {
+            botpad = reflowed.getBottomPadding();
+            mBottomPadding = botpad;
+            ht += botpad;
+        }
 
-            int[] ints;
+        mInts.adjustValuesBelow(startline, START, after - before);
+        mInts.adjustValuesBelow(startline, TOP, startv - endv + ht);
+
+        // insert new layout
+
+        int[] ints;
+
+        if (mEllipsize) {
+            ints = new int[COLUMNS_ELLIPSIZE];
+            ints[ELLIPSIS_START] = ELLIPSIS_UNDEFINED;
+        } else {
+            ints = new int[COLUMNS_NORMAL];
+        }
+
+        Directions[] objects = new Directions[1];
+
+        for (int i = 0; i < n; i++) {
+            final int start = reflowed.getLineStart(i);
+            ints[START] = start;
+            ints[DIR] |= reflowed.getParagraphDirection(i) << DIR_SHIFT;
+            ints[TAB] |= reflowed.getLineContainsTab(i) ? TAB_MASK : 0;
+
+            int top = reflowed.getLineTop(i) + startv;
+            if (i > 0)
+                top -= toppad;
+            ints[TOP] = top;
+
+            int desc = reflowed.getLineDescent(i);
+            if (i == n - 1)
+                desc += botpad;
+
+            ints[DESCENT] = desc;
+            ints[EXTRA] = reflowed.getLineExtra(i);
+            objects[0] = reflowed.getLineDirections(i);
+
+            final int end = (i == n - 1) ? where + after : reflowed.getLineStart(i + 1);
+            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;
 
             if (mEllipsize) {
-                ints = new int[COLUMNS_ELLIPSIZE];
-                ints[ELLIPSIS_START] = ELLIPSIS_UNDEFINED;
-            } else {
-                ints = new int[COLUMNS_NORMAL];
+                ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i);
+                ints[ELLIPSIS_COUNT] = reflowed.getEllipsisCount(i);
             }
 
-            Directions[] objects = new Directions[1];
+            mInts.insertAt(startline + i, ints);
+            mObjects.insertAt(startline + i, objects);
+        }
 
-            for (int i = 0; i < n; i++) {
-                final int start = reflowed.getLineStart(i);
-                ints[START] = start;
-                ints[DIR] |= reflowed.getParagraphDirection(i) << DIR_SHIFT;
-                ints[TAB] |= reflowed.getLineContainsTab(i) ? TAB_MASK : 0;
+        updateBlocks(startline, endline - 1, n);
 
-                int top = reflowed.getLineTop(i) + startv;
-                if (i > 0) {
-                    top -= toppad;
-                }
-                ints[TOP] = top;
-
-                int desc = reflowed.getLineDescent(i);
-                if (i == n - 1) {
-                    desc += botpad;
-                }
-
-                ints[DESCENT] = desc;
-                ints[EXTRA] = reflowed.getLineExtra(i);
-                objects[0] = reflowed.getLineDirections(i);
-
-                final int end = (i == n - 1) ? where + after : reflowed.getLineStart(i + 1);
-                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;
-
-                if (mEllipsize) {
-                    ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i);
-                    ints[ELLIPSIS_COUNT] = reflowed.getEllipsisCount(i);
-                }
-
-                mInts.insertAt(startline + i, ints);
-                mObjects.insertAt(startline + i, objects);
-            }
-
-            updateBlocks(startline, endline - 1, n);
-
-            b.finish();
-            synchronized (sLock) {
-                sStaticLayout = reflowed;
-                sBuilder = b;
-            }
-        } finally {
-            if (TRACE_LAYOUT) {
-                Trace.endSection();
-            }
+        b.finish();
+        synchronized (sLock) {
+            sStaticLayout = reflowed;
+            sBuilder = b;
         }
     }
 
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index ce238a7..8dee4b1 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -39,7 +39,6 @@
 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;
@@ -71,11 +70,6 @@
  * 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,
@@ -478,51 +472,40 @@
             @Nullable Path selectionPath,
             @Nullable Paint selectionPaint,
             int cursorOffsetVertical) {
-        if (TRACE_LAYOUT) {
-            Trace.beginSection("Layout#draw");
+        float leftShift = 0;
+        if (mUseBoundsForWidth && mShiftDrawingOffsetForStartOverhang) {
+            RectF drawingRect = computeDrawingBoundingBox();
+            if (drawingRect.left < 0) {
+                leftShift = -drawingRect.left;
+                canvas.translate(leftShift, 0);
+            }
         }
-        try {
-            float leftShift = 0;
-            if (mUseBoundsForWidth && mShiftDrawingOffsetForStartOverhang) {
-                RectF drawingRect = computeDrawingBoundingBox();
-                if (drawingRect.left < 0) {
-                    leftShift = -drawingRect.left;
-                    canvas.translate(leftShift, 0);
-                }
-            }
-            final long lineRange = getLineRangeForDraw(canvas);
-            int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
-            int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
-            if (lastLine < 0) return;
+        final long lineRange = getLineRangeForDraw(canvas);
+        int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
+        int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
+        if (lastLine < 0) return;
 
-            if (shouldDrawHighlightsOnTop(canvas)) {
-                drawBackground(canvas, firstLine, lastLine);
-            } else {
-                drawWithoutText(canvas, highlightPaths, highlightPaints, selectionPath,
-                        selectionPaint,
-                        cursorOffsetVertical, firstLine, lastLine);
-            }
+        if (shouldDrawHighlightsOnTop(canvas)) {
+            drawBackground(canvas, firstLine, lastLine);
+        } else {
+            drawWithoutText(canvas, highlightPaths, highlightPaints, selectionPath, selectionPaint,
+                    cursorOffsetVertical, firstLine, lastLine);
+        }
 
-            drawText(canvas, 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.
-            if (shouldDrawHighlightsOnTop(canvas)) {
-                drawHighlights(canvas, highlightPaths, highlightPaints, selectionPath,
-                        selectionPaint,
-                        cursorOffsetVertical, 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.
+        if (shouldDrawHighlightsOnTop(canvas)) {
+            drawHighlights(canvas, highlightPaths, highlightPaints, selectionPath, selectionPaint,
+                    cursorOffsetVertical, firstLine, lastLine);
+        }
 
-            if (leftShift != 0) {
-                // Manually translate back to the original position because of b/324498002, using
-                // save/restore disappears the toggle switch drawables.
-                canvas.translate(-leftShift, 0);
-            }
-        } finally {
-            if (TRACE_LAYOUT) {
-                Trace.endSection();
-            }
+        if (leftShift != 0) {
+            // Manually translate back to the original position because of b/324498002, using
+            // save/restore disappears the toggle switch drawables.
+            canvas.translate(-leftShift, 0);
         }
     }
 
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
index 14401a6..5f6a9bd 100644
--- a/core/java/android/text/PrecomputedText.java
+++ b/core/java/android/text/PrecomputedText.java
@@ -25,8 +25,6 @@
 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;
@@ -80,8 +78,6 @@
 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}.
      *
@@ -451,47 +447,35 @@
 
     private static ParagraphInfo[] createMeasuredParagraphsFromPrecomputedText(
             @NonNull PrecomputedText pct, @NonNull Params params, boolean computeLayout) {
-        if (TRACE_PCT) {
-            Trace.beginSection("PrecomputedText#createMeasuredParagraphsFromPrecomputedText");
-            Trace.setCounter("PrecomputedText#textCharCount", pct.length());
+        final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
+                && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE;
+        final int hyphenationMode;
+        if (needHyphenation) {
+            hyphenationMode = isFastHyphenation(params.getHyphenationFrequency())
+                    ? MeasuredText.Builder.HYPHENATION_MODE_FAST :
+                    MeasuredText.Builder.HYPHENATION_MODE_NORMAL;
+        } else {
+            hyphenationMode = MeasuredText.Builder.HYPHENATION_MODE_NONE;
         }
-        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())
-                        ? MeasuredText.Builder.HYPHENATION_MODE_FAST :
-                        MeasuredText.Builder.HYPHENATION_MODE_NORMAL;
-            } else {
-                hyphenationMode = MeasuredText.Builder.HYPHENATION_MODE_NONE;
-            }
-            LineBreakConfig config = params.getLineBreakConfig();
-            if (config.getLineBreakWordStyle() == LineBreakConfig.LINE_BREAK_WORD_STYLE_AUTO
-                    && pct.getParagraphCount() != 1) {
-                // If the text has multiple paragraph, resolve line break word style auto to none.
-                config = new LineBreakConfig.Builder()
-                        .merge(config)
-                        .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
-                        .build();
-            }
-            ArrayList<ParagraphInfo> result = new ArrayList<>();
-            for (int i = 0; i < pct.getParagraphCount(); ++i) {
-                final int paraStart = pct.getParagraphStart(i);
-                final int paraEnd = pct.getParagraphEnd(i);
-                result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
-                        params.getTextPaint(), config, pct, paraStart, paraEnd,
-                        params.getTextDirection(), hyphenationMode, computeLayout, true,
-                        pct.getMeasuredParagraph(i), null /* no recycle */)));
-            }
-            return result.toArray(new ParagraphInfo[result.size()]);
-        } finally {
-            if (TRACE_PCT) {
-                Trace.endSection();
-            }
+        LineBreakConfig config = params.getLineBreakConfig();
+        if (config.getLineBreakWordStyle() == LineBreakConfig.LINE_BREAK_WORD_STYLE_AUTO
+                && pct.getParagraphCount() != 1) {
+            // If the text has multiple paragraph, resolve line break word style auto to none.
+            config = new LineBreakConfig.Builder()
+                    .merge(config)
+                    .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
+                    .build();
         }
+        ArrayList<ParagraphInfo> result = new ArrayList<>();
+        for (int i = 0; i < pct.getParagraphCount(); ++i) {
+            final int paraStart = pct.getParagraphStart(i);
+            final int paraEnd = pct.getParagraphEnd(i);
+            result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
+                    params.getTextPaint(), config, pct, paraStart, paraEnd,
+                    params.getTextDirection(), hyphenationMode, computeLayout, true,
+                    pct.getMeasuredParagraph(i), null /* no recycle */)));
+        }
+        return result.toArray(new ParagraphInfo[result.size()]);
     }
 
     /** @hide */
@@ -499,65 +483,53 @@
             @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<>();
+        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 int hyphenationMode;
-            if (needHyphenation) {
-                hyphenationMode = isFastHyphenation(params.getHyphenationFrequency())
-                        ? MeasuredText.Builder.HYPHENATION_MODE_FAST :
-                        MeasuredText.Builder.HYPHENATION_MODE_NORMAL;
+        Preconditions.checkNotNull(text);
+        Preconditions.checkNotNull(params);
+        final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
+                && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE;
+        final int hyphenationMode;
+        if (needHyphenation) {
+            hyphenationMode = isFastHyphenation(params.getHyphenationFrequency())
+                    ? MeasuredText.Builder.HYPHENATION_MODE_FAST :
+                    MeasuredText.Builder.HYPHENATION_MODE_NORMAL;
+        } else {
+            hyphenationMode = MeasuredText.Builder.HYPHENATION_MODE_NONE;
+        }
+
+        LineBreakConfig config = null;
+        int paraEnd = 0;
+        for (int paraStart = start; paraStart < end; paraStart = paraEnd) {
+            paraEnd = TextUtils.indexOf(text, LINE_FEED, paraStart, end);
+            if (paraEnd < 0) {
+                // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph
+                // end.
+                paraEnd = end;
             } else {
-                hyphenationMode = MeasuredText.Builder.HYPHENATION_MODE_NONE;
+                paraEnd++;  // Includes LINE_FEED(U+000A) to the prev paragraph.
             }
 
-            LineBreakConfig config = null;
-            int paraEnd = 0;
-            for (int paraStart = start; paraStart < end; paraStart = paraEnd) {
-                paraEnd = TextUtils.indexOf(text, LINE_FEED, paraStart, end);
-                if (paraEnd < 0) {
-                    // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph
-                    // end.
-                    paraEnd = end;
-                } else {
-                    paraEnd++;  // Includes LINE_FEED(U+000A) to the prev paragraph.
+            if (config == null) {
+                config = params.getLineBreakConfig();
+                if (config.getLineBreakWordStyle() == LineBreakConfig.LINE_BREAK_WORD_STYLE_AUTO
+                        && !(paraStart == start && paraEnd == end)) {
+                    // If the text has multiple paragraph, resolve line break word style auto to
+                    // none.
+                    config = new LineBreakConfig.Builder()
+                            .merge(config)
+                            .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
+                            .build();
                 }
-
-                if (config == null) {
-                    config = params.getLineBreakConfig();
-                    if (config.getLineBreakWordStyle() == LineBreakConfig.LINE_BREAK_WORD_STYLE_AUTO
-                            && !(paraStart == start && paraEnd == end)) {
-                        // If the text has multiple paragraph, resolve line break word style auto to
-                        // none.
-                        config = new LineBreakConfig.Builder()
-                                .merge(config)
-                                .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
-                                .build();
-                    }
-                }
-
-                result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
-                        params.getTextPaint(), config, text, paraStart, paraEnd,
-                        params.getTextDirection(), hyphenationMode, computeLayout, computeBounds,
-                        null /* no hint */,
-                        null /* no recycle */)));
             }
-            return result.toArray(new ParagraphInfo[result.size()]);
-        } finally {
-            if (TRACE_PCT) {
-                Trace.endSection();
-            }
+
+            result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
+                    params.getTextPaint(), config, text, paraStart, paraEnd,
+                    params.getTextDirection(), hyphenationMode, computeLayout, computeBounds,
+                    null /* no hint */,
+                    null /* no recycle */)));
         }
+        return result.toArray(new ParagraphInfo[result.size()]);
     }
 
     // Use PrecomputedText.create instead.
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index d1b14d1..3dd3a9e 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -542,20 +542,10 @@
          */
         @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();
-                }
-            }
+            StaticLayout result = new StaticLayout(this, mIncludePad, mEllipsize != null
+                    ? COLUMNS_ELLIPSIZE : COLUMNS_NORMAL);
+            Builder.recycle(this);
+            return result;
         }
 
         /**
@@ -572,21 +562,16 @@
          */
         /* package */ @NonNull StaticLayout buildPartialStaticLayoutForDynamicLayout(
                 boolean trackpadding, StaticLayout recycle) {
-            if (TRACE_LAYOUT) {
-                Trace.beginSection("StaticLayout#forDynamicLayout");
-                Trace.setCounter("StaticLayout#textLength", mText.length());
+            if (recycle == null) {
+                recycle = new StaticLayout();
             }
+            Trace.beginSection("Generating StaticLayout For DynamicLayout");
             try {
-                if (recycle == null) {
-                    recycle = new StaticLayout();
-                }
                 recycle.generate(this, mIncludePad, trackpadding);
-                return recycle;
             } finally {
-                if (TRACE_LAYOUT) {
-                    Trace.endSection();
-                }
+                Trace.endSection();
             }
+            return recycle;
         }
 
         private CharSequence mText;
@@ -742,7 +727,12 @@
         mLeftIndents = b.mLeftIndents;
         mRightIndents = b.mRightIndents;
 
-        generate(b, b.mIncludePad, trackPadding);
+        Trace.beginSection("Constructing StaticLayout");
+        try {
+            generate(b, b.mIncludePad, trackPadding);
+        } finally {
+            Trace.endSection();
+        }
     }
 
     private static int getBaseHyphenationFrequency(int frequency) {
@@ -852,23 +842,14 @@
                 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)
-                                    .setHyphenationFrequency(b.mHyphenationFrequency)
-                                    .setTextDirection(textDir)
-                                    .setLineBreakConfig(b.mLineBreakConfig)
-                                    .build();
-                        precomputed = PrecomputedText.create(precomputed, newParams);
-                    } finally {
-                        if (TRACE_LAYOUT) {
-                            Trace.endSection();
-                        }
-                    }
+                    final PrecomputedText.Params newParams =
+                            new PrecomputedText.Params.Builder(paint)
+                                .setBreakStrategy(b.mBreakStrategy)
+                                .setHyphenationFrequency(b.mHyphenationFrequency)
+                                .setTextDirection(textDir)
+                                .setLineBreakConfig(b.mLineBreakConfig)
+                                .build();
+                    precomputed = PrecomputedText.create(precomputed, newParams);
                     paragraphInfo = precomputed.getParagraphInfo();
                     break;
                 case PrecomputedText.Params.USABLE:
@@ -879,261 +860,232 @@
         }
 
         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();
-                }
-            }
+            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);
         }
 
         for (int paraIndex = 0; paraIndex < paragraphInfo.length; paraIndex++) {
-            if (TRACE_LAYOUT) {
-                Trace.beginSection("StaticLayout#processParagraph");
-                Trace.setCounter("StaticLayout#paragraph", paraIndex);
+            final int paraStart = paraIndex == 0
+                    ? bufStart : paragraphInfo[paraIndex - 1].paragraphEnd;
+            final int paraEnd = paragraphInfo[paraIndex].paragraphEnd;
+
+            int firstWidthLineCount = 1;
+            int firstWidth = outerWidth;
+            int restWidth = outerWidth;
+
+            LineHeightSpan[] chooseHt = null;
+            if (spanned != null) {
+                LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd,
+                        LeadingMarginSpan.class);
+                for (int i = 0; i < sp.length; i++) {
+                    LeadingMarginSpan lms = sp[i];
+                    firstWidth -= sp[i].getLeadingMargin(true);
+                    restWidth -= sp[i].getLeadingMargin(false);
+
+                    // LeadingMarginSpan2 is odd.  The count affects all
+                    // leading margin spans, not just this particular one
+                    if (lms instanceof LeadingMarginSpan2) {
+                        LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
+                        firstWidthLineCount = Math.max(firstWidthLineCount,
+                                lms2.getLeadingMarginLineCount());
+                    }
+                }
+
+                chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class);
+
+                if (chooseHt.length == 0) {
+                    chooseHt = null; // So that out() would not assume it has any contents
+                } else {
+                    if (chooseHtv == null || chooseHtv.length < chooseHt.length) {
+                        chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
+                    }
+
+                    for (int i = 0; i < chooseHt.length; i++) {
+                        int o = spanned.getSpanStart(chooseHt[i]);
+
+                        if (o < paraStart) {
+                            // starts in this layout, before the
+                            // current paragraph
+
+                            chooseHtv[i] = getLineTop(getLineForOffset(o));
+                        } else {
+                            // starts in this paragraph
+
+                            chooseHtv[i] = v;
+                        }
+                    }
+                }
             }
-            try {
-                final int paraStart = paraIndex == 0
-                        ? bufStart : paragraphInfo[paraIndex - 1].paragraphEnd;
-                final int paraEnd = paragraphInfo[paraIndex].paragraphEnd;
-
-                int firstWidthLineCount = 1;
-                int firstWidth = outerWidth;
-                int restWidth = outerWidth;
-
-                LineHeightSpan[] chooseHt = null;
-                if (spanned != null) {
-                    LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd,
-                            LeadingMarginSpan.class);
-                    for (int i = 0; i < sp.length; i++) {
-                        LeadingMarginSpan lms = sp[i];
-                        firstWidth -= sp[i].getLeadingMargin(true);
-                        restWidth -= sp[i].getLeadingMargin(false);
-
-                        // LeadingMarginSpan2 is odd.  The count affects all
-                        // leading margin spans, not just this particular one
-                        if (lms instanceof LeadingMarginSpan2) {
-                            LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
-                            firstWidthLineCount = Math.max(firstWidthLineCount,
-                                    lms2.getLeadingMarginLineCount());
-                        }
+            // tab stop locations
+            float[] variableTabStops = null;
+            if (spanned != null) {
+                TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
+                        paraEnd, TabStopSpan.class);
+                if (spans.length > 0) {
+                    float[] stops = new float[spans.length];
+                    for (int i = 0; i < spans.length; i++) {
+                        stops[i] = (float) spans[i].getTabStop();
                     }
+                    Arrays.sort(stops, 0, stops.length);
+                    variableTabStops = stops;
+                }
+            }
 
-                    chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class);
+            final MeasuredParagraph measuredPara = paragraphInfo[paraIndex].measured;
+            final char[] chs = measuredPara.getChars();
+            final int[] spanEndCache = measuredPara.getSpanEndCache().getRawArray();
+            final int[] fmCache = measuredPara.getFontMetrics().getRawArray();
 
-                    if (chooseHt.length == 0) {
-                        chooseHt = null; // So that out() would not assume it has any contents
+            constraints.setWidth(restWidth);
+            constraints.setIndent(firstWidth, firstWidthLineCount);
+            constraints.setTabStops(variableTabStops, TAB_INCREMENT);
+
+            LineBreaker.Result res = lineBreaker.computeLineBreaks(
+                    measuredPara.getMeasuredText(), constraints, mLineCount);
+            int breakCount = res.getLineCount();
+            if (lineBreakCapacity < breakCount) {
+                lineBreakCapacity = breakCount;
+                breaks = new int[lineBreakCapacity];
+                lineWidths = new float[lineBreakCapacity];
+                ascents = new float[lineBreakCapacity];
+                descents = new float[lineBreakCapacity];
+                hasTabs = new boolean[lineBreakCapacity];
+                hyphenEdits = new int[lineBreakCapacity];
+            }
+
+            for (int i = 0; i < breakCount; ++i) {
+                breaks[i] = res.getLineBreakOffset(i);
+                lineWidths[i] = res.getLineWidth(i);
+                ascents[i] = res.getLineAscent(i);
+                descents[i] = res.getLineDescent(i);
+                hasTabs[i] = res.hasLineTab(i);
+                hyphenEdits[i] =
+                    packHyphenEdit(res.getStartLineHyphenEdit(i), res.getEndLineHyphenEdit(i));
+            }
+
+            final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
+            final boolean ellipsisMayBeApplied = ellipsize != null
+                    && (ellipsize == TextUtils.TruncateAt.END
+                        || (mMaximumVisibleLineCount == 1
+                                && ellipsize != TextUtils.TruncateAt.MARQUEE));
+            if (0 < remainingLineCount && remainingLineCount < breakCount
+                    && ellipsisMayBeApplied) {
+                // Calculate width
+                float width = 0;
+                boolean hasTab = false;  // XXX May need to also have starting hyphen edit
+                for (int i = remainingLineCount - 1; i < breakCount; i++) {
+                    if (i == breakCount - 1) {
+                        width += lineWidths[i];
                     } else {
-                        if (chooseHtv == null || chooseHtv.length < chooseHt.length) {
-                            chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
-                        }
-
-                        for (int i = 0; i < chooseHt.length; i++) {
-                            int o = spanned.getSpanStart(chooseHt[i]);
-
-                            if (o < paraStart) {
-                                // starts in this layout, before the
-                                // current paragraph
-
-                                chooseHtv[i] = getLineTop(getLineForOffset(o));
-                            } else {
-                                // starts in this paragraph
-
-                                chooseHtv[i] = v;
-                            }
+                        for (int j = (i == 0 ? 0 : breaks[i - 1]); j < breaks[i]; j++) {
+                            width += measuredPara.getCharWidthAt(j);
                         }
                     }
+                    hasTab |= hasTabs[i];
                 }
-                // tab stop locations
-                float[] variableTabStops = null;
-                if (spanned != null) {
-                    TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
-                            paraEnd, TabStopSpan.class);
-                    if (spans.length > 0) {
-                        float[] stops = new float[spans.length];
-                        for (int i = 0; i < spans.length; i++) {
-                            stops[i] = (float) spans[i].getTabStop();
+                // Treat the last line and overflowed lines as a single line.
+                breaks[remainingLineCount - 1] = breaks[breakCount - 1];
+                lineWidths[remainingLineCount - 1] = width;
+                hasTabs[remainingLineCount - 1] = hasTab;
+
+                breakCount = remainingLineCount;
+            }
+
+            // here is the offset of the starting character of the line we are currently
+            // measuring
+            int here = paraStart;
+
+            int fmTop = defaultTop;
+            int fmBottom = defaultBottom;
+            int fmAscent = defaultAscent;
+            int fmDescent = defaultDescent;
+            int fmCacheIndex = 0;
+            int spanEndCacheIndex = 0;
+            int breakIndex = 0;
+            for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
+                // retrieve end of span
+                spanEnd = spanEndCache[spanEndCacheIndex++];
+
+                // retrieve cached metrics, order matches above
+                fm.top = fmCache[fmCacheIndex * 4 + 0];
+                fm.bottom = fmCache[fmCacheIndex * 4 + 1];
+                fm.ascent = fmCache[fmCacheIndex * 4 + 2];
+                fm.descent = fmCache[fmCacheIndex * 4 + 3];
+                fmCacheIndex++;
+
+                if (fm.top < fmTop) {
+                    fmTop = fm.top;
+                }
+                if (fm.ascent < fmAscent) {
+                    fmAscent = fm.ascent;
+                }
+                if (fm.descent > fmDescent) {
+                    fmDescent = fm.descent;
+                }
+                if (fm.bottom > fmBottom) {
+                    fmBottom = fm.bottom;
+                }
+
+                // skip breaks ending before current span range
+                while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) {
+                    breakIndex++;
+                }
+
+                while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
+                    int endPos = paraStart + breaks[breakIndex];
+
+                    boolean moreChars = (endPos < bufEnd);
+
+                    final int ascent = isFallbackLineSpacing
+                            ? Math.min(fmAscent, Math.round(ascents[breakIndex]))
+                            : fmAscent;
+                    final int descent = isFallbackLineSpacing
+                            ? 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.
+                    if (isFallbackLineSpacing) {
+                        if (ascent < fmTop) {
+                            fmTop = ascent;
                         }
-                        Arrays.sort(stops, 0, stops.length);
-                        variableTabStops = stops;
-                    }
-                }
-
-                final MeasuredParagraph measuredPara = paragraphInfo[paraIndex].measured;
-                final char[] chs = measuredPara.getChars();
-                final int[] spanEndCache = measuredPara.getSpanEndCache().getRawArray();
-                final int[] fmCache = measuredPara.getFontMetrics().getRawArray();
-
-                constraints.setWidth(restWidth);
-                constraints.setIndent(firstWidth, firstWidthLineCount);
-                constraints.setTabStops(variableTabStops, TAB_INCREMENT);
-
-                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;
-                    breaks = new int[lineBreakCapacity];
-                    lineWidths = new float[lineBreakCapacity];
-                    ascents = new float[lineBreakCapacity];
-                    descents = new float[lineBreakCapacity];
-                    hasTabs = new boolean[lineBreakCapacity];
-                    hyphenEdits = new int[lineBreakCapacity];
-                }
-
-                for (int i = 0; i < breakCount; ++i) {
-                    breaks[i] = res.getLineBreakOffset(i);
-                    lineWidths[i] = res.getLineWidth(i);
-                    ascents[i] = res.getLineAscent(i);
-                    descents[i] = res.getLineDescent(i);
-                    hasTabs[i] = res.hasLineTab(i);
-                    hyphenEdits[i] =
-                        packHyphenEdit(res.getStartLineHyphenEdit(i), res.getEndLineHyphenEdit(i));
-                }
-
-                final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
-                final boolean ellipsisMayBeApplied = ellipsize != null
-                        && (ellipsize == TextUtils.TruncateAt.END
-                            || (mMaximumVisibleLineCount == 1
-                                    && ellipsize != TextUtils.TruncateAt.MARQUEE));
-                if (0 < remainingLineCount && remainingLineCount < breakCount
-                        && ellipsisMayBeApplied) {
-                    // Calculate width
-                    float width = 0;
-                    boolean hasTab = false;  // XXX May need to also have starting hyphen edit
-                    for (int i = remainingLineCount - 1; i < breakCount; i++) {
-                        if (i == breakCount - 1) {
-                            width += lineWidths[i];
-                        } else {
-                            for (int j = (i == 0 ? 0 : breaks[i - 1]); j < breaks[i]; j++) {
-                                width += measuredPara.getCharWidthAt(j);
-                            }
-                        }
-                        hasTab |= hasTabs[i];
-                    }
-                    // Treat the last line and overflowed lines as a single line.
-                    breaks[remainingLineCount - 1] = breaks[breakCount - 1];
-                    lineWidths[remainingLineCount - 1] = width;
-                    hasTabs[remainingLineCount - 1] = hasTab;
-
-                    breakCount = remainingLineCount;
-                }
-
-                // here is the offset of the starting character of the line we are currently
-                // measuring
-                int here = paraStart;
-
-                int fmTop = defaultTop;
-                int fmBottom = defaultBottom;
-                int fmAscent = defaultAscent;
-                int fmDescent = defaultDescent;
-                int fmCacheIndex = 0;
-                int spanEndCacheIndex = 0;
-                int breakIndex = 0;
-                for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
-                    // retrieve end of span
-                    spanEnd = spanEndCache[spanEndCacheIndex++];
-
-                    // retrieve cached metrics, order matches above
-                    fm.top = fmCache[fmCacheIndex * 4 + 0];
-                    fm.bottom = fmCache[fmCacheIndex * 4 + 1];
-                    fm.ascent = fmCache[fmCacheIndex * 4 + 2];
-                    fm.descent = fmCache[fmCacheIndex * 4 + 3];
-                    fmCacheIndex++;
-
-                    if (fm.top < fmTop) {
-                        fmTop = fm.top;
-                    }
-                    if (fm.ascent < fmAscent) {
-                        fmAscent = fm.ascent;
-                    }
-                    if (fm.descent > fmDescent) {
-                        fmDescent = fm.descent;
-                    }
-                    if (fm.bottom > fmBottom) {
-                        fmBottom = fm.bottom;
-                    }
-
-                    // skip breaks ending before current span range
-                    while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) {
-                        breakIndex++;
-                    }
-
-                    while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
-                        int endPos = paraStart + breaks[breakIndex];
-
-                        boolean moreChars = (endPos < bufEnd);
-
-                        final int ascent = isFallbackLineSpacing
-                                ? Math.min(fmAscent, Math.round(ascents[breakIndex]))
-                                : fmAscent;
-                        final int descent = isFallbackLineSpacing
-                                ? 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.
-                        if (isFallbackLineSpacing) {
-                            if (ascent < fmTop) {
-                                fmTop = ascent;
-                            }
-                            if (descent > fmBottom) {
-                                fmBottom = descent;
-                            }
-                        }
-
-                        v = out(source, here, endPos,
-                                ascent, descent, fmTop, fmBottom,
-                                v, spacingmult, spacingadd, chooseHt, chooseHtv, fm,
-                                hasTabs[breakIndex], hyphenEdits[breakIndex], needMultiply,
-                                measuredPara, bufEnd, includepad, trackpad, addLastLineSpacing, chs,
-                                paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex],
-                                paint, moreChars);
-
-                        if (endPos < spanEnd) {
-                            // preserve metrics for current span
-                            fmTop = Math.min(defaultTop, fm.top);
-                            fmBottom = Math.max(defaultBottom, fm.bottom);
-                            fmAscent = Math.min(defaultAscent, fm.ascent);
-                            fmDescent = Math.max(defaultDescent, fm.descent);
-                        } else {
-                            fmTop = fmBottom = fmAscent = fmDescent = 0;
-                        }
-
-                        here = endPos;
-                        breakIndex++;
-
-                        if (mLineCount >= mMaximumVisibleLineCount && mEllipsized) {
-                            return;
+                        if (descent > fmBottom) {
+                            fmBottom = descent;
                         }
                     }
-                }
 
-                if (paraEnd == bufEnd) {
-                    break;
+                    v = out(source, here, endPos,
+                            ascent, descent, fmTop, fmBottom,
+                            v, spacingmult, spacingadd, chooseHt, chooseHtv, fm,
+                            hasTabs[breakIndex], hyphenEdits[breakIndex], needMultiply,
+                            measuredPara, bufEnd, includepad, trackpad, addLastLineSpacing, chs,
+                            paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex],
+                            paint, moreChars);
+
+                    if (endPos < spanEnd) {
+                        // preserve metrics for current span
+                        fmTop = Math.min(defaultTop, fm.top);
+                        fmBottom = Math.max(defaultBottom, fm.bottom);
+                        fmAscent = Math.min(defaultAscent, fm.ascent);
+                        fmDescent = Math.max(defaultDescent, fm.descent);
+                    } else {
+                        fmTop = fmBottom = fmAscent = fmDescent = 0;
+                    }
+
+                    here = endPos;
+                    breakIndex++;
+
+                    if (mLineCount >= mMaximumVisibleLineCount && mEllipsized) {
+                        return;
+                    }
                 }
-            } finally {
-                if (TRACE_LAYOUT) {
-                    Trace.endSection();
-                }
+            }
+
+            if (paraEnd == bufEnd) {
+                break;
             }
         }
 
@@ -1227,18 +1179,9 @@
                     (!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();
-                    }
-                }
+                calculateEllipsis(start, end, measured, widthStart,
+                        ellipsisWidth, ellipsize, j,
+                        textWidth, paint, forceEllipsis);
             } else {
                 mLines[mColumns * j + ELLIPSIS_START] = 0;
                 mLines[mColumns * j + ELLIPSIS_COUNT] = 0;
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index a439478..bde9c77 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -28,7 +28,6 @@
 import android.graphics.text.PositionedGlyphs;
 import android.graphics.text.TextRunShaper;
 import android.os.Build;
-import android.os.Trace;
 import android.text.Layout.Directions;
 import android.text.Layout.TabStops;
 import android.text.style.CharacterStyle;
@@ -57,8 +56,6 @@
 public class TextLine {
     private static final boolean DEBUG = false;
 
-    private static final boolean TRACE_TEXTLINE = Build.isDebuggable();
-
     private static final char TAB_CHAR = '\t';
 
     private TextPaint mPaint;
@@ -433,37 +430,28 @@
      * @param bottom the bottom of the line
      */
     void draw(Canvas c, float x, int top, int y, int bottom) {
-        if (TRACE_TEXTLINE) {
-            Trace.beginSection("TextLine#draw");
-        }
-        try {
-            float h = 0;
-            final int runCount = mDirections.getRunCount();
-            for (int runIndex = 0; runIndex < runCount; runIndex++) {
-                final int runStart = mDirections.getRunStart(runIndex);
-                if (runStart > mLen) break;
-                final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen);
-                final boolean runIsRtl = mDirections.isRunRtl(runIndex);
+        float h = 0;
+        final int runCount = mDirections.getRunCount();
+        for (int runIndex = 0; runIndex < runCount; runIndex++) {
+            final int runStart = mDirections.getRunStart(runIndex);
+            if (runStart > mLen) break;
+            final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen);
+            final boolean runIsRtl = mDirections.isRunRtl(runIndex);
 
-                final int runFlag = calculateRunFlag(runIndex, runCount, mDir);
+            final int runFlag = calculateRunFlag(runIndex, runCount, mDir);
 
-                int segStart = runStart;
-                for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
-                    if (j == runLimit || charAt(j) == TAB_CHAR) {
-                        h += drawRun(c, segStart, j, runIsRtl, x + h, top, y, bottom,
-                                runIndex != (runCount - 1) || j != mLen, runFlag);
+            int segStart = runStart;
+            for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
+                if (j == runLimit || charAt(j) == TAB_CHAR) {
+                    h += drawRun(c, segStart, j, runIsRtl, x + h, top, y, bottom,
+                            runIndex != (runCount - 1) || j != mLen, runFlag);
 
-                        if (j != runLimit) {  // charAt(j) == TAB_CHAR
-                            h = mDir * nextTab(h * mDir);
-                        }
-                        segStart = j + 1;
+                    if (j != runLimit) {  // charAt(j) == TAB_CHAR
+                        h = mDir * nextTab(h * mDir);
                     }
+                    segStart = j + 1;
                 }
             }
-        } finally {
-            if (TRACE_TEXTLINE) {
-                Trace.endSection();
-            }
         }
     }
 
@@ -576,76 +564,63 @@
      */
     public float measure(@IntRange(from = 0) int offset, boolean trailing,
             @NonNull FontMetricsInt fmi, @Nullable RectF drawBounds, @Nullable LineInfo lineInfo) {
-        if (TRACE_TEXTLINE) {
-            Trace.beginSection("TextLine#measure");
+        if (offset > mLen) {
+            throw new IndexOutOfBoundsException(
+                    "offset(" + offset + ") should be less than line limit(" + mLen + ")");
         }
-        try {
-            if (offset > mLen) {
-                throw new IndexOutOfBoundsException(
-                        "offset(" + offset + ") should be less than line limit(" + mLen + ")");
-            }
-            if (lineInfo != null) {
-                lineInfo.setClusterCount(0);
-            }
-            final int target = trailing ? offset - 1 : offset;
-            if (target < 0) {
-                return 0;
-            }
+        if (lineInfo != null) {
+            lineInfo.setClusterCount(0);
+        }
+        final int target = trailing ? offset - 1 : offset;
+        if (target < 0) {
+            return 0;
+        }
 
-            float h = 0;
-            final int runCount = mDirections.getRunCount();
-            for (int runIndex = 0; runIndex < runCount; runIndex++) {
-                final int runStart = mDirections.getRunStart(runIndex);
-                if (runStart > mLen) break;
-                final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen);
-                final boolean runIsRtl = mDirections.isRunRtl(runIndex);
-                final int runFlag = calculateRunFlag(runIndex, runCount, mDir);
+        float h = 0;
+        final int runCount = mDirections.getRunCount();
+        for (int runIndex = 0; runIndex < runCount; runIndex++) {
+            final int runStart = mDirections.getRunStart(runIndex);
+            if (runStart > mLen) break;
+            final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen);
+            final boolean runIsRtl = mDirections.isRunRtl(runIndex);
+            final int runFlag = calculateRunFlag(runIndex, runCount, mDir);
 
-                int segStart = runStart;
-                for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
-                    if (j == runLimit || charAt(j) == TAB_CHAR) {
-                        final boolean targetIsInThisSegment = target >= segStart && target < j;
-                        final boolean sameDirection =
-                                (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
+            int segStart = runStart;
+            for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
+                if (j == runLimit || charAt(j) == TAB_CHAR) {
+                    final boolean targetIsInThisSegment = target >= segStart && target < j;
+                    final boolean sameDirection = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
 
-                        if (targetIsInThisSegment && sameDirection) {
-                            return h + measureRun(segStart, offset, j, runIsRtl, fmi, drawBounds,
-                                    null,
-                                    0, h, lineInfo, runFlag);
-                        }
-
-                        final float segmentWidth = measureRun(segStart, j, j, runIsRtl, fmi,
-                                drawBounds,
-                                null, 0, h, lineInfo, runFlag);
-                        h += sameDirection ? segmentWidth : -segmentWidth;
-
-                        if (targetIsInThisSegment) {
-                            return h + measureRun(segStart, offset, j, runIsRtl, null, null, null,
-                                    0,
-                                    h, lineInfo, runFlag);
-                        }
-
-                        if (j != runLimit) {  // charAt(j) == TAB_CHAR
-                            if (offset == j) {
-                                return h;
-                            }
-                            h = mDir * nextTab(h * mDir);
-                            if (target == j) {
-                                return h;
-                            }
-                        }
-
-                        segStart = j + 1;
+                    if (targetIsInThisSegment && sameDirection) {
+                        return h + measureRun(segStart, offset, j, runIsRtl, fmi, drawBounds, null,
+                                0, h, lineInfo, runFlag);
                     }
+
+                    final float segmentWidth = measureRun(segStart, j, j, runIsRtl, fmi, drawBounds,
+                            null, 0, h, lineInfo, runFlag);
+                    h += sameDirection ? segmentWidth : -segmentWidth;
+
+                    if (targetIsInThisSegment) {
+                        return h + measureRun(segStart, offset, j, runIsRtl, null, null,  null, 0,
+                                h, lineInfo, runFlag);
+                    }
+
+                    if (j != runLimit) {  // charAt(j) == TAB_CHAR
+                        if (offset == j) {
+                            return h;
+                        }
+                        h = mDir * nextTab(h * mDir);
+                        if (target == j) {
+                            return h;
+                        }
+                    }
+
+                    segStart = j + 1;
                 }
             }
-
-            return h;
-        } finally {
-            if (TRACE_TEXTLINE) {
-                Trace.endSection();
-            }
         }
+
+        return h;
     }
 
     /**