Skip to content

Commit

Permalink
Port "setAndroidLayoutDirection" to Paper (#45422)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #45422

When `ReactNativeFeatureFlags.setAndroidLayoutDirection()` is set, we assume in components like ReactHorizontalScrolView that the Yoga contextual layout direction has been set on the underlying component, and skip using I18nManager global direction.

These native views are also used in Paper, so we need to make the change there as well to avoid regressions.

This change mechanically ports the change from Fabric to Paper, at the same layer as used in Fabric (applying ShadowNode layout to the Android view tree).

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D59708408

fbshipit-source-id: 52d6fa80c102250eae7ccccedd7184569f6a727f
  • Loading branch information
NickGerleman authored and pull[bot] committed Jul 29, 2024
1 parent 26df440 commit 1292480
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 8 deletions.
4 changes: 3 additions & 1 deletion packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -4309,7 +4309,8 @@ public class com/facebook/react/uimanager/NativeViewHierarchyManager {
public fun setJSResponder (IIZ)V
public fun setLayoutAnimationEnabled (Z)V
public fun updateInstanceHandle (IJ)V
public fun updateLayout (IIIIII)V
public fun updateLayout (IIIII)V
public fun updateLayout (IIIIIILcom/facebook/yoga/YogaDirection;)V
public fun updateProperties (ILcom/facebook/react/uimanager/ReactStylesDiffMap;)V
public fun updateViewExtraData (ILjava/lang/Object;)V
}
Expand Down Expand Up @@ -5206,6 +5207,7 @@ public class com/facebook/react/uimanager/UIViewOperationQueue {
public fun enqueueUpdateExtraData (ILjava/lang/Object;)V
public fun enqueueUpdateInstanceHandle (IJ)V
public fun enqueueUpdateLayout (IIIIII)V
public fun enqueueUpdateLayout (IIIIIILcom/facebook/yoga/YogaDirection;)V
public fun enqueueUpdateProperties (ILjava/lang/String;Lcom/facebook/react/uimanager/ReactStylesDiffMap;)V
public fun getProfiledBatchPerfCounters ()Ljava/util/Map;
public fun isEmpty ()Z
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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.
*/

package com.facebook.react.uimanager

import android.view.View
import com.facebook.yoga.YogaDirection

internal object LayoutDirectionUtil {
@JvmStatic
public fun toAndroidFromYoga(direction: YogaDirection): Int =
when (direction) {
YogaDirection.LTR -> View.LAYOUT_DIRECTION_LTR
YogaDirection.RTL -> View.LAYOUT_DIRECTION_RTL
else -> View.LAYOUT_DIRECTION_INHERIT
}

@JvmStatic
public fun toYogaFromAndroid(direction: Int): YogaDirection =
when (direction) {
View.LAYOUT_DIRECTION_LTR -> YogaDirection.LTR
View.LAYOUT_DIRECTION_RTL -> YogaDirection.RTL
else -> YogaDirection.INHERIT
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@
import com.facebook.react.bridge.SoftAssertions;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
import com.facebook.react.touch.JSResponderHandler;
import com.facebook.react.uimanager.layoutanimation.LayoutAnimationController;
import com.facebook.react.uimanager.layoutanimation.LayoutAnimationListener;
import com.facebook.systrace.Systrace;
import com.facebook.systrace.SystraceMessage;
import com.facebook.yoga.YogaDirection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
Expand Down Expand Up @@ -153,8 +155,17 @@ public synchronized void updateViewExtraData(int tag, Object extraData) {
viewManager.updateExtraData(viewToUpdate, extraData);
}

/**
* @deprecated Please use {@link #updateLayout(int tag, int x, int y, int width, int height,
* YogaDirection layoutDirection)} instead.
*/
@Deprecated
public void updateLayout(int tag, int x, int y, int width, int height) {
updateLayout(tag, tag, x, y, width, height, YogaDirection.INHERIT);
}

public synchronized void updateLayout(
int parentTag, int tag, int x, int y, int width, int height) {
int parentTag, int tag, int x, int y, int width, int height, YogaDirection layoutDirection) {
if (DEBUG_MODE) {
FLog.d(TAG, "updateLayout[%d]->[%d]: %d %d %d %d", tag, parentTag, x, y, width, height);
}
Expand All @@ -167,6 +178,10 @@ public synchronized void updateLayout(
try {
View viewToUpdate = resolveView(tag);

if (ReactNativeFeatureFlags.setAndroidLayoutDirection()) {
viewToUpdate.setLayoutDirection(LayoutDirectionUtil.toAndroidFromYoga(layoutDirection));
}

// Even though we have exact dimensions, we still call measure because some platform views
// (e.g.
// Switch) assume that method will always be called before onLayout and onDraw. They use it to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ public void handleUpdateLayout(ReactShadowNode node) {
node.getScreenX(),
node.getScreenY(),
node.getScreenWidth(),
node.getScreenHeight());
node.getScreenHeight(),
node.getLayoutDirection());
return;
}

Expand Down Expand Up @@ -370,7 +371,8 @@ private void applyLayoutRecursive(ReactShadowNode toUpdate, int x, int y) {
x,
y,
toUpdate.getScreenWidth(),
toUpdate.getScreenHeight());
toUpdate.getScreenHeight(),
toUpdate.getLayoutDirection());
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,8 @@ public void dispatchUpdates(
getScreenX(),
getScreenY(),
getScreenWidth(),
getScreenHeight());
getScreenHeight(),
getLayoutDirection());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
import com.facebook.systrace.Systrace;
import com.facebook.systrace.SystraceMessage;
import com.facebook.yoga.YogaDirection;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -118,21 +119,31 @@ public void execute() {
private final class UpdateLayoutOperation extends ViewOperation {

private final int mParentTag, mX, mY, mWidth, mHeight;
private final YogaDirection mLayoutDirection;

public UpdateLayoutOperation(int parentTag, int tag, int x, int y, int width, int height) {
public UpdateLayoutOperation(
int parentTag,
int tag,
int x,
int y,
int width,
int height,
YogaDirection layoutDirection) {
super(tag);
mParentTag = parentTag;
mX = x;
mY = y;
mWidth = width;
mHeight = height;
mLayoutDirection = layoutDirection;
Systrace.startAsyncFlow(Systrace.TRACE_TAG_REACT_VIEW, "updateLayout", mTag);
}

@Override
public void execute() {
Systrace.endAsyncFlow(Systrace.TRACE_TAG_REACT_VIEW, "updateLayout", mTag);
mNativeViewHierarchyManager.updateLayout(mParentTag, mTag, mX, mY, mWidth, mHeight);
mNativeViewHierarchyManager.updateLayout(
mParentTag, mTag, mX, mY, mWidth, mHeight, mLayoutDirection);
}
}

Expand Down Expand Up @@ -698,9 +709,26 @@ public void enqueueUpdateProperties(int reactTag, String className, ReactStylesD
mOperations.add(new UpdatePropertiesOperation(reactTag, props));
}

/**
* @deprecated Use {@link #enqueueUpdateLayout(int, int, int, int, int, int, YogaDirection)}
* instead.
*/
@Deprecated
public void enqueueUpdateLayout(
int parentTag, int reactTag, int x, int y, int width, int height) {
mOperations.add(new UpdateLayoutOperation(parentTag, reactTag, x, y, width, height));
enqueueUpdateLayout(parentTag, reactTag, x, y, width, height, YogaDirection.INHERIT);
}

public void enqueueUpdateLayout(
int parentTag,
int reactTag,
int x,
int y,
int width,
int height,
YogaDirection layoutDirection) {
mOperations.add(
new UpdateLayoutOperation(parentTag, reactTag, x, y, width, height, layoutDirection));
}

public void enqueueManageChildren(
Expand Down

0 comments on commit 1292480

Please sign in to comment.