Propagate layout direction to Android Views and Drawables

Summary:
Right now we use layout direction determined by I18NManager to influence the root Yoga layout direction.

Individual views may have a different resolved layout direction (e.g. due to `direction` style prop), and even though we don't rely on Android layout props, Android components still need to inherit or know the right layout direction to still do correct drawing. Example of this was scrollbar showing up on the left, instead of right in RTL, as soon as ScrollView knew it was in RTL.

This has potential to change a good amount of behavior, so this is under QE.

Changelog:
[Android][Fixed] - Propagate layout direction to Android Views and Drawables

Reviewed By: joevilches

Differential Revision: D57248417

fbshipit-source-id: 4bcdf2b23277ff926a796b8377df08d49c7b914c
This commit is contained in:
Nick Gerleman
2024-05-17 20:38:26 -07:00
committed by Facebook GitHub Bot
parent 355ca28b5d
commit e16faca18c
27 changed files with 216 additions and 79 deletions
@@ -2790,7 +2790,7 @@ public class com/facebook/react/fabric/mounting/SurfaceMountingManager {
public fun setJSResponder (IIZ)V
public fun stopSurface ()V
public fun updateEventEmitter (ILcom/facebook/react/fabric/events/EventEmitterWrapper;)V
public fun updateLayout (IIIIIII)V
public fun updateLayout (IIIIIIII)V
public fun updateOverflowInset (IIIII)V
public fun updatePadding (IIIII)V
public fun updateProps (ILcom/facebook/react/bridge/ReadableMap;)V
@@ -5527,12 +5527,11 @@ public class com/facebook/react/uimanager/drawable/CSSBackgroundDrawable : andro
public fun getComputedBorderRadius ()Lcom/facebook/react/uimanager/style/ComputedBorderRadius;
public fun getDirectionAwareBorderInsets ()Landroid/graphics/RectF;
public fun getFullBorderWidth ()F
public fun getLayoutDirection ()I
public fun getOpacity ()I
public fun getOutline (Landroid/graphics/Outline;)V
public fun getResolvedLayoutDirection ()I
public fun hasRoundedBorders ()Z
protected fun onBoundsChange (Landroid/graphics/Rect;)V
public fun onResolvedLayoutDirectionChanged (I)Z
public fun paddingBoxPath ()Landroid/graphics/Path;
public fun setAlpha (I)V
public fun setBorderColor (IFF)V
@@ -5542,9 +5541,9 @@ public class com/facebook/react/uimanager/drawable/CSSBackgroundDrawable : andro
public fun setBorderWidth (IF)V
public fun setColor (I)V
public fun setColorFilter (Landroid/graphics/ColorFilter;)V
public fun setLayoutDirectionOverride (I)V
public fun setRadius (F)V
public fun setRadius (FI)V
public fun setResolvedLayoutDirection (I)Z
}
public abstract interface class com/facebook/react/uimanager/events/BatchEventDispatchedListener {
@@ -6633,6 +6632,7 @@ public class com/facebook/react/views/scroll/OnScrollDispatchHelper {
public class com/facebook/react/views/scroll/ReactHorizontalScrollContainerView : com/facebook/react/views/view/ReactViewGroup {
public fun <init> (Landroid/content/Context;)V
public fun getLayoutDirection ()I
protected fun onLayout (ZIIII)V
public fun setRemoveClippedSubviews (Z)V
}
@@ -7927,7 +7927,6 @@ public class com/facebook/react/views/view/ReactViewGroup : android/view/ViewGro
public fun onInterceptTouchEvent (Landroid/view/MotionEvent;)Z
protected fun onLayout (ZIIII)V
protected fun onMeasure (II)V
public fun onRtlPropertiesChanged (I)V
protected fun onSizeChanged (IIII)V
public fun onTouchEvent (Landroid/view/MotionEvent;)Z
public fun removeView (Landroid/view/View;)V
@@ -938,7 +938,14 @@ public class SurfaceMountingManager {
@UiThread
public void updateLayout(
int reactTag, int parentTag, int x, int y, int width, int height, int displayType) {
int reactTag,
int parentTag,
int x,
int y,
int width,
int height,
int displayType,
int layoutDirection) {
if (isStopped()) {
return;
}
@@ -954,6 +961,13 @@ public class SurfaceMountingManager {
throw new IllegalStateException("Unable to find View for tag: " + reactTag);
}
if (ReactNativeFeatureFlags.setAndroidLayoutDirection()) {
viewToUpdate.setLayoutDirection(
layoutDirection == 1
? View.LAYOUT_DIRECTION_LTR
: layoutDirection == 2 ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_INHERIT);
}
viewToUpdate.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
@@ -20,6 +20,7 @@ import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.fabric.events.EventEmitterWrapper;
import com.facebook.react.fabric.mounting.MountingManager;
import com.facebook.react.fabric.mounting.SurfaceMountingManager;
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
import com.facebook.react.uimanager.StateWrapper;
import com.facebook.systrace.Systrace;
@@ -150,9 +151,14 @@ final class IntBufferBatchMountItem implements BatchMountItem {
int height = mIntBuffer[i++];
int displayType = mIntBuffer[i++];
surfaceMountingManager.updateLayout(
reactTag, parentTag, x, y, width, height, displayType);
if (ReactNativeFeatureFlags.setAndroidLayoutDirection()) {
int layoutDirection = mIntBuffer[i++];
surfaceMountingManager.updateLayout(
reactTag, parentTag, x, y, width, height, displayType, layoutDirection);
} else {
surfaceMountingManager.updateLayout(
reactTag, parentTag, x, y, width, height, displayType, 0);
}
} else if (type == INSTRUCTION_UPDATE_PADDING) {
surfaceMountingManager.updatePadding(
mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]);
@@ -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<<fbc717f14e387b92aea7cb71202cce95>>
* @generated SignedSource<<0ae7be647ca12c3efcc34f6098155550>>
*/
/**
@@ -130,6 +130,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun preventDoubleTextMeasure(): Boolean = accessor.preventDoubleTextMeasure()
/**
* Propagate layout direction to Android views.
*/
@JvmStatic
public fun setAndroidLayoutDirection(): Boolean = accessor.setAndroidLayoutDirection()
/**
* When enabled, it uses the modern fork of RuntimeScheduler that allows scheduling tasks with priorities from any thread.
*/
@@ -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<<cfbb7879b105079fe76e37b0683f7083>>
* @generated SignedSource<<5323fb8be9ec7ee6ac43d7f01bca020e>>
*/
/**
@@ -37,6 +37,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
private var inspectorEnableModernCDPRegistryCache: Boolean? = null
private var lazyAnimationCallbacksCache: Boolean? = null
private var preventDoubleTextMeasureCache: Boolean? = null
private var setAndroidLayoutDirectionCache: Boolean? = null
private var useModernRuntimeSchedulerCache: Boolean? = null
private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null
private var useStateAlignmentMechanismCache: Boolean? = null
@@ -194,6 +195,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
return cached
}
override fun setAndroidLayoutDirection(): Boolean {
var cached = setAndroidLayoutDirectionCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.setAndroidLayoutDirection()
setAndroidLayoutDirectionCache = cached
}
return cached
}
override fun useModernRuntimeScheduler(): Boolean {
var cached = useModernRuntimeSchedulerCache
if (cached == null) {
@@ -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<<77b8e93114ed0cc2b6bdd9ee46e162c7>>
* @generated SignedSource<<e68ae1e7b4f0d7714722fb7b442c66c9>>
*/
/**
@@ -62,6 +62,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
@DoNotStrip @JvmStatic public external fun preventDoubleTextMeasure(): Boolean
@DoNotStrip @JvmStatic public external fun setAndroidLayoutDirection(): Boolean
@DoNotStrip @JvmStatic public external fun useModernRuntimeScheduler(): Boolean
@DoNotStrip @JvmStatic public external fun useNativeViewConfigsInBridgelessMode(): Boolean
@@ -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<<13a5d73dea53b8d4f16946cebc49e684>>
* @generated SignedSource<<4f50dab251c41380a14506975355e49d>>
*/
/**
@@ -57,6 +57,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun preventDoubleTextMeasure(): Boolean = false
override fun setAndroidLayoutDirection(): Boolean = false
override fun useModernRuntimeScheduler(): Boolean = false
override fun useNativeViewConfigsInBridgelessMode(): Boolean = false
@@ -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<<67f1828f6a4cf9b2cf808be12d3fb06b>>
* @generated SignedSource<<00a695402781a9f3c45ba0594a785b57>>
*/
/**
@@ -41,6 +41,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
private var inspectorEnableModernCDPRegistryCache: Boolean? = null
private var lazyAnimationCallbacksCache: Boolean? = null
private var preventDoubleTextMeasureCache: Boolean? = null
private var setAndroidLayoutDirectionCache: Boolean? = null
private var useModernRuntimeSchedulerCache: Boolean? = null
private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null
private var useStateAlignmentMechanismCache: Boolean? = null
@@ -215,6 +216,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun setAndroidLayoutDirection(): Boolean {
var cached = setAndroidLayoutDirectionCache
if (cached == null) {
cached = currentProvider.setAndroidLayoutDirection()
accessedFeatureFlags.add("setAndroidLayoutDirection")
setAndroidLayoutDirectionCache = cached
}
return cached
}
override fun useModernRuntimeScheduler(): Boolean {
var cached = useModernRuntimeSchedulerCache
if (cached == null) {
@@ -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<<a6a65fe7d9b04671de407a03e1feb161>>
* @generated SignedSource<<e63ccfcb6e8d1db840cefb3d0a6df6cd>>
*/
/**
@@ -57,6 +57,8 @@ public interface ReactNativeFeatureFlagsProvider {
@DoNotStrip public fun preventDoubleTextMeasure(): Boolean
@DoNotStrip public fun setAndroidLayoutDirection(): Boolean
@DoNotStrip public fun useModernRuntimeScheduler(): Boolean
@DoNotStrip public fun useNativeViewConfigsInBridgelessMode(): Boolean
@@ -7,6 +7,7 @@
package com.facebook.react.uimanager.drawable;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -119,7 +120,9 @@ public class CSSBackgroundDrawable extends Drawable {
private BorderRadiusStyle mBorderRadius = new BorderRadiusStyle();
private ComputedBorderRadius mComputedBorderRadius = new ComputedBorderRadius();
private final Context mContext;
private int mLayoutDirection;
// Should be removed after migrating to Android layout direction.
private int mLayoutDirectionOverride = -1;
public CSSBackgroundDrawable(Context context) {
mContext = context;
@@ -163,6 +166,19 @@ public class CSSBackgroundDrawable extends Drawable {
// do nothing
}
@Deprecated
public void setLayoutDirectionOverride(int layoutDirection) {
if (mLayoutDirectionOverride != layoutDirection) {
mLayoutDirectionOverride = layoutDirection;
}
}
@Override
@SuppressLint("WrongConstant")
public int getLayoutDirection() {
return mLayoutDirectionOverride == -1 ? super.getLayoutDirection() : mLayoutDirectionOverride;
}
@Override
public int getOpacity() {
return (Color.alpha(mColor) * mAlpha) >> 8;
@@ -292,25 +308,6 @@ public class CSSBackgroundDrawable extends Drawable {
invalidateSelf();
}
/** Similar to Drawable.getLayoutDirection, but available in APIs < 23. */
public int getResolvedLayoutDirection() {
return mLayoutDirection;
}
/** Similar to Drawable.setLayoutDirection, but available in APIs < 23. */
public boolean setResolvedLayoutDirection(int layoutDirection) {
if (mLayoutDirection != layoutDirection) {
mLayoutDirection = layoutDirection;
return onResolvedLayoutDirectionChanged(layoutDirection);
}
return false;
}
/** Similar to Drawable.onLayoutDirectionChanged, but available in APIs < 23. */
public boolean onResolvedLayoutDirectionChanged(int layoutDirection) {
return false;
}
@VisibleForTesting
public int getColor() {
return mColor;
@@ -392,7 +389,7 @@ public class CSSBackgroundDrawable extends Drawable {
// Clip inner border
canvas.clipPath(mInnerClipPathForBorderRadius, Region.Op.DIFFERENCE);
final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
final boolean isRTL = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
int colorStart = getBorderColor(Spacing.START);
int colorEnd = getBorderColor(Spacing.END);
@@ -591,7 +588,7 @@ public class CSSBackgroundDrawable extends Drawable {
mComputedBorderRadius =
mBorderRadius.resolve(
mLayoutDirection,
getLayoutDirection(),
mContext,
mOuterClipTempRectForBorderRadius.width(),
mOuterClipTempRectForBorderRadius.height());
@@ -1080,7 +1077,7 @@ public class CSSBackgroundDrawable extends Drawable {
colorTop = colorBlockStart;
}
final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
final boolean isRTL = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
int colorStart = getBorderColor(Spacing.START);
int colorEnd = getBorderColor(Spacing.END);
@@ -1305,7 +1302,7 @@ public class CSSBackgroundDrawable extends Drawable {
float borderRightWidth = getBorderWidthOrDefaultTo(borderWidth, Spacing.RIGHT);
if (mBorderWidth != null) {
final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
final boolean isRTL = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
float borderStartWidth = mBorderWidth.getRaw(Spacing.START);
float borderEndWidth = mBorderWidth.getRaw(Spacing.END);
@@ -10,6 +10,7 @@ package com.facebook.react.views.scroll;
import android.content.Context;
import androidx.core.view.ViewCompat;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
import com.facebook.react.modules.i18nmanager.I18nUtil;
import com.facebook.react.views.view.ReactViewGroup;
@@ -27,6 +28,14 @@ public class ReactHorizontalScrollContainerView extends ReactViewGroup {
: ViewCompat.LAYOUT_DIRECTION_LTR;
}
@Override
public int getLayoutDirection() {
if (ReactNativeFeatureFlags.setAndroidLayoutDirection()) {
return super.getLayoutDirection();
}
return mLayoutDirection;
}
@Override
public void setRemoveClippedSubviews(boolean removeClippedSubviews) {
// Clipping doesn't work well for horizontal scroll views in RTL mode - in both
@@ -34,7 +43,7 @@ public class ReactHorizontalScrollContainerView extends ReactViewGroup {
// is TextInputs being blurred immediately after being focused. So, for now,
// it's easier to just disable this for these specific RTL views.
// TODO T86027499: support `setRemoveClippedSubviews` in RTL mode
if (mLayoutDirection == LAYOUT_DIRECTION_RTL) {
if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
super.setRemoveClippedSubviews(false);
return;
}
@@ -44,7 +53,7 @@ public class ReactHorizontalScrollContainerView extends ReactViewGroup {
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (mLayoutDirection == LAYOUT_DIRECTION_RTL) {
if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
// When the layout direction is RTL, we expect Yoga to give us a layout
// that extends off the screen to the left so we re-center it with left=0
int newLeft = 0;
@@ -35,6 +35,7 @@ import com.facebook.infer.annotation.Assertions;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
import com.facebook.react.modules.i18nmanager.I18nUtil;
import com.facebook.react.uimanager.MeasureSpecAssertions;
import com.facebook.react.uimanager.PointerEvents;
@@ -1061,7 +1062,10 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
int firstOffset = 0;
int lastOffset = maximumOffset;
int width = getWidth() - ViewCompat.getPaddingStart(this) - ViewCompat.getPaddingEnd(this);
int layoutDirection = getReactScrollViewScrollState().getLayoutDirection();
int layoutDirection =
ReactNativeFeatureFlags.setAndroidLayoutDirection()
? getLayoutDirection()
: mReactScrollViewScrollState.getLayoutDirection();
// offsets are from the right edge in RTL layouts
if (layoutDirection == LAYOUT_DIRECTION_RTL) {
@@ -1385,7 +1389,11 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
// does not shift layout. If `maintainVisibleContentPosition` is enabled, we try to adjust
// position so that the viewport keeps the same insets to previously visible views. TODO: MVCP
// does not work in RTL.
if (mReactScrollViewScrollState.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
int layoutDirection =
ReactNativeFeatureFlags.setAndroidLayoutDirection()
? v.getLayoutDirection()
: mReactScrollViewScrollState.getLayoutDirection();
if (layoutDirection == LAYOUT_DIRECTION_RTL) {
adjustPositionForContentChangeRTL(left, right, oldLeft, oldRight);
} else if (mMaintainVisibleContentPositionHelper != null) {
mMaintainVisibleContentPositionHelper.updateScrollPosition();
@@ -32,6 +32,7 @@ import com.facebook.react.bridge.ReactNoCrashSoftException;
import com.facebook.react.bridge.ReactSoftExceptionLogger;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
import com.facebook.react.modules.i18nmanager.I18nUtil;
import com.facebook.react.touch.OnInterceptTouchEventListener;
import com.facebook.react.touch.ReactHitSlopView;
@@ -129,7 +130,6 @@ public class ReactViewGroup extends ViewGroup
private boolean mNeedsOffscreenAlphaCompositing;
private @Nullable ViewGroupDrawingOrderHelper mDrawingOrderHelper;
private @Nullable Path mPath;
private int mLayoutDirection;
private float mBackfaceOpacity;
private String mBackfaceVisibility;
@@ -159,7 +159,6 @@ public class ReactViewGroup extends ViewGroup
mNeedsOffscreenAlphaCompositing = false;
mDrawingOrderHelper = null;
mPath = null;
mLayoutDirection = 0; // set when background is created
mBackfaceOpacity = 1.f;
mBackfaceVisibility = "visible";
}
@@ -199,13 +198,6 @@ public class ReactViewGroup extends ViewGroup
// No-op since UIManagerModule handles actually laying out children.
}
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
if (mCSSBackgroundDrawable != null) {
mCSSBackgroundDrawable.setResolvedLayoutDirection(mLayoutDirection);
}
}
@Override
@SuppressLint("MissingSuperCall")
public void requestLayout() {
@@ -806,10 +798,12 @@ public class ReactViewGroup extends ViewGroup
new LayerDrawable(new Drawable[] {mCSSBackgroundDrawable, backgroundDrawable});
updateBackgroundDrawable(layerDrawable);
}
mLayoutDirection =
I18nUtil.getInstance().isRTL(getContext()) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
mCSSBackgroundDrawable.setResolvedLayoutDirection(mLayoutDirection);
if (!ReactNativeFeatureFlags.setAndroidLayoutDirection()) {
mCSSBackgroundDrawable.setLayoutDirectionOverride(
I18nUtil.getInstance().isRTL(getContext())
? LAYOUT_DIRECTION_RTL
: LAYOUT_DIRECTION_LTR);
}
}
return mCSSBackgroundDrawable;
}
@@ -63,7 +63,9 @@ static inline int getIntBufferSizeForType(CppMountItem::Type mountItemType) {
case CppMountItem::Type::UpdatePadding:
return 5; // tag, top, left, bottom, right
case CppMountItem::Type::UpdateLayout:
return 7; // tag, parentTag, x, y, w, h, DisplayType
return ReactNativeFeatureFlags::setAndroidLayoutDirection()
? 8 // tag, parentTag, x, y, w, h, DisplayType, LayoutDirection
: 7; // tag, parentTag, x, y, w, h, DisplayType
case CppMountItem::Type::UpdateOverflowInset:
return 5; // tag, left, top, right, bottom
case CppMountItem::Undefined:
@@ -496,7 +498,7 @@ void FabricMountingManager::executeMount(
int intBufferPosition = 0;
int objBufferPosition = 0;
int prevMountItemType = -1;
jint temp[7];
jint temp[8];
for (int i = 0; i < cppCommonMountItems.size(); i++) {
const auto& mountItem = cppCommonMountItems[i];
const auto& mountItemType = mountItem.type;
@@ -656,7 +658,7 @@ void FabricMountingManager::executeMount(
intBufferPosition);
for (const auto& mountItem : cppUpdateLayoutMountItems) {
auto layoutMetrics = mountItem.newChildShadowView.layoutMetrics;
const auto& layoutMetrics = mountItem.newChildShadowView.layoutMetrics;
auto pointScaleFactor = layoutMetrics.pointScaleFactor;
auto frame = layoutMetrics.frame;
@@ -664,8 +666,8 @@ void FabricMountingManager::executeMount(
int y = round(scale(frame.origin.y, pointScaleFactor));
int w = round(scale(frame.size.width, pointScaleFactor));
int h = round(scale(frame.size.height, pointScaleFactor));
int displayType =
toInt(mountItem.newChildShadowView.layoutMetrics.displayType);
int displayType = toInt(layoutMetrics.displayType);
int layoutDirection = toInt(layoutMetrics.layoutDirection);
temp[0] = mountItem.newChildShadowView.tag;
temp[1] = mountItem.parentShadowView.tag;
@@ -674,8 +676,15 @@ void FabricMountingManager::executeMount(
temp[4] = w;
temp[5] = h;
temp[6] = displayType;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 7, temp);
intBufferPosition += 7;
if (ReactNativeFeatureFlags::setAndroidLayoutDirection()) {
temp[7] = layoutDirection;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 8, temp);
intBufferPosition += 8;
} else {
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 7, temp);
intBufferPosition += 7;
}
}
}
if (!cppUpdateOverflowInsetMountItems.empty()) {
@@ -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<<ad6b81206d1f410cd6c8d9109bd340bd>>
* @generated SignedSource<<5d0f0b1953af3f0dd2ee66fed2b1115a>>
*/
/**
@@ -141,6 +141,12 @@ class ReactNativeFeatureFlagsProviderHolder
return method(javaProvider_);
}
bool setAndroidLayoutDirection() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("setAndroidLayoutDirection");
return method(javaProvider_);
}
bool useModernRuntimeScheduler() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("useModernRuntimeScheduler");
@@ -248,6 +254,11 @@ bool JReactNativeFeatureFlagsCxxInterop::preventDoubleTextMeasure(
return ReactNativeFeatureFlags::preventDoubleTextMeasure();
}
bool JReactNativeFeatureFlagsCxxInterop::setAndroidLayoutDirection(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::setAndroidLayoutDirection();
}
bool JReactNativeFeatureFlagsCxxInterop::useModernRuntimeScheduler(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::useModernRuntimeScheduler();
@@ -331,6 +342,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"preventDoubleTextMeasure",
JReactNativeFeatureFlagsCxxInterop::preventDoubleTextMeasure),
makeNativeMethod(
"setAndroidLayoutDirection",
JReactNativeFeatureFlagsCxxInterop::setAndroidLayoutDirection),
makeNativeMethod(
"useModernRuntimeScheduler",
JReactNativeFeatureFlagsCxxInterop::useModernRuntimeScheduler),
@@ -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<<eb5c66cf6c5ceb117b7cad784cbe20a1>>
* @generated SignedSource<<d2f016e3a0648f6fd0b6c1f45b9a1f62>>
*/
/**
@@ -81,6 +81,9 @@ class JReactNativeFeatureFlagsCxxInterop
static bool preventDoubleTextMeasure(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool setAndroidLayoutDirection(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool useModernRuntimeScheduler(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
@@ -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<<5001001b2979f9b759ddac1b035842bf>>
* @generated SignedSource<<71ea09d31186aea96ff207b1015f155e>>
*/
/**
@@ -89,6 +89,10 @@ bool ReactNativeFeatureFlags::preventDoubleTextMeasure() {
return getAccessor().preventDoubleTextMeasure();
}
bool ReactNativeFeatureFlags::setAndroidLayoutDirection() {
return getAccessor().setAndroidLayoutDirection();
}
bool ReactNativeFeatureFlags::useModernRuntimeScheduler() {
return getAccessor().useModernRuntimeScheduler();
}
@@ -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<<4dd4bd2c61bff37de19a52b1bb60211c>>
* @generated SignedSource<<c53481eb714387bf0a390fba1c02c331>>
*/
/**
@@ -122,6 +122,11 @@ class ReactNativeFeatureFlags {
*/
RN_EXPORT static bool preventDoubleTextMeasure();
/**
* Propagate layout direction to Android views.
*/
RN_EXPORT static bool setAndroidLayoutDirection();
/**
* When enabled, it uses the modern fork of RuntimeScheduler that allows scheduling tasks with priorities from any thread.
*/
@@ -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<<7766e3504d137c8dee703a23d776689c>>
* @generated SignedSource<<2e874e6368f85709ecbb4c1e086ae7a9>>
*/
/**
@@ -335,6 +335,24 @@ bool ReactNativeFeatureFlagsAccessor::preventDoubleTextMeasure() {
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::setAndroidLayoutDirection() {
auto flagValue = setAndroidLayoutDirection_.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(17, "setAndroidLayoutDirection");
flagValue = currentProvider_->setAndroidLayoutDirection();
setAndroidLayoutDirection_ = flagValue;
}
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::useModernRuntimeScheduler() {
auto flagValue = useModernRuntimeScheduler_.load();
@@ -344,7 +362,7 @@ bool ReactNativeFeatureFlagsAccessor::useModernRuntimeScheduler() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(17, "useModernRuntimeScheduler");
markFlagAsAccessed(18, "useModernRuntimeScheduler");
flagValue = currentProvider_->useModernRuntimeScheduler();
useModernRuntimeScheduler_ = flagValue;
@@ -362,7 +380,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(18, "useNativeViewConfigsInBridgelessMode");
markFlagAsAccessed(19, "useNativeViewConfigsInBridgelessMode");
flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode();
useNativeViewConfigsInBridgelessMode_ = flagValue;
@@ -380,7 +398,7 @@ bool ReactNativeFeatureFlagsAccessor::useStateAlignmentMechanism() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(19, "useStateAlignmentMechanism");
markFlagAsAccessed(20, "useStateAlignmentMechanism");
flagValue = currentProvider_->useStateAlignmentMechanism();
useStateAlignmentMechanism_ = flagValue;
@@ -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<<00646bb38ef65efa782e5f601cd91716>>
* @generated SignedSource<<7d1c4c90d5e1feb0015376f20943ee51>>
*/
/**
@@ -48,6 +48,7 @@ class ReactNativeFeatureFlagsAccessor {
bool inspectorEnableModernCDPRegistry();
bool lazyAnimationCallbacks();
bool preventDoubleTextMeasure();
bool setAndroidLayoutDirection();
bool useModernRuntimeScheduler();
bool useNativeViewConfigsInBridgelessMode();
bool useStateAlignmentMechanism();
@@ -61,7 +62,7 @@ class ReactNativeFeatureFlagsAccessor {
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
bool wasOverridden_;
std::array<std::atomic<const char*>, 20> accessedFeatureFlags_;
std::array<std::atomic<const char*>, 21> accessedFeatureFlags_;
std::atomic<std::optional<bool>> commonTestFlag_;
std::atomic<std::optional<bool>> allowCollapsableChildren_;
@@ -80,6 +81,7 @@ class ReactNativeFeatureFlagsAccessor {
std::atomic<std::optional<bool>> inspectorEnableModernCDPRegistry_;
std::atomic<std::optional<bool>> lazyAnimationCallbacks_;
std::atomic<std::optional<bool>> preventDoubleTextMeasure_;
std::atomic<std::optional<bool>> setAndroidLayoutDirection_;
std::atomic<std::optional<bool>> useModernRuntimeScheduler_;
std::atomic<std::optional<bool>> useNativeViewConfigsInBridgelessMode_;
std::atomic<std::optional<bool>> useStateAlignmentMechanism_;
@@ -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<<aaa836c9ea5775a2a22bb74a0617922b>>
* @generated SignedSource<<2bfa4670757aa340c88ae8ff57270308>>
*/
/**
@@ -95,6 +95,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
return false;
}
bool setAndroidLayoutDirection() override {
return false;
}
bool useModernRuntimeScheduler() override {
return false;
}
@@ -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<<ccf01596c8d61a07a25b1821c42669bd>>
* @generated SignedSource<<de25e5a8394c37217e0cfd98715493fc>>
*/
/**
@@ -42,6 +42,7 @@ class ReactNativeFeatureFlagsProvider {
virtual bool inspectorEnableModernCDPRegistry() = 0;
virtual bool lazyAnimationCallbacks() = 0;
virtual bool preventDoubleTextMeasure() = 0;
virtual bool setAndroidLayoutDirection() = 0;
virtual bool useModernRuntimeScheduler() = 0;
virtual bool useNativeViewConfigsInBridgelessMode() = 0;
virtual bool useStateAlignmentMechanism() = 0;
@@ -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<<b68b3923749ae7fc0cf0f0125b40d612>>
* @generated SignedSource<<1fdca69483db9e0fc9f9ab7a2cd9ff85>>
*/
/**
@@ -122,6 +122,11 @@ bool NativeReactNativeFeatureFlags::preventDoubleTextMeasure(
return ReactNativeFeatureFlags::preventDoubleTextMeasure();
}
bool NativeReactNativeFeatureFlags::setAndroidLayoutDirection(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::setAndroidLayoutDirection();
}
bool NativeReactNativeFeatureFlags::useModernRuntimeScheduler(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::useModernRuntimeScheduler();
@@ -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<<07b3c6e705bdc70c7eba50d70b0dbf32>>
* @generated SignedSource<<9653b7699416f1702ba2f5e8b8f6da93>>
*/
/**
@@ -69,6 +69,8 @@ class NativeReactNativeFeatureFlags
bool preventDoubleTextMeasure(jsi::Runtime& runtime);
bool setAndroidLayoutDirection(jsi::Runtime& runtime);
bool useModernRuntimeScheduler(jsi::Runtime& runtime);
bool useNativeViewConfigsInBridgelessMode(jsi::Runtime& runtime);
@@ -118,6 +118,10 @@ const definitions: FeatureFlagDefinitions = {
description:
'When enabled, ParagraphShadowNode will no longer call measure twice.',
},
setAndroidLayoutDirection: {
defaultValue: false,
description: 'Propagate layout direction to Android views.',
},
useModernRuntimeScheduler: {
defaultValue: false,
description:
@@ -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<<7d51e120696413a287b048d6c4dd7b5c>>
* @generated SignedSource<<20c3c50d2124fbfc7bbe434c940ce3bf>>
* @flow strict-local
*/
@@ -57,6 +57,7 @@ export type ReactNativeFeatureFlags = {
inspectorEnableModernCDPRegistry: Getter<boolean>,
lazyAnimationCallbacks: Getter<boolean>,
preventDoubleTextMeasure: Getter<boolean>,
setAndroidLayoutDirection: Getter<boolean>,
useModernRuntimeScheduler: Getter<boolean>,
useNativeViewConfigsInBridgelessMode: Getter<boolean>,
useStateAlignmentMechanism: Getter<boolean>,
@@ -170,6 +171,10 @@ export const lazyAnimationCallbacks: Getter<boolean> = createNativeFlagGetter('l
* When enabled, ParagraphShadowNode will no longer call measure twice.
*/
export const preventDoubleTextMeasure: Getter<boolean> = createNativeFlagGetter('preventDoubleTextMeasure', false);
/**
* Propagate layout direction to Android views.
*/
export const setAndroidLayoutDirection: Getter<boolean> = createNativeFlagGetter('setAndroidLayoutDirection', false);
/**
* When enabled, it uses the modern fork of RuntimeScheduler that allows scheduling tasks with priorities from any thread.
*/
@@ -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<<aaecbb0de4d3bd75c6735484b853d420>>
* @generated SignedSource<<c892b2d381564962b505e389ed78e9f2>>
* @flow strict-local
*/
@@ -40,6 +40,7 @@ export interface Spec extends TurboModule {
+inspectorEnableModernCDPRegistry?: () => boolean;
+lazyAnimationCallbacks?: () => boolean;
+preventDoubleTextMeasure?: () => boolean;
+setAndroidLayoutDirection?: () => boolean;
+useModernRuntimeScheduler?: () => boolean;
+useNativeViewConfigsInBridgelessMode?: () => boolean;
+useStateAlignmentMechanism?: () => boolean;