Files
react-native/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp
T
Nick Gerleman 71ef049065 Directly Trust Text Layout Width (#51206)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/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 https://github.com/facebook/react-native/pull/47435 later undid this change
3. https://github.com/facebook/react-native/pull/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
2025-05-09 12:52:36 -07:00

250 lines
7.5 KiB
C++

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<42a15fd8d0ea1cfe23bc3f98627a9090>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags --update
*/
#include "ReactNativeFeatureFlags.h"
namespace facebook::react {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wglobal-constructors"
std::unique_ptr<ReactNativeFeatureFlagsAccessor> accessor_;
#pragma GCC diagnostic pop
bool ReactNativeFeatureFlags::commonTestFlag() {
return getAccessor().commonTestFlag();
}
bool ReactNativeFeatureFlags::animatedShouldSignalBatch() {
return getAccessor().animatedShouldSignalBatch();
}
bool ReactNativeFeatureFlags::cxxNativeAnimatedEnabled() {
return getAccessor().cxxNativeAnimatedEnabled();
}
bool ReactNativeFeatureFlags::disableMainQueueSyncDispatchIOS() {
return getAccessor().disableMainQueueSyncDispatchIOS();
}
bool ReactNativeFeatureFlags::disableMountItemReorderingAndroid() {
return getAccessor().disableMountItemReorderingAndroid();
}
bool ReactNativeFeatureFlags::enableAccessibilityOrder() {
return getAccessor().enableAccessibilityOrder();
}
bool ReactNativeFeatureFlags::enableAccumulatedUpdatesInRawPropsAndroid() {
return getAccessor().enableAccumulatedUpdatesInRawPropsAndroid();
}
bool ReactNativeFeatureFlags::enableBridgelessArchitecture() {
return getAccessor().enableBridgelessArchitecture();
}
bool ReactNativeFeatureFlags::enableCppPropsIteratorSetter() {
return getAccessor().enableCppPropsIteratorSetter();
}
bool ReactNativeFeatureFlags::enableCustomFocusSearchOnClippedElementsAndroid() {
return getAccessor().enableCustomFocusSearchOnClippedElementsAndroid();
}
bool ReactNativeFeatureFlags::enableDestroyShadowTreeRevisionAsync() {
return getAccessor().enableDestroyShadowTreeRevisionAsync();
}
bool ReactNativeFeatureFlags::enableDoubleMeasurementFixAndroid() {
return getAccessor().enableDoubleMeasurementFixAndroid();
}
bool ReactNativeFeatureFlags::enableEagerRootViewAttachment() {
return getAccessor().enableEagerRootViewAttachment();
}
bool ReactNativeFeatureFlags::enableFabricLogs() {
return getAccessor().enableFabricLogs();
}
bool ReactNativeFeatureFlags::enableFabricRenderer() {
return getAccessor().enableFabricRenderer();
}
bool ReactNativeFeatureFlags::enableFixForParentTagDuringReparenting() {
return getAccessor().enableFixForParentTagDuringReparenting();
}
bool ReactNativeFeatureFlags::enableFontScaleChangesUpdatingLayout() {
return getAccessor().enableFontScaleChangesUpdatingLayout();
}
bool ReactNativeFeatureFlags::enableIOSViewClipToPaddingBox() {
return getAccessor().enableIOSViewClipToPaddingBox();
}
bool ReactNativeFeatureFlags::enableJSRuntimeGCOnMemoryPressureOnIOS() {
return getAccessor().enableJSRuntimeGCOnMemoryPressureOnIOS();
}
bool ReactNativeFeatureFlags::enableLayoutAnimationsOnAndroid() {
return getAccessor().enableLayoutAnimationsOnAndroid();
}
bool ReactNativeFeatureFlags::enableLayoutAnimationsOnIOS() {
return getAccessor().enableLayoutAnimationsOnIOS();
}
bool ReactNativeFeatureFlags::enableMainQueueModulesOnIOS() {
return getAccessor().enableMainQueueModulesOnIOS();
}
bool ReactNativeFeatureFlags::enableNativeCSSParsing() {
return getAccessor().enableNativeCSSParsing();
}
bool ReactNativeFeatureFlags::enableNetworkEventReporting() {
return getAccessor().enableNetworkEventReporting();
}
bool ReactNativeFeatureFlags::enableNewBackgroundAndBorderDrawables() {
return getAccessor().enableNewBackgroundAndBorderDrawables();
}
bool ReactNativeFeatureFlags::enablePreparedTextLayout() {
return getAccessor().enablePreparedTextLayout();
}
bool ReactNativeFeatureFlags::enablePropsUpdateReconciliationAndroid() {
return getAccessor().enablePropsUpdateReconciliationAndroid();
}
bool ReactNativeFeatureFlags::enableResourceTimingAPI() {
return getAccessor().enableResourceTimingAPI();
}
bool ReactNativeFeatureFlags::enableSynchronousStateUpdates() {
return getAccessor().enableSynchronousStateUpdates();
}
bool ReactNativeFeatureFlags::enableViewCulling() {
return getAccessor().enableViewCulling();
}
bool ReactNativeFeatureFlags::enableViewRecycling() {
return getAccessor().enableViewRecycling();
}
bool ReactNativeFeatureFlags::enableViewRecyclingForText() {
return getAccessor().enableViewRecyclingForText();
}
bool ReactNativeFeatureFlags::enableViewRecyclingForView() {
return getAccessor().enableViewRecyclingForView();
}
bool ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact() {
return getAccessor().fixMappingOfEventPrioritiesBetweenFabricAndReact();
}
bool ReactNativeFeatureFlags::fuseboxEnabledRelease() {
return getAccessor().fuseboxEnabledRelease();
}
bool ReactNativeFeatureFlags::fuseboxNetworkInspectionEnabled() {
return getAccessor().fuseboxNetworkInspectionEnabled();
}
bool ReactNativeFeatureFlags::incorporateMaxLinesDuringAndroidLayout() {
return getAccessor().incorporateMaxLinesDuringAndroidLayout();
}
bool ReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid() {
return getAccessor().traceTurboModulePromiseRejectionsOnAndroid();
}
bool ReactNativeFeatureFlags::updateRuntimeShadowNodeReferencesOnCommit() {
return getAccessor().updateRuntimeShadowNodeReferencesOnCommit();
}
bool ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling() {
return getAccessor().useAlwaysAvailableJSErrorHandling();
}
bool ReactNativeFeatureFlags::useAndroidTextLayoutWidthDirectly() {
return getAccessor().useAndroidTextLayoutWidthDirectly();
}
bool ReactNativeFeatureFlags::useFabricInterop() {
return getAccessor().useFabricInterop();
}
bool ReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode() {
return getAccessor().useNativeViewConfigsInBridgelessMode();
}
bool ReactNativeFeatureFlags::useOptimizedEventBatchingOnAndroid() {
return getAccessor().useOptimizedEventBatchingOnAndroid();
}
bool ReactNativeFeatureFlags::useRawPropsJsiValue() {
return getAccessor().useRawPropsJsiValue();
}
bool ReactNativeFeatureFlags::useShadowNodeStateOnClone() {
return getAccessor().useShadowNodeStateOnClone();
}
bool ReactNativeFeatureFlags::useTurboModuleInterop() {
return getAccessor().useTurboModuleInterop();
}
bool ReactNativeFeatureFlags::useTurboModules() {
return getAccessor().useTurboModules();
}
void ReactNativeFeatureFlags::override(
std::unique_ptr<ReactNativeFeatureFlagsProvider> provider) {
getAccessor().override(std::move(provider));
}
void ReactNativeFeatureFlags::dangerouslyReset() {
accessor_ = std::make_unique<ReactNativeFeatureFlagsAccessor>();
}
std::optional<std::string> ReactNativeFeatureFlags::dangerouslyForceOverride(
std::unique_ptr<ReactNativeFeatureFlagsProvider> provider) {
auto accessor = std::make_unique<ReactNativeFeatureFlagsAccessor>();
accessor->override(std::move(provider));
std::swap(accessor_, accessor);
// Now accessor is the old accessor
return accessor == nullptr ? std::nullopt
: accessor->getAccessedFeatureFlagNames();
}
ReactNativeFeatureFlagsAccessor& ReactNativeFeatureFlags::getAccessor() {
if (accessor_ == nullptr) {
accessor_ = std::make_unique<ReactNativeFeatureFlagsAccessor>();
}
return *accessor_;
}
} // namespace facebook::react