diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt index 96b3f40988a..3e856366795 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.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<<43590bc324e803ccf299e2a6ae6c5304>> + * @generated SignedSource<<62715a19c87a010716eb7d2e904258fa>> */ /** @@ -138,6 +138,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun enableFontScaleChangesUpdatingLayout(): Boolean = accessor.enableFontScaleChangesUpdatingLayout() + /** + * Applies base offset for each line of text separately on iOS. + */ + @JvmStatic + public fun enableIOSTextBaselineOffsetPerLine(): Boolean = accessor.enableIOSTextBaselineOffsetPerLine() + /** * iOS Views will clip to their padding box vs border box */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt index 9e8b53f411a..917536c853f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.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<<5609be38b50c62ff5097b3571940f400>> + * @generated SignedSource<<53e2f9241b9b3396b1ddf5893c7f3c4e>> */ /** @@ -38,6 +38,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces private var enableFabricRendererCache: Boolean? = null private var enableFixForParentTagDuringReparentingCache: Boolean? = null private var enableFontScaleChangesUpdatingLayoutCache: Boolean? = null + private var enableIOSTextBaselineOffsetPerLineCache: Boolean? = null private var enableIOSViewClipToPaddingBoxCache: Boolean? = null private var enableIntersectionObserverEventLoopIntegrationCache: Boolean? = null private var enableLayoutAnimationsOnAndroidCache: Boolean? = null @@ -232,6 +233,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun enableIOSTextBaselineOffsetPerLine(): Boolean { + var cached = enableIOSTextBaselineOffsetPerLineCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.enableIOSTextBaselineOffsetPerLine() + enableIOSTextBaselineOffsetPerLineCache = cached + } + return cached + } + override fun enableIOSViewClipToPaddingBox(): Boolean { var cached = enableIOSViewClipToPaddingBoxCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt index 6b8f3a264f8..18aea3d585c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.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<<15645e36bbca81dfcec07fc82f8f6264>> + * @generated SignedSource<<918dcdb416bb3e2e3f83cded78e06363>> */ /** @@ -64,6 +64,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun enableFontScaleChangesUpdatingLayout(): Boolean + @DoNotStrip @JvmStatic public external fun enableIOSTextBaselineOffsetPerLine(): Boolean + @DoNotStrip @JvmStatic public external fun enableIOSViewClipToPaddingBox(): Boolean @DoNotStrip @JvmStatic public external fun enableIntersectionObserverEventLoopIntegration(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index 4961fc2358b..df1df830bc6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.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<<9c7d04c48c4c5feb0d2fb250966550c8>> + * @generated SignedSource<<7151e167c4e45a732a341a2cfcf67b58>> */ /** @@ -59,6 +59,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun enableFontScaleChangesUpdatingLayout(): Boolean = false + override fun enableIOSTextBaselineOffsetPerLine(): Boolean = false + override fun enableIOSViewClipToPaddingBox(): Boolean = false override fun enableIntersectionObserverEventLoopIntegration(): Boolean = true diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt index 99153fc2adb..b849113bc6a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.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<> + * @generated SignedSource<> */ /** @@ -42,6 +42,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc private var enableFabricRendererCache: Boolean? = null private var enableFixForParentTagDuringReparentingCache: Boolean? = null private var enableFontScaleChangesUpdatingLayoutCache: Boolean? = null + private var enableIOSTextBaselineOffsetPerLineCache: Boolean? = null private var enableIOSViewClipToPaddingBoxCache: Boolean? = null private var enableIntersectionObserverEventLoopIntegrationCache: Boolean? = null private var enableLayoutAnimationsOnAndroidCache: Boolean? = null @@ -254,6 +255,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc return cached } + override fun enableIOSTextBaselineOffsetPerLine(): Boolean { + var cached = enableIOSTextBaselineOffsetPerLineCache + if (cached == null) { + cached = currentProvider.enableIOSTextBaselineOffsetPerLine() + accessedFeatureFlags.add("enableIOSTextBaselineOffsetPerLine") + enableIOSTextBaselineOffsetPerLineCache = cached + } + return cached + } + override fun enableIOSViewClipToPaddingBox(): Boolean { var cached = enableIOSViewClipToPaddingBoxCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt index 508199f083b..b89f5292d55 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.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<<3a61d9b66a7ed6fc9c76548aa72e3ed3>> + * @generated SignedSource<<722ed5b36a043d4eadb095f092c95707>> */ /** @@ -59,6 +59,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun enableFontScaleChangesUpdatingLayout(): Boolean + @DoNotStrip public fun enableIOSTextBaselineOffsetPerLine(): Boolean + @DoNotStrip public fun enableIOSViewClipToPaddingBox(): Boolean @DoNotStrip public fun enableIntersectionObserverEventLoopIntegration(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp index 2875ddf0278..e70adc38cc1 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp @@ -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<<93037428475b39d3f2c208e1326b3e86>> + * @generated SignedSource<<422a5922cfe14a1c5f7c0728410dbe8a>> */ /** @@ -147,6 +147,12 @@ class ReactNativeFeatureFlagsJavaProvider return method(javaProvider_); } + bool enableIOSTextBaselineOffsetPerLine() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableIOSTextBaselineOffsetPerLine"); + return method(javaProvider_); + } + bool enableIOSViewClipToPaddingBox() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableIOSViewClipToPaddingBox"); @@ -427,6 +433,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableFontScaleChangesUpdatingLayout( return ReactNativeFeatureFlags::enableFontScaleChangesUpdatingLayout(); } +bool JReactNativeFeatureFlagsCxxInterop::enableIOSTextBaselineOffsetPerLine( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::enableIOSTextBaselineOffsetPerLine(); +} + bool JReactNativeFeatureFlagsCxxInterop::enableIOSViewClipToPaddingBox( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::enableIOSViewClipToPaddingBox(); @@ -667,6 +678,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "enableFontScaleChangesUpdatingLayout", JReactNativeFeatureFlagsCxxInterop::enableFontScaleChangesUpdatingLayout), + makeNativeMethod( + "enableIOSTextBaselineOffsetPerLine", + JReactNativeFeatureFlagsCxxInterop::enableIOSTextBaselineOffsetPerLine), makeNativeMethod( "enableIOSViewClipToPaddingBox", JReactNativeFeatureFlagsCxxInterop::enableIOSViewClipToPaddingBox), diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h index 8eac16b566b..8de4854606c 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h @@ -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<<18d7c9c2577450a0bb7e6da91b8597ed>> */ /** @@ -84,6 +84,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool enableFontScaleChangesUpdatingLayout( facebook::jni::alias_ref); + static bool enableIOSTextBaselineOffsetPerLine( + facebook::jni::alias_ref); + static bool enableIOSViewClipToPaddingBox( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index 550ab56014d..2cab45a1578 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp @@ -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<<9f34463a7cddcfd1a76631041297c4b7>> */ /** @@ -98,6 +98,10 @@ bool ReactNativeFeatureFlags::enableFontScaleChangesUpdatingLayout() { return getAccessor().enableFontScaleChangesUpdatingLayout(); } +bool ReactNativeFeatureFlags::enableIOSTextBaselineOffsetPerLine() { + return getAccessor().enableIOSTextBaselineOffsetPerLine(); +} + bool ReactNativeFeatureFlags::enableIOSViewClipToPaddingBox() { return getAccessor().enableIOSViewClipToPaddingBox(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index bccadbae54f..e175480022e 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -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<<83ef02f26eaf2d847efd7042ae6d1dfc>> + * @generated SignedSource<> */ /** @@ -129,6 +129,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool enableFontScaleChangesUpdatingLayout(); + /** + * Applies base offset for each line of text separately on iOS. + */ + RN_EXPORT static bool enableIOSTextBaselineOffsetPerLine(); + /** * iOS Views will clip to their padding box vs border box */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index 606fe8c01a6..b46a6ac59a9 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp @@ -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<<0d1e4f0581e3aa90e18dc70ccee8a50a>> + * @generated SignedSource<> */ /** @@ -353,6 +353,24 @@ bool ReactNativeFeatureFlagsAccessor::enableFontScaleChangesUpdatingLayout() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::enableIOSTextBaselineOffsetPerLine() { + auto flagValue = enableIOSTextBaselineOffsetPerLine_.load(); + + if (!flagValue.has_value()) { + // This block is not exclusive but it is not necessary. + // If multiple threads try to initialize the feature flag, we would only + // be accessing the provider multiple times but the end state of this + // instance and the returned flag value would be the same. + + markFlagAsAccessed(18, "enableIOSTextBaselineOffsetPerLine"); + + flagValue = currentProvider_->enableIOSTextBaselineOffsetPerLine(); + enableIOSTextBaselineOffsetPerLine_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::enableIOSViewClipToPaddingBox() { auto flagValue = enableIOSViewClipToPaddingBox_.load(); @@ -362,7 +380,7 @@ bool ReactNativeFeatureFlagsAccessor::enableIOSViewClipToPaddingBox() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(18, "enableIOSViewClipToPaddingBox"); + markFlagAsAccessed(19, "enableIOSViewClipToPaddingBox"); flagValue = currentProvider_->enableIOSViewClipToPaddingBox(); enableIOSViewClipToPaddingBox_ = flagValue; @@ -380,7 +398,7 @@ bool ReactNativeFeatureFlagsAccessor::enableIntersectionObserverEventLoopIntegra // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(19, "enableIntersectionObserverEventLoopIntegration"); + markFlagAsAccessed(20, "enableIntersectionObserverEventLoopIntegration"); flagValue = currentProvider_->enableIntersectionObserverEventLoopIntegration(); enableIntersectionObserverEventLoopIntegration_ = flagValue; @@ -398,7 +416,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(20, "enableLayoutAnimationsOnAndroid"); + markFlagAsAccessed(21, "enableLayoutAnimationsOnAndroid"); flagValue = currentProvider_->enableLayoutAnimationsOnAndroid(); enableLayoutAnimationsOnAndroid_ = flagValue; @@ -416,7 +434,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(21, "enableLayoutAnimationsOnIOS"); + markFlagAsAccessed(22, "enableLayoutAnimationsOnIOS"); flagValue = currentProvider_->enableLayoutAnimationsOnIOS(); enableLayoutAnimationsOnIOS_ = flagValue; @@ -434,7 +452,7 @@ bool ReactNativeFeatureFlagsAccessor::enableMainQueueModulesOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(22, "enableMainQueueModulesOnIOS"); + markFlagAsAccessed(23, "enableMainQueueModulesOnIOS"); flagValue = currentProvider_->enableMainQueueModulesOnIOS(); enableMainQueueModulesOnIOS_ = flagValue; @@ -452,7 +470,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNativeCSSParsing() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(23, "enableNativeCSSParsing"); + markFlagAsAccessed(24, "enableNativeCSSParsing"); flagValue = currentProvider_->enableNativeCSSParsing(); enableNativeCSSParsing_ = flagValue; @@ -470,7 +488,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNetworkEventReporting() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(24, "enableNetworkEventReporting"); + markFlagAsAccessed(25, "enableNetworkEventReporting"); flagValue = currentProvider_->enableNetworkEventReporting(); enableNetworkEventReporting_ = flagValue; @@ -488,7 +506,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNewBackgroundAndBorderDrawables() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(25, "enableNewBackgroundAndBorderDrawables"); + markFlagAsAccessed(26, "enableNewBackgroundAndBorderDrawables"); flagValue = currentProvider_->enableNewBackgroundAndBorderDrawables(); enableNewBackgroundAndBorderDrawables_ = flagValue; @@ -506,7 +524,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePreparedTextLayout() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(26, "enablePreparedTextLayout"); + markFlagAsAccessed(27, "enablePreparedTextLayout"); flagValue = currentProvider_->enablePreparedTextLayout(); enablePreparedTextLayout_ = flagValue; @@ -524,7 +542,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePropsUpdateReconciliationAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(27, "enablePropsUpdateReconciliationAndroid"); + markFlagAsAccessed(28, "enablePropsUpdateReconciliationAndroid"); flagValue = currentProvider_->enablePropsUpdateReconciliationAndroid(); enablePropsUpdateReconciliationAndroid_ = flagValue; @@ -542,7 +560,7 @@ bool ReactNativeFeatureFlagsAccessor::enableResourceTimingAPI() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(28, "enableResourceTimingAPI"); + markFlagAsAccessed(29, "enableResourceTimingAPI"); flagValue = currentProvider_->enableResourceTimingAPI(); enableResourceTimingAPI_ = flagValue; @@ -560,7 +578,7 @@ bool ReactNativeFeatureFlagsAccessor::enableSynchronousStateUpdates() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(29, "enableSynchronousStateUpdates"); + markFlagAsAccessed(30, "enableSynchronousStateUpdates"); flagValue = currentProvider_->enableSynchronousStateUpdates(); enableSynchronousStateUpdates_ = flagValue; @@ -578,7 +596,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewCulling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(30, "enableViewCulling"); + markFlagAsAccessed(31, "enableViewCulling"); flagValue = currentProvider_->enableViewCulling(); enableViewCulling_ = flagValue; @@ -596,7 +614,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecycling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(31, "enableViewRecycling"); + markFlagAsAccessed(32, "enableViewRecycling"); flagValue = currentProvider_->enableViewRecycling(); enableViewRecycling_ = flagValue; @@ -614,7 +632,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForText() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(32, "enableViewRecyclingForText"); + markFlagAsAccessed(33, "enableViewRecyclingForText"); flagValue = currentProvider_->enableViewRecyclingForText(); enableViewRecyclingForText_ = flagValue; @@ -632,7 +650,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForView() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(33, "enableViewRecyclingForView"); + markFlagAsAccessed(34, "enableViewRecyclingForView"); flagValue = currentProvider_->enableViewRecyclingForView(); enableViewRecyclingForView_ = flagValue; @@ -650,7 +668,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAn // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(34, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); + markFlagAsAccessed(35, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact(); fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue; @@ -668,7 +686,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledRelease() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(35, "fuseboxEnabledRelease"); + markFlagAsAccessed(36, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -686,7 +704,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxNetworkInspectionEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(36, "fuseboxNetworkInspectionEnabled"); + markFlagAsAccessed(37, "fuseboxNetworkInspectionEnabled"); flagValue = currentProvider_->fuseboxNetworkInspectionEnabled(); fuseboxNetworkInspectionEnabled_ = flagValue; @@ -704,7 +722,7 @@ bool ReactNativeFeatureFlagsAccessor::incorporateMaxLinesDuringAndroidLayout() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(37, "incorporateMaxLinesDuringAndroidLayout"); + markFlagAsAccessed(38, "incorporateMaxLinesDuringAndroidLayout"); flagValue = currentProvider_->incorporateMaxLinesDuringAndroidLayout(); incorporateMaxLinesDuringAndroidLayout_ = flagValue; @@ -722,7 +740,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(38, "traceTurboModulePromiseRejectionsOnAndroid"); + markFlagAsAccessed(39, "traceTurboModulePromiseRejectionsOnAndroid"); flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid(); traceTurboModulePromiseRejectionsOnAndroid_ = flagValue; @@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommit( // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(39, "updateRuntimeShadowNodeReferencesOnCommit"); + markFlagAsAccessed(40, "updateRuntimeShadowNodeReferencesOnCommit"); flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit(); updateRuntimeShadowNodeReferencesOnCommit_ = flagValue; @@ -758,7 +776,7 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(40, "useAlwaysAvailableJSErrorHandling"); + markFlagAsAccessed(41, "useAlwaysAvailableJSErrorHandling"); flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling(); useAlwaysAvailableJSErrorHandling_ = flagValue; @@ -776,7 +794,7 @@ bool ReactNativeFeatureFlagsAccessor::useAndroidTextLayoutWidthDirectly() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(41, "useAndroidTextLayoutWidthDirectly"); + markFlagAsAccessed(42, "useAndroidTextLayoutWidthDirectly"); flagValue = currentProvider_->useAndroidTextLayoutWidthDirectly(); useAndroidTextLayoutWidthDirectly_ = flagValue; @@ -794,7 +812,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(42, "useFabricInterop"); + markFlagAsAccessed(43, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -812,7 +830,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(43, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(44, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -830,7 +848,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(44, "useOptimizedEventBatchingOnAndroid"); + markFlagAsAccessed(45, "useOptimizedEventBatchingOnAndroid"); flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid(); useOptimizedEventBatchingOnAndroid_ = flagValue; @@ -848,7 +866,7 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(45, "useRawPropsJsiValue"); + markFlagAsAccessed(46, "useRawPropsJsiValue"); flagValue = currentProvider_->useRawPropsJsiValue(); useRawPropsJsiValue_ = flagValue; @@ -866,7 +884,7 @@ bool ReactNativeFeatureFlagsAccessor::useShadowNodeStateOnClone() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(46, "useShadowNodeStateOnClone"); + markFlagAsAccessed(47, "useShadowNodeStateOnClone"); flagValue = currentProvider_->useShadowNodeStateOnClone(); useShadowNodeStateOnClone_ = flagValue; @@ -884,7 +902,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(47, "useTurboModuleInterop"); + markFlagAsAccessed(48, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -902,7 +920,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(48, "useTurboModules"); + markFlagAsAccessed(49, "useTurboModules"); flagValue = currentProvider_->useTurboModules(); useTurboModules_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index 8f1f9f0311c..0dac38c1d3f 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -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<<867dd37ee489203791b933b87562fc67>> + * @generated SignedSource<> */ /** @@ -50,6 +50,7 @@ class ReactNativeFeatureFlagsAccessor { bool enableFabricRenderer(); bool enableFixForParentTagDuringReparenting(); bool enableFontScaleChangesUpdatingLayout(); + bool enableIOSTextBaselineOffsetPerLine(); bool enableIOSViewClipToPaddingBox(); bool enableIntersectionObserverEventLoopIntegration(); bool enableLayoutAnimationsOnAndroid(); @@ -92,7 +93,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 49> accessedFeatureFlags_; + std::array, 50> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> animatedShouldSignalBatch_; @@ -112,6 +113,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> enableFabricRenderer_; std::atomic> enableFixForParentTagDuringReparenting_; std::atomic> enableFontScaleChangesUpdatingLayout_; + std::atomic> enableIOSTextBaselineOffsetPerLine_; std::atomic> enableIOSViewClipToPaddingBox_; std::atomic> enableIntersectionObserverEventLoopIntegration_; std::atomic> enableLayoutAnimationsOnAndroid_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index fd5e21833d2..e61d8d45dea 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -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<<1a4bc240cbc6dbdac756555f98f69147>> + * @generated SignedSource<<4c463bb7d1aa97478abe0e74955aa854>> */ /** @@ -99,6 +99,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool enableIOSTextBaselineOffsetPerLine() override { + return false; + } + bool enableIOSViewClipToPaddingBox() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index dca5dd84636..03429d3c955 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h @@ -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<<425dc272cba3224430f9948e6773b30f>> + * @generated SignedSource<> */ /** @@ -207,6 +207,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::enableFontScaleChangesUpdatingLayout(); } + bool enableIOSTextBaselineOffsetPerLine() override { + auto value = values_["enableIOSTextBaselineOffsetPerLine"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::enableIOSTextBaselineOffsetPerLine(); + } + bool enableIOSViewClipToPaddingBox() override { auto value = values_["enableIOSViewClipToPaddingBox"]; if (!value.isNull()) { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index d287951bd93..7345df9164e 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -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<<53bd41086143a19f52e1e96025b24c76>> */ /** @@ -43,6 +43,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool enableFabricRenderer() = 0; virtual bool enableFixForParentTagDuringReparenting() = 0; virtual bool enableFontScaleChangesUpdatingLayout() = 0; + virtual bool enableIOSTextBaselineOffsetPerLine() = 0; virtual bool enableIOSViewClipToPaddingBox() = 0; virtual bool enableIntersectionObserverEventLoopIntegration() = 0; virtual bool enableLayoutAnimationsOnAndroid() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 6bf86650527..db7577c3a23 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp @@ -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<<74f011324e9d4647fa757f29b602c6c3>> */ /** @@ -134,6 +134,11 @@ bool NativeReactNativeFeatureFlags::enableFontScaleChangesUpdatingLayout( return ReactNativeFeatureFlags::enableFontScaleChangesUpdatingLayout(); } +bool NativeReactNativeFeatureFlags::enableIOSTextBaselineOffsetPerLine( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::enableIOSTextBaselineOffsetPerLine(); +} + bool NativeReactNativeFeatureFlags::enableIOSViewClipToPaddingBox( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::enableIOSViewClipToPaddingBox(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index ff5cf3f2c45..18d0bc43060 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h @@ -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<<33c4be38d881a6e09e4a58cac6eeca53>> + * @generated SignedSource<<2b33a7fe9086343c427f06cc62c67a62>> */ /** @@ -73,6 +73,8 @@ class NativeReactNativeFeatureFlags bool enableFontScaleChangesUpdatingLayout(jsi::Runtime& runtime); + bool enableIOSTextBaselineOffsetPerLine(jsi::Runtime& runtime); + bool enableIOSViewClipToPaddingBox(jsi::Runtime& runtime); bool enableIntersectionObserverEventLoopIntegration(jsi::Runtime& runtime); diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm index d08d0ba6e13..10628144a22 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm @@ -7,6 +7,7 @@ #import "RCTAttributedTextUtils.h" +#include #include #include #include @@ -291,12 +292,12 @@ NSMutableDictionary *RCTNSTextAttributesFromTextAttri return attributes; } -void RCTApplyBaselineOffset(NSMutableAttributedString *attributedText) +static void RCTApplyBaselineOffsetForRange(NSMutableAttributedString *attributedText, NSRange attributedTextRange) { __block CGFloat maximumLineHeight = 0; [attributedText enumerateAttribute:NSParagraphStyleAttributeName - inRange:NSMakeRange(0, attributedText.length) + inRange:attributedTextRange options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:^(NSParagraphStyle *paragraphStyle, __unused NSRange range, __unused BOOL *stop) { if (!paragraphStyle) { @@ -314,7 +315,7 @@ void RCTApplyBaselineOffset(NSMutableAttributedString *attributedText) __block CGFloat maximumFontLineHeight = 0; [attributedText enumerateAttribute:NSFontAttributeName - inRange:NSMakeRange(0, attributedText.length) + inRange:attributedTextRange options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:^(UIFont *font, NSRange range, __unused BOOL *stop) { if (!font) { @@ -330,9 +331,25 @@ void RCTApplyBaselineOffset(NSMutableAttributedString *attributedText) CGFloat baseLineOffset = (maximumLineHeight - maximumFontLineHeight) / 2.0; - [attributedText addAttribute:NSBaselineOffsetAttributeName - value:@(baseLineOffset) - range:NSMakeRange(0, attributedText.length)]; + [attributedText addAttribute:NSBaselineOffsetAttributeName value:@(baseLineOffset) range:attributedTextRange]; +} + +void RCTApplyBaselineOffset(NSMutableAttributedString *attributedText) +{ + if (ReactNativeFeatureFlags::enableIOSTextBaselineOffsetPerLine()) { + [attributedText.string + enumerateSubstringsInRange:NSMakeRange(0, attributedText.length) + options:NSStringEnumerationByLines | NSStringEnumerationSubstringNotRequired + usingBlock:^( + NSString *_Nullable substring, + NSRange substringRange, + NSRange enclosingRange, + BOOL *_Nonnull stop) { + RCTApplyBaselineOffsetForRange(attributedText, enclosingRange); + }]; + } else { + RCTApplyBaselineOffsetForRange(attributedText, NSMakeRange(0, attributedText.length)); + } } static NSMutableAttributedString *RCTNSAttributedStringFragmentFromFragment( diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index dbbe77a4f39..781e267ba30 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -237,6 +237,17 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'none', }, + enableIOSTextBaselineOffsetPerLine: { + defaultValue: false, + metadata: { + dateAdded: '2025-05-21', + description: + 'Applies base offset for each line of text separately on iOS.', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + ossReleaseStage: 'none', + }, enableIOSViewClipToPaddingBox: { defaultValue: false, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 8da51702cd6..105233cc641 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -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<<2b128035e6890d34737a2cfc5d8fa5ad>> + * @generated SignedSource<> * @flow strict * @noformat */ @@ -68,6 +68,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{ enableFabricRenderer: Getter, enableFixForParentTagDuringReparenting: Getter, enableFontScaleChangesUpdatingLayout: Getter, + enableIOSTextBaselineOffsetPerLine: Getter, enableIOSViewClipToPaddingBox: Getter, enableIntersectionObserverEventLoopIntegration: Getter, enableLayoutAnimationsOnAndroid: Getter, @@ -252,6 +253,10 @@ export const enableFixForParentTagDuringReparenting: Getter = createNat * Enables font scale changes updating layout for measurable nodes. */ export const enableFontScaleChangesUpdatingLayout: Getter = createNativeFlagGetter('enableFontScaleChangesUpdatingLayout', false); +/** + * Applies base offset for each line of text separately on iOS. + */ +export const enableIOSTextBaselineOffsetPerLine: Getter = createNativeFlagGetter('enableIOSTextBaselineOffsetPerLine', false); /** * iOS Views will clip to their padding box vs border box */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 394143bc10e..e8df6ffde41 100644 --- a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js @@ -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<<620ba7ace3df80067aa6ba1ed44aec60>> * @flow strict * @noformat */ @@ -43,6 +43,7 @@ export interface Spec extends TurboModule { +enableFabricRenderer?: () => boolean; +enableFixForParentTagDuringReparenting?: () => boolean; +enableFontScaleChangesUpdatingLayout?: () => boolean; + +enableIOSTextBaselineOffsetPerLine?: () => boolean; +enableIOSViewClipToPaddingBox?: () => boolean; +enableIntersectionObserverEventLoopIntegration?: () => boolean; +enableLayoutAnimationsOnAndroid?: () => boolean;