Skip to content

Commit 71ef049

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Directly Trust Text Layout Width (facebook#51206)
Summary: Pull Request resolved: facebook#51206 When we create a layout from measure constraints, we do some processing of the width, to return a different one, potentially smaller than the layout width, sometimes using line width, and sometimes using the container width. This logic has gotten spooooky over time, and after a series of changes, and bugfixes, now effectively does nothing! 1. Way back in 2020, yungsters made D21056031 introducing this logic to "shrink wrap" text which is wrapped. 2. "Shrink wrapping" is not how web works when text is wrapped, (though it is how it works when there is explicit newline), and facebook#47435 later undid this change 3. facebook#37790 made changes specific to the case of trailing newline, because the logic to "shrink wrap" did not handle correctly. After D74366936, which changes width used for layout creation to correctly respect `Layout.desiredWidth`, we should be back to multiline layouts, with no paragraph whose lines take up more than container width, being "shrink wrapped", while not doing so when there is wrapping or ellipsization, like current behavior. The desired width also excludes the non-visible trailing whitespace. It means we can remove all of this logic, while preserving the same behavior. Mismatched measure widths from those used in the intermediate layout may also result in issues for Facsimile (see example in last diff of stack). Changelog: [Internal] Reviewed By: javache Differential Revision: D74368513 fbshipit-source-id: df5d7b773ad1888ebca1966ee4020a5c2ce7fd64
1 parent 3a84d42 commit 71ef049

21 files changed

+147
-27
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<453f8c0a593b173c197fcf54ed834a1b>>
7+
* @generated SignedSource<<a9968341533b3d6347ee99ce117dc62c>>
88
*/
99

1010
/**
@@ -270,6 +270,12 @@ public object ReactNativeFeatureFlags {
270270
@JvmStatic
271271
public fun useAlwaysAvailableJSErrorHandling(): Boolean = accessor.useAlwaysAvailableJSErrorHandling()
272272

273+
/**
274+
* Trust the width of a text layout we create, instead of re-deriving it from its contents
275+
*/
276+
@JvmStatic
277+
public fun useAndroidTextLayoutWidthDirectly(): Boolean = accessor.useAndroidTextLayoutWidthDirectly()
278+
273279
/**
274280
* Should this application enable the Fabric Interop Layer for Android? If yes, the application will behave so that it can accept non-Fabric components and render them on Fabric. This toggle is controlling extra logic such as custom event dispatching that are needed for the Fabric Interop Layer to work correctly.
275281
*/

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<a51441451ec25033040ba044ee3371fc>>
7+
* @generated SignedSource<<c0dbb15487fd85e3beff70699ce99882>>
88
*/
99

1010
/**
@@ -60,6 +60,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
6060
private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null
6161
private var updateRuntimeShadowNodeReferencesOnCommitCache: Boolean? = null
6262
private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null
63+
private var useAndroidTextLayoutWidthDirectlyCache: Boolean? = null
6364
private var useFabricInteropCache: Boolean? = null
6465
private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null
6566
private var useOptimizedEventBatchingOnAndroidCache: Boolean? = null
@@ -428,6 +429,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
428429
return cached
429430
}
430431

432+
override fun useAndroidTextLayoutWidthDirectly(): Boolean {
433+
var cached = useAndroidTextLayoutWidthDirectlyCache
434+
if (cached == null) {
435+
cached = ReactNativeFeatureFlagsCxxInterop.useAndroidTextLayoutWidthDirectly()
436+
useAndroidTextLayoutWidthDirectlyCache = cached
437+
}
438+
return cached
439+
}
440+
431441
override fun useFabricInterop(): Boolean {
432442
var cached = useFabricInteropCache
433443
if (cached == null) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<9d0b02395a08331bca956ea600602a31>>
7+
* @generated SignedSource<<25a09b653b2094cb7b5399a44642cf0e>>
88
*/
99

1010
/**
@@ -108,6 +108,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
108108

109109
@DoNotStrip @JvmStatic public external fun useAlwaysAvailableJSErrorHandling(): Boolean
110110

111+
@DoNotStrip @JvmStatic public external fun useAndroidTextLayoutWidthDirectly(): Boolean
112+
111113
@DoNotStrip @JvmStatic public external fun useFabricInterop(): Boolean
112114

113115
@DoNotStrip @JvmStatic public external fun useNativeViewConfigsInBridgelessMode(): Boolean

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<cf12cdfdfb343e79247379b5549ae92a>>
7+
* @generated SignedSource<<86773a0948ff9dd3b150678f336e6ff4>>
88
*/
99

1010
/**
@@ -103,6 +103,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
103103

104104
override fun useAlwaysAvailableJSErrorHandling(): Boolean = false
105105

106+
override fun useAndroidTextLayoutWidthDirectly(): Boolean = true
107+
106108
override fun useFabricInterop(): Boolean = true
107109

108110
override fun useNativeViewConfigsInBridgelessMode(): Boolean = false

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<4c81ed8a06c192eb4007219d163650e5>>
7+
* @generated SignedSource<<a6fc25aa098ac76ba77e53c5a1dfec58>>
88
*/
99

1010
/**
@@ -64,6 +64,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
6464
private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null
6565
private var updateRuntimeShadowNodeReferencesOnCommitCache: Boolean? = null
6666
private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null
67+
private var useAndroidTextLayoutWidthDirectlyCache: Boolean? = null
6768
private var useFabricInteropCache: Boolean? = null
6869
private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null
6970
private var useOptimizedEventBatchingOnAndroidCache: Boolean? = null
@@ -472,6 +473,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
472473
return cached
473474
}
474475

476+
override fun useAndroidTextLayoutWidthDirectly(): Boolean {
477+
var cached = useAndroidTextLayoutWidthDirectlyCache
478+
if (cached == null) {
479+
cached = currentProvider.useAndroidTextLayoutWidthDirectly()
480+
accessedFeatureFlags.add("useAndroidTextLayoutWidthDirectly")
481+
useAndroidTextLayoutWidthDirectlyCache = cached
482+
}
483+
return cached
484+
}
485+
475486
override fun useFabricInterop(): Boolean {
476487
var cached = useFabricInteropCache
477488
if (cached == null) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<2482f57e0652cfaa4806b5333c50ad9f>>
7+
* @generated SignedSource<<d3ac43cad11c74d7f7ee12e776f99282>>
88
*/
99

1010
/**
@@ -103,6 +103,8 @@ public interface ReactNativeFeatureFlagsProvider {
103103

104104
@DoNotStrip public fun useAlwaysAvailableJSErrorHandling(): Boolean
105105

106+
@DoNotStrip public fun useAndroidTextLayoutWidthDirectly(): Boolean
107+
106108
@DoNotStrip public fun useFabricInterop(): Boolean
107109

108110
@DoNotStrip public fun useNativeViewConfigsInBridgelessMode(): Boolean

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,10 @@ private static float calculateWidth(
787787
float width,
788788
YogaMeasureMode widthYogaMeasureMode,
789789
int calculatedLineCount) {
790+
if (ReactNativeFeatureFlags.useAndroidTextLayoutWidthDirectly()) {
791+
return layout.getWidth();
792+
}
793+
790794
// Instead of using `layout.getWidth()` (which may yield a significantly larger width for
791795
// text that is wrapping), compute width using the longest line.
792796
float calculatedWidth = 0;

packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<49dbfe02e06cc5d6b12683ed91ea1d13>>
7+
* @generated SignedSource<<9a8d560adc9345a33b72f760f08628bd>>
88
*/
99

1010
/**
@@ -279,6 +279,12 @@ class ReactNativeFeatureFlagsJavaProvider
279279
return method(javaProvider_);
280280
}
281281

282+
bool useAndroidTextLayoutWidthDirectly() override {
283+
static const auto method =
284+
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("useAndroidTextLayoutWidthDirectly");
285+
return method(javaProvider_);
286+
}
287+
282288
bool useFabricInterop() override {
283289
static const auto method =
284290
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("useFabricInterop");
@@ -525,6 +531,11 @@ bool JReactNativeFeatureFlagsCxxInterop::useAlwaysAvailableJSErrorHandling(
525531
return ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling();
526532
}
527533

534+
bool JReactNativeFeatureFlagsCxxInterop::useAndroidTextLayoutWidthDirectly(
535+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
536+
return ReactNativeFeatureFlags::useAndroidTextLayoutWidthDirectly();
537+
}
538+
528539
bool JReactNativeFeatureFlagsCxxInterop::useFabricInterop(
529540
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
530541
return ReactNativeFeatureFlags::useFabricInterop();
@@ -711,6 +722,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
711722
makeNativeMethod(
712723
"useAlwaysAvailableJSErrorHandling",
713724
JReactNativeFeatureFlagsCxxInterop::useAlwaysAvailableJSErrorHandling),
725+
makeNativeMethod(
726+
"useAndroidTextLayoutWidthDirectly",
727+
JReactNativeFeatureFlagsCxxInterop::useAndroidTextLayoutWidthDirectly),
714728
makeNativeMethod(
715729
"useFabricInterop",
716730
JReactNativeFeatureFlagsCxxInterop::useFabricInterop),

packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<ae23312f2dccee934a8a91c05625662a>>
7+
* @generated SignedSource<<656fc82f692a639b7c08f289a7637507>>
88
*/
99

1010
/**
@@ -150,6 +150,9 @@ class JReactNativeFeatureFlagsCxxInterop
150150
static bool useAlwaysAvailableJSErrorHandling(
151151
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
152152

153+
static bool useAndroidTextLayoutWidthDirectly(
154+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
155+
153156
static bool useFabricInterop(
154157
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
155158

packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<8410561a80edd67b4528181b1f8557fe>>
7+
* @generated SignedSource<<42a15fd8d0ea1cfe23bc3f98627a9090>>
88
*/
99

1010
/**
@@ -186,6 +186,10 @@ bool ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling() {
186186
return getAccessor().useAlwaysAvailableJSErrorHandling();
187187
}
188188

189+
bool ReactNativeFeatureFlags::useAndroidTextLayoutWidthDirectly() {
190+
return getAccessor().useAndroidTextLayoutWidthDirectly();
191+
}
192+
189193
bool ReactNativeFeatureFlags::useFabricInterop() {
190194
return getAccessor().useFabricInterop();
191195
}

0 commit comments

Comments
 (0)