Skip to content

Commit 873c6ff

Browse files
MengjueWFacebook Github Bot 9
authored andcommitted
Fix CSSLayout to Support RTL
Summary: The current CSSLayout can't support RTL because wrong calculation for absolute position. This change is mainly to fix the issue: facebook/yoga#197 Three main problems I fixed: 1. Calculate the position in the same way as margin, boarder, and padding. So that to fix the absolute problem. 2. Fix one wrong calculation for leading value when we only know the trailing value. It was hard code for the LTR situation. Now I changed it to depends on the main Axis. 3. Expose getter and setter function for RN to read layout direction and start/end position value. Reviewed By: fkgozali Differential Revision: D3616949 fbshipit-source-id: ae7a47cc0a5d02b42b95f87232be51ab144056d9
1 parent b5abb87 commit 873c6ff

File tree

6 files changed

+201
-135
lines changed

6 files changed

+201
-135
lines changed

React/CSSLayout/CSSLayout-internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ typedef struct CSSStyle {
6565
CSSOverflow overflow;
6666
float flex;
6767
float margin[6];
68-
float position[4];
68+
float position[6];
6969
/**
7070
* You should skip all the rules that contain negative values for the
7171
* following attributes. For example:

React/CSSLayout/CSSLayout.c

Lines changed: 84 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ void CSSNodeInit(CSSNodeRef node) {
7070
node->style.position[CSSPositionTop] = CSSUndefined;
7171
node->style.position[CSSPositionRight] = CSSUndefined;
7272
node->style.position[CSSPositionBottom] = CSSUndefined;
73+
node->style.position[CSSPositionStart] = CSSUndefined;
74+
node->style.position[CSSPositionEnd] = CSSUndefined;
7375

7476
node->style.margin[CSSPositionStart] = CSSUndefined;
7577
node->style.margin[CSSPositionEnd] = CSSUndefined;
@@ -173,6 +175,8 @@ CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionLeft, positionLeft, position[CSSPosi
173175
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionTop, positionTop, position[CSSPositionTop]);
174176
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionRight, positionRight, position[CSSPositionRight]);
175177
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionBottom, positionBottom, position[CSSPositionBottom]);
178+
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionStart, positionStart, position[CSSPositionStart]);
179+
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionEnd, positionEnd, position[CSSPositionEnd]);
176180

177181
CSS_NODE_STYLE_PROPERTY_IMPL(float, MarginLeft, marginLeft, margin[CSSPositionLeft]);
178182
CSS_NODE_STYLE_PROPERTY_IMPL(float, MarginTop, marginTop, margin[CSSPositionTop]);
@@ -208,6 +212,7 @@ CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Right, position[CSSPositionRight]);
208212
CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Bottom, position[CSSPositionBottom]);
209213
CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Width, dimensions[CSSDimensionWidth]);
210214
CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Height, dimensions[CSSDimensionHeight]);
215+
CSS_NODE_LAYOUT_PROPERTY_IMPL(CSSDirection, Direction, direction);
211216

212217
int gCurrentGenerationCount = 0;
213218

@@ -623,18 +628,36 @@ static bool isLayoutDimDefined(CSSNode* node, CSSFlexDirection axis) {
623628
return !isUndefined(value) && value >= 0.0;
624629
}
625630

626-
static bool isPosDefined(CSSNode* node, CSSPosition position) {
627-
return !isUndefined(node->style.position[position]);
631+
static bool isLeadingPosDefined(CSSNode* node, CSSFlexDirection axis) {
632+
return (isRowDirection(axis) && !isUndefined(node->style.position[CSSPositionStart]))
633+
|| !isUndefined(node->style.position[leading[axis]]);
634+
}
635+
636+
static bool isTrailingPosDefined(CSSNode* node, CSSFlexDirection axis) {
637+
return (isRowDirection(axis) && !isUndefined(node->style.position[CSSPositionEnd]))
638+
|| !isUndefined(node->style.position[trailing[axis]]);
628639
}
629640

630641
static bool isMeasureDefined(CSSNode* node) {
631642
return node->measure;
632643
}
633644

634-
static float getPosition(CSSNode* node, CSSPosition position) {
635-
float result = node->style.position[position];
636-
if (!isUndefined(result)) {
637-
return result;
645+
static float getLeadingPosition(CSSNode* node, CSSFlexDirection axis) {
646+
if (isRowDirection(axis) && !isUndefined(node->style.position[CSSPositionStart])) {
647+
return node->style.position[CSSPositionStart];
648+
}
649+
if (!isUndefined(node->style.position[leading[axis]])) {
650+
return node->style.position[leading[axis]];
651+
}
652+
return 0;
653+
}
654+
655+
static float getTrailingPosition(CSSNode* node, CSSFlexDirection axis) {
656+
if (isRowDirection(axis) && !isUndefined(node->style.position[CSSPositionEnd])) {
657+
return node->style.position[CSSPositionEnd];
658+
}
659+
if (!isUndefined(node->style.position[trailing[axis]])) {
660+
return node->style.position[trailing[axis]];
638661
}
639662
return 0;
640663
}
@@ -670,20 +693,18 @@ static float boundAxis(CSSNode* node, CSSFlexDirection axis, float value) {
670693
}
671694

672695
static void setTrailingPosition(CSSNode* node, CSSNode* child, CSSFlexDirection axis) {
673-
float size = child->style.positionType == CSSPositionTypeAbsolute ?
674-
0 :
675-
child->layout.measuredDimensions[dim[axis]];
696+
float size = child->layout.measuredDimensions[dim[axis]];
676697
child->layout.position[trailing[axis]] = node->layout.measuredDimensions[dim[axis]] - size - child->layout.position[pos[axis]];
677698
}
678699

679700
// If both left and right are defined, then use left. Otherwise return
680701
// +left or -right depending on which is defined.
681702
static float getRelativePosition(CSSNode* node, CSSFlexDirection axis) {
682-
float lead = node->style.position[leading[axis]];
703+
float lead = getLeadingPosition(node, axis);
683704
if (!isUndefined(lead)) {
684705
return lead;
685706
}
686-
return -getPosition(node, trailing[axis]);
707+
return -getTrailingPosition(node, axis);
687708
}
688709

689710
static void setPosition(CSSNode* node, CSSDirection direction) {
@@ -1294,12 +1315,12 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH
12941315
child = CSSNodeListGet(node->children, i);
12951316

12961317
if (child->style.positionType == CSSPositionTypeAbsolute &&
1297-
isPosDefined(child, leading[mainAxis])) {
1318+
isLeadingPosDefined(child, mainAxis)) {
12981319
if (performLayout) {
12991320
// In case the child is position absolute and has left/top being
13001321
// defined, we override the position to whatever the user said
13011322
// (and margin/border).
1302-
child->layout.position[pos[mainAxis]] = getPosition(child, leading[mainAxis]) +
1323+
child->layout.position[pos[mainAxis]] = getLeadingPosition(child, mainAxis) +
13031324
getLeadingBorder(node, mainAxis) +
13041325
getLeadingMargin(child, mainAxis);
13051326
}
@@ -1361,8 +1382,8 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH
13611382
if (child->style.positionType == CSSPositionTypeAbsolute) {
13621383
// If the child is absolutely positioned and has a top/left/bottom/right
13631384
// set, override all the previously computed positions to set it correctly.
1364-
if (isPosDefined(child, leading[crossAxis])) {
1365-
child->layout.position[pos[crossAxis]] = getPosition(child, leading[crossAxis]) +
1385+
if (isLeadingPosDefined(child, crossAxis)) {
1386+
child->layout.position[pos[crossAxis]] = getLeadingPosition(child, crossAxis) +
13661387
getLeadingBorder(node, crossAxis) +
13671388
getLeadingMargin(child, crossAxis);
13681389
} else {
@@ -1518,38 +1539,7 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH
15181539
paddingAndBorderAxisCross);
15191540
}
15201541

1521-
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
1522-
if (performLayout) {
1523-
bool needsMainTrailingPos = false;
1524-
bool needsCrossTrailingPos = false;
1525-
1526-
if (mainAxis == CSSFlexDirectionRowReverse ||
1527-
mainAxis == CSSFlexDirectionColumnReverse) {
1528-
needsMainTrailingPos = true;
1529-
}
1530-
1531-
if (crossAxis == CSSFlexDirectionRowReverse ||
1532-
crossAxis == CSSFlexDirectionColumnReverse) {
1533-
needsCrossTrailingPos = true;
1534-
}
1535-
1536-
// Set trailing position if necessary.
1537-
if (needsMainTrailingPos || needsCrossTrailingPos) {
1538-
for (i = 0; i < childCount; ++i) {
1539-
child = CSSNodeListGet(node->children, i);
1540-
1541-
if (needsMainTrailingPos) {
1542-
setTrailingPosition(node, child, mainAxis);
1543-
}
1544-
1545-
if (needsCrossTrailingPos) {
1546-
setTrailingPosition(node, child, crossAxis);
1547-
}
1548-
}
1549-
}
1550-
}
1551-
1552-
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
1542+
// STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN
15531543
currentAbsoluteChild = firstAbsoluteChild;
15541544
while (currentAbsoluteChild != NULL) {
15551545
// Now that we know the bounds of the container, perform layout again on the
@@ -1563,10 +1553,10 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH
15631553
childWidth = currentAbsoluteChild->style.dimensions[CSSDimensionWidth] + getMarginAxis(currentAbsoluteChild, CSSFlexDirectionRow);
15641554
} else {
15651555
// If the child doesn't have a specified width, compute the width based on the left/right offsets if they're defined.
1566-
if (isPosDefined(currentAbsoluteChild, CSSPositionLeft) && isPosDefined(currentAbsoluteChild, CSSPositionRight)) {
1556+
if (isLeadingPosDefined(currentAbsoluteChild, CSSFlexDirectionRow) && isTrailingPosDefined(currentAbsoluteChild, CSSFlexDirectionRow)) {
15671557
childWidth = node->layout.measuredDimensions[CSSDimensionWidth] -
15681558
(getLeadingBorder(node, CSSFlexDirectionRow) + getTrailingBorder(node, CSSFlexDirectionRow)) -
1569-
(currentAbsoluteChild->style.position[CSSPositionLeft] + currentAbsoluteChild->style.position[CSSPositionRight]);
1559+
(getLeadingPosition(currentAbsoluteChild, CSSFlexDirectionRow) + getTrailingPosition(currentAbsoluteChild, CSSFlexDirectionRow));
15701560
childWidth = boundAxis(currentAbsoluteChild, CSSFlexDirectionRow, childWidth);
15711561
}
15721562
}
@@ -1575,10 +1565,10 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH
15751565
childHeight = currentAbsoluteChild->style.dimensions[CSSDimensionHeight] + getMarginAxis(currentAbsoluteChild, CSSFlexDirectionColumn);
15761566
} else {
15771567
// If the child doesn't have a specified height, compute the height based on the top/bottom offsets if they're defined.
1578-
if (isPosDefined(currentAbsoluteChild, CSSPositionTop) && isPosDefined(currentAbsoluteChild, CSSPositionBottom)) {
1568+
if (isLeadingPosDefined(currentAbsoluteChild, CSSFlexDirectionColumn) && isTrailingPosDefined(currentAbsoluteChild, CSSFlexDirectionColumn)) {
15791569
childHeight = node->layout.measuredDimensions[CSSDimensionHeight] -
15801570
(getLeadingBorder(node, CSSFlexDirectionColumn) + getTrailingBorder(node, CSSFlexDirectionColumn)) -
1581-
(currentAbsoluteChild->style.position[CSSPositionTop] + currentAbsoluteChild->style.position[CSSPositionBottom]);
1571+
(getLeadingPosition(currentAbsoluteChild, CSSFlexDirectionColumn) + getTrailingPosition(currentAbsoluteChild, CSSFlexDirectionColumn));
15821572
childHeight = boundAxis(currentAbsoluteChild, CSSFlexDirectionColumn, childHeight);
15831573
}
15841574
}
@@ -1613,25 +1603,56 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH
16131603

16141604
layoutNodeInternal(currentAbsoluteChild, childWidth, childHeight, direction, CSSMeasureModeExactly, CSSMeasureModeExactly, true, "abs-layout");
16151605

1616-
if (isPosDefined(currentAbsoluteChild, trailing[CSSFlexDirectionRow]) &&
1617-
!isPosDefined(currentAbsoluteChild, leading[CSSFlexDirectionRow])) {
1618-
currentAbsoluteChild->layout.position[leading[CSSFlexDirectionRow]] =
1619-
node->layout.measuredDimensions[dim[CSSFlexDirectionRow]] -
1620-
currentAbsoluteChild->layout.measuredDimensions[dim[CSSFlexDirectionRow]] -
1621-
getPosition(currentAbsoluteChild, trailing[CSSFlexDirectionRow]);
1606+
if (isTrailingPosDefined(currentAbsoluteChild, mainAxis) &&
1607+
!isLeadingPosDefined(currentAbsoluteChild, mainAxis)) {
1608+
currentAbsoluteChild->layout.position[leading[mainAxis]] =
1609+
node->layout.measuredDimensions[dim[mainAxis]] -
1610+
currentAbsoluteChild->layout.measuredDimensions[dim[mainAxis]] -
1611+
getTrailingPosition(currentAbsoluteChild, mainAxis);
16221612
}
16231613

1624-
if (isPosDefined(currentAbsoluteChild, trailing[CSSFlexDirectionColumn]) &&
1625-
!isPosDefined(currentAbsoluteChild, leading[CSSFlexDirectionColumn])) {
1626-
currentAbsoluteChild->layout.position[leading[CSSFlexDirectionColumn]] =
1627-
node->layout.measuredDimensions[dim[CSSFlexDirectionColumn]] -
1628-
currentAbsoluteChild->layout.measuredDimensions[dim[CSSFlexDirectionColumn]] -
1629-
getPosition(currentAbsoluteChild, trailing[CSSFlexDirectionColumn]);
1614+
if (isTrailingPosDefined(currentAbsoluteChild, crossAxis) &&
1615+
!isLeadingPosDefined(currentAbsoluteChild, crossAxis)) {
1616+
currentAbsoluteChild->layout.position[leading[crossAxis]] =
1617+
node->layout.measuredDimensions[dim[crossAxis]] -
1618+
currentAbsoluteChild->layout.measuredDimensions[dim[crossAxis]] -
1619+
getTrailingPosition(currentAbsoluteChild, crossAxis);
16301620
}
16311621
}
16321622

16331623
currentAbsoluteChild = currentAbsoluteChild->nextChild;
16341624
}
1625+
1626+
// STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN
1627+
if (performLayout) {
1628+
bool needsMainTrailingPos = false;
1629+
bool needsCrossTrailingPos = false;
1630+
1631+
if (mainAxis == CSSFlexDirectionRowReverse ||
1632+
mainAxis == CSSFlexDirectionColumnReverse) {
1633+
needsMainTrailingPos = true;
1634+
}
1635+
1636+
if (crossAxis == CSSFlexDirectionRowReverse ||
1637+
crossAxis == CSSFlexDirectionColumnReverse) {
1638+
needsCrossTrailingPos = true;
1639+
}
1640+
1641+
// Set trailing position if necessary.
1642+
if (needsMainTrailingPos || needsCrossTrailingPos) {
1643+
for (i = 0; i < childCount; ++i) {
1644+
child = CSSNodeListGet(node->children, i);
1645+
1646+
if (needsMainTrailingPos) {
1647+
setTrailingPosition(node, child, mainAxis);
1648+
}
1649+
1650+
if (needsCrossTrailingPos) {
1651+
setTrailingPosition(node, child, crossAxis);
1652+
}
1653+
}
1654+
}
1655+
}
16351656
}
16361657

16371658
int gDepth = 0;

React/CSSLayout/CSSLayout.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ CSS_NODE_STYLE_PROPERTY(float, PositionLeft, positionLeft);
169169
CSS_NODE_STYLE_PROPERTY(float, PositionTop, positionTop);
170170
CSS_NODE_STYLE_PROPERTY(float, PositionRight, positionRight);
171171
CSS_NODE_STYLE_PROPERTY(float, PositionBottom, positionBottom);
172+
CSS_NODE_STYLE_PROPERTY(float, PositionStart, positionStart);
173+
CSS_NODE_STYLE_PROPERTY(float, PositionEnd, positionEnd);
172174

173175
CSS_NODE_STYLE_PROPERTY(float, MarginLeft, marginLeft);
174176
CSS_NODE_STYLE_PROPERTY(float, MarginTop, marginTop);
@@ -204,6 +206,7 @@ CSS_NODE_LAYOUT_PROPERTY(float, Right);
204206
CSS_NODE_LAYOUT_PROPERTY(float, Bottom);
205207
CSS_NODE_LAYOUT_PROPERTY(float, Width);
206208
CSS_NODE_LAYOUT_PROPERTY(float, Height);
209+
CSS_NODE_LAYOUT_PROPERTY(CSSDirection, Direction);
207210

208211
CSS_EXTERN_C_END
209212

ReactAndroid/src/main/java/com/facebook/csslayout/CSSNode.java

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717

1818
import static com.facebook.csslayout.CSSLayout.DIMENSION_HEIGHT;
1919
import static com.facebook.csslayout.CSSLayout.DIMENSION_WIDTH;
20-
import static com.facebook.csslayout.CSSLayout.POSITION_BOTTOM;
2120
import static com.facebook.csslayout.CSSLayout.POSITION_LEFT;
22-
import static com.facebook.csslayout.CSSLayout.POSITION_RIGHT;
2321
import static com.facebook.csslayout.CSSLayout.POSITION_TOP;
22+
import static com.facebook.csslayout.Spacing.BOTTOM;
23+
import static com.facebook.csslayout.Spacing.LEFT;
24+
import static com.facebook.csslayout.Spacing.RIGHT;
25+
import static com.facebook.csslayout.Spacing.TOP;
2426

2527
/**
2628
* A CSS Node. It has a style object you can manipulate at {@link #style}. After calling
@@ -373,16 +375,28 @@ public void setBorder(int spacingType, float border) {
373375
}
374376
}
375377

378+
/**
379+
* Get this node's position, as defined by style.
380+
*/
381+
public Spacing getPosition() {
382+
return style.position;
383+
}
384+
385+
public void setPosition(int spacingType, float position) {
386+
if (style.position.set(spacingType, position)) {
387+
dirty();
388+
}
389+
}
390+
376391
/**
377392
* Get this node's position top, as defined by style.
378393
*/
379394
public float getPositionTop() {
380-
return style.position[POSITION_TOP];
395+
return style.position.get(TOP);
381396
}
382397

383398
public void setPositionTop(float positionTop) {
384-
if (!valuesEqual(style.position[POSITION_TOP], positionTop)) {
385-
style.position[POSITION_TOP] = positionTop;
399+
if (style.position.set(TOP, positionTop)) {
386400
dirty();
387401
}
388402
}
@@ -391,12 +405,11 @@ public void setPositionTop(float positionTop) {
391405
* Get this node's position bottom, as defined by style.
392406
*/
393407
public float getPositionBottom() {
394-
return style.position[POSITION_BOTTOM];
408+
return style.position.get(BOTTOM);
395409
}
396410

397411
public void setPositionBottom(float positionBottom) {
398-
if (!valuesEqual(style.position[POSITION_BOTTOM], positionBottom)) {
399-
style.position[POSITION_BOTTOM] = positionBottom;
412+
if (style.position.set(BOTTOM, positionBottom)) {
400413
dirty();
401414
}
402415
}
@@ -405,12 +418,11 @@ public void setPositionBottom(float positionBottom) {
405418
* Get this node's position left, as defined by style.
406419
*/
407420
public float getPositionLeft() {
408-
return style.position[POSITION_LEFT];
421+
return style.position.get(LEFT);
409422
}
410423

411424
public void setPositionLeft(float positionLeft) {
412-
if (!valuesEqual(style.position[POSITION_LEFT], positionLeft)) {
413-
style.position[POSITION_LEFT] = positionLeft;
425+
if (style.position.set(LEFT, positionLeft)) {
414426
dirty();
415427
}
416428
}
@@ -419,12 +431,11 @@ public void setPositionLeft(float positionLeft) {
419431
* Get this node's position right, as defined by style.
420432
*/
421433
public float getPositionRight() {
422-
return style.position[POSITION_RIGHT];
434+
return style.position.get(RIGHT);
423435
}
424436

425437
public void setPositionRight(float positionRight) {
426-
if (!valuesEqual(style.position[POSITION_RIGHT], positionRight)) {
427-
style.position[POSITION_RIGHT] = positionRight;
438+
if (style.position.set(RIGHT, positionRight)) {
428439
dirty();
429440
}
430441
}

0 commit comments

Comments
 (0)