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

Commit 70200b0f authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

Make LineBreaker public

This CL includes:
- Move NativeLineBreaker/NativeMeasuredParagraph to android.graphics.text
package since these two uses the shaping result of the text which is a
part of graphics responsibility. At the same time, by this moving,
minikin is only used by android.graphics package.
- Rename NativeLineBreaker/NativeMeasuredParagraph to
LineBreaker/MeasuredText.
- Updated comments of the break strategy and hyphenation frequency.

Bug: 112327179
Test: atest CtsTextTestCases CtsGraphicsTestCases CtsWidgetTestCases
Change-Id: Id69c328e7c9097b9fc11b5c0bd04d1c2e0939c6a
parent 002f63d0
Loading
Loading
Loading
Loading
+63 −0
Original line number Diff line number Diff line
@@ -15404,6 +15404,69 @@ package android.graphics.pdf {
}
package android.graphics.text {
  public class LineBreaker {
    method public android.graphics.text.LineBreaker.Result computeLineBreaks(android.graphics.text.MeasuredText, android.graphics.text.LineBreaker.ParagraphConstraints, int);
    field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
    field public static final int BREAK_STRATEGY_HIGH_QUALITY = 1; // 0x1
    field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
    field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2
    field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0
    field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1
    field public static final int JUSTIFICATION_MODE_INTER_WORD = 1; // 0x1
    field public static final int JUSTIFICATION_MODE_NONE = 0; // 0x0
  }
  public static class LineBreaker.Builder {
    ctor public LineBreaker.Builder();
    method public android.graphics.text.LineBreaker build();
    method public android.graphics.text.LineBreaker.Builder setBreakStrategy(int);
    method public android.graphics.text.LineBreaker.Builder setHyphenationFrequency(int);
    method public android.graphics.text.LineBreaker.Builder setIndents(int[]);
    method public android.graphics.text.LineBreaker.Builder setJustified(int);
  }
  public static class LineBreaker.ParagraphConstraints {
    ctor public LineBreaker.ParagraphConstraints();
    method public int getDefaultTabStop();
    method public float getFirstWidth();
    method public int getFirstWidthLineCount();
    method public int[] getTabStops();
    method public float getWidth();
    method public void setIndent(float, int);
    method public void setTabStops(int[], int);
    method public void setWidth(float);
  }
  public static class LineBreaker.Result {
    method public float getLineAscent(int);
    method public int getLineBreakOffset(int);
    method public int getLineCount();
    method public float getLineDescent(int);
    method public int getLineHyphenEdit(int);
    method public float getLineWidth(int);
    method public boolean hasLineTab(int);
  }
  public class MeasuredText {
    method public void getBounds(int, int, android.graphics.Rect);
    method public float getCharWidthAt(int);
    method public char[] getChars();
    method public float getWidth(int, int);
  }
  public static class MeasuredText.Builder {
    ctor public MeasuredText.Builder(char[]);
    method public android.graphics.text.MeasuredText.Builder addReplacementRun(android.graphics.Paint, int, int, float);
    method public android.graphics.text.MeasuredText.Builder addStyleRun(android.graphics.Paint, int, int, boolean);
    method public android.graphics.text.MeasuredText build();
    method public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean);
    method public android.graphics.text.MeasuredText.Builder setComputeLayout(boolean);
  }
}
package android.hardware {
  public deprecated class Camera {
+14 −17
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.text.LineBreaker;
import android.text.method.TextKeyListener;
import android.text.style.AlignmentSpan;
import android.text.style.LeadingMarginSpan;
@@ -50,9 +51,9 @@ import java.util.Arrays;
public abstract class Layout {
    /** @hide */
    @IntDef(prefix = { "BREAK_STRATEGY_" }, value = {
            NativeLineBreaker.BREAK_STRATEGY_SIMPLE,
            NativeLineBreaker.BREAK_STRATEGY_HIGH_QUALITY,
            NativeLineBreaker.BREAK_STRATEGY_BALANCED
            LineBreaker.BREAK_STRATEGY_SIMPLE,
            LineBreaker.BREAK_STRATEGY_HIGH_QUALITY,
            LineBreaker.BREAK_STRATEGY_BALANCED
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface BreakStrategy {}
@@ -63,20 +64,19 @@ public abstract class Layout {
     * before it (which yields a more consistent user experience when editing), but layout may not
     * be the highest quality.
     */
    public static final int BREAK_STRATEGY_SIMPLE = NativeLineBreaker.BREAK_STRATEGY_SIMPLE;
    public static final int BREAK_STRATEGY_SIMPLE = LineBreaker.BREAK_STRATEGY_SIMPLE;

    /**
     * Value for break strategy indicating high quality line breaking, including automatic
     * hyphenation and doing whole-paragraph optimization of line breaks.
     */
    public static final int BREAK_STRATEGY_HIGH_QUALITY =
            NativeLineBreaker.BREAK_STRATEGY_HIGH_QUALITY;
    public static final int BREAK_STRATEGY_HIGH_QUALITY = LineBreaker.BREAK_STRATEGY_HIGH_QUALITY;

    /**
     * Value for break strategy indicating balanced line breaking. The breaks are chosen to
     * make all lines as close to the same length as possible, including automatic hyphenation.
     */
    public static final int BREAK_STRATEGY_BALANCED = NativeLineBreaker.BREAK_STRATEGY_BALANCED;
    public static final int BREAK_STRATEGY_BALANCED = LineBreaker.BREAK_STRATEGY_BALANCED;

    /** @hide */
    @IntDef(prefix = { "HYPHENATION_FREQUENCY_" }, value = {
@@ -94,32 +94,29 @@ public abstract class Layout {
     * layout and there is otherwise no valid break. Soft hyphens are ignored and will not be used
     * as suggestions for potential line breaks.
     */
    public static final int HYPHENATION_FREQUENCY_NONE =
            NativeLineBreaker.HYPHENATION_FREQUENCY_NONE;
    public static final int HYPHENATION_FREQUENCY_NONE = LineBreaker.HYPHENATION_FREQUENCY_NONE;

    /**
     * Value for hyphenation frequency indicating a light amount of automatic hyphenation, which
     * is a conservative default. Useful for informal cases, such as short sentences or chat
     * messages.
     */
    public static final int HYPHENATION_FREQUENCY_NORMAL =
            NativeLineBreaker.HYPHENATION_FREQUENCY_NORMAL;
    public static final int HYPHENATION_FREQUENCY_NORMAL = LineBreaker.HYPHENATION_FREQUENCY_NORMAL;

    /**
     * Value for hyphenation frequency indicating the full amount of automatic hyphenation, typical
     * in typography. Useful for running text and where it's important to put the maximum amount of
     * text in a screen with limited space.
     */
    public static final int HYPHENATION_FREQUENCY_FULL =
            NativeLineBreaker.HYPHENATION_FREQUENCY_FULL;
    public static final int HYPHENATION_FREQUENCY_FULL = LineBreaker.HYPHENATION_FREQUENCY_FULL;

    private static final ParagraphStyle[] NO_PARA_SPANS =
        ArrayUtils.emptyArray(ParagraphStyle.class);

    /** @hide */
    @IntDef(prefix = { "JUSTIFICATION_MODE_" }, value = {
            NativeLineBreaker.JUSTIFICATION_MODE_NONE,
            NativeLineBreaker.JUSTIFICATION_MODE_INTER_WORD
            LineBreaker.JUSTIFICATION_MODE_NONE,
            LineBreaker.JUSTIFICATION_MODE_INTER_WORD
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface JustificationMode {}
@@ -127,13 +124,13 @@ public abstract class Layout {
    /**
     * Value for justification mode indicating no justification.
     */
    public static final int JUSTIFICATION_MODE_NONE = NativeLineBreaker.JUSTIFICATION_MODE_NONE;
    public static final int JUSTIFICATION_MODE_NONE = LineBreaker.JUSTIFICATION_MODE_NONE;

    /**
     * Value for justification mode indicating the text is justified by stretching word spacing.
     */
    public static final int JUSTIFICATION_MODE_INTER_WORD =
            NativeLineBreaker.JUSTIFICATION_MODE_INTER_WORD;
            LineBreaker.JUSTIFICATION_MODE_INTER_WORD;

    /*
     * Line spacing multiplier for default line spacing.
+18 −17
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.text.MeasuredText;
import android.text.AutoGrowArray.ByteArray;
import android.text.AutoGrowArray.FloatArray;
import android.text.AutoGrowArray.IntArray;
@@ -121,7 +122,7 @@ public class MeasuredParagraph {
    private @Nullable IntArray mFontMetrics = new IntArray(4 * 4);

    // The native MeasuredParagraph.
    private @Nullable NativeMeasuredParagraph mNativeMeasuredParagraph;
    private @Nullable MeasuredText mMeasuredText;

    // Following two objects are for avoiding object allocation.
    private @NonNull TextPaint mCachedPaint = new TextPaint();
@@ -149,7 +150,7 @@ public class MeasuredParagraph {
        mWidths.clear();
        mFontMetrics.clear();
        mSpanEndCache.clear();
        mNativeMeasuredParagraph = null;
        mMeasuredText = null;
    }

    /**
@@ -245,8 +246,8 @@ public class MeasuredParagraph {
     * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
     * Returns null in other cases.
     */
    public NativeMeasuredParagraph getNativeMeasuredParagraph() {
        return mNativeMeasuredParagraph;
    public MeasuredText getMeasuredText() {
        return mMeasuredText;
    }

    /**
@@ -259,7 +260,7 @@ public class MeasuredParagraph {
     * @param end the exclusive end offset of the target region in the text
     */
    public float getWidth(int start, int end) {
        if (mNativeMeasuredParagraph == null) {
        if (mMeasuredText == null) {
            // We have result in Java.
            final float[] widths = mWidths.getRawArray();
            float r = 0.0f;
@@ -269,7 +270,7 @@ public class MeasuredParagraph {
            return r;
        } else {
            // We have result in native.
            return mNativeMeasuredParagraph.getWidth(start, end);
            return mMeasuredText.getWidth(start, end);
        }
    }

@@ -281,7 +282,7 @@ public class MeasuredParagraph {
     */
    public void getBounds(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
            @NonNull Rect bounds) {
        mNativeMeasuredParagraph.getBounds(mCopiedBuffer, start, end, bounds);
        mMeasuredText.getBounds(start, end, bounds);
    }

    /**
@@ -290,7 +291,7 @@ public class MeasuredParagraph {
     * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
     */
    public float getCharWidthAt(@IntRange(from = 0) int offset) {
        return mNativeMeasuredParagraph.getCharWidthAt(offset);
        return mMeasuredText.getCharWidthAt(offset);
    }

    /**
@@ -391,12 +392,13 @@ public class MeasuredParagraph {
            @Nullable MeasuredParagraph recycle) {
        final MeasuredParagraph mt = recycle == null ? obtain() : recycle;
        mt.resetAndAnalyzeBidi(text, start, end, textDir);
        final NativeMeasuredParagraph.Builder builder = new NativeMeasuredParagraph.Builder();
        final MeasuredText.Builder builder = new MeasuredText.Builder(mt.mCopiedBuffer);
        builder.setComputeHyphenation(computeHyphenation);
        builder.setComputeLayout(computeLayout);
        if (mt.mTextLength == 0) {
            // Need to build empty native measured text for StaticLayout.
            // TODO: Stop creating empty measured text for empty lines.
            mt.mNativeMeasuredParagraph = builder.build(mt.mCopiedBuffer, computeHyphenation,
                        computeLayout);
            mt.mMeasuredText = builder.build();
        } else {
            if (mt.mSpanned == null) {
                // No style change by MetricsAffectingSpan. Just measure all text.
@@ -417,8 +419,7 @@ public class MeasuredParagraph {
                    mt.mSpanEndCache.append(spanEnd);
                }
            }
            mt.mNativeMeasuredParagraph = builder.build(mt.mCopiedBuffer, computeHyphenation,
                    computeLayout);
            mt.mMeasuredText = builder.build();
        }

        return mt;
@@ -490,7 +491,7 @@ public class MeasuredParagraph {
    private void applyReplacementRun(@NonNull ReplacementSpan replacement,
                                     @IntRange(from = 0) int start,  // inclusive, in copied buffer
                                     @IntRange(from = 0) int end,  // exclusive, in copied buffer
                                     @Nullable NativeMeasuredParagraph.Builder builder) {
                                     @Nullable MeasuredText.Builder builder) {
        // Use original text. Shouldn't matter.
        // TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for
        //       backward compatibility? or Should we initialize them for getFontMetricsInt?
@@ -510,7 +511,7 @@ public class MeasuredParagraph {

    private void applyStyleRun(@IntRange(from = 0) int start,  // inclusive, in copied buffer
                               @IntRange(from = 0) int end,  // exclusive, in copied buffer
                               @Nullable NativeMeasuredParagraph.Builder builder) {
                               @Nullable MeasuredText.Builder builder) {

        if (mLtrWithoutBidi) {
            // If the whole text is LTR direction, just apply whole region.
@@ -552,7 +553,7 @@ public class MeasuredParagraph {
            @Nullable MetricAffectingSpan[] spans,
            @IntRange(from = 0) int start,  // inclusive, in original text buffer
            @IntRange(from = 0) int end,  // exclusive, in original text buffer
            @Nullable NativeMeasuredParagraph.Builder builder) {
            @Nullable MeasuredText.Builder builder) {
        mCachedPaint.set(paint);
        // XXX paint should not have a baseline shift, but...
        mCachedPaint.baselineShift = 0;
@@ -658,6 +659,6 @@ public class MeasuredParagraph {
     * This only works if the MeasuredParagraph is computed with buildForStaticLayout.
     */
    public @IntRange(from = 0) int getMemoryUsage() {
        return mNativeMeasuredParagraph.getMemoryUsage();
        return mMeasuredText.getMemoryUsage();
    }
}
+7 −6
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.graphics.Paint;
import android.graphics.text.LineBreaker;
import android.os.Build;
import android.text.style.LeadingMarginSpan;
import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
@@ -55,7 +56,7 @@ public class StaticLayout extends Layout {
     *
     *   - Create MeasuredParagraph by MeasuredParagraph.buildForStaticLayout which measures in
     *     native.
     *   - Run NativeLineBreaker.computeLineBreaks() to obtain line breaks for the paragraph.
     *   - Run LineBreaker.computeLineBreaks() to obtain line breaks for the paragraph.
     *
     * After all paragraphs, call finish() to release expensive buffers.
     */
@@ -634,7 +635,7 @@ public class StaticLayout extends Layout {
            indents = null;
        }

        final NativeLineBreaker lineBreaker = new NativeLineBreaker.Builder()
        final LineBreaker lineBreaker = new LineBreaker.Builder()
                .setBreakStrategy(b.mBreakStrategy)
                .setHyphenationFrequency(b.mHyphenationFrequency)
                // TODO: Support more justification mode, e.g. letter spacing, stretching.
@@ -642,8 +643,8 @@ public class StaticLayout extends Layout {
                .setIndents(indents)
                .build();

        NativeLineBreaker.ParagraphConstraints constraints =
                new NativeLineBreaker.ParagraphConstraints();
        LineBreaker.ParagraphConstraints constraints =
                new LineBreaker.ParagraphConstraints();

        PrecomputedText.ParagraphInfo[] paragraphInfo = null;
        final Spanned spanned = (source instanceof Spanned) ? (Spanned) source : null;
@@ -739,8 +740,8 @@ public class StaticLayout extends Layout {
            constraints.setIndent(firstWidth, firstWidthLineCount);
            constraints.setTabStops(variableTabStops, TAB_INCREMENT);

            NativeLineBreaker.Result res = lineBreaker.computeLineBreaks(
                    measuredPara.getNativeMeasuredParagraph(), constraints, mLineCount);
            LineBreaker.Result res = lineBreaker.computeLineBreaks(
                    measuredPara.getMeasuredText(), constraints, mLineCount);
            int breakCount = res.getLineCount();
            if (lineBreakCapacity < breakCount) {
                lineBreakCapacity = breakCount;
+2 −2
Original line number Diff line number Diff line
@@ -84,8 +84,6 @@ cc_library_shared {
        "android_view_VelocityTracker.cpp",
        "android_text_AndroidCharacter.cpp",
        "android_text_Hyphenator.cpp",
        "android_text_LineBreaker.cpp",
        "android_text_MeasuredParagraph.cpp",
        "android_os_Debug.cpp",
        "android_os_GraphicsEnvironment.cpp",
        "android_os_HidlSupport.cpp",
@@ -161,6 +159,8 @@ cc_library_shared {
        "android/graphics/pdf/PdfEditor.cpp",
        "android/graphics/pdf/PdfRenderer.cpp",
        "android/graphics/pdf/PdfUtils.cpp",
        "android/graphics/text/LineBreaker.cpp",
        "android/graphics/text/MeasuredText.cpp",
        "android_media_AudioRecord.cpp",
        "android_media_AudioSystem.cpp",
        "android_media_AudioTrack.cpp",
Loading