From f3e8ea9c2910b33db17001e98b96720b07dce0b3 Mon Sep 17 00:00:00 2001 From: Genki Kondo Date: Fri, 27 Aug 2021 09:02:26 -0700 Subject: [PATCH] Use hyphenationFrequency for text measurement Summary: Implements the calculation of measurement and position of Text attachments in Android Changelog: [Internal] Reviewed By: JoshuaGross Differential Revision: D30586616 fbshipit-source-id: e9ecc002f03477e3465d746855e1dff2e5f0b321 --- .../react/views/text/TextAttributeProps.java | 21 ++++++++++++- .../react/views/text/TextLayoutManager.java | 31 +++++++++++++++---- .../text/TextLayoutManagerMapBuffer.java | 30 +++++++++++++++--- .../renderer/attributedstring/conversions.h | 4 +++ 4 files changed, 74 insertions(+), 12 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java index 13311fef41b..6c93d200e85 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java @@ -68,9 +68,10 @@ public class TextAttributeProps { private static final int DEFAULT_TEXT_SHADOW_COLOR = 0x55000000; private static final int DEFAULT_JUSTIFICATION_MODE = (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) ? 0 : Layout.JUSTIFICATION_MODE_NONE; - private static final int DEFAULT_BREAK_STRATEGY = (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ? 0 : Layout.BREAK_STRATEGY_HIGH_QUALITY; + private static final int DEFAULT_HYPHENATION_FREQUENCY = + (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ? 0 : Layout.HYPHENATION_FREQUENCY_NONE; protected float mLineHeight = Float.NaN; protected boolean mIsColorSet = false; @@ -568,4 +569,22 @@ public class TextAttributeProps { } return androidTextBreakStrategy; } + + public static int getHyphenationFrequency(@Nullable String hyphenationFrequency) { + int androidHyphenationFrequency = DEFAULT_HYPHENATION_FREQUENCY; + if (hyphenationFrequency != null) { + switch (hyphenationFrequency) { + case "none": + androidHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE; + break; + case "normal": + androidHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NORMAL; + break; + default: + androidHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_FULL; + break; + } + } + return androidHyphenationFrequency; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java index b0715e7d6be..f31eee22e30 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java @@ -64,6 +64,7 @@ public class TextLayoutManager { private static final boolean DEFAULT_INCLUDE_FONT_PADDING = true; private static final String INCLUDE_FONT_PADDING_KEY = "includeFontPadding"; private static final String TEXT_BREAK_STRATEGY_KEY = "textBreakStrategy"; + private static final String HYPHENATION_FREQUENCY_KEY = "android_hyphenationFrequency"; private static final String MAXIMUM_NUMBER_OF_LINES_KEY = "maximumNumberOfLines"; private static final LruCache sSpannableCache = new LruCache<>(spannableCacheSize); @@ -250,7 +251,8 @@ public class TextLayoutManager { float width, YogaMeasureMode widthYogaMeasureMode, boolean includeFontPadding, - int textBreakStrategy) { + int textBreakStrategy, + int hyphenationFrequency) { Layout layout; int spanLength = text.length(); boolean unconstrainedWidth = widthYogaMeasureMode == YogaMeasureMode.UNDEFINED || width < 0; @@ -281,10 +283,9 @@ public class TextLayoutManager { .setLineSpacing(0.f, 1.f) .setIncludePad(includeFontPadding) .setBreakStrategy(textBreakStrategy) - .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .setHyphenationFrequency(hyphenationFrequency) .build(); } - } else if (boring != null && (unconstrainedWidth || boring.width <= width)) { int boringLayoutWidth = boring.width; if (boring.width < 0) { @@ -325,7 +326,7 @@ public class TextLayoutManager { .setLineSpacing(0.f, 1.f) .setIncludePad(includeFontPadding) .setBreakStrategy(textBreakStrategy) - .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL); + .setHyphenationFrequency(hyphenationFrequency); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { builder.setUseLineSpacingFromFallbacks(true); @@ -378,6 +379,9 @@ public class TextLayoutManager { paragraphAttributes.hasKey(INCLUDE_FONT_PADDING_KEY) ? paragraphAttributes.getBoolean(INCLUDE_FONT_PADDING_KEY) : DEFAULT_INCLUDE_FONT_PADDING; + int hyphenationFrequency = + TextAttributeProps.getHyphenationFrequency( + paragraphAttributes.getString(HYPHENATION_FREQUENCY_KEY)); if (text == null) { throw new IllegalStateException("Spannable element has not been prepared in onBeforeLayout"); @@ -387,7 +391,13 @@ public class TextLayoutManager { Layout layout = createLayout( - text, boring, width, widthYogaMeasureMode, includeFontPadding, textBreakStrategy); + text, + boring, + width, + widthYogaMeasureMode, + includeFontPadding, + textBreakStrategy, + hyphenationFrequency); int maximumNumberOfLines = paragraphAttributes.hasKey(MAXIMUM_NUMBER_OF_LINES_KEY) @@ -539,10 +549,19 @@ public class TextLayoutManager { paragraphAttributes.hasKey(INCLUDE_FONT_PADDING_KEY) ? paragraphAttributes.getBoolean(INCLUDE_FONT_PADDING_KEY) : DEFAULT_INCLUDE_FONT_PADDING; + int hyphenationFrequency = + TextAttributeProps.getTextBreakStrategy( + paragraphAttributes.getString(HYPHENATION_FREQUENCY_KEY)); Layout layout = createLayout( - text, boring, width, YogaMeasureMode.EXACTLY, includeFontPadding, textBreakStrategy); + text, + boring, + width, + YogaMeasureMode.EXACTLY, + includeFontPadding, + textBreakStrategy, + hyphenationFrequency); return FontMetricsUtil.getFontMetrics(text, layout, sTextPaintInstance, context); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java index 1e5287708a0..ee86e49d97e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java @@ -61,6 +61,7 @@ public class TextLayoutManagerMapBuffer { public static final short PA_KEY_TEXT_BREAK_STRATEGY = 2; public static final short PA_KEY_ADJUST_FONT_SIZE_TO_FIT = 3; public static final short PA_KEY_INCLUDE_FONT_PADDING = 4; + public static final short PA_KEY_HYPHENATION_FREQUENCY = 5; private static final boolean ENABLE_MEASURE_LOGGING = ReactBuildConfig.DEBUG && false; @@ -264,7 +265,8 @@ public class TextLayoutManagerMapBuffer { float width, YogaMeasureMode widthYogaMeasureMode, boolean includeFontPadding, - int textBreakStrategy) { + int textBreakStrategy, + int hyphenationFrequency) { Layout layout; int spanLength = text.length(); boolean unconstrainedWidth = widthYogaMeasureMode == YogaMeasureMode.UNDEFINED || width < 0; @@ -295,7 +297,7 @@ public class TextLayoutManagerMapBuffer { .setLineSpacing(0.f, 1.f) .setIncludePad(includeFontPadding) .setBreakStrategy(textBreakStrategy) - .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .setHyphenationFrequency(hyphenationFrequency) .build(); } @@ -338,7 +340,7 @@ public class TextLayoutManagerMapBuffer { .setLineSpacing(0.f, 1.f) .setIncludePad(includeFontPadding) .setBreakStrategy(textBreakStrategy) - .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL); + .setHyphenationFrequency(hyphenationFrequency); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { builder.setUseLineSpacingFromFallbacks(true); @@ -391,6 +393,9 @@ public class TextLayoutManagerMapBuffer { paragraphAttributes.hasKey(PA_KEY_INCLUDE_FONT_PADDING) ? paragraphAttributes.getBoolean(PA_KEY_INCLUDE_FONT_PADDING) : DEFAULT_INCLUDE_FONT_PADDING; + int hyphenationFrequency = + TextAttributeProps.getTextBreakStrategy( + paragraphAttributes.getString(PA_KEY_HYPHENATION_FREQUENCY)); if (text == null) { throw new IllegalStateException("Spannable element has not been prepared in onBeforeLayout"); @@ -404,7 +409,13 @@ public class TextLayoutManagerMapBuffer { Layout layout = createLayout( - text, boring, width, widthYogaMeasureMode, includeFontPadding, textBreakStrategy); + text, + boring, + width, + widthYogaMeasureMode, + includeFontPadding, + textBreakStrategy, + hyphenationFrequency); int maximumNumberOfLines = paragraphAttributes.hasKey(PA_KEY_MAX_NUMBER_OF_LINES) @@ -561,10 +572,19 @@ public class TextLayoutManagerMapBuffer { paragraphAttributes.hasKey(PA_KEY_INCLUDE_FONT_PADDING) ? paragraphAttributes.getBoolean(PA_KEY_INCLUDE_FONT_PADDING) : DEFAULT_INCLUDE_FONT_PADDING; + int hyphenationFrequency = + TextAttributeProps.getTextBreakStrategy( + paragraphAttributes.getString(PA_KEY_HYPHENATION_FREQUENCY)); Layout layout = createLayout( - text, boring, width, YogaMeasureMode.EXACTLY, includeFontPadding, textBreakStrategy); + text, + boring, + width, + YogaMeasureMode.EXACTLY, + includeFontPadding, + textBreakStrategy, + hyphenationFrequency); return FontMetricsUtil.getFontMetrics(text, layout, sTextPaintInstance, context); } diff --git a/ReactCommon/react/renderer/attributedstring/conversions.h b/ReactCommon/react/renderer/attributedstring/conversions.h index 8e3ed812eef..56ab6bdef94 100644 --- a/ReactCommon/react/renderer/attributedstring/conversions.h +++ b/ReactCommon/react/renderer/attributedstring/conversions.h @@ -1044,6 +1044,7 @@ constexpr static Key PA_KEY_ELLIPSIZE_MODE = 1; constexpr static Key PA_KEY_TEXT_BREAK_STRATEGY = 2; constexpr static Key PA_KEY_ADJUST_FONT_SIZE_TO_FIT = 3; constexpr static Key PA_KEY_INCLUDE_FONT_PADDING = 4; +constexpr static Key PA_KEY_HYPHENATION_FREQUENCY = 5; inline MapBuffer toMapBuffer(const ParagraphAttributes ¶graphAttributes) { auto builder = MapBufferBuilder(); @@ -1058,6 +1059,9 @@ inline MapBuffer toMapBuffer(const ParagraphAttributes ¶graphAttributes) { PA_KEY_ADJUST_FONT_SIZE_TO_FIT, paragraphAttributes.adjustsFontSizeToFit); builder.putBool( PA_KEY_INCLUDE_FONT_PADDING, paragraphAttributes.includeFontPadding); + builder.putString( + PA_KEY_HYPHENATION_FREQUENCY, + toString(paragraphAttributes.android_hyphenationFrequency)); return builder.build(); }