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

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

Merge "Compute full text layout in MeasuredText and use it for drawing"

parents 3741b349 783f961d
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -347,7 +347,14 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
        TextLine line = TextLine.obtain();
        line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT,
                Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null);
        if (text instanceof MeasuredText) {
            MeasuredText mt = (MeasuredText) text;
            // Reaching here means there is only one paragraph.
            MeasuredParagraph mp = mt.getMeasuredParagraph(0);
            fm.width = (int) Math.ceil(mp.getWidth(0, mp.getTextLength()));
        } else {
            fm.width = (int) Math.ceil(line.metrics(fm));
        }
        TextLine.recycle(line);

        return fm;
+50 −10
Original line number Diff line number Diff line
@@ -175,6 +175,15 @@ public class MeasuredParagraph {
        unbindNativeObject();
    }

    /**
     * Returns the length of the paragraph.
     *
     * This is always available.
     */
    public int getTextLength() {
        return mTextLength;
    }

    /**
     * Returns the characters to be measured.
     *
@@ -212,7 +221,7 @@ public class MeasuredParagraph {
    /**
     * Returns the whole text width.
     *
     * This is available only if the MeasureText is computed with computeForMeasurement.
     * This is available only if the MeasuredParagraph is computed with buildForMeasurement.
     * Returns 0 in other cases.
     */
    public @FloatRange(from = 0.0f) float getWholeWidth() {
@@ -222,7 +231,7 @@ public class MeasuredParagraph {
    /**
     * Returns the individual character's width.
     *
     * This is available only if the MeasureText is computed with computeForMeasurement.
     * This is available only if the MeasuredParagraph is computed with buildForMeasurement.
     * Returns empty array in other cases.
     */
    public @NonNull FloatArray getWidths() {
@@ -234,7 +243,7 @@ public class MeasuredParagraph {
     *
     * If the input text is not a spanned string, this has one value that is the length of the text.
     *
     * This is available only if the MeasureText is computed with computeForStaticLayout.
     * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
     * Returns empty array in other cases.
     */
    public @NonNull IntArray getSpanEndCache() {
@@ -246,7 +255,7 @@ public class MeasuredParagraph {
     *
     * This array holds the repeat of top, bottom, ascent, descent of font metrics value.
     *
     * This is available only if the MeasureText is computed with computeForStaticLayout.
     * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
     * Returns empty array in other cases.
     */
    public @NonNull IntArray getFontMetrics() {
@@ -256,13 +265,37 @@ public class MeasuredParagraph {
    /**
     * Returns the native ptr of the MeasuredParagraph.
     *
     * This is available only if the MeasureText is computed with computeForStaticLayout.
     * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
     * Returns 0 in other cases.
     */
    public /* Maybe Zero */ long getNativePtr() {
        return mNativePtr;
    }

    /**
     * Returns the width of the given range.
     *
     * This is not available if the MeasuredParagraph is computed with buildForBidi.
     * Returns 0 if the MeasuredParagraph is computed with buildForBidi.
     *
     * @param start the inclusive start offset of the target region in the text
     * @param end the exclusive end offset of the target region in the text
     */
    public float getWidth(int start, int end) {
        if (mNativePtr == 0) {
            // We have result in Java.
            final float[] widths = mWidths.getRawArray();
            float r = 0.0f;
            for (int i = start; i < end; ++i) {
                r += widths[i];
            }
            return r;
        } else {
            // We have result in native.
            return nGetWidth(mNativePtr, start, end);
        }
    }

    /**
     * Generates new MeasuredParagraph for Bidi computation.
     *
@@ -357,6 +390,7 @@ public class MeasuredParagraph {
            @IntRange(from = 0) int end,
            @NonNull TextDirectionHeuristic textDir,
            boolean computeHyphenation,
            boolean computeLayout,
            @Nullable MeasuredParagraph recycle) {
        final MeasuredParagraph mt = recycle == null ? obtain() : recycle;
        mt.resetAndAnalyzeBidi(text, start, end, textDir);
@@ -367,7 +401,7 @@ public class MeasuredParagraph {
            try {
                mt.bindNativeObject(
                        nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer,
                              computeHyphenation));
                              computeHyphenation, computeLayout));
            } finally {
                nFreeBuilder(nativeBuilderPtr);
            }
@@ -397,7 +431,7 @@ public class MeasuredParagraph {
                }
            }
            mt.bindNativeObject(nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer,
                      computeHyphenation));
                      computeHyphenation, computeLayout));
        } finally {
            nFreeBuilder(nativeBuilderPtr);
        }
@@ -595,7 +629,7 @@ public class MeasuredParagraph {
     *
     * If forward=false is passed, returns the minimum index from the end instead.
     *
     * This only works if the MeasuredParagraph is computed with computeForMeasurement.
     * This only works if the MeasuredParagraph is computed with buildForMeasurement.
     * Undefined behavior in other case.
     */
    @IntRange(from = 0) int breakText(int limit, boolean forwards, float width) {
@@ -626,7 +660,7 @@ public class MeasuredParagraph {
    /**
     * Returns the length of the substring.
     *
     * This only works if the MeasuredParagraph is computed with computeForMeasurement.
     * This only works if the MeasuredParagraph is computed with buildForMeasurement.
     * Undefined behavior in other case.
     */
    @FloatRange(from = 0.0f) float measure(int start, int limit) {
@@ -672,10 +706,16 @@ public class MeasuredParagraph {

    private static native long nBuildNativeMeasuredParagraph(/* Non Zero */ long nativeBuilderPtr,
                                                 @NonNull char[] text,
                                                 boolean computeHyphenation);
                                                 boolean computeHyphenation,
                                                 boolean computeLayout);

    private static native void nFreeBuilder(/* Non Zero */ long nativeBuilderPtr);

    @CriticalNative
    private static native float nGetWidth(/* Non Zero */ long nativePtr,
                                         @IntRange(from = 0) int start,
                                         @IntRange(from = 0) int end);

    @CriticalNative
    private static native /* Non Zero */ long nGetReleaseFunc();
}
+52 −2
Original line number Diff line number Diff line
@@ -155,6 +155,11 @@ public class MeasuredText implements Spanned {
         * @return the measured text.
         */
        public @NonNull MeasuredText build() {
            return build(true /* build full layout result */);
        }

        /** @hide */
        public @NonNull MeasuredText build(boolean computeLayout) {
            final boolean needHyphenation = mBreakStrategy != Layout.BREAK_STRATEGY_SIMPLE
                    && mHyphenationFrequency != Layout.HYPHENATION_FREQUENCY_NONE;

@@ -175,7 +180,7 @@ public class MeasuredText implements Spanned {
                paragraphEnds.add(paraEnd);
                measuredTexts.add(MeasuredParagraph.buildForStaticLayout(
                        mPaint, mText, paraStart, paraEnd, mTextDir, needHyphenation,
                        null /* no recycle */));
                        computeLayout, null /* no recycle */));
            }

            return new MeasuredText(mText, mStart, mEnd, mPaint, mTextDir, mBreakStrategy,
@@ -198,7 +203,8 @@ public class MeasuredText implements Spanned {
        mText = text;
        mStart = start;
        mEnd = end;
        mPaint = paint;
        // Copy the paint so that we can keep the reference of typeface in native layout result.
        mPaint = new TextPaint(paint);
        mMeasuredParagraphs = measuredTexts;
        mParagraphBreakPoints = paragraphBreakPoints;
        mTextDir = textDir;
@@ -283,6 +289,50 @@ public class MeasuredText implements Spanned {
        return mHyphenationFrequency;
    }

    /**
     * Returns true if the given TextPaint gives the same result of text layout for this text.
     * @hide
     */
    public boolean canUseMeasuredResult(@NonNull TextPaint paint) {
        return mPaint.getTextSize() == paint.getTextSize()
            && mPaint.getTextSkewX() == paint.getTextSkewX()
            && mPaint.getTextScaleX() == paint.getTextScaleX()
            && mPaint.getLetterSpacing() == paint.getLetterSpacing()
            && mPaint.getWordSpacing() == paint.getWordSpacing()
            && mPaint.getFlags() == paint.getFlags()  // Maybe not all flag affects text layout.
            && mPaint.getTextLocales() == paint.getTextLocales()  // need to be equals?
            && mPaint.getFontVariationSettings() == paint.getFontVariationSettings()
            && mPaint.getTypeface() == paint.getTypeface()
            && TextUtils.equals(mPaint.getFontFeatureSettings(), paint.getFontFeatureSettings());
    }

    /** @hide */
    public int findParaIndex(@IntRange(from = 0) int pos) {
        // TODO: Maybe good to remove paragraph concept from MeasuredText and add substring layout
        //       support to StaticLayout.
        for (int i = 0; i < mParagraphBreakPoints.length; ++i) {
            if (pos < mParagraphBreakPoints[i]) {
                return i;
            }
        }
        throw new IndexOutOfBoundsException(
            "pos must be less than " + mParagraphBreakPoints[mParagraphBreakPoints.length - 1]
            + ", gave " + pos);
    }

    /** @hide */
    public float getWidth(@IntRange(from = 0) int start, @IntRange(from = 0) int end) {
        final int paraIndex = findParaIndex(start);
        final int paraStart = getParagraphStart(paraIndex);
        final int paraEnd = getParagraphEnd(paraIndex);
        if (start < paraStart || paraEnd < end) {
            throw new RuntimeException("Cannot measured across the paragraph:"
                + "para: (" + paraStart + ", " + paraEnd + "), "
                + "request: (" + start + ", " + end + ")");
        }
        return getMeasuredParagraph(paraIndex).getWidth(start - paraStart, end - paraStart);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Spanned overrides
    //
+1 −1
Original line number Diff line number Diff line
@@ -678,7 +678,7 @@ public class StaticLayout extends Layout {
                    .setTextDirection(textDir)
                    .setBreakStrategy(b.mBreakStrategy)
                    .setHyphenationFrequency(b.mHyphenationFrequency)
                    .build();
                    .build(false /* full layout is not necessary for line breaking */);
            spanned = (source instanceof Spanned) ? (Spanned) source : null;
        } else {
            final CharSequence original = measured.getText();
+17 −2
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ public class TextLine {
    private char[] mChars;
    private boolean mCharsValid;
    private Spanned mSpanned;
    private MeasuredText mMeasured;

    // Additional width of whitespace for justification. This value is per whitespace, thus
    // the line width will increase by mAddedWidth x (number of stretchable whitespaces).
@@ -118,6 +119,7 @@ public class TextLine {
        tl.mSpanned = null;
        tl.mTabs = null;
        tl.mChars = null;
        tl.mMeasured = null;

        tl.mMetricAffectingSpanSpanSet.recycle();
        tl.mCharacterStyleSpanSet.recycle();
@@ -168,6 +170,14 @@ public class TextLine {
            hasReplacement = mReplacementSpanSpanSet.numberOfSpans > 0;
        }

        mMeasured = null;
        if (text instanceof MeasuredText) {
            MeasuredText mt = (MeasuredText) text;
            if (mt.canUseMeasuredResult(paint)) {
                mMeasured = mt;
            }
        }

        mCharsValid = hasReplacement || hasTabs || directions != Layout.DIRS_ALL_LEFT_TO_RIGHT;

        if (mCharsValid) {
@@ -736,8 +746,13 @@ public class TextLine {
            return wp.getRunAdvance(mChars, start, end, contextStart, contextEnd, runIsRtl, offset);
        } else {
            final int delta = mStart;
            if (mMeasured == null) {
                // TODO: Enable measured getRunAdvance for ReplacementSpan and RTL text.
                return wp.getRunAdvance(mText, delta + start, delta + end,
                        delta + contextStart, delta + contextEnd, runIsRtl, delta + offset);
            } else {
                return mMeasured.getWidth(start + delta, end + delta);
            }
        }
    }

Loading