Add line break word style parameter in the LineBreakConfig
The line break word style(lw) provides the phrase-based breaking opportunities. When the line break word style is set, it will be brought to ICU for calculation.
Bug: 183780874
Test: atest minikin_tests; atest TextViewTest; atest MeasuredTextTest; atest PrecomputedTextTest
Change-Id: Idd851497e46c1fca87ff590230d93f8bb5c9afae
diff --git a/core/api/current.txt b/core/api/current.txt
index 688b66e..1bc3e81 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -950,6 +950,7 @@
field public static final int letterSpacing = 16843958; // 0x10104b6
field public static final int level = 16844032; // 0x1010500
field public static final int lineBreakStyle = 16844365; // 0x101064d
+ field public static final int lineBreakWordStyle = 16844366; // 0x101064e
field public static final int lineHeight = 16844159; // 0x101057f
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
@@ -17581,12 +17582,16 @@
public final class LineBreakConfig {
ctor public LineBreakConfig();
method public int getLineBreakStyle();
- method public void set(@Nullable android.graphics.text.LineBreakConfig);
+ method public int getLineBreakWordStyle();
+ method public void set(@NonNull android.graphics.text.LineBreakConfig);
method public void setLineBreakStyle(int);
+ method public void setLineBreakWordStyle(int);
field public static final int LINE_BREAK_STYLE_LOOSE = 1; // 0x1
field public static final int LINE_BREAK_STYLE_NONE = 0; // 0x0
field public static final int LINE_BREAK_STYLE_NORMAL = 2; // 0x2
field public static final int LINE_BREAK_STYLE_STRICT = 3; // 0x3
+ field public static final int LINE_BREAK_WORD_STYLE_NONE = 0; // 0x0
+ field public static final int LINE_BREAK_WORD_STYLE_PHRASE = 1; // 0x1
}
public class LineBreaker {
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
index ce63376..be66db2 100644
--- a/core/java/android/text/PrecomputedText.java
+++ b/core/java/android/text/PrecomputedText.java
@@ -363,6 +363,9 @@
public String toString() {
int lineBreakStyle = (mLineBreakConfig != null)
? mLineBreakConfig.getLineBreakStyle() : LineBreakConfig.LINE_BREAK_STYLE_NONE;
+ int lineBreakWordStyle = (mLineBreakConfig != null)
+ ? mLineBreakConfig.getLineBreakWordStyle()
+ : LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE;
return "{"
+ "textSize=" + mPaint.getTextSize()
+ ", textScaleX=" + mPaint.getTextScaleX()
@@ -376,6 +379,7 @@
+ ", breakStrategy=" + mBreakStrategy
+ ", hyphenationFrequency=" + mHyphenationFrequency
+ ", lineBreakStyle=" + lineBreakStyle
+ + ", lineBreakWordStyle=" + lineBreakWordStyle
+ "}";
}
};
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0fe06be..a710a80 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -350,6 +350,7 @@
* @attr ref android.R.styleable#TextView_breakStrategy
* @attr ref android.R.styleable#TextView_hyphenationFrequency
* @attr ref android.R.styleable#TextView_lineBreakStyle
+ * @attr ref android.R.styleable#TextView_lineBreakWordStyle
* @attr ref android.R.styleable#TextView_autoSizeTextType
* @attr ref android.R.styleable#TextView_autoSizeMinTextSize
* @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
@@ -458,6 +459,13 @@
private static final int FLOATING_TOOLBAR_SELECT_ALL_REFRESH_DELAY = 500;
+ // The default value of the line break style.
+ private static final int DEFAULT_LINE_BREAK_STYLE = LineBreakConfig.LINE_BREAK_STYLE_NONE;
+
+ // The default value of the line break word style.
+ private static final int DEFAULT_LINE_BREAK_WORD_STYLE =
+ LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE;
+
/**
* This change ID enables the fallback text line spacing (line height) for BoringLayout.
* @hide
@@ -1450,6 +1458,11 @@
a.getInt(attr, LineBreakConfig.LINE_BREAK_STYLE_NONE));
break;
+ case com.android.internal.R.styleable.TextView_lineBreakWordStyle:
+ mLineBreakConfig.setLineBreakWordStyle(
+ a.getInt(attr, LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE));
+ break;
+
case com.android.internal.R.styleable.TextView_autoSizeTextType:
mAutoSizeTextType = a.getInt(attr, AUTO_SIZE_TEXT_TYPE_NONE);
break;
@@ -3982,6 +3995,10 @@
float mLetterSpacing = 0;
String mFontFeatureSettings = null;
String mFontVariationSettings = null;
+ boolean mHasLineBreakStyle = false;
+ boolean mHasLineBreakWordStyle = false;
+ int mLineBreakStyle = DEFAULT_LINE_BREAK_STYLE;
+ int mLineBreakWordStyle = DEFAULT_LINE_BREAK_WORD_STYLE;
@Override
public String toString() {
@@ -4012,6 +4029,10 @@
+ " mLetterSpacing:" + mLetterSpacing + "\n"
+ " mFontFeatureSettings:" + mFontFeatureSettings + "\n"
+ " mFontVariationSettings:" + mFontVariationSettings + "\n"
+ + " mHasLineBreakStyle:" + mHasLineBreakStyle + "\n"
+ + " mHasLineBreakWordStyle:" + mHasLineBreakWordStyle + "\n"
+ + " mLineBreakStyle:" + mLineBreakStyle + "\n"
+ + " mLineBreakWordStyle:" + mLineBreakWordStyle + "\n"
+ "}";
}
}
@@ -4059,6 +4080,10 @@
com.android.internal.R.styleable.TextAppearance_fontFeatureSettings);
sAppearanceValues.put(com.android.internal.R.styleable.TextView_fontVariationSettings,
com.android.internal.R.styleable.TextAppearance_fontVariationSettings);
+ sAppearanceValues.put(com.android.internal.R.styleable.TextView_lineBreakStyle,
+ com.android.internal.R.styleable.TextAppearance_lineBreakStyle);
+ sAppearanceValues.put(com.android.internal.R.styleable.TextView_lineBreakWordStyle,
+ com.android.internal.R.styleable.TextAppearance_lineBreakWordStyle);
}
/**
@@ -4174,6 +4199,16 @@
case com.android.internal.R.styleable.TextAppearance_fontVariationSettings:
attributes.mFontVariationSettings = appearance.getString(attr);
break;
+ case com.android.internal.R.styleable.TextAppearance_lineBreakStyle:
+ attributes.mHasLineBreakStyle = true;
+ attributes.mLineBreakStyle =
+ appearance.getInt(attr, attributes.mLineBreakStyle);
+ break;
+ case com.android.internal.R.styleable.TextAppearance_lineBreakWordStyle:
+ attributes.mHasLineBreakWordStyle = true;
+ attributes.mLineBreakWordStyle =
+ appearance.getInt(attr, attributes.mLineBreakWordStyle);
+ break;
default:
}
}
@@ -4239,9 +4274,46 @@
if (attributes.mFontVariationSettings != null) {
setFontVariationSettings(attributes.mFontVariationSettings);
}
+
+ if (attributes.mHasLineBreakStyle || attributes.mHasLineBreakWordStyle) {
+ updateLineBreakConfigFromTextAppearance(attributes.mHasLineBreakStyle,
+ attributes.mHasLineBreakWordStyle, attributes.mLineBreakStyle,
+ attributes.mLineBreakWordStyle);
+ }
}
/**
+ * Updates the LineBreakConfig from the TextAppearance.
+ *
+ * This method updates the given line configuration from the TextAppearance. This method will
+ * request new layout if line break config has been changed.
+ *
+ * @param isLineBreakStyleSpecified true if the line break style is specified.
+ * @param isLineBreakWordStyleSpecified true if the line break word style is specified.
+ * @param lineBreakStyle the value of the line break style in the TextAppearance.
+ * @param lineBreakWordStyle the value of the line break word style in the TextAppearance.
+ */
+ private void updateLineBreakConfigFromTextAppearance(boolean isLineBreakStyleSpecified,
+ boolean isLineBreakWordStyleSpecified,
+ @LineBreakConfig.LineBreakStyle int lineBreakStyle,
+ @LineBreakConfig.LineBreakWordStyle int lineBreakWordStyle) {
+ boolean updated = false;
+ if (isLineBreakStyleSpecified && mLineBreakConfig.getLineBreakStyle() != lineBreakStyle) {
+ mLineBreakConfig.setLineBreakStyle(lineBreakStyle);
+ updated = true;
+ }
+ if (isLineBreakWordStyleSpecified
+ && mLineBreakConfig.getLineBreakWordStyle() != lineBreakWordStyle) {
+ mLineBreakConfig.setLineBreakWordStyle(lineBreakWordStyle);
+ updated = true;
+ }
+ if (updated && mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
+ }
+ /**
* Get the default primary {@link Locale} of the text in this TextView. This will always be
* the first member of {@link #getTextLocales()}.
* @return the default primary {@link Locale} of the text in this TextView.
@@ -4797,18 +4869,29 @@
/**
* Sets line break configuration indicates which strategy needs to be used when calculating the
- * text wrapping. There are thee strategies for the line break style(lb):
+ * text wrapping.
+ * <P>
+ * There are two types of line break rules that can be configured at the same time. One is
+ * line break style(lb) and the other is line break word style(lw). The line break style
+ * affects rule-based breaking. The line break word style affects dictionary-based breaking
+ * and provide phrase-based breaking opportunities. There are several types for the
+ * line break style:
* {@link LineBreakConfig#LINE_BREAK_STYLE_LOOSE},
* {@link LineBreakConfig#LINE_BREAK_STYLE_NORMAL} and
* {@link LineBreakConfig#LINE_BREAK_STYLE_STRICT}.
- * The default value of the line break style is {@link LineBreakConfig#LINE_BREAK_STYLE_NONE},
- * which means no line break style is specified.
+ * The type for the line break word style is
+ * {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_PHRASE}.
+ * The default values of the line break style and the line break word style are
+ * {@link LineBreakConfig#LINE_BREAK_STYLE_NONE} and
+ * {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_NONE} respectively, indicating that no line
+ * breaking rules are specified.
* See <a href="https://drafts.csswg.org/css-text/#line-break-property">
* the line-break property</a>
*
* @param lineBreakConfig the line break config for text wrapping.
*/
public void setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) {
+ Objects.requireNonNull(lineBreakConfig);
if (mLineBreakConfig.equals(lineBreakConfig)) {
return;
}
@@ -4855,7 +4938,13 @@
mTextDir = params.getTextDirection();
mBreakStrategy = params.getBreakStrategy();
mHyphenationFrequency = params.getHyphenationFrequency();
- mLineBreakConfig.set(params.getLineBreakConfig());
+ if (params.getLineBreakConfig() != null) {
+ mLineBreakConfig.set(params.getLineBreakConfig());
+ } else {
+ // Set default value if the line break config in the PrecomputedText.Params is null.
+ mLineBreakConfig.setLineBreakStyle(DEFAULT_LINE_BREAK_STYLE);
+ mLineBreakConfig.setLineBreakWordStyle(DEFAULT_LINE_BREAK_WORD_STYLE);
+ }
if (mLayout != null) {
nullLayouts();
requestLayout();
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e232d85..69fdea4 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5030,6 +5030,10 @@
<attr name="fontFeatureSettings" format="string" />
<!-- Font variation settings. -->
<attr name="fontVariationSettings" format="string"/>
+ <!-- Specifies the strictness of line-breaking rules applied within an element. -->
+ <attr name="lineBreakStyle" />
+ <!-- Specifies the phrase-based breaking opportunities. -->
+ <attr name="lineBreakWordStyle" />
</declare-styleable>
<declare-styleable name="TextClock">
<!-- Specifies the formatting pattern used to show the time and/or date
@@ -5428,6 +5432,13 @@
<!-- ndicates breaking text with the most strictest line-breaking rules. -->
<enum name="strict" value="3" />
</attr>
+ <!-- Specify the phrase-based line break can be used when calculating the text wrapping.-->
+ <attr name="lineBreakWordStyle">
+ <!-- No line break word style specific. -->
+ <enum name="none" value="0" />
+ <!-- Specify the phrase based breaking. -->
+ <enum name="phrase" value="1" />
+ </attr>
<!-- Specify the type of auto-size. Note that this feature is not supported by EditText,
works only for TextView. -->
<attr name="autoSizeTextType" format="enum">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e83f4a6..6aff511 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3212,6 +3212,7 @@
<public type="attr" name="shouldUseDefaultUnfoldTransition" id="0x0101064c" />
<public type="attr" name="lineBreakStyle" id="0x0101064d" />
+ <public type="attr" name="lineBreakWordStyle" id="0x0101064e" />
<staging-public-group-final type="id" first-id="0x01fe0000">
<public name="accessibilityActionDragStart" />
diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java
index 4d81858..cffdf28 100644
--- a/graphics/java/android/graphics/text/LineBreakConfig.java
+++ b/graphics/java/android/graphics/text/LineBreakConfig.java
@@ -17,7 +17,7 @@
package android.graphics.text;
import android.annotation.IntDef;
-import android.annotation.Nullable;
+import android.annotation.NonNull;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -58,7 +58,28 @@
@Retention(RetentionPolicy.SOURCE)
public @interface LineBreakStyle {}
+ /**
+ * No line break word style specified.
+ */
+ public static final int LINE_BREAK_WORD_STYLE_NONE = 0;
+
+ /**
+ * Indicates the line breaking is based on the phrased. This makes text wrapping only on
+ * meaningful words. The support of the text wrapping word style varies depending on the
+ * locales. If the locale does not support the phrase based text wrapping,
+ * there will be no effect.
+ */
+ public static final int LINE_BREAK_WORD_STYLE_PHRASE = 1;
+
+ /** @hide */
+ @IntDef(prefix = { "LINE_BREAK_WORD_STYLE_" }, value = {
+ LINE_BREAK_WORD_STYLE_NONE, LINE_BREAK_WORD_STYLE_PHRASE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LineBreakWordStyle {}
+
private @LineBreakStyle int mLineBreakStyle = LINE_BREAK_STYLE_NONE;
+ private @LineBreakWordStyle int mLineBreakWordStyle = LINE_BREAK_WORD_STYLE_NONE;
public LineBreakConfig() {
}
@@ -66,14 +87,12 @@
/**
* Set the line break configuration.
*
- * @param config the new line break configuration.
+ * @param lineBreakConfig the new line break configuration.
*/
- public void set(@Nullable LineBreakConfig config) {
- if (config != null) {
- mLineBreakStyle = config.getLineBreakStyle();
- } else {
- mLineBreakStyle = LineBreakConfig.LINE_BREAK_STYLE_NONE;
- }
+ public void set(@NonNull LineBreakConfig lineBreakConfig) {
+ Objects.requireNonNull(lineBreakConfig);
+ mLineBreakStyle = lineBreakConfig.getLineBreakStyle();
+ mLineBreakWordStyle = lineBreakConfig.getLineBreakWordStyle();
}
/**
@@ -94,17 +113,36 @@
mLineBreakStyle = lineBreakStyle;
}
+ /**
+ * Get the line break word style.
+ *
+ * @return The current line break word style to be used for the text wrapping.
+ */
+ public @LineBreakWordStyle int getLineBreakWordStyle() {
+ return mLineBreakWordStyle;
+ }
+
+ /**
+ * Set the line break word style.
+ *
+ * @param lineBreakWordStyle the new line break word style.
+ */
+ public void setLineBreakWordStyle(@LineBreakWordStyle int lineBreakWordStyle) {
+ mLineBreakWordStyle = lineBreakWordStyle;
+ }
+
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (this == o) return true;
if (!(o instanceof LineBreakConfig)) return false;
LineBreakConfig that = (LineBreakConfig) o;
- return mLineBreakStyle == that.mLineBreakStyle;
+ return (mLineBreakStyle == that.mLineBreakStyle)
+ && (mLineBreakWordStyle == that.mLineBreakWordStyle);
}
@Override
public int hashCode() {
- return Objects.hash(mLineBreakStyle);
+ return Objects.hash(mLineBreakStyle, mLineBreakWordStyle);
}
}
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
index 5f4afb7..6d691c1 100644
--- a/graphics/java/android/graphics/text/MeasuredText.java
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -264,8 +264,10 @@
Preconditions.checkArgument(end <= mText.length, "Style exceeds the text length");
int lbStyle = (lineBreakConfig != null) ? lineBreakConfig.getLineBreakStyle() :
LineBreakConfig.LINE_BREAK_STYLE_NONE;
- nAddStyleRun(mNativePtr, paint.getNativeInstance(), lbStyle, mCurrentOffset, end,
- isRtl);
+ int lbWordStyle = (lineBreakConfig != null) ? lineBreakConfig.getLineBreakWordStyle() :
+ LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE;
+ nAddStyleRun(mNativePtr, paint.getNativeInstance(), lbStyle, lbWordStyle,
+ mCurrentOffset, end, isRtl);
mCurrentOffset = end;
return this;
}
@@ -445,7 +447,8 @@
*
* @param nativeBuilderPtr The native MeasuredParagraph builder pointer.
* @param paintPtr The native paint pointer to be applied.
- * @param lineBreakStyle The line break style of the text.
+ * @param lineBreakStyle The line break style(lb) of the text.
+ * @param lineBreakWordStyle The line break word style(lw) of the text.
* @param start The start offset in the copied buffer.
* @param end The end offset in the copied buffer.
* @param isRtl True if the text is RTL.
@@ -453,6 +456,7 @@
private static native void nAddStyleRun(/* Non Zero */ long nativeBuilderPtr,
/* Non Zero */ long paintPtr,
int lineBreakStyle,
+ int lineBreakWordStyle,
@IntRange(from = 0) int start,
@IntRange(from = 0) int end,
boolean isRtl);
diff --git a/libs/hwui/jni/text/MeasuredText.cpp b/libs/hwui/jni/text/MeasuredText.cpp
index 09539ec..76ea2d5 100644
--- a/libs/hwui/jni/text/MeasuredText.cpp
+++ b/libs/hwui/jni/text/MeasuredText.cpp
@@ -65,11 +65,13 @@
// Regular JNI
static void nAddStyleRun(JNIEnv* /* unused */, jclass /* unused */, jlong builderPtr,
- jlong paintPtr, jint lbStyle, jint start, jint end, jboolean isRtl) {
+ jlong paintPtr, jint lbStyle, jint lbWordStyle, jint start, jint end,
+ jboolean isRtl) {
Paint* paint = toPaint(paintPtr);
const Typeface* typeface = Typeface::resolveDefault(paint->getAndroidTypeface());
minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(paint, typeface);
- toBuilder(builderPtr)->addStyleRun(start, end, std::move(minikinPaint), lbStyle, isRtl);
+ toBuilder(builderPtr)
+ ->addStyleRun(start, end, std::move(minikinPaint), lbStyle, lbWordStyle, isRtl);
}
// Regular JNI
@@ -144,7 +146,7 @@
static const JNINativeMethod gMTBuilderMethods[] = {
// MeasuredParagraphBuilder native functions.
{"nInitBuilder", "()J", (void*)nInitBuilder},
- {"nAddStyleRun", "(JJIIIZ)V", (void*)nAddStyleRun},
+ {"nAddStyleRun", "(JJIIIIZ)V", (void*)nAddStyleRun},
{"nAddReplacementRun", "(JJIIF)V", (void*)nAddReplacementRun},
{"nBuildMeasuredText", "(JJ[CZZZ)J", (void*)nBuildMeasuredText},
{"nFreeBuilder", "(J)V", (void*)nFreeBuilder},