From da95ef967010488cb789f3f4f574c59e8fecea19 Mon Sep 17 00:00:00 2001 From: Evan Katz Date: Wed, 5 Aug 2026 15:00:36 -0700 Subject: [PATCH] Add Android text font variation settings (#57804) Summary: Pull Request resolved: https://github.com/react/react-native/pull/57804 Add a `fontVariationSettings` text style prop and carry it through Fabric text attributes into Android text rendering. Android now deserializes the prop for ``, applies it to `Paint`, and includes it in text measurement cache identity because variable axes can affect layout. Preserve the distinction between an absent setting and an explicitly empty setting so nested text can inherit or clear the parent variation axes. Apply high-level font properties before low-level variation settings so explicit axes take precedence, matching CSS font realization order. Settings syntax is intentionally forwarded unchanged through common text attributes and validated only by the Android font variation parser. This avoids narrowing the grammar Android accepts. As a result, malformed child settings are outside the supported inheritance contract: they replace an inherited value before Android validation and are not guaranteed to fall back to the parent settings. Android also accepts `normal` and the React Native empty-string convention as explicit resets. Changelog: [Android][Added] - Add `fontVariationSettings` support for `` Reviewed By: Abbondanzo, huntie Differential Revision: D113580491 --- .../View/ReactNativeStyleAttributes.js | 1 + .../Libraries/StyleSheet/StyleSheetTypes.d.ts | 6 ++ .../Libraries/StyleSheet/StyleSheetTypes.js | 6 ++ .../ReactAndroid/api/ReactAndroid.api | 3 + .../com/facebook/react/uimanager/ViewProps.kt | 1 + .../views/scroll/ReactNestedScrollView.kt | 4 +- .../scroll/ReactNestedScrollViewManager.kt | 8 +-- .../react/views/text/ReactTypefaceUtils.kt | 43 +++++++++++ .../react/views/text/TextAttributeProps.kt | 10 +++ .../react/views/text/TextLayoutManager.kt | 7 ++ .../text/internal/span/CustomStyleSpan.kt | 5 ++ .../react/views/textinput/ReactEditText.kt | 4 +- .../views/text/TextAttributePropsTest.kt | 57 +++++++++++++++ ...xtLayoutManagerFontWeightAdjustmentTest.kt | 63 ++++++++++++++++ .../attributedstring/TextAttributes.cpp | 9 +++ .../attributedstring/TextAttributes.h | 2 + .../renderer/attributedstring/conversions.h | 4 ++ .../components/text/BaseTextProps.cpp | 20 ++++++ .../text/tests/BaseTextShadowNodeTest.cpp | 72 +++++++++++++++++++ .../textlayoutmanager/TextMeasureCache.h | 3 + .../tests/TextLayoutManagerTest.cpp | 33 +++++++++ packages/react-native/ReactNativeApi.d.ts | 17 ++--- .../api-snapshots/ReactAndroidDebugCxx.api | 2 + .../api-snapshots/ReactAndroidNewarchCxx.api | 2 + .../api-snapshots/ReactAndroidReleaseCxx.api | 2 + .../api-snapshots/ReactAppleDebugCxx.api | 1 + .../api-snapshots/ReactAppleNewarchCxx.api | 1 + .../api-snapshots/ReactAppleReleaseCxx.api | 1 + .../api-snapshots/ReactCommonDebugCxx.api | 1 + .../api-snapshots/ReactCommonNewarchCxx.api | 1 + .../api-snapshots/ReactCommonReleaseCxx.api | 1 + 31 files changed, 375 insertions(+), 15 deletions(-) diff --git a/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js b/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js index bb1e941b57af..68d4fa451f56 100644 --- a/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -258,6 +258,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { fontSize: true, fontStyle: true, fontVariant: fontVariantAttribute, + fontVariationSettings: true, fontWeight: true, includeFontPadding: true, letterSpacing: true, diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts index 80c004612b10..8e17f07e04fc 100644 --- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts +++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts @@ -601,6 +601,12 @@ export interface TextStyle extends TextStyleIOS, TextStyleAndroid, ViewStyle { | 'heavy' | 'black' | undefined; + /** + * Specifies OpenType font variation axis values using CSS syntax. An empty + * string resets inherited variation settings. On Android, this requires API + * level 26 or later. + */ + fontVariationSettings?: string | undefined; letterSpacing?: number | undefined; lineHeight?: number | undefined; textAlign?: diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js index c04cfe1c4b20..9df143c6efe1 100644 --- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js +++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js @@ -1011,6 +1011,12 @@ type ____TextStyle_InternalBase = Readonly<{ */ fontWeight?: ____FontWeight_Internal, fontVariant?: ____FontVariantArray_Internal | string, + /** + * Specifies OpenType font variation axis values using CSS syntax. An empty + * string resets inherited variation settings. On Android, this requires API + * level 26 or later. + */ + fontVariationSettings?: string, textShadowOffset?: Readonly<{ width: number, height: number, diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index f69f43bce001..02bfc4b552f0 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -4543,6 +4543,7 @@ public final class com/facebook/react/uimanager/ViewProps { public static final field FONT_SIZE Ljava/lang/String; public static final field FONT_STYLE Ljava/lang/String; public static final field FONT_VARIANT Ljava/lang/String; + public static final field FONT_VARIATION_SETTINGS Ljava/lang/String; public static final field FONT_WEIGHT Ljava/lang/String; public static final field FOREGROUND_COLOR Ljava/lang/String; public static final field GAP Ljava/lang/String; @@ -6140,6 +6141,7 @@ public final class com/facebook/react/views/text/TextAttributeProps { public static final field TA_KEY_FONT_SIZE_MULTIPLIER I public static final field TA_KEY_FONT_STYLE I public static final field TA_KEY_FONT_VARIANT I + public static final field TA_KEY_FONT_VARIATION_SETTINGS I public static final field TA_KEY_FONT_WEIGHT I public static final field TA_KEY_FOREGROUND_COLOR I public static final field TA_KEY_IS_HIGHLIGHTED I @@ -6170,6 +6172,7 @@ public final class com/facebook/react/views/text/TextAttributeProps { public final fun getFontFeatureSettings ()Ljava/lang/String; public final fun getFontSize ()I public final fun getFontStyle ()I + public final fun getFontVariationSettings ()Ljava/lang/String; public final fun getFontWeight ()I public final fun getLayoutDirection ()I public final fun getLetterSpacing ()F diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.kt index 23c4b0a97443..07d7e132e7d6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.kt @@ -84,6 +84,7 @@ public object ViewProps { public const val FONT_WEIGHT: String = "fontWeight" public const val FONT_STYLE: String = "fontStyle" public const val FONT_VARIANT: String = "fontVariant" + public const val FONT_VARIATION_SETTINGS: String = "fontVariationSettings" public const val FONT_FAMILY: String = "fontFamily" public const val LINE_HEIGHT: String = "lineHeight" public const val LETTER_SPACING: String = "letterSpacing" diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollView.kt index d4db73d704b1..b284e2437b96 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollView.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<21f8ac172eefdbfa94cab925e21d7a99>> + * @generated SignedSource<<497c1f334f6b3325e032e09947f6fce4>> */ /** @@ -403,7 +403,7 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) : } internal open fun setMaintainVisibleContentPosition( - config: MaintainVisibleScrollPositionHelper.Config? + config: MaintainVisibleScrollPositionHelper.Config?, ) { if (config != null && maintainVisibleContentPositionHelper == null) { maintainVisibleContentPositionHelper = diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollViewManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollViewManager.kt index 09e25e2d6243..d5a3740c647a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollViewManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollViewManager.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<543b6175d2ce5e4ec68f1625f0c04095>> + * @generated SignedSource<<1ea0f64fa8acd99b50c7ef54da014b3e>> */ /** @@ -321,7 +321,7 @@ constructor(private val fpsListener: FpsListener? = null) : val child = scrollView.getChildAt(0) ?: throw RetryableMountingLayerException( - "scrollToEnd called on ScrollView without child" + "scrollToEnd called on ScrollView without child", ) // ScrollView always has one child - the scrollable area @@ -367,7 +367,7 @@ constructor(private val fpsListener: FpsListener? = null) : if (view.fadingEdgeLengthStart > 0 || view.fadingEdgeLengthEnd > 0) { view.isVerticalFadingEdgeEnabled = true view.setFadingEdgeLength( - Math.round(Math.max(view.fadingEdgeLengthStart, view.fadingEdgeLengthEnd).dpToPx()) + Math.round(Math.max(view.fadingEdgeLengthStart, view.fadingEdgeLengthEnd).dpToPx()), ) } else { view.isVerticalFadingEdgeEnabled = false @@ -384,7 +384,7 @@ constructor(private val fpsListener: FpsListener? = null) : public fun setMaintainVisibleContentPosition(view: ReactNestedScrollView, value: ReadableMap?) { if (value != null) { view.setMaintainVisibleContentPosition( - MaintainVisibleScrollPositionHelper.Config.fromReadableMap(value) + MaintainVisibleScrollPositionHelper.Config.fromReadableMap(value), ) } else { view.setMaintainVisibleContentPosition(null) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTypefaceUtils.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTypefaceUtils.kt index 71dc93dda720..df6eb1dd880f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTypefaceUtils.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTypefaceUtils.kt @@ -10,8 +10,11 @@ package com.facebook.react.views.text import android.content.Context import android.content.res.AssetManager import android.content.res.Configuration +import android.graphics.Paint import android.graphics.Typeface +import android.graphics.fonts.FontVariationAxis import android.os.Build +import com.facebook.common.logging.FLog import com.facebook.react.bridge.ReadableArray import com.facebook.react.common.ReactConstants import com.facebook.react.common.assets.ReactFontManager @@ -151,4 +154,44 @@ public object ReactTypefaceUtils { return Typeface.create(baseTypeface, adjustedWeight, italic) } + + internal fun parseFontVariationSettings(fontVariationSettings: String?): String? { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + return null + } + + if (fontVariationSettings.isNullOrEmpty()) { + return fontVariationSettings + } + + if (fontVariationSettings.trim().equals("normal", ignoreCase = true)) { + return "" + } + + return try { + FontVariationAxis.fromFontVariationSettings(fontVariationSettings) + fontVariationSettings + } catch (exception: IllegalArgumentException) { + FLog.w(ReactConstants.TAG, "Invalid fontVariationSettings: $fontVariationSettings") + null + } + } + + internal fun applyFontVariationSettings(paint: Paint, fontVariationSettings: String?) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + return + } + + try { + paint.setFontVariationSettings(fontVariationSettings) + } catch (exception: IllegalArgumentException) { + // Paint instances are reused, so explicitly clear axes from a previous layout. + paint.setFontVariationSettings(null) + FLog.w( + ReactConstants.TAG, + "Invalid fontVariationSettings: $fontVariationSettings", + exception, + ) + } + } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.kt index 7ad338167d5e..4ebaa5630c09 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.kt @@ -25,6 +25,7 @@ import com.facebook.react.uimanager.ReactStylesDiffMap import com.facebook.react.uimanager.ViewProps import com.facebook.react.views.text.ReactTypefaceUtils.parseFontStyle import com.facebook.react.views.text.ReactTypefaceUtils.parseFontVariant +import com.facebook.react.views.text.ReactTypefaceUtils.parseFontVariationSettings import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight import kotlin.math.ceil @@ -153,6 +154,10 @@ public class TextAttributeProps private constructor() { public var fontFeatureSettings: String? = null private set + /** @see android.graphics.Paint.setFontVariationSettings */ + public var fontVariationSettings: String? = null + private set + @Deprecated("Use lineHeight instead", ReplaceWith("lineHeight")) public val effectiveLineHeight: Float get() = lineHeight @@ -396,6 +401,7 @@ public class TextAttributeProps private constructor() { public const val TA_KEY_TEXT_TRANSFORM: Int = 27 public const val TA_KEY_MAX_FONT_SIZE_MULTIPLIER: Int = 29 public const val TA_KEY_TEXT_EFFECTS: Int = 30 + public const val TA_KEY_FONT_VARIATION_SETTINGS: Int = 31 private const val TE_KEY_NAME: Int = 0 private const val TE_KEY_PROPS: Int = 1 @@ -433,6 +439,8 @@ public class TextAttributeProps private constructor() { TA_KEY_FONT_WEIGHT -> result.setFontWeight(entry.stringValue) TA_KEY_FONT_STYLE -> result.setFontStyle(entry.stringValue) TA_KEY_FONT_VARIANT -> result.setFontVariant(entry.mapBufferValue) + TA_KEY_FONT_VARIATION_SETTINGS -> + result.fontVariationSettings = parseFontVariationSettings(entry.stringValue) TA_KEY_ALLOW_FONT_SCALING -> result.allowFontScaling = entry.booleanValue TA_KEY_LETTER_SPACING -> result.letterSpacing = entry.doubleValue.toFloat() TA_KEY_LINE_HEIGHT -> result.lineHeight = entry.doubleValue.toFloat() @@ -500,6 +508,8 @@ public class TextAttributeProps private constructor() { result.setFontWeight(getStringProp(props, ViewProps.FONT_WEIGHT)) result.setFontStyle(getStringProp(props, ViewProps.FONT_STYLE)) result.setFontVariant(getArrayProp(props, ViewProps.FONT_VARIANT)) + result.fontVariationSettings = + parseFontVariationSettings(getStringProp(props, ViewProps.FONT_VARIATION_SETTINGS)) result.includeFontPadding = getBooleanProp(props, ViewProps.INCLUDE_FONT_PADDING, true) result.setTextDecorationLine(getStringProp(props, ViewProps.TEXT_DECORATION_LINE)) result.textDecorationColor = diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt index e64f5de40759..5e0f6575c6dc 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt @@ -313,6 +313,7 @@ internal object TextLayoutManager { if ( textAttributes.fontStyle != ReactConstants.UNSET || textAttributes.fontWeight != ReactConstants.UNSET || + textAttributes.fontVariationSettings != null || textAttributes.fontFamily != null ) { ops.add( @@ -323,6 +324,7 @@ internal object TextLayoutManager { textAttributes.fontStyle, textAttributes.fontWeight, textAttributes.fontFeatureSettings, + textAttributes.fontVariationSettings, textAttributes.fontFamily, assets, fontWeightAdjustment, @@ -547,6 +549,7 @@ internal object TextLayoutManager { if ( fragment.props.fontStyle != ReactConstants.UNSET || fragment.props.fontWeight != ReactConstants.UNSET || + fragment.props.fontVariationSettings != null || fragment.props.fontFamily != null ) { spannable.setSpan( @@ -554,6 +557,7 @@ internal object TextLayoutManager { fragment.props.fontStyle, fragment.props.fontWeight, fragment.props.fontFeatureSettings, + fragment.props.fontVariationSettings, fragment.props.fontFamily, assets, fontWeightAdjustment, @@ -883,6 +887,7 @@ internal object TextLayoutManager { if ( baseTextAttributes.fontStyle != ReactConstants.UNSET || baseTextAttributes.fontWeight != ReactConstants.UNSET || + baseTextAttributes.fontVariationSettings != null || baseTextAttributes.fontFamily != null ) { val typeface = @@ -912,6 +917,8 @@ internal object TextLayoutManager { paint.setTypeface(typeface) } } + + ReactTypefaceUtils.applyFontVariationSettings(paint, baseTextAttributes.fontVariationSettings) } /** diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/CustomStyleSpan.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/CustomStyleSpan.kt index 29eb30f14470..a0607b012be6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/CustomStyleSpan.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/CustomStyleSpan.kt @@ -31,6 +31,7 @@ internal class CustomStyleSpan( private val privateStyle: Int, private val privateWeight: Int, val fontFeatureSettings: String?, + val fontVariationSettings: String?, val fontFamily: String?, private val assetManager: AssetManager, private val fontWeightAdjustment: Int = 0, @@ -41,6 +42,7 @@ internal class CustomStyleSpan( privateStyle, privateWeight, fontFeatureSettings, + fontVariationSettings, fontFamily, assetManager, fontWeightAdjustment, @@ -53,6 +55,7 @@ internal class CustomStyleSpan( privateStyle, privateWeight, fontFeatureSettings, + fontVariationSettings, fontFamily, assetManager, fontWeightAdjustment, @@ -81,6 +84,7 @@ internal class CustomStyleSpan( style: Int, weight: Int, fontFeatureSettingsParam: String?, + fontVariationSettingsParam: String?, family: String?, assetManager: AssetManager, fontWeightAdjustment: Int, @@ -92,6 +96,7 @@ internal class CustomStyleSpan( paint.apply { fontFeatureSettings = fontFeatureSettingsParam setTypeface(adjustedTypeface) + ReactTypefaceUtils.applyFontVariationSettings(this, fontVariationSettingsParam) isSubpixelText = true isLinearText = true } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt index 50dea1239a40..fd9e3f123d8f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt @@ -826,7 +826,8 @@ public open class ReactEditText public constructor(context: Context) : AppCompat span.style == fontStyle && span.fontFamily == fontFamily && span.weight == fontWeight && - span.fontFeatureSettings == fontFeatureSettings + span.fontFeatureSettings == fontFeatureSettings && + span.fontVariationSettings == null } } @@ -908,6 +909,7 @@ public open class ReactEditText public constructor(context: Context) : AppCompat fontStyle, fontWeight, fontFeatureSettings, + null, fontFamily, context.assets, getFontWeightAdjustment(context), diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextAttributePropsTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextAttributePropsTest.kt index 0b63ff69a2a6..81d269ffd167 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextAttributePropsTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextAttributePropsTest.kt @@ -9,12 +9,69 @@ package com.facebook.react.views.text import android.view.Gravity import com.facebook.react.bridge.JavaOnlyMap +import com.facebook.react.uimanager.DisplayMetricsHolder import com.facebook.react.uimanager.ReactStylesDiffMap import org.assertj.core.api.Assertions.assertThat +import org.junit.After +import org.junit.Before import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +@RunWith(RobolectricTestRunner::class) class TextAttributePropsTest { + @Before + fun setUp() { + DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(RuntimeEnvironment.getApplication()) + } + + @After + fun tearDown() { + DisplayMetricsHolder.setScreenDisplayMetrics(null) + } + + @Test + fun readableMapSetsFontVariationSettings() { + val textAttributes = + TextAttributeProps.fromReadableMap( + ReactStylesDiffMap(JavaOnlyMap.of("fontVariationSettings", "'wght' 550")) + ) + + assertThat(textAttributes.fontVariationSettings).isEqualTo("'wght' 550") + } + + @Test + fun readableMapSetsDoubleQuotedFontVariationSettings() { + val textAttributes = + TextAttributeProps.fromReadableMap( + ReactStylesDiffMap(JavaOnlyMap.of("fontVariationSettings", "\"wght\" 450")) + ) + + assertThat(textAttributes.fontVariationSettings).isEqualTo("\"wght\" 450") + } + + @Test + fun readableMapIgnoresInvalidFontVariationSettings() { + val textAttributes = + TextAttributeProps.fromReadableMap( + ReactStylesDiffMap(JavaOnlyMap.of("fontVariationSettings", "invalid")) + ) + + assertThat(textAttributes.fontVariationSettings).isNull() + } + + @Test + fun readableMapTreatsNormalFontVariationSettingsAsExplicitReset() { + val textAttributes = + TextAttributeProps.fromReadableMap( + ReactStylesDiffMap(JavaOnlyMap.of("fontVariationSettings", "NoRmAl")) + ) + + assertThat(textAttributes.fontVariationSettings).isEmpty() + } + @Test fun textAlignStartUsesStartSide() { assertThat(textAlignment("start", isRTL = false)).isEqualTo(Gravity.LEFT) diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerFontWeightAdjustmentTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerFontWeightAdjustmentTest.kt index 3cc6751e6e0b..cfa95850489c 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerFontWeightAdjustmentTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerFontWeightAdjustmentTest.kt @@ -7,19 +7,30 @@ package com.facebook.react.views.text +import android.graphics.Paint +import android.graphics.Typeface +import android.os.Build import android.text.TextPaint +import androidx.annotation.RequiresApi import com.facebook.react.bridge.JavaOnlyMap import com.facebook.react.uimanager.DisplayMetricsHolder import com.facebook.react.uimanager.ReactStylesDiffMap +import com.facebook.react.views.text.internal.span.CustomStyleSpan import org.assertj.core.api.Assertions.assertThat import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.inOrder +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config +@RequiresApi(Build.VERSION_CODES.O) @RunWith(RobolectricTestRunner::class) @Config(sdk = [34]) class TextLayoutManagerFontWeightAdjustmentTest { @@ -64,6 +75,58 @@ class TextLayoutManagerFontWeightAdjustmentTest { assertThat(paint.typeface).isNull() } + @Test + fun `plain text paint ignores invalid font variation settings`() { + val paint = TextPaint(TextPaint.ANTI_ALIAS_FLAG) + val textAttributes = + TextAttributeProps.fromReadableMap( + ReactStylesDiffMap(JavaOnlyMap.of("fontVariationSettings", "invalid")) + ) + + TextLayoutManager.updateTextPaint( + paint, + textAttributes, + RuntimeEnvironment.getApplication().assets, + 0, + ) + + assertThat(paint.fontVariationSettings).isNull() + } + + @Test + fun `custom style applies font variation settings after high level font properties`() { + val paint = mock() + val span = CustomStyleSpan( + Typeface.NORMAL, + 700, + null, + "'wght' 450", + "sans-serif", + RuntimeEnvironment.getApplication().assets, + ) + + span.updateMeasureState(paint) + + inOrder(paint) { + verify(paint).setTypeface(any()) + verify(paint).setFontVariationSettings("'wght' 450") + } + } + + @Test + fun `invalid font variation settings defensively clear a reused paint`() { + val paint = mock() + val invalidSettings = "invalid-reused-paint-test" + whenever(paint.setFontVariationSettings(invalidSettings)).thenThrow(IllegalArgumentException()) + + ReactTypefaceUtils.applyFontVariationSettings(paint, "'wght' 700") + ReactTypefaceUtils.applyFontVariationSettings(paint, invalidSettings) + + verify(paint).setFontVariationSettings("'wght' 700") + verify(paint).setFontVariationSettings(invalidSettings) + verify(paint).setFontVariationSettings(null) + } + private companion object { const val FONT_WEIGHT_ADJUSTMENT_BOLD_TEXT = 300 } diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp index be2e1a2d481b..5851ec21dfff 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp @@ -43,6 +43,9 @@ void TextAttributes::apply(TextAttributes textAttributes) { fontVariant = textAttributes.fontVariant.has_value() ? textAttributes.fontVariant : fontVariant; + fontVariationSettings = textAttributes.fontVariationSettings.has_value() + ? textAttributes.fontVariationSettings + : fontVariationSettings; allowFontScaling = textAttributes.allowFontScaling.has_value() ? textAttributes.allowFontScaling : allowFontScaling; @@ -128,6 +131,7 @@ bool TextAttributes::operator==(const TextAttributes& rhs) const { fontWeight, fontStyle, fontVariant, + fontVariationSettings, allowFontScaling, dynamicTypeRamp, alignment, @@ -152,6 +156,7 @@ bool TextAttributes::operator==(const TextAttributes& rhs) const { rhs.fontWeight, rhs.fontStyle, rhs.fontVariant, + rhs.fontVariationSettings, rhs.allowFontScaling, rhs.dynamicTypeRamp, rhs.alignment, @@ -218,6 +223,10 @@ SharedDebugStringConvertibleList TextAttributes::getDebugProps() const { "fontStyle", fontStyle, textAttributes.fontStyle), debugStringConvertibleItem( "fontVariant", fontVariant, textAttributes.fontVariant), + debugStringConvertibleItem( + "fontVariationSettings", + fontVariationSettings, + textAttributes.fontVariationSettings), debugStringConvertibleItem( "allowFontScaling", allowFontScaling, diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h index c162deee2f73..683c993bf968 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h @@ -58,6 +58,7 @@ class TextAttributes : public DebugStringConvertible { std::optional fontWeight{}; std::optional fontStyle{}; std::optional fontVariant{}; + std::optional fontVariationSettings{}; std::optional allowFontScaling{}; Float maxFontSizeMultiplier{std::numeric_limits::quiet_NaN()}; std::optional dynamicTypeRamp{}; @@ -143,6 +144,7 @@ struct hash { textAttributes.fontWeight, textAttributes.fontStyle, textAttributes.fontVariant, + textAttributes.fontVariationSettings, textAttributes.allowFontScaling, textAttributes.letterSpacing, textAttributes.textTransform, diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h b/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h index 235e966ae131..beed96737801 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h @@ -1142,6 +1142,7 @@ constexpr static MapBuffer::Key TA_KEY_TEXT_TRANSFORM = 27; constexpr static MapBuffer::Key TA_KEY_ALIGNMENT_VERTICAL = 28; constexpr static MapBuffer::Key TA_KEY_MAX_FONT_SIZE_MULTIPLIER = 29; constexpr static MapBuffer::Key TA_KEY_TEXT_EFFECTS = 30; +constexpr static MapBuffer::Key TA_KEY_FONT_VARIATION_SETTINGS = 31; // Keys within each text effect entry MapBuffer constexpr static MapBuffer::Key TE_KEY_NAME = 0; @@ -1290,6 +1291,9 @@ inline MapBuffer toMapBuffer(const TextAttributes &textAttributes) auto fontVariantMap = toMapBuffer(*textAttributes.fontVariant); builder.putMapBuffer(TA_KEY_FONT_VARIANT, fontVariantMap); } + if (textAttributes.fontVariationSettings.has_value()) { + builder.putString(TA_KEY_FONT_VARIATION_SETTINGS, *textAttributes.fontVariationSettings); + } if (textAttributes.allowFontScaling.has_value()) { builder.putBool(TA_KEY_ALLOW_FONT_SCALING, *textAttributes.allowFontScaling); } diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp index 51fd245e4209..135463aa2d09 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp @@ -67,6 +67,12 @@ static TextAttributes convertRawProp( "fontVariant", sourceTextAttributes.fontVariant, defaultTextAttributes.fontVariant); + textAttributes.fontVariationSettings = convertRawProp( + context, + rawProps, + "fontVariationSettings", + sourceTextAttributes.fontVariationSettings, + defaultTextAttributes.fontVariationSettings); textAttributes.allowFontScaling = convertRawProp( context, rawProps, @@ -261,6 +267,12 @@ void BaseTextProps::setProp( defaults, value, textAttributes, fontStyle, "fontStyle"); REBUILD_FIELD_SWITCH_CASE( defaults, value, textAttributes, fontVariant, "fontVariant"); + REBUILD_FIELD_SWITCH_CASE( + defaults, + value, + textAttributes, + fontVariationSettings, + "fontVariationSettings"); REBUILD_FIELD_SWITCH_CASE( defaults, value, textAttributes, allowFontScaling, "allowFontScaling"); REBUILD_FIELD_SWITCH_CASE( @@ -393,6 +405,14 @@ void BaseTextProps::appendTextAttributesProps( : folly::dynamic(nullptr); } + if (textAttributes.fontVariationSettings != + oldProps->textAttributes.fontVariationSettings) { + result["fontVariationSettings"] = + textAttributes.fontVariationSettings.has_value() + ? folly::dynamic(*textAttributes.fontVariationSettings) + : folly::dynamic(nullptr); + } + if (textAttributes.allowFontScaling != oldProps->textAttributes.allowFontScaling) { result["allowFontScaling"] = textAttributes.allowFontScaling.has_value() diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/tests/BaseTextShadowNodeTest.cpp b/packages/react-native/ReactCommon/react/renderer/components/text/tests/BaseTextShadowNodeTest.cpp index 560f2e661e84..0d4ad930c520 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/tests/BaseTextShadowNodeTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/text/tests/BaseTextShadowNodeTest.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,43 @@ std::string roundTripTextAlignment(const char* textAlignment) { return toString(result); } +TextAttributes nestedTextAttributes( + const std::shared_ptr& parentProps, + const std::shared_ptr& childProps) { + auto builder = simpleComponentBuilder(); + auto shadowNode = builder.build( + Element().children({ + Element() + .props(parentProps) + .children({ + Element() + .props(childProps) + .children({rawTextElement("Text")}), + }), + })); + + auto baseTextAttributes = TextAttributes::defaultTextAttributes(); + AttributedString output; + BaseTextShadowNode::Attachments attachments; + BaseTextShadowNode::buildAttributedString( + baseTextAttributes, *shadowNode, output, attachments); + + EXPECT_EQ(output.getFragments().size(), 1); + return output.getFragments()[0].textAttributes; +} + +std::shared_ptr textPropsWithRawFontVariationSettings( + const char* fontVariationSettings) { + ContextContainer contextContainer{}; + PropsParserContext parserContext{-1, contextContainer}; + auto rawProps = RawProps( + folly::dynamic::object("fontVariationSettings", fontVariationSettings)); + auto rawPropsParser = RawPropsParser{}; + rawPropsParser.prepare(); + rawProps.parse(rawPropsParser); + return std::make_shared(parserContext, TextProps{}, rawProps); +} + } // namespace TEST(BaseTextShadowNodeTest, textAlignmentStartAndEndRoundTrip) { @@ -107,4 +145,38 @@ TEST(BaseTextShadowNodeTest, rawTextIsMerged) { EXPECT_EQ(output.getFragments().size(), 1); } +TEST(BaseTextShadowNodeTest, childInheritsParentFontVariationSettings) { + auto parentProps = std::make_shared(); + parentProps->textAttributes.fontVariationSettings = "'wght' 650"; + auto childProps = std::make_shared(); + + const auto attributes = nestedTextAttributes(parentProps, childProps); + + EXPECT_EQ(attributes.fontVariationSettings, "'wght' 650"); +} + +TEST(BaseTextShadowNodeTest, childFontVariationSettingsReplaceParentList) { + auto parentProps = std::make_shared(); + parentProps->textAttributes.fontVariationSettings = "'wght' 650, 'wdth' 90"; + auto childProps = textPropsWithRawFontVariationSettings("'wdth' 110"); + + const auto attributes = nestedTextAttributes(parentProps, childProps); + + EXPECT_EQ(attributes.fontVariationSettings, "'wdth' 110"); +} + +TEST( + BaseTextShadowNodeTest, + childFontWeightCoexistsWithInheritedFontVariationSettings) { + auto parentProps = std::make_shared(); + parentProps->textAttributes.fontVariationSettings = "'wght' 650"; + auto childProps = std::make_shared(); + childProps->textAttributes.fontWeight = FontWeight::Weight400; + + const auto attributes = nestedTextAttributes(parentProps, childProps); + + EXPECT_EQ(attributes.fontWeight, FontWeight::Weight400); + EXPECT_EQ(attributes.fontVariationSettings, "'wght' 650"); +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/TextMeasureCache.h b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/TextMeasureCache.h index f062132f2741..e302e5f7dded 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/TextMeasureCache.h +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/TextMeasureCache.h @@ -125,6 +125,7 @@ inline bool areTextAttributesEquivalentLayoutWise(const TextAttributes &lhs, con lhs.fontWeight, lhs.fontStyle, lhs.fontVariant, + lhs.fontVariationSettings, lhs.allowFontScaling, lhs.dynamicTypeRamp, lhs.alignment) == @@ -133,6 +134,7 @@ inline bool areTextAttributesEquivalentLayoutWise(const TextAttributes &lhs, con rhs.fontWeight, rhs.fontStyle, rhs.fontVariant, + rhs.fontVariationSettings, rhs.allowFontScaling, rhs.dynamicTypeRamp, rhs.alignment) && @@ -152,6 +154,7 @@ inline size_t textAttributesHashLayoutWise(const TextAttributes &textAttributes) textAttributes.fontWeight, textAttributes.fontStyle, textAttributes.fontVariant, + textAttributes.fontVariationSettings, textAttributes.allowFontScaling, textAttributes.maxFontSizeMultiplier, textAttributes.dynamicTypeRamp, diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/tests/TextLayoutManagerTest.cpp b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/tests/TextLayoutManagerTest.cpp index d19545a83f67..3b687657917b 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/tests/TextLayoutManagerTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/tests/TextLayoutManagerTest.cpp @@ -48,6 +48,39 @@ TEST(TextLayoutManagerTest, maxFontSizeMultiplierAffectsLayoutCacheHash) { textAttributesHashLayoutWise(lhs), textAttributesHashLayoutWise(rhs)); } +TEST(TextLayoutManagerTest, fontVariationSettingsAffectLayoutCacheEquality) { + TextAttributes lhs; + TextAttributes rhs; + + lhs.fontVariationSettings = "'wght' 400"; + rhs.fontVariationSettings = "'wght' 700"; + + EXPECT_FALSE(areTextAttributesEquivalentLayoutWise(lhs, rhs)); +} + +TEST(TextLayoutManagerTest, fontVariationSettingsAffectLayoutCacheHash) { + TextAttributes lhs; + TextAttributes rhs; + + lhs.fontVariationSettings = "'wght' 400"; + rhs.fontVariationSettings = "'wght' 700"; + + EXPECT_NE( + textAttributesHashLayoutWise(lhs), textAttributesHashLayoutWise(rhs)); +} + +TEST(TextLayoutManagerTest, emptyFontVariationSettingsClearInheritedSettings) { + TextAttributes parent; + TextAttributes child; + + parent.fontVariationSettings = "'wght' 700"; + child.fontVariationSettings = ""; + parent.apply(child); + + EXPECT_TRUE(parent.fontVariationSettings.has_value()); + EXPECT_TRUE(parent.fontVariationSettings->empty()); +} + // Measurements are rounded to the pixel grid, so a measurement cached at one // pixel scale factor must not satisfy a lookup at another. Keys that differ // only by pointScaleFactor must compare unequal. diff --git a/packages/react-native/ReactNativeApi.d.ts b/packages/react-native/ReactNativeApi.d.ts index 24f632825a84..b895f37a3ff0 100644 --- a/packages/react-native/ReactNativeApi.d.ts +++ b/packages/react-native/ReactNativeApi.d.ts @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> * * This file was generated by scripts/js-api/build-types/index.js. */ @@ -744,6 +744,7 @@ declare type ____TextStyle_InternalBase = { readonly fontSize?: number readonly fontStyle?: "italic" | "normal" readonly fontVariant?: ____FontVariantArray_Internal | string + readonly fontVariationSettings?: string readonly fontWeight?: ____FontWeight_Internal readonly includeFontPadding?: boolean readonly letterSpacing?: number @@ -5714,7 +5715,7 @@ export { AlertOptions, // 8a116d2a AlertType, // 5ab91217 AndroidKeyboardEvent, // e03becc8 - Animated, // 50cbe576 + Animated, // 4bf77b70 AppConfig, // 35c0ca70 AppRegistry, // 1e8c5a00 AppState, // 12012be5 @@ -5937,7 +5938,7 @@ export { StatusBarProps, // c2a44d88 StatusBarStyle, // 78f53eea StyleProp, // fa0e9b4a - StyleSheet, // e734acd4 + StyleSheet, // 3c21ec63 SubmitBehavior, // c4ddf490 Switch, // f495bab3 SwitchChangeEvent, // 899635b1 @@ -5947,9 +5948,9 @@ export { TVViewPropsIOS, // 330ce7b5 TargetedEvent, // 16e98910 TaskProvider, // 266dedf2 - Text, // 9ceaff08 + Text, // 09e783b9 TextContentType, // 239b3ecc - TextInput, // ce1e41ff + TextInput, // a2cc82d1 TextInputAndroidProps, // 9ebbc103 TextInputBlurEvent, // b77af40e TextInputChangeEvent, // f55eef98 @@ -5959,13 +5960,13 @@ export { TextInputIOSProps, // fb3c9327 TextInputInstance, // 5a0c0e0d TextInputKeyPressEvent, // 546c5d07 - TextInputProps, // c692f4de + TextInputProps, // dd91ebaa TextInputSelectionChangeEvent, // e58f2abc TextInputSubmitEditingEvent, // 6bcb2aa5 TextInstance, // 05463a96 TextLayoutEvent, // 3f54186f - TextProps, // 93309fac - TextStyle, // b62b8399 + TextProps, // 4a122c2b + TextStyle, // 6ad4307f ToastAndroid, // 88a8969a TouchableHighlight, // 3a6eaed4 TouchableHighlightInstance, // b510c0eb diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api index dff12a0398b3..c46ce0ae25dc 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api @@ -523,6 +523,7 @@ static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_SI static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_SIZE_MULTIPLIER; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_STYLE; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_VARIANT; +static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_VARIATION_SETTINGS; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_WEIGHT; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FOREGROUND_COLOR; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_IS_HIGHLIGHTED; @@ -5011,6 +5012,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api index bae821b61ec2..9aaf7be6052a 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api @@ -523,6 +523,7 @@ static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_SI static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_SIZE_MULTIPLIER; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_STYLE; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_VARIANT; +static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_VARIATION_SETTINGS; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_WEIGHT; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FOREGROUND_COLOR; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_IS_HIGHLIGHTED; @@ -4822,6 +4823,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api index beb96517ca4e..2dcd7df641bf 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api @@ -523,6 +523,7 @@ static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_SI static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_SIZE_MULTIPLIER; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_STYLE; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_VARIANT; +static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_VARIATION_SETTINGS; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_WEIGHT; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FOREGROUND_COLOR; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_IS_HIGHLIGHTED; @@ -5002,6 +5003,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index c27595d7f77a..08edbf9b8886 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -7202,6 +7202,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api index c8a738e9069d..381fe9367c80 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api @@ -7041,6 +7041,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index 3d09b6d29173..fe6bc0e042b4 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -7193,6 +7193,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api index 0c7d0a5b8a1c..82f34060bfaf 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api @@ -3525,6 +3525,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api index 4b6b80e8c2b8..26ed4473aab4 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api @@ -3376,6 +3376,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api index a0e1c10862b6..ec7d627bb4e2 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api @@ -3516,6 +3516,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes);