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

Commit 0f761404 authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

Implement fast hyphenation algorithm

RandomText Balanced Hyphenation ON
	min: 2,312,291
	mean: 2,320,574
	median: 2,320,112

RandomText Balanced Hyphenation ON(Fast)
	min: 985,850
	mean: 990,922
	median: 986,586

RandomText Balanced Hyphenation OFF
	min: 909,060
	median: 923,585
	mean: 930,052

Bug: 201096525
Test: TreeHugger and minikin_tests
Change-Id: Ide2d73acb3de85e91018e524c89df2c949235a4e
parent ac6c0e9c
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -137,6 +137,21 @@ public class StaticLayoutPerfTest {
        }
    }

    @Test
    public void testCreate_RandomText_NoStyled_Balanced_Hyphenation_Fast() {
        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            state.pauseTiming();
            final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
            state.resumeTiming();

            StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
                    .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL_FAST)
                    .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
                    .build();
        }
    }

    @Test
    public void testCreate_RandomText_Styled_Greedy_NoHyphenation() {
        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+7 −1
Original line number Diff line number Diff line
@@ -17264,8 +17264,12 @@ package android.graphics.text {
    method @NonNull public android.graphics.text.MeasuredText.Builder appendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) @Px float);
    method @NonNull public android.graphics.text.MeasuredText.Builder appendStyleRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, boolean);
    method @NonNull public android.graphics.text.MeasuredText build();
    method @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean);
    method @Deprecated @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean);
    method @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(int);
    method @NonNull public android.graphics.text.MeasuredText.Builder setComputeLayout(boolean);
    field public static final int HYPHENATION_MODE_FAST = 2; // 0x2
    field public static final int HYPHENATION_MODE_NONE = 0; // 0x0
    field public static final int HYPHENATION_MODE_NORMAL = 1; // 0x1
  }
  public final class PositionedGlyphs {
@@ -44451,8 +44455,10 @@ package android.text {
    field public static final int DIR_LEFT_TO_RIGHT = 1; // 0x1
    field public static final int DIR_RIGHT_TO_LEFT = -1; // 0xffffffff
    field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2
    field public static final int HYPHENATION_FREQUENCY_FULL_FAST = 4; // 0x4
    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 HYPHENATION_FREQUENCY_NORMAL_FAST = 3; // 0x3
    field public static final int JUSTIFICATION_MODE_INTER_WORD = 1; // 0x1
    field public static final int JUSTIFICATION_MODE_NONE = 0; // 0x0
  }
+24 −3
Original line number Diff line number Diff line
@@ -82,7 +82,9 @@ public abstract class Layout {
    /** @hide */
    @IntDef(prefix = { "HYPHENATION_FREQUENCY_" }, value = {
            HYPHENATION_FREQUENCY_NORMAL,
            HYPHENATION_FREQUENCY_NORMAL_FAST,
            HYPHENATION_FREQUENCY_FULL,
            HYPHENATION_FREQUENCY_FULL_FAST,
            HYPHENATION_FREQUENCY_NONE
    })
    @Retention(RetentionPolicy.SOURCE)
@@ -95,21 +97,40 @@ 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 = LineBreaker.HYPHENATION_FREQUENCY_NONE;
    public static final int HYPHENATION_FREQUENCY_NONE = 0;

    /**
     * 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 = LineBreaker.HYPHENATION_FREQUENCY_NORMAL;
    public static final int HYPHENATION_FREQUENCY_NORMAL = 1;

    /**
     * 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 = LineBreaker.HYPHENATION_FREQUENCY_FULL;
    public static final int HYPHENATION_FREQUENCY_FULL = 2;

    /**
     * Value for hyphenation frequency indicating a light amount of automatic hyphenation with
     * using faster algorithm.
     *
     * This option is useful for informal cases, such as short sentences or chat messages. To make
     * text rendering faster with hyphenation, this algorithm ignores some hyphen character related
     * typographic features, e.g. kerning.
     */
    public static final int HYPHENATION_FREQUENCY_NORMAL_FAST = 3;
    /**
     * Value for hyphenation frequency indicating the full amount of automatic hyphenation with
     * using faster algorithm.
     *
     * This option is useful for running text and where it's important to put the maximum amount of
     * text in a screen with limited space. To make text rendering faster with hyphenation, this
     * algorithm ignores some hyphen character related typographic features, e.g. kerning.
     */
    public static final int HYPHENATION_FREQUENCY_FULL_FAST = 4;

    private static final ParagraphStyle[] NO_PARA_SPANS =
        ArrayUtils.emptyArray(ParagraphStyle.class);
+3 −3
Original line number Diff line number Diff line
@@ -377,7 +377,7 @@ public class MeasuredParagraph {
     * @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
     * @param textDir the text direction
     * @param computeHyphenation true if need to compute hyphenation, otherwise false
     * @param hyphenationMode a hyphenation mode
     * @param computeLayout true if need to compute full layout, otherwise false.
     * @param hint pass if you already have measured paragraph.
     * @param recycle pass existing MeasuredParagraph if you want to recycle it.
@@ -390,7 +390,7 @@ public class MeasuredParagraph {
            @IntRange(from = 0) int start,
            @IntRange(from = 0) int end,
            @NonNull TextDirectionHeuristic textDir,
            boolean computeHyphenation,
            int hyphenationMode,
            boolean computeLayout,
            @Nullable MeasuredParagraph hint,
            @Nullable MeasuredParagraph recycle) {
@@ -399,7 +399,7 @@ public class MeasuredParagraph {
        final MeasuredText.Builder builder;
        if (hint == null) {
            builder = new MeasuredText.Builder(mt.mCopiedBuffer)
                    .setComputeHyphenation(computeHyphenation)
                    .setComputeHyphenation(hyphenationMode)
                    .setComputeLayout(computeLayout);
        } else {
            builder = new MeasuredText.Builder(hint.mMeasuredText);
+24 −3
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.graphics.text.MeasuredText;
import android.text.style.MetricAffectingSpan;

import com.android.internal.util.Preconditions;
@@ -395,17 +396,30 @@ public class PrecomputedText implements Spannable {
        return new PrecomputedText(text, 0, text.length(), params, paraInfo);
    }

    private static boolean isFastHyphenation(int frequency) {
        return frequency == Layout.HYPHENATION_FREQUENCY_FULL_FAST
                || frequency == Layout.HYPHENATION_FREQUENCY_NORMAL_FAST;
    }

    private static ParagraphInfo[] createMeasuredParagraphsFromPrecomputedText(
            @NonNull PrecomputedText pct, @NonNull Params params, boolean computeLayout) {
        final boolean needHyphenation = params.getBreakStrategy() != Layout.BREAK_STRATEGY_SIMPLE
                && params.getHyphenationFrequency() != Layout.HYPHENATION_FREQUENCY_NONE;
        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;
        }
        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(), pct, paraStart, paraEnd, params.getTextDirection(),
                    needHyphenation, computeLayout, pct.getMeasuredParagraph(i),
                    hyphenationMode, computeLayout, pct.getMeasuredParagraph(i),
                    null /* no recycle */)));
        }
        return result.toArray(new ParagraphInfo[result.size()]);
@@ -421,6 +435,14 @@ public class PrecomputedText implements Spannable {
        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;
        }

        int paraEnd = 0;
        for (int paraStart = start; paraStart < end; paraStart = paraEnd) {
@@ -435,8 +457,7 @@ public class PrecomputedText implements Spannable {

            result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
                    params.getTextPaint(), text, paraStart, paraEnd, params.getTextDirection(),
                    needHyphenation, computeLayout, null /* no hint */,
                    null /* no recycle */)));
                    hyphenationMode, computeLayout, null /* no hint */, null /* no recycle */)));
        }
        return result.toArray(new ParagraphInfo[result.size()]);
    }
Loading