Loading core/java/android/text/Layout.java +18 −13 Original line number Diff line number Diff line Loading @@ -50,9 +50,9 @@ import java.util.Arrays; public abstract class Layout { /** @hide */ @IntDef(prefix = { "BREAK_STRATEGY_" }, value = { BREAK_STRATEGY_SIMPLE, BREAK_STRATEGY_HIGH_QUALITY, BREAK_STRATEGY_BALANCED NativeLineBreaker.BREAK_STRATEGY_SIMPLE, NativeLineBreaker.BREAK_STRATEGY_HIGH_QUALITY, NativeLineBreaker.BREAK_STRATEGY_BALANCED }) @Retention(RetentionPolicy.SOURCE) public @interface BreakStrategy {} Loading @@ -63,19 +63,20 @@ 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 = 0; public static final int BREAK_STRATEGY_SIMPLE = NativeLineBreaker.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 = 1; public static final int BREAK_STRATEGY_HIGH_QUALITY = NativeLineBreaker.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 = 2; public static final int BREAK_STRATEGY_BALANCED = NativeLineBreaker.BREAK_STRATEGY_BALANCED; /** @hide */ @IntDef(prefix = { "HYPHENATION_FREQUENCY_" }, value = { Loading @@ -93,29 +94,32 @@ 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 = 0; public static final int HYPHENATION_FREQUENCY_NONE = NativeLineBreaker.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 = 1; public static final int HYPHENATION_FREQUENCY_NORMAL = NativeLineBreaker.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 = 2; public static final int HYPHENATION_FREQUENCY_FULL = NativeLineBreaker.HYPHENATION_FREQUENCY_FULL; private static final ParagraphStyle[] NO_PARA_SPANS = ArrayUtils.emptyArray(ParagraphStyle.class); /** @hide */ @IntDef(prefix = { "JUSTIFICATION_MODE_" }, value = { JUSTIFICATION_MODE_NONE, JUSTIFICATION_MODE_INTER_WORD NativeLineBreaker.JUSTIFICATION_MODE_NONE, NativeLineBreaker.JUSTIFICATION_MODE_INTER_WORD }) @Retention(RetentionPolicy.SOURCE) public @interface JustificationMode {} Loading @@ -123,12 +127,13 @@ public abstract class Layout { /** * Value for justification mode indicating no justification. */ public static final int JUSTIFICATION_MODE_NONE = 0; public static final int JUSTIFICATION_MODE_NONE = NativeLineBreaker.JUSTIFICATION_MODE_NONE; /** * Value for justification mode indicating the text is justified by stretching word spacing. */ public static final int JUSTIFICATION_MODE_INTER_WORD = 1; public static final int JUSTIFICATION_MODE_INTER_WORD = NativeLineBreaker.JUSTIFICATION_MODE_INTER_WORD; /* * Line spacing multiplier for default line spacing. Loading core/java/android/text/NativeLineBreaker.java +249 −38 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.text; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -26,12 +27,233 @@ import dalvik.annotation.optimization.FastNative; import libcore.util.NativeAllocationRegistry; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * A native implementation of the line breaker. * TODO: Consider to make this class public. * @hide */ public class NativeLineBreaker { @IntDef(prefix = { "BREAK_STRATEGY_" }, value = { BREAK_STRATEGY_SIMPLE, BREAK_STRATEGY_HIGH_QUALITY, BREAK_STRATEGY_BALANCED }) @Retention(RetentionPolicy.SOURCE) public @interface BreakStrategy {} /** * Value for break strategy indicating simple line breaking. Automatic hyphens are not added * (though soft hyphens are respected), and modifying text generally doesn't affect the 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 = 0; /** * 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 = 1; /** * 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 = 2; @IntDef(prefix = { "HYPHENATION_FREQUENCY_" }, value = { HYPHENATION_FREQUENCY_NORMAL, HYPHENATION_FREQUENCY_FULL, HYPHENATION_FREQUENCY_NONE }) @Retention(RetentionPolicy.SOURCE) public @interface HyphenationFrequency {} /** * Value for hyphenation frequency indicating no automatic hyphenation. Useful * for backward compatibility, and for cases where the automatic hyphenation algorithm results * in incorrect hyphenation. Mid-word breaks may still happen when a word is wider than the * 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 = 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 = 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 = 2; @IntDef(prefix = { "JUSTIFICATION_MODE_" }, value = { JUSTIFICATION_MODE_NONE, JUSTIFICATION_MODE_INTER_WORD }) @Retention(RetentionPolicy.SOURCE) public @interface JustificationMode {} /** * Value for justification mode indicating no justification. */ public static final int JUSTIFICATION_MODE_NONE = 0; /** * Value for justification mode indicating the text is justified by stretching word spacing. */ public static final int JUSTIFICATION_MODE_INTER_WORD = 1; /** * A builder class of NativeLineBreaker. */ public static class Builder { private @BreakStrategy int mBreakStrategy = BREAK_STRATEGY_SIMPLE; private @HyphenationFrequency int mHyphenationFrequency = HYPHENATION_FREQUENCY_NONE; private @JustificationMode int mJustified = JUSTIFICATION_MODE_NONE; private @Nullable int[] mIndents = null; /** * Construct a builder class. */ public Builder() {} /** * Set break strategy. */ public Builder setBreakStrategy(@BreakStrategy int breakStrategy) { mBreakStrategy = breakStrategy; return this; } /** * Set hyphenation frequency. */ public Builder setHyphenationFrequency(@HyphenationFrequency int hyphenationFrequency) { mHyphenationFrequency = hyphenationFrequency; return this; } /** * Set whether the text is justified. */ public Builder setJustified(@JustificationMode int justified) { mJustified = justified; return this; } /** * Set indents for entire text. * * Sets the total (left + right) indents in pixel per lines. */ public Builder setIndents(@Nullable int[] indents) { mIndents = indents; return this; } /** * Returns the NativeLineBreaker with given parameters. */ NativeLineBreaker build() { return new NativeLineBreaker(mBreakStrategy, mHyphenationFrequency, mJustified, mIndents); } } /** * Line breaking constraints for single paragraph. */ public static class ParagraphConstraints { private @FloatRange(from = 0.0f) float mWidth = 0; private @FloatRange(from = 0.0f) float mFirstWidth = 0; private @IntRange(from = 0) int mFirstWidthLineCount = 0; private @Nullable int[] mVariableTabStops = null; private @IntRange(from = 0) int mDefaultTabStop = 0; public ParagraphConstraints() {} /** * Set width for this paragraph. */ public void setWidth(@FloatRange(from = 0.0f) float width) { mWidth = width; } /** * Set indent for this paragraph. * * @param firstWidth the line width of the starting of the paragraph * @param firstWidthLineCount the number of lines that applies the firstWidth */ public void setIndent(@FloatRange(from = 0.0f) float firstWidth, @IntRange(from = 0) int firstWidthLineCount) { mFirstWidth = firstWidth; mFirstWidthLineCount = firstWidthLineCount; } /** * Set tab stops for this paragraph. * * @param tabStops the array of pixels of tap stopping position * @param defaultTabStop pixels of the default tab stopping position */ public void setTabStops(@Nullable int[] tabStops, @IntRange(from = 0) int defaultTabStop) { mVariableTabStops = tabStops; mDefaultTabStop = defaultTabStop; } /** * Return the width for this paragraph in pixels. */ public @FloatRange(from = 0.0f) float getWidth() { return mWidth; } /** * Return the first line's width for this paragraph in pixel. * * @see #setIndent(float, int) */ public @FloatRange(from = 0.0f) float getFirstWidth() { return mFirstWidth; } /** * Return the number of lines to apply the first line's width. * * @see #setIndent(float, int) */ public @IntRange(from = 0) int getFirstWidthLineCount() { return mFirstWidthLineCount; } /** * Returns the array of tab stops in pixels. * * @see #setTabStops(int[], int) */ public @Nullable int[] getTabStops() { return mVariableTabStops; } /** * Returns the default tab stops in pixels. * * @see #setTabStop(int[], int) */ public @IntRange(from = 0) int getDefaultTabStop() { return mDefaultTabStop; } } /** * A result object of a line breaking Loading @@ -43,6 +265,7 @@ public class NativeLineBreaker { public float[] widths = new float[INITIAL_SIZE]; public float[] ascents = new float[INITIAL_SIZE]; public float[] descents = new float[INITIAL_SIZE]; // TODO: Introduce Hyphenator for explaining the meaning of flags. public int[] flags = new int[INITIAL_SIZE]; // breaks, widths, and flags should all have the same length } Loading @@ -53,54 +276,44 @@ public class NativeLineBreaker { private final long mNativePtr; /** * A constructor of NativeLineBreaker * Use Builder instead. */ public NativeLineBreaker(@Layout.BreakStrategy int breakStrategy, @Layout.HyphenationFrequency int hyphenationFrequency, boolean justify, @Nullable int[] indents) { mNativePtr = nInit(breakStrategy, hyphenationFrequency, justify, indents); private NativeLineBreaker(@BreakStrategy int breakStrategy, @HyphenationFrequency int hyphenationFrequency, @JustificationMode int justify, @Nullable int[] indents) { mNativePtr = nInit(breakStrategy, hyphenationFrequency, justify == JUSTIFICATION_MODE_INTER_WORD, indents); sRegistry.registerNativeAllocation(this, mNativePtr); } /** * Break text into lines * Break paragraph into lines. * * The result is filled to out param. * * @param chars an array of characters * @param measuredPara a result of the text measurement * @param length a length of the target text from the begining * @param firstWidth a width of the first width of the line in this paragraph * @param firstWidthLineCount a number of lines that has the length of the firstWidth * @param restWidth a width of the rest of the lines. * @param variableTabStops an array of tab stop widths * @param defaultTabStop a width of the tab stop * @param indentsOffset an offset of the indents to be used. * @param out output buffer * @return a number of the lines */ @NonNull public int computeLineBreaks( @NonNull char[] chars, * @param constraints for a single paragraph * @param lineNumber a line number of this paragraph * @param out object to set line break information for the given paragraph */ public void computeLineBreaks( @NonNull NativeMeasuredParagraph measuredPara, @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, @NonNull ParagraphConstraints constraints, @IntRange(from = 0) int lineNumber, @NonNull LineBreaks out) { return nComputeLineBreaks( out.breakCount = nComputeLineBreaks( mNativePtr, // Inputs chars, measuredPara.getChars(), measuredPara.getNativePtr(), length, firstWidth, firstWidthLineCount, restWidth, variableTabStops, defaultTabStop, indentsOffset, measuredPara.getChars().length, constraints.mFirstWidth, constraints.mFirstWidthLineCount, constraints.mWidth, constraints.mVariableTabStops, constraints.mDefaultTabStop, lineNumber, // Outputs out, Loading @@ -114,10 +327,8 @@ public class NativeLineBreaker { } @FastNative private static native long nInit( @Layout.BreakStrategy int breakStrategy, @Layout.HyphenationFrequency int hyphenationFrequency, boolean isJustified, private static native long nInit(@BreakStrategy int breakStrategy, @HyphenationFrequency int hyphenationFrequency, boolean isJustified, @Nullable int[] indents); @CriticalNative Loading core/java/android/text/NativeMeasuredParagraph.java +11 −2 Original line number Diff line number Diff line Loading @@ -36,10 +36,19 @@ public class NativeMeasuredParagraph { NativeMeasuredParagraph.class.getClassLoader(), nGetReleaseFunc(), 1024); private long mNativePtr; private @NonNull char[] mChars; // Use builder instead. private NativeMeasuredParagraph(long ptr) { private NativeMeasuredParagraph(long ptr, @NonNull char[] chars) { mNativePtr = ptr; mChars = chars; } /** * Returns a characters of this paragraph. */ public char[] getChars() { return mChars; } /** Loading Loading @@ -126,7 +135,7 @@ public class NativeMeasuredParagraph { try { long ptr = nBuildNativeMeasuredParagraph(mNativePtr, text, computeHyphenation, computeLayout); NativeMeasuredParagraph res = new NativeMeasuredParagraph(ptr); NativeMeasuredParagraph res = new NativeMeasuredParagraph(ptr, text); sRegistry.registerNativeAllocation(res, ptr); return res; } finally { Loading core/java/android/text/StaticLayout.java +16 −15 Original line number Diff line number Diff line Loading @@ -626,11 +626,16 @@ public class StaticLayout extends Layout { indents = null; } final NativeLineBreaker lineBreaker = new NativeLineBreaker( b.mBreakStrategy, b.mHyphenationFrequency, final NativeLineBreaker lineBreaker = new NativeLineBreaker.Builder() .setBreakStrategy(b.mBreakStrategy) .setHyphenationFrequency(b.mHyphenationFrequency) // TODO: Support more justification mode, e.g. letter spacing, stretching. b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE, indents); .setJustified(b.mJustificationMode) .setIndents(indents) .build(); NativeLineBreaker.ParagraphConstraints constraints = new NativeLineBreaker.ParagraphConstraints(); PrecomputedText.ParagraphInfo[] paragraphInfo = null; final Spanned spanned = (source instanceof Spanned) ? (Spanned) source : null; Loading Loading @@ -721,18 +726,14 @@ public class StaticLayout extends Layout { final char[] chs = measuredPara.getChars(); final int[] spanEndCache = measuredPara.getSpanEndCache().getRawArray(); final int[] fmCache = measuredPara.getFontMetrics().getRawArray(); int breakCount = lineBreaker.computeLineBreaks( measuredPara.getChars(), measuredPara.getNativeMeasuredParagraph(), paraEnd - paraStart, firstWidth, firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, mLineCount, lineBreaks); constraints.setWidth(restWidth); constraints.setIndent(firstWidth, firstWidthLineCount); constraints.setTabStops(variableTabStops, TAB_INCREMENT); lineBreaker.computeLineBreaks(measuredPara.getNativeMeasuredParagraph(), constraints, mLineCount, lineBreaks); int breakCount = lineBreaks.breakCount; final int[] breaks = lineBreaks.breaks; final float[] lineWidths = lineBreaks.widths; final float[] ascents = lineBreaks.ascents; Loading Loading
core/java/android/text/Layout.java +18 −13 Original line number Diff line number Diff line Loading @@ -50,9 +50,9 @@ import java.util.Arrays; public abstract class Layout { /** @hide */ @IntDef(prefix = { "BREAK_STRATEGY_" }, value = { BREAK_STRATEGY_SIMPLE, BREAK_STRATEGY_HIGH_QUALITY, BREAK_STRATEGY_BALANCED NativeLineBreaker.BREAK_STRATEGY_SIMPLE, NativeLineBreaker.BREAK_STRATEGY_HIGH_QUALITY, NativeLineBreaker.BREAK_STRATEGY_BALANCED }) @Retention(RetentionPolicy.SOURCE) public @interface BreakStrategy {} Loading @@ -63,19 +63,20 @@ 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 = 0; public static final int BREAK_STRATEGY_SIMPLE = NativeLineBreaker.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 = 1; public static final int BREAK_STRATEGY_HIGH_QUALITY = NativeLineBreaker.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 = 2; public static final int BREAK_STRATEGY_BALANCED = NativeLineBreaker.BREAK_STRATEGY_BALANCED; /** @hide */ @IntDef(prefix = { "HYPHENATION_FREQUENCY_" }, value = { Loading @@ -93,29 +94,32 @@ 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 = 0; public static final int HYPHENATION_FREQUENCY_NONE = NativeLineBreaker.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 = 1; public static final int HYPHENATION_FREQUENCY_NORMAL = NativeLineBreaker.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 = 2; public static final int HYPHENATION_FREQUENCY_FULL = NativeLineBreaker.HYPHENATION_FREQUENCY_FULL; private static final ParagraphStyle[] NO_PARA_SPANS = ArrayUtils.emptyArray(ParagraphStyle.class); /** @hide */ @IntDef(prefix = { "JUSTIFICATION_MODE_" }, value = { JUSTIFICATION_MODE_NONE, JUSTIFICATION_MODE_INTER_WORD NativeLineBreaker.JUSTIFICATION_MODE_NONE, NativeLineBreaker.JUSTIFICATION_MODE_INTER_WORD }) @Retention(RetentionPolicy.SOURCE) public @interface JustificationMode {} Loading @@ -123,12 +127,13 @@ public abstract class Layout { /** * Value for justification mode indicating no justification. */ public static final int JUSTIFICATION_MODE_NONE = 0; public static final int JUSTIFICATION_MODE_NONE = NativeLineBreaker.JUSTIFICATION_MODE_NONE; /** * Value for justification mode indicating the text is justified by stretching word spacing. */ public static final int JUSTIFICATION_MODE_INTER_WORD = 1; public static final int JUSTIFICATION_MODE_INTER_WORD = NativeLineBreaker.JUSTIFICATION_MODE_INTER_WORD; /* * Line spacing multiplier for default line spacing. Loading
core/java/android/text/NativeLineBreaker.java +249 −38 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.text; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -26,12 +27,233 @@ import dalvik.annotation.optimization.FastNative; import libcore.util.NativeAllocationRegistry; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * A native implementation of the line breaker. * TODO: Consider to make this class public. * @hide */ public class NativeLineBreaker { @IntDef(prefix = { "BREAK_STRATEGY_" }, value = { BREAK_STRATEGY_SIMPLE, BREAK_STRATEGY_HIGH_QUALITY, BREAK_STRATEGY_BALANCED }) @Retention(RetentionPolicy.SOURCE) public @interface BreakStrategy {} /** * Value for break strategy indicating simple line breaking. Automatic hyphens are not added * (though soft hyphens are respected), and modifying text generally doesn't affect the 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 = 0; /** * 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 = 1; /** * 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 = 2; @IntDef(prefix = { "HYPHENATION_FREQUENCY_" }, value = { HYPHENATION_FREQUENCY_NORMAL, HYPHENATION_FREQUENCY_FULL, HYPHENATION_FREQUENCY_NONE }) @Retention(RetentionPolicy.SOURCE) public @interface HyphenationFrequency {} /** * Value for hyphenation frequency indicating no automatic hyphenation. Useful * for backward compatibility, and for cases where the automatic hyphenation algorithm results * in incorrect hyphenation. Mid-word breaks may still happen when a word is wider than the * 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 = 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 = 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 = 2; @IntDef(prefix = { "JUSTIFICATION_MODE_" }, value = { JUSTIFICATION_MODE_NONE, JUSTIFICATION_MODE_INTER_WORD }) @Retention(RetentionPolicy.SOURCE) public @interface JustificationMode {} /** * Value for justification mode indicating no justification. */ public static final int JUSTIFICATION_MODE_NONE = 0; /** * Value for justification mode indicating the text is justified by stretching word spacing. */ public static final int JUSTIFICATION_MODE_INTER_WORD = 1; /** * A builder class of NativeLineBreaker. */ public static class Builder { private @BreakStrategy int mBreakStrategy = BREAK_STRATEGY_SIMPLE; private @HyphenationFrequency int mHyphenationFrequency = HYPHENATION_FREQUENCY_NONE; private @JustificationMode int mJustified = JUSTIFICATION_MODE_NONE; private @Nullable int[] mIndents = null; /** * Construct a builder class. */ public Builder() {} /** * Set break strategy. */ public Builder setBreakStrategy(@BreakStrategy int breakStrategy) { mBreakStrategy = breakStrategy; return this; } /** * Set hyphenation frequency. */ public Builder setHyphenationFrequency(@HyphenationFrequency int hyphenationFrequency) { mHyphenationFrequency = hyphenationFrequency; return this; } /** * Set whether the text is justified. */ public Builder setJustified(@JustificationMode int justified) { mJustified = justified; return this; } /** * Set indents for entire text. * * Sets the total (left + right) indents in pixel per lines. */ public Builder setIndents(@Nullable int[] indents) { mIndents = indents; return this; } /** * Returns the NativeLineBreaker with given parameters. */ NativeLineBreaker build() { return new NativeLineBreaker(mBreakStrategy, mHyphenationFrequency, mJustified, mIndents); } } /** * Line breaking constraints for single paragraph. */ public static class ParagraphConstraints { private @FloatRange(from = 0.0f) float mWidth = 0; private @FloatRange(from = 0.0f) float mFirstWidth = 0; private @IntRange(from = 0) int mFirstWidthLineCount = 0; private @Nullable int[] mVariableTabStops = null; private @IntRange(from = 0) int mDefaultTabStop = 0; public ParagraphConstraints() {} /** * Set width for this paragraph. */ public void setWidth(@FloatRange(from = 0.0f) float width) { mWidth = width; } /** * Set indent for this paragraph. * * @param firstWidth the line width of the starting of the paragraph * @param firstWidthLineCount the number of lines that applies the firstWidth */ public void setIndent(@FloatRange(from = 0.0f) float firstWidth, @IntRange(from = 0) int firstWidthLineCount) { mFirstWidth = firstWidth; mFirstWidthLineCount = firstWidthLineCount; } /** * Set tab stops for this paragraph. * * @param tabStops the array of pixels of tap stopping position * @param defaultTabStop pixels of the default tab stopping position */ public void setTabStops(@Nullable int[] tabStops, @IntRange(from = 0) int defaultTabStop) { mVariableTabStops = tabStops; mDefaultTabStop = defaultTabStop; } /** * Return the width for this paragraph in pixels. */ public @FloatRange(from = 0.0f) float getWidth() { return mWidth; } /** * Return the first line's width for this paragraph in pixel. * * @see #setIndent(float, int) */ public @FloatRange(from = 0.0f) float getFirstWidth() { return mFirstWidth; } /** * Return the number of lines to apply the first line's width. * * @see #setIndent(float, int) */ public @IntRange(from = 0) int getFirstWidthLineCount() { return mFirstWidthLineCount; } /** * Returns the array of tab stops in pixels. * * @see #setTabStops(int[], int) */ public @Nullable int[] getTabStops() { return mVariableTabStops; } /** * Returns the default tab stops in pixels. * * @see #setTabStop(int[], int) */ public @IntRange(from = 0) int getDefaultTabStop() { return mDefaultTabStop; } } /** * A result object of a line breaking Loading @@ -43,6 +265,7 @@ public class NativeLineBreaker { public float[] widths = new float[INITIAL_SIZE]; public float[] ascents = new float[INITIAL_SIZE]; public float[] descents = new float[INITIAL_SIZE]; // TODO: Introduce Hyphenator for explaining the meaning of flags. public int[] flags = new int[INITIAL_SIZE]; // breaks, widths, and flags should all have the same length } Loading @@ -53,54 +276,44 @@ public class NativeLineBreaker { private final long mNativePtr; /** * A constructor of NativeLineBreaker * Use Builder instead. */ public NativeLineBreaker(@Layout.BreakStrategy int breakStrategy, @Layout.HyphenationFrequency int hyphenationFrequency, boolean justify, @Nullable int[] indents) { mNativePtr = nInit(breakStrategy, hyphenationFrequency, justify, indents); private NativeLineBreaker(@BreakStrategy int breakStrategy, @HyphenationFrequency int hyphenationFrequency, @JustificationMode int justify, @Nullable int[] indents) { mNativePtr = nInit(breakStrategy, hyphenationFrequency, justify == JUSTIFICATION_MODE_INTER_WORD, indents); sRegistry.registerNativeAllocation(this, mNativePtr); } /** * Break text into lines * Break paragraph into lines. * * The result is filled to out param. * * @param chars an array of characters * @param measuredPara a result of the text measurement * @param length a length of the target text from the begining * @param firstWidth a width of the first width of the line in this paragraph * @param firstWidthLineCount a number of lines that has the length of the firstWidth * @param restWidth a width of the rest of the lines. * @param variableTabStops an array of tab stop widths * @param defaultTabStop a width of the tab stop * @param indentsOffset an offset of the indents to be used. * @param out output buffer * @return a number of the lines */ @NonNull public int computeLineBreaks( @NonNull char[] chars, * @param constraints for a single paragraph * @param lineNumber a line number of this paragraph * @param out object to set line break information for the given paragraph */ public void computeLineBreaks( @NonNull NativeMeasuredParagraph measuredPara, @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, @NonNull ParagraphConstraints constraints, @IntRange(from = 0) int lineNumber, @NonNull LineBreaks out) { return nComputeLineBreaks( out.breakCount = nComputeLineBreaks( mNativePtr, // Inputs chars, measuredPara.getChars(), measuredPara.getNativePtr(), length, firstWidth, firstWidthLineCount, restWidth, variableTabStops, defaultTabStop, indentsOffset, measuredPara.getChars().length, constraints.mFirstWidth, constraints.mFirstWidthLineCount, constraints.mWidth, constraints.mVariableTabStops, constraints.mDefaultTabStop, lineNumber, // Outputs out, Loading @@ -114,10 +327,8 @@ public class NativeLineBreaker { } @FastNative private static native long nInit( @Layout.BreakStrategy int breakStrategy, @Layout.HyphenationFrequency int hyphenationFrequency, boolean isJustified, private static native long nInit(@BreakStrategy int breakStrategy, @HyphenationFrequency int hyphenationFrequency, boolean isJustified, @Nullable int[] indents); @CriticalNative Loading
core/java/android/text/NativeMeasuredParagraph.java +11 −2 Original line number Diff line number Diff line Loading @@ -36,10 +36,19 @@ public class NativeMeasuredParagraph { NativeMeasuredParagraph.class.getClassLoader(), nGetReleaseFunc(), 1024); private long mNativePtr; private @NonNull char[] mChars; // Use builder instead. private NativeMeasuredParagraph(long ptr) { private NativeMeasuredParagraph(long ptr, @NonNull char[] chars) { mNativePtr = ptr; mChars = chars; } /** * Returns a characters of this paragraph. */ public char[] getChars() { return mChars; } /** Loading Loading @@ -126,7 +135,7 @@ public class NativeMeasuredParagraph { try { long ptr = nBuildNativeMeasuredParagraph(mNativePtr, text, computeHyphenation, computeLayout); NativeMeasuredParagraph res = new NativeMeasuredParagraph(ptr); NativeMeasuredParagraph res = new NativeMeasuredParagraph(ptr, text); sRegistry.registerNativeAllocation(res, ptr); return res; } finally { Loading
core/java/android/text/StaticLayout.java +16 −15 Original line number Diff line number Diff line Loading @@ -626,11 +626,16 @@ public class StaticLayout extends Layout { indents = null; } final NativeLineBreaker lineBreaker = new NativeLineBreaker( b.mBreakStrategy, b.mHyphenationFrequency, final NativeLineBreaker lineBreaker = new NativeLineBreaker.Builder() .setBreakStrategy(b.mBreakStrategy) .setHyphenationFrequency(b.mHyphenationFrequency) // TODO: Support more justification mode, e.g. letter spacing, stretching. b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE, indents); .setJustified(b.mJustificationMode) .setIndents(indents) .build(); NativeLineBreaker.ParagraphConstraints constraints = new NativeLineBreaker.ParagraphConstraints(); PrecomputedText.ParagraphInfo[] paragraphInfo = null; final Spanned spanned = (source instanceof Spanned) ? (Spanned) source : null; Loading Loading @@ -721,18 +726,14 @@ public class StaticLayout extends Layout { final char[] chs = measuredPara.getChars(); final int[] spanEndCache = measuredPara.getSpanEndCache().getRawArray(); final int[] fmCache = measuredPara.getFontMetrics().getRawArray(); int breakCount = lineBreaker.computeLineBreaks( measuredPara.getChars(), measuredPara.getNativeMeasuredParagraph(), paraEnd - paraStart, firstWidth, firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, mLineCount, lineBreaks); constraints.setWidth(restWidth); constraints.setIndent(firstWidth, firstWidthLineCount); constraints.setTabStops(variableTabStops, TAB_INCREMENT); lineBreaker.computeLineBreaks(measuredPara.getNativeMeasuredParagraph(), constraints, mLineCount, lineBreaks); int breakCount = lineBreaks.breakCount; final int[] breaks = lineBreaks.breaks; final float[] lineWidths = lineBreaks.widths; final float[] ascents = lineBreaks.ascents; Loading