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

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

Merge "Reorganize JNI in StaticLayout"

parents 0e0621a4 b90e08f9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1910,7 +1910,7 @@ public abstract class Layout {
        MeasuredText mt = MeasuredText.obtain();
        TextLine tl = TextLine.obtain();
        try {
            mt.setPara(text, start, end, textDir, null);
            mt.setPara(text, start, end, textDir);
            Directions directions;
            int dir;
            if (mt.mEasy) {
+24 −19
Original line number Diff line number Diff line
@@ -39,7 +39,6 @@ class MeasuredText {

    private int mPos;
    private TextPaint mWorkPaint;
    private StaticLayout.Builder mBuilder;

    private MeasuredText() {
        mWorkPaint = new TextPaint();
@@ -82,7 +81,6 @@ class MeasuredText {

    void finish() {
        mText = null;
        mBuilder = null;
        if (mLen > 1000) {
            mWidths = null;
            mChars = null;
@@ -93,9 +91,7 @@ class MeasuredText {
    /**
     * Analyzes text for bidirectional runs.  Allocates working buffers.
     */
    void setPara(CharSequence text, int start, int end, TextDirectionHeuristic textDir,
            StaticLayout.Builder builder) {
        mBuilder = builder;
    void setPara(CharSequence text, int start, int end, TextDirectionHeuristic textDir) {
        mText = text;
        mTextStart = start;

@@ -159,12 +155,12 @@ class MeasuredText {
    /**
     * Apply the style.
     *
     * If StaticLyaout.Builder is not provided in setPara() method, this method measures the styled
     * text width.
     * If StaticLayout.Builder is provided in setPara() method, this method just passes the style
     * information to native code by calling StaticLayout.Builder.addstyleRun() and returns 0.
     * If nativeStaticLayoutPtr is 0, this method measures the styled text width.
     * If nativeStaticLayoutPtr is not 0, this method just passes the style information to native
     * code by calling StaticLayout.addstyleRun() and returns 0.
     */
    float addStyleRun(TextPaint paint, int len, Paint.FontMetricsInt fm) {
    float addStyleRun(TextPaint paint, int len, Paint.FontMetricsInt fm,
            long nativeStaticLayoutPtr) {
        if (fm != null) {
            paint.getFontMetricsInt(fm);
        }
@@ -174,10 +170,10 @@ class MeasuredText {

        if (mEasy) {
            final boolean isRtl = mDir != Layout.DIR_LEFT_TO_RIGHT;
            if (mBuilder == null) {
            if (nativeStaticLayoutPtr == 0) {
                return paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, mWidths, p);
            } else {
                mBuilder.addStyleRun(paint, p, p + len, isRtl);
                StaticLayout.addStyleRun(nativeStaticLayoutPtr, paint, p, p + len, isRtl);
                return 0.0f;  // Builder.addStyleRun doesn't return the width.
            }
        }
@@ -187,12 +183,12 @@ class MeasuredText {
        for (int q = p, i = p + 1, e = p + len;; ++i) {
            if (i == e || mLevels[i] != level) {
                final boolean isRtl = (level & 0x1) != 0;
                if (mBuilder == null) {
                if (nativeStaticLayoutPtr == 0) {
                    totalAdvance +=
                            paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, mWidths, q);
                } else {
                    // Builder.addStyleRun doesn't return the width.
                    mBuilder.addStyleRun(paint, q, i, isRtl);
                    StaticLayout.addStyleRun(nativeStaticLayoutPtr, paint, q, i, isRtl);
                }
                if (i == e) {
                    break;
@@ -201,11 +197,15 @@ class MeasuredText {
                level = mLevels[i];
            }
        }
        return totalAdvance;  // If mBuilder is null, the result is zero.
        return totalAdvance;  // If nativeStaticLayoutPtr is 0, the result is zero.
    }

    float addStyleRun(TextPaint paint, int len, Paint.FontMetricsInt fm) {
        return addStyleRun(paint, len, fm, 0 /* native ptr */);
    }

    float addStyleRun(TextPaint paint, MetricAffectingSpan[] spans, int len,
            Paint.FontMetricsInt fm) {
            Paint.FontMetricsInt fm, long nativeStaticLayoutPtr) {

        TextPaint workPaint = mWorkPaint;
        workPaint.set(paint);
@@ -224,18 +224,18 @@ class MeasuredText {

        float wid;
        if (replacement == null) {
            wid = addStyleRun(workPaint, len, fm);
            wid = addStyleRun(workPaint, len, fm, nativeStaticLayoutPtr);
        } else {
            // Use original text.  Shouldn't matter.
            wid = replacement.getSize(workPaint, mText, mTextStart + mPos,
                    mTextStart + mPos + len, fm);
            if (mBuilder == null) {
            if (nativeStaticLayoutPtr == 0) {
                float[] w = mWidths;
                w[mPos] = wid;
                for (int i = mPos + 1, e = mPos + len; i < e; i++)
                    w[i] = 0;
            } else {
                mBuilder.addReplacementRun(paint, mPos, mPos + len, wid);
                StaticLayout.addReplacementRun(nativeStaticLayoutPtr, paint, mPos, mPos + len, wid);
            }
            mPos += len;
        }
@@ -253,6 +253,11 @@ class MeasuredText {
        return wid;
    }

    float addStyleRun(TextPaint paint, MetricAffectingSpan[] spans, int len,
            Paint.FontMetricsInt fm) {
        return addStyleRun(paint, spans, len, fm, 0 /* native ptr */);
    }

    int breakText(int limit, boolean forwards, float width) {
        float[] w = mWidths;
        if (forwards) {
+321 −292
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@ import android.util.Pools.SynchronizedPool;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;

import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;

import java.util.Arrays;

/**
@@ -57,9 +60,7 @@ public class StaticLayout extends Layout {
     * default values.
     */
    public final static class Builder {
        private Builder() {
            mNativePtr = nNewBuilder();
        }
        private Builder() {}

        /**
         * Obtain a builder for constructing StaticLayout objects.
@@ -116,13 +117,11 @@ public class StaticLayout extends Layout {
            b.mRightIndents = null;
            b.mLeftPaddings = null;
            b.mRightPaddings = null;
            nFinishBuilder(b.mNativePtr);
            sPool.release(b);
        }

        // release any expensive state
        /* package */ void finish() {
            nFinishBuilder(mNativePtr);
            mText = null;
            mPaint = null;
            mLeftIndents = null;
@@ -404,32 +403,6 @@ public class StaticLayout extends Layout {
            return this;
        }

        /**
         * Measurement and break iteration is done in native code. The protocol for using
         * the native code is as follows.
         *
         * For each paragraph, do a nSetupParagraph, which sets paragraph text, line width, tab
         * stops, break strategy, and hyphenation frequency (and possibly other parameters in the
         * future).
         *
         * Then, for each run within the paragraph:
         *  - one of the following, depending on the type of run:
         *    + addStyleRun (a text run, to be measured in native code)
         *    + addReplacementRun (a replacement run, width is given)
         *
         * Run nComputeLineBreaks() to obtain line breaks for the paragraph.
         *
         * After all paragraphs, call finish() to release expensive buffers.
         */

        /* package */ void addStyleRun(TextPaint paint, int start, int end, boolean isRtl) {
            nAddStyleRun(mNativePtr, paint.getNativeInstance(), start, end, isRtl);
        }

        /* package */ void addReplacementRun(TextPaint paint, int start, int end, float width) {
            nAddReplacementRun(mNativePtr, paint.getNativeInstance(), start, end, width);
        }

        /**
         * Build the {@link StaticLayout} after options have been set.
         *
@@ -446,17 +419,6 @@ public class StaticLayout extends Layout {
            return result;
        }

        @Override
        protected void finalize() throws Throwable {
            try {
                nFreeBuilder(mNativePtr);
            } finally {
                super.finalize();
            }
        }

        /* package */ long mNativePtr;

        private CharSequence mText;
        private int mStart;
        private int mEnd;
@@ -694,13 +656,21 @@ public class StaticLayout extends Layout {
            indents = null;
        }

        final long nativePtr = nInit(
                b.mBreakStrategy, b.mHyphenationFrequency,
                // TODO: Support more justification mode, e.g. letter spacing, stretching.
                b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE,
                indents, mLeftPaddings, mRightPaddings);

        try {
            int paraEnd;
            for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) {
                paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd);
            if (paraEnd < 0)
                if (paraEnd < 0) {
                    paraEnd = bufEnd;
            else
                } else {
                    paraEnd++;
                }

                int firstWidthLineCount = 1;
                int firstWidth = outerWidth;
@@ -730,8 +700,7 @@ public class StaticLayout extends Layout {
                    if (chooseHt.length == 0) {
                        chooseHt = null; // So that out() would not assume it has any contents
                    } else {
                    if (chooseHtv == null ||
                        chooseHtv.length < chooseHt.length) {
                        if (chooseHtv == null || chooseHtv.length < chooseHt.length) {
                            chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
                        }

@@ -752,7 +721,7 @@ public class StaticLayout extends Layout {
                    }
                }

            measured.setPara(source, paraStart, paraEnd, textDir, b);
                measured.setPara(source, paraStart, paraEnd, textDir);
                char[] chs = measured.mChars;
                float[] widths = measured.mWidths;
                byte[] chdirs = measured.mLevels;
@@ -774,15 +743,6 @@ public class StaticLayout extends Layout {
                    }
                }

            nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
                    firstWidth, firstWidthLineCount, restWidth,
                    variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency,
                    // TODO: Support more justification mode, e.g. letter spacing, stretching.
                    b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE,
                    // TODO: indents and paddings don't need to get passed to native code for every
                    // paragraph. Pass them to native code just once.
                    indents, mLeftPaddings, mRightPaddings, mLineCount);

                // measurement has to be done before performing line breaking
                // but we don't want to recompute fontmetrics or span ranges the
                // second time, so we cache those and then use those stored values
@@ -804,19 +764,20 @@ public class StaticLayout extends Layout {
                    if (spanned == null) {
                        spanEnd = paraEnd;
                        int spanLen = spanEnd - spanStart;
                    measured.addStyleRun(paint, spanLen, fm);
                        measured.addStyleRun(paint, spanLen, fm, nativePtr);
                    } else {
                        spanEnd = spanned.nextSpanTransition(spanStart, paraEnd,
                                MetricAffectingSpan.class);
                        int spanLen = spanEnd - spanStart;
                        MetricAffectingSpan[] spans =
                                spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
                    spans = TextUtils.removeEmptySpans(spans, spanned, MetricAffectingSpan.class);
                    measured.addStyleRun(paint, spans, spanLen, fm);
                        spans = TextUtils.removeEmptySpans(spans, spanned,
                                MetricAffectingSpan.class);
                        measured.addStyleRun(paint, spans, spanLen, fm, nativePtr);
                    }

                // the order of storage here (top, bottom, ascent, descent) has to match the code below
                // where these values are retrieved
                    // the order of storage here (top, bottom, ascent, descent) has to match the
                    // code below where these values are retrieved
                    fmCache[fmCacheCount * 4 + 0] = fm.top;
                    fmCache[fmCacheCount * 4 + 1] = fm.bottom;
                    fmCache[fmCacheCount * 4 + 2] = fm.ascent;
@@ -827,9 +788,28 @@ public class StaticLayout extends Layout {
                    spanEndCacheCount++;
                }

            int breakCount = nComputeLineBreaks(b.mNativePtr, lineBreaks, lineBreaks.breaks,
                    lineBreaks.widths, lineBreaks.ascents, lineBreaks.descents, lineBreaks.flags,
                    lineBreaks.breaks.length, widths);
                int breakCount = nComputeLineBreaks(
                        nativePtr,

                        // Inputs
                        chs,
                        paraEnd - paraStart,
                        firstWidth,
                        firstWidthLineCount,
                        restWidth,
                        variableTabStops,
                        TAB_INCREMENT,
                        mLineCount,

                        // Outputs
                        lineBreaks,
                        lineBreaks.breaks.length,
                        lineBreaks.breaks,
                        lineBreaks.widths,
                        lineBreaks.ascents,
                        lineBreaks.descents,
                        lineBreaks.flags,
                        widths);

                final int[] breaks = lineBreaks.breaks;
                final float[] lineWidths = lineBreaks.widths;
@@ -865,7 +845,8 @@ public class StaticLayout extends Layout {
                    breakCount = remainingLineCount;
                }

            // here is the offset of the starting character of the line we are currently measuring
                // here is the offset of the starting character of the line we are currently
                // measuring
                int here = paraStart;

                int fmTop = 0, fmBottom = 0, fmAscent = 0, fmDescent = 0;
@@ -914,10 +895,11 @@ public class StaticLayout extends Layout {
                                : fmDescent;
                        v = out(source, here, endPos,
                                ascent, descent, fmTop, fmBottom,
                            v, spacingmult, spacingadd, chooseHt, chooseHtv, fm, flags[breakIndex],
                            needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad,
                            addLastLineSpacing, chs, widths, paraStart, ellipsize,
                            ellipsizedWidth, lineWidths[breakIndex], paint, moreChars);
                                v, spacingmult, spacingadd, chooseHt, chooseHtv, fm,
                                flags[breakIndex], needMultiply, chdirs, dir, easy, bufEnd,
                                includepad, trackpad, addLastLineSpacing, chs, widths, paraStart,
                                ellipsize, ellipsizedWidth, lineWidths[breakIndex], paint,
                                moreChars);

                        if (endPos < spanEnd) {
                            // preserve metrics for current span
@@ -938,13 +920,14 @@ public class StaticLayout extends Layout {
                    }
                }

            if (paraEnd == bufEnd)
                if (paraEnd == bufEnd) {
                    break;
                }
            }

        if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) &&
                mLineCount < mMaximumVisibleLineCount) {
            measured.setPara(source, bufEnd, bufEnd, textDir, b);
            if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE)
                    && mLineCount < mMaximumVisibleLineCount) {
                measured.setPara(source, bufEnd, bufEnd, textDir);

                paint.getFontMetricsInt(fm);

@@ -959,6 +942,9 @@ public class StaticLayout extends Layout {
                        null, bufStart, ellipsize,
                        ellipsizedWidth, 0, paint, false);
            }
        } finally {
            nFinish(nativePtr);
        }
    }

    // The parameters that are not changed in the method are marked as final to make the code
@@ -1487,26 +1473,51 @@ public class StaticLayout extends Layout {
                mMaxLineHeight : super.getHeight();
    }

    private static native long nNewBuilder();
    private static native void nFreeBuilder(long nativePtr);
    private static native void nFinishBuilder(long nativePtr);
    /**
     * Measurement and break iteration is done in native code. The protocol for using
     * the native code is as follows.
     *
     * First, call nInit to setup native line breaker object. Then, for each paragraph, do the
     * following:
     *
     *   - Call one of the following methods for each run within the paragraph depending on the type
     *     of run:
     *     + addStyleRun (a text run, to be measured in native code)
     *     + addReplacementRun (a replacement run, width is given)
     *
     *   - Run nComputeLineBreaks() to obtain line breaks for the paragraph.
     *
     * After all paragraphs, call finish() to release expensive buffers.
     */

    /* package */ static void addStyleRun(long nativePtr, TextPaint paint, int start, int end,
            boolean isRtl) {
        nAddStyleRun(nativePtr, paint.getNativeInstance(), start, end, isRtl);
    }

    /* package */ static void addReplacementRun(long nativePtr, TextPaint paint, int start, int end,
            float width) {
        nAddReplacementRun(nativePtr, paint.getNativeInstance(), start, end, width);
    }

    @FastNative
    private static native long nInit(
            @BreakStrategy int breakStrategy,
            @HyphenationFrequency int hyphenationFrequency,
            boolean isJustified,
            @Nullable int[] indents,
            @Nullable int[] leftPaddings,
            @Nullable int[] rightPaddings);

    // Set up paragraph text and settings; done as one big method to minimize jni crossings
    private static native void nSetupParagraph(
            /* non zero */ long nativePtr, @NonNull char[] text, @IntRange(from = 0) int length,
            @FloatRange(from = 0.0f) float firstWidth, @IntRange(from = 0) int firstWidthLineCount,
            @FloatRange(from = 0.0f) float restWidth, @Nullable int[] variableTabStops,
            int defaultTabStop, @BreakStrategy int breakStrategy,
            @HyphenationFrequency int hyphenationFrequency, boolean isJustified,
            @Nullable int[] indents, @Nullable int[] leftPaddings, @Nullable int[] rightPaddings,
            @IntRange(from = 0) int indentsOffset);
    @CriticalNative
    private static native void nFinish(long nativePtr);

    // TODO: Make this method CriticalNative once native code defers doing layouts.
    @CriticalNative
    private static native void nAddStyleRun(
            /* non-zero */ long nativePtr, /* non-zero */ long nativePaint,
            @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean isRtl);

    // TODO: Make this method CriticalNative once native code defers doing layouts.
    @CriticalNative
    private static native void nAddReplacementRun(
            /* non-zero */ long nativePtr, /* non-zero */ long nativePaint,
            @IntRange(from = 0) int start, @IntRange(from = 0) int end,
@@ -1519,10 +1530,28 @@ public class StaticLayout extends Layout {
    // arrays do not have to be resized
    // The individual character widths will be returned in charWidths. The length of charWidths must
    // be at least the length of the text.
    private static native int nComputeLineBreaks(long nativePtr, LineBreaks recycle,
            int[] recycleBreaks, float[] recycleWidths, float[] recycleAscents,
            float[] recycleDescents, int[] recycleFlags, int recycleLength,
            float[] charWidths);
    private static native int nComputeLineBreaks(
            /* non zero */ long nativePtr,

            // Inputs
            @NonNull char[] text,
            @IntRange(from = 0) int length,
            @FloatRange(from = 0.0f) float firstWidth,
            @IntRange(from = 0) int firstWidthLineCount,
            @FloatRange(from = 0.0f) float restWidth,
            @Nullable int[] variableTabStops,
            int defaultTabStop,
            @IntRange(from = 0) int indentsOffset,

            // Outputs
            @NonNull LineBreaks recycle,
            @IntRange(from  = 0) int recycleLength,
            @NonNull int[] recycleBreaks,
            @NonNull float[] recycleWidths,
            @NonNull float[] recycleAscents,
            @NonNull float[] recycleDescents,
            @NonNull int[] recycleFlags,
            @NonNull float[] charWidths);

    private int mLineCount;
    private int mTopPadding, mBottomPadding;
+2 −2
Original line number Diff line number Diff line
@@ -1519,7 +1519,7 @@ public class TextUtils {
                    }

                    // XXX this is probably ok, but need to look at it more
                    tempMt.setPara(format, 0, format.length(), textDir, null);
                    tempMt.setPara(format, 0, format.length(), textDir);
                    float moreWid = tempMt.addStyleRun(p, tempMt.mLen, null);

                    if (w + moreWid <= avail) {
@@ -1541,7 +1541,7 @@ public class TextUtils {
    private static float setPara(MeasuredText mt, TextPaint paint,
            CharSequence text, int start, int end, TextDirectionHeuristic textDir) {

        mt.setPara(text, start, end, textDir, null);
        mt.setPara(text, start, end, textDir);

        float width;
        Spanned sp = text instanceof Spanned ? (Spanned) text : null;
+225 −69

File changed.

Preview size limit exceeded, changes collapsed.