mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Swap left and right yoga position with start and end in RTL context
Summary: Changelog: [Internal] Paper swaps right and left in RTL setting, this logic is in [RCTShadowView.m](https://our.intern.facebook.com/intern/diffusion/FBS/browse/master/xplat/js/react-native-github/React/Views/RCTShadowView.m?commit=cdd504cfbee66ae0659495604c4ff7b5764a1d9e&lines=529-549). For Fabric instead of doing it during yoga props assignment, I swap the left/right with start/end just before we pass yoga nodes to layout calculation. Reviewed By: shergin Differential Revision: D20420040 fbshipit-source-id: b777f2658f56c173743b2034b8b5059e3e0c9840
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f6de7b826d
commit
46722dcfc2
@@ -37,6 +37,22 @@
|
||||
|
||||
using namespace facebook::react;
|
||||
|
||||
static inline LayoutConstraints RCTGetLayoutConstraintsForSize(CGSize minimumSize, CGSize maximumSize)
|
||||
{
|
||||
return {
|
||||
.minimumSize = RCTSizeFromCGSize(minimumSize),
|
||||
.maximumSize = RCTSizeFromCGSize(maximumSize),
|
||||
.layoutDirection = RCTLayoutDirection([[RCTI18nUtil sharedInstance] isRTL]),
|
||||
};
|
||||
}
|
||||
|
||||
static inline LayoutContext RCTGetLayoutContext()
|
||||
{
|
||||
return {.pointScaleFactor = RCTScreenScale(),
|
||||
.swapLeftAndRightInRTL =
|
||||
[[RCTI18nUtil sharedInstance] isRTL] && [[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL]};
|
||||
}
|
||||
|
||||
@interface RCTSurfacePresenter () <RCTSchedulerDelegate, RCTMountingManagerDelegate>
|
||||
@end
|
||||
|
||||
@@ -147,10 +163,8 @@ using namespace facebook::react;
|
||||
if (!scheduler) {
|
||||
return minimumSize;
|
||||
}
|
||||
LayoutContext layoutContext = {.pointScaleFactor = RCTScreenScale()};
|
||||
LayoutConstraints layoutConstraints = {.minimumSize = RCTSizeFromCGSize(minimumSize),
|
||||
.maximumSize = RCTSizeFromCGSize(maximumSize),
|
||||
.layoutDirection = RCTLayoutDirection([[RCTI18nUtil sharedInstance] isRTL])};
|
||||
LayoutContext layoutContext = RCTGetLayoutContext();
|
||||
LayoutConstraints layoutConstraints = RCTGetLayoutConstraintsForSize(minimumSize, maximumSize);
|
||||
return [scheduler measureSurfaceWithLayoutConstraints:layoutConstraints
|
||||
layoutContext:layoutContext
|
||||
surfaceId:surface.rootTag];
|
||||
@@ -163,10 +177,8 @@ using namespace facebook::react;
|
||||
return;
|
||||
}
|
||||
|
||||
LayoutContext layoutContext = {.pointScaleFactor = RCTScreenScale()};
|
||||
LayoutConstraints layoutConstraints = {.minimumSize = RCTSizeFromCGSize(minimumSize),
|
||||
.maximumSize = RCTSizeFromCGSize(maximumSize),
|
||||
.layoutDirection = RCTLayoutDirection([[RCTI18nUtil sharedInstance] isRTL])};
|
||||
LayoutContext layoutContext = RCTGetLayoutContext();
|
||||
LayoutConstraints layoutConstraints = RCTGetLayoutConstraintsForSize(minimumSize, maximumSize);
|
||||
[scheduler constraintSurfaceLayoutWithLayoutConstraints:layoutConstraints
|
||||
layoutContext:layoutContext
|
||||
surfaceId:surface.rootTag];
|
||||
@@ -298,11 +310,9 @@ using namespace facebook::react;
|
||||
tag:surface.rootTag];
|
||||
});
|
||||
|
||||
LayoutContext layoutContext = {.pointScaleFactor = RCTScreenScale()};
|
||||
LayoutContext layoutContext = RCTGetLayoutContext();
|
||||
|
||||
LayoutConstraints layoutConstraints = {.minimumSize = RCTSizeFromCGSize(surface.minimumSize),
|
||||
.maximumSize = RCTSizeFromCGSize(surface.maximumSize),
|
||||
.layoutDirection = RCTLayoutDirection([[RCTI18nUtil sharedInstance] isRTL])};
|
||||
LayoutConstraints layoutConstraints = RCTGetLayoutConstraintsForSize(surface.minimumSize, surface.maximumSize);
|
||||
|
||||
[scheduler startSurfaceWithSurfaceId:surface.rootTag
|
||||
moduleName:surface.moduleName
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
#include <react/components/view/ViewProps.h>
|
||||
#include <react/components/view/conversions.h>
|
||||
#include <react/core/LayoutConstraints.h>
|
||||
#include <react/core/LayoutContext.h>
|
||||
#include <react/debug/DebugStringConvertibleItem.h>
|
||||
#include <react/debug/SystraceSection.h>
|
||||
#include <yoga/Yoga.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
@@ -78,11 +80,9 @@ YogaLayoutableShadowNode::YogaLayoutableShadowNode(
|
||||
updateYogaProps();
|
||||
}
|
||||
|
||||
// Yoga children have `yogaNode_` set as owner. At this point that yogaNode_
|
||||
// is from previous `YogaLayoutableShadowNode` that is being cloned here.
|
||||
// Calling `updateYogaChildren` is needed in order to update owner of
|
||||
// children.
|
||||
updateYogaChildren();
|
||||
if (fragment.children) {
|
||||
updateYogaChildren();
|
||||
}
|
||||
}
|
||||
|
||||
void YogaLayoutableShadowNode::cleanLayout() {
|
||||
@@ -126,6 +126,11 @@ void YogaLayoutableShadowNode::appendChild(ShadowNode::Shared const &child) {
|
||||
}
|
||||
}
|
||||
|
||||
bool YogaLayoutableShadowNode::doesOwn(
|
||||
YogaLayoutableShadowNode const &child) const {
|
||||
return child.yogaNode_.getOwner() == &yogaNode_;
|
||||
}
|
||||
|
||||
void YogaLayoutableShadowNode::appendChildYogaNode(
|
||||
YogaLayoutableShadowNode const &child) {
|
||||
ensureUnsealed();
|
||||
@@ -258,6 +263,10 @@ void YogaLayoutableShadowNode::layoutTree(
|
||||
|
||||
applyLayoutConstraints(yogaNode_.getStyle(), layoutConstraints);
|
||||
|
||||
if (layoutContext.swapLeftAndRightInRTL) {
|
||||
swapLeftAndRightInTree(*this);
|
||||
}
|
||||
|
||||
{
|
||||
SystraceSection s("YogaLayoutableShadowNode::YGNodeCalculateLayout");
|
||||
|
||||
@@ -388,5 +397,123 @@ YGConfig &YogaLayoutableShadowNode::initializeYogaConfig(YGConfig &config) {
|
||||
return config;
|
||||
}
|
||||
|
||||
#pragma mark - RTL left and right swapping
|
||||
|
||||
void YogaLayoutableShadowNode::swapLeftAndRightInTree(
|
||||
YogaLayoutableShadowNode const &shadowNode) {
|
||||
swapLeftAndRightInYogaStyleProps(shadowNode);
|
||||
swapLeftAndRightInViewProps(shadowNode);
|
||||
|
||||
for (auto &child : shadowNode.getChildren()) {
|
||||
auto const yogaLayoutableChild =
|
||||
traitCast<YogaLayoutableShadowNode const *>(child.get());
|
||||
if (yogaLayoutableChild && !yogaLayoutableChild->doesOwn(shadowNode)) {
|
||||
swapLeftAndRightInTree(*yogaLayoutableChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void YogaLayoutableShadowNode::swapLeftAndRightInYogaStyleProps(
|
||||
YogaLayoutableShadowNode const &shadowNode) {
|
||||
auto yogaStyle = shadowNode.yogaNode_.getStyle();
|
||||
|
||||
YGStyle::Edges const &position = yogaStyle.position();
|
||||
YGStyle::Edges const &padding = yogaStyle.padding();
|
||||
YGStyle::Edges const &margin = yogaStyle.margin();
|
||||
|
||||
// Swap Yoga node values, position, padding and margin.
|
||||
|
||||
if (yogaStyle.position()[YGEdgeLeft] != YGValueUndefined) {
|
||||
yogaStyle.position()[YGEdgeStart] = position[YGEdgeLeft];
|
||||
yogaStyle.position()[YGEdgeLeft] = YGValueUndefined;
|
||||
}
|
||||
|
||||
if (yogaStyle.position()[YGEdgeRight] != YGValueUndefined) {
|
||||
yogaStyle.position()[YGEdgeEnd] = position[YGEdgeRight];
|
||||
yogaStyle.position()[YGEdgeRight] = YGValueUndefined;
|
||||
}
|
||||
|
||||
if (yogaStyle.padding()[YGEdgeLeft] != YGValueUndefined) {
|
||||
yogaStyle.padding()[YGEdgeStart] = padding[YGEdgeLeft];
|
||||
yogaStyle.padding()[YGEdgeLeft] = YGValueUndefined;
|
||||
}
|
||||
|
||||
if (yogaStyle.padding()[YGEdgeRight] != YGValueUndefined) {
|
||||
yogaStyle.padding()[YGEdgeEnd] = padding[YGEdgeRight];
|
||||
yogaStyle.padding()[YGEdgeRight] = YGValueUndefined;
|
||||
}
|
||||
|
||||
if (yogaStyle.margin()[YGEdgeLeft] != YGValueUndefined) {
|
||||
yogaStyle.margin()[YGEdgeStart] = margin[YGEdgeLeft];
|
||||
yogaStyle.margin()[YGEdgeLeft] = YGValueUndefined;
|
||||
}
|
||||
|
||||
if (yogaStyle.margin()[YGEdgeRight] != YGValueUndefined) {
|
||||
yogaStyle.margin()[YGEdgeEnd] = margin[YGEdgeRight];
|
||||
yogaStyle.margin()[YGEdgeLeft] = YGValueUndefined;
|
||||
}
|
||||
|
||||
shadowNode.yogaNode_.setStyle(yogaStyle);
|
||||
}
|
||||
|
||||
void YogaLayoutableShadowNode::swapLeftAndRightInViewProps(
|
||||
YogaLayoutableShadowNode const &shadowNode) {
|
||||
auto &typedCasting = static_cast<ViewProps const &>(*shadowNode.props_);
|
||||
auto &props = const_cast<ViewProps &>(typedCasting);
|
||||
|
||||
// Swap border node values, borderRadii, borderColors and borderStyles.
|
||||
if (props.borderRadii.topLeft.hasValue()) {
|
||||
props.borderRadii.topStart = props.borderRadii.topLeft;
|
||||
props.borderRadii.topLeft.clear();
|
||||
}
|
||||
|
||||
if (props.borderRadii.bottomLeft.hasValue()) {
|
||||
props.borderRadii.bottomStart = props.borderRadii.bottomLeft;
|
||||
props.borderRadii.bottomLeft.clear();
|
||||
}
|
||||
|
||||
if (props.borderRadii.topRight.hasValue()) {
|
||||
props.borderRadii.topEnd = props.borderRadii.topRight;
|
||||
props.borderRadii.topRight.clear();
|
||||
}
|
||||
|
||||
if (props.borderRadii.bottomRight.hasValue()) {
|
||||
props.borderRadii.bottomEnd = props.borderRadii.bottomRight;
|
||||
props.borderRadii.bottomRight.clear();
|
||||
}
|
||||
|
||||
if (props.borderColors.left.hasValue()) {
|
||||
props.borderColors.start = props.borderColors.left;
|
||||
props.borderColors.left.clear();
|
||||
}
|
||||
|
||||
if (props.borderColors.right.hasValue()) {
|
||||
props.borderColors.end = props.borderColors.right;
|
||||
props.borderColors.right.clear();
|
||||
}
|
||||
|
||||
if (props.borderStyles.left.hasValue()) {
|
||||
props.borderStyles.start = props.borderStyles.left;
|
||||
props.borderStyles.left.clear();
|
||||
}
|
||||
|
||||
if (props.borderStyles.right.hasValue()) {
|
||||
props.borderStyles.end = props.borderStyles.right;
|
||||
props.borderStyles.right.clear();
|
||||
}
|
||||
|
||||
YGStyle::Edges const &border = props.yogaStyle.border();
|
||||
|
||||
if (props.yogaStyle.border()[YGEdgeLeft] != YGValueUndefined) {
|
||||
props.yogaStyle.border()[YGEdgeStart] = border[YGEdgeLeft];
|
||||
props.yogaStyle.border()[YGEdgeLeft] = YGValueUndefined;
|
||||
}
|
||||
|
||||
if (props.yogaStyle.border()[YGEdgeRight] != YGValueUndefined) {
|
||||
props.yogaStyle.border()[YGEdgeEnd] = border[YGEdgeRight];
|
||||
props.yogaStyle.border()[YGEdgeRight] = YGValueUndefined;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
||||
@@ -100,6 +100,12 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode {
|
||||
mutable YGNode yogaNode_;
|
||||
|
||||
private:
|
||||
/*
|
||||
* Return true if child's yogaNode's owner is this->yogaNode_. Otherwise
|
||||
* returns false.
|
||||
*/
|
||||
bool doesOwn(YogaLayoutableShadowNode const &child) const;
|
||||
|
||||
/*
|
||||
* Appends `child`'s Yoga node to the own Yoga node.
|
||||
* Complements `ShadowNode::appendChild(...)` functionality from Yoga
|
||||
@@ -122,6 +128,38 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode {
|
||||
YGMeasureMode widthMode,
|
||||
float height,
|
||||
YGMeasureMode heightMode);
|
||||
|
||||
/*
|
||||
* Walks though shadow node hierarchy and reassign following values:
|
||||
* - (left|right) → (start|end)
|
||||
* - margin(Left|Right) → margin(Start|End)
|
||||
* - padding(Left|Right) → padding(Start|End)
|
||||
* - borderTop(Left|Right)Radius → borderTop(Start|End)Radius
|
||||
* - borderBottom(Left|Right)Radius → borderBottom(Start|End)Radius
|
||||
* - border(Left|Right)Width → border(Start|End)Width
|
||||
* - border(Left|Right)Color → border(Start|End)Color
|
||||
* This is neccesarry to be backwards compatible with Paper, it swaps the
|
||||
* values as well in https://fburl.com/diffusion/kl7bjr3h
|
||||
*/
|
||||
static void swapLeftAndRightInTree(
|
||||
YogaLayoutableShadowNode const &shadowNode);
|
||||
/*
|
||||
* In shadow node passed as argument, reassigns following values
|
||||
* - borderTop(Left|Right)Radius → borderTop(Start|End)Radius
|
||||
* - borderBottom(Left|Right)Radius → borderBottom(Start|End)Radius
|
||||
* - border(Left|Right)Width → border(Start|End)Width
|
||||
* - border(Left|Right)Color → border(Start|End)Color
|
||||
*/
|
||||
static void swapLeftAndRightInViewProps(
|
||||
YogaLayoutableShadowNode const &shadowNode);
|
||||
/*
|
||||
* In yoga node passed as argument, reassigns following values
|
||||
* - (left|right) → (start|end)
|
||||
* - margin(Left|Right) → margin(Start|End)
|
||||
* - padding(Left|Right) → padding(Start|End)
|
||||
*/
|
||||
static void swapLeftAndRightInYogaStyleProps(
|
||||
YogaLayoutableShadowNode const &shadowNode);
|
||||
};
|
||||
|
||||
template <>
|
||||
|
||||
@@ -41,6 +41,20 @@ struct LayoutContext {
|
||||
* purpose), make sure the memory is managed responsibly.
|
||||
*/
|
||||
std::vector<LayoutableShadowNode const *> *affectedNodes{};
|
||||
|
||||
/*
|
||||
* Flag indicating whether in reassignment of direction
|
||||
* aware properties should take place. If yes, following
|
||||
* reassignment will occur in RTL context.
|
||||
* - (left|right) → (start|end)
|
||||
* - margin(Left|Right) → margin(Start|End)
|
||||
* - padding(Left|Right) → padding(Start|End)
|
||||
* - borderTop(Left|Right)Radius → borderTop(Start|End)Radius
|
||||
* - borderBottom(Left|Right)Radius → borderBottom(Start|End)Radius
|
||||
* - border(Left|Right)Width → border(Start|End)Width
|
||||
* - border(Left|Right)Color → border(Start|End)Color
|
||||
*/
|
||||
bool swapLeftAndRightInRTL{false};
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
|
||||
Reference in New Issue
Block a user