diff --git a/CSSLayout/CSSLayout-internal.h b/CSSLayout/CSSLayout-internal.h index 2c65026c..ec0e5fb3 100644 --- a/CSSLayout/CSSLayout-internal.h +++ b/CSSLayout/CSSLayout-internal.h @@ -65,7 +65,7 @@ typedef struct CSSStyle { CSSOverflow overflow; float flex; float margin[6]; - float position[4]; + float position[6]; /** * You should skip all the rules that contain negative values for the * following attributes. For example: diff --git a/CSSLayout/CSSLayout.c b/CSSLayout/CSSLayout.c index 49136970..19962383 100644 --- a/CSSLayout/CSSLayout.c +++ b/CSSLayout/CSSLayout.c @@ -70,6 +70,8 @@ void CSSNodeInit(CSSNodeRef node) { node->style.position[CSSPositionTop] = CSSUndefined; node->style.position[CSSPositionRight] = CSSUndefined; node->style.position[CSSPositionBottom] = CSSUndefined; + node->style.position[CSSPositionStart] = CSSUndefined; + node->style.position[CSSPositionEnd] = CSSUndefined; node->style.margin[CSSPositionStart] = CSSUndefined; node->style.margin[CSSPositionEnd] = CSSUndefined; @@ -173,6 +175,8 @@ CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionLeft, positionLeft, position[CSSPosi CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionTop, positionTop, position[CSSPositionTop]); CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionRight, positionRight, position[CSSPositionRight]); CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionBottom, positionBottom, position[CSSPositionBottom]); +CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionStart, positionStart, position[CSSPositionStart]); +CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionEnd, positionEnd, position[CSSPositionEnd]); CSS_NODE_STYLE_PROPERTY_IMPL(float, MarginLeft, marginLeft, margin[CSSPositionLeft]); CSS_NODE_STYLE_PROPERTY_IMPL(float, MarginTop, marginTop, margin[CSSPositionTop]); @@ -208,6 +212,7 @@ CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Right, position[CSSPositionRight]); CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Bottom, position[CSSPositionBottom]); CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Width, dimensions[CSSDimensionWidth]); CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Height, dimensions[CSSDimensionHeight]); +CSS_NODE_LAYOUT_PROPERTY_IMPL(CSSDirection, Direction, direction); int gCurrentGenerationCount = 0; @@ -623,18 +628,36 @@ static bool isLayoutDimDefined(CSSNode* node, CSSFlexDirection axis) { return !isUndefined(value) && value >= 0.0; } -static bool isPosDefined(CSSNode* node, CSSPosition position) { - return !isUndefined(node->style.position[position]); +static bool isLeadingPosDefined(CSSNode* node, CSSFlexDirection axis) { + return (isRowDirection(axis) && !isUndefined(node->style.position[CSSPositionStart])) + || !isUndefined(node->style.position[leading[axis]]); +} + +static bool isTrailingPosDefined(CSSNode* node, CSSFlexDirection axis) { + return (isRowDirection(axis) && !isUndefined(node->style.position[CSSPositionEnd])) + || !isUndefined(node->style.position[trailing[axis]]); } static bool isMeasureDefined(CSSNode* node) { return node->measure; } -static float getPosition(CSSNode* node, CSSPosition position) { - float result = node->style.position[position]; - if (!isUndefined(result)) { - return result; +static float getLeadingPosition(CSSNode* node, CSSFlexDirection axis) { + if (isRowDirection(axis) && !isUndefined(node->style.position[CSSPositionStart])) { + return node->style.position[CSSPositionStart]; + } + if (!isUndefined(node->style.position[leading[axis]])) { + return node->style.position[leading[axis]]; + } + return 0; +} + +static float getTrailingPosition(CSSNode* node, CSSFlexDirection axis) { + if (isRowDirection(axis) && !isUndefined(node->style.position[CSSPositionEnd])) { + return node->style.position[CSSPositionEnd]; + } + if (!isUndefined(node->style.position[trailing[axis]])) { + return node->style.position[trailing[axis]]; } return 0; } @@ -670,20 +693,18 @@ static float boundAxis(CSSNode* node, CSSFlexDirection axis, float value) { } static void setTrailingPosition(CSSNode* node, CSSNode* child, CSSFlexDirection axis) { - float size = child->style.positionType == CSSPositionTypeAbsolute ? - 0 : - child->layout.measuredDimensions[dim[axis]]; + float size = child->layout.measuredDimensions[dim[axis]]; child->layout.position[trailing[axis]] = node->layout.measuredDimensions[dim[axis]] - size - child->layout.position[pos[axis]]; } // If both left and right are defined, then use left. Otherwise return // +left or -right depending on which is defined. static float getRelativePosition(CSSNode* node, CSSFlexDirection axis) { - float lead = node->style.position[leading[axis]]; + float lead = getLeadingPosition(node, axis); if (!isUndefined(lead)) { return lead; } - return -getPosition(node, trailing[axis]); + return -getTrailingPosition(node, axis); } static void setPosition(CSSNode* node, CSSDirection direction) { @@ -1294,12 +1315,12 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH child = CSSNodeListGet(node->children, i); if (child->style.positionType == CSSPositionTypeAbsolute && - isPosDefined(child, leading[mainAxis])) { + isLeadingPosDefined(child, mainAxis)) { if (performLayout) { // In case the child is position absolute and has left/top being // defined, we override the position to whatever the user said // (and margin/border). - child->layout.position[pos[mainAxis]] = getPosition(child, leading[mainAxis]) + + child->layout.position[pos[mainAxis]] = getLeadingPosition(child, mainAxis) + getLeadingBorder(node, mainAxis) + getLeadingMargin(child, mainAxis); } @@ -1361,8 +1382,8 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH if (child->style.positionType == CSSPositionTypeAbsolute) { // If the child is absolutely positioned and has a top/left/bottom/right // set, override all the previously computed positions to set it correctly. - if (isPosDefined(child, leading[crossAxis])) { - child->layout.position[pos[crossAxis]] = getPosition(child, leading[crossAxis]) + + if (isLeadingPosDefined(child, crossAxis)) { + child->layout.position[pos[crossAxis]] = getLeadingPosition(child, crossAxis) + getLeadingBorder(node, crossAxis) + getLeadingMargin(child, crossAxis); } else { @@ -1518,38 +1539,7 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH paddingAndBorderAxisCross); } - // STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN - if (performLayout) { - bool needsMainTrailingPos = false; - bool needsCrossTrailingPos = false; - - if (mainAxis == CSSFlexDirectionRowReverse || - mainAxis == CSSFlexDirectionColumnReverse) { - needsMainTrailingPos = true; - } - - if (crossAxis == CSSFlexDirectionRowReverse || - crossAxis == CSSFlexDirectionColumnReverse) { - needsCrossTrailingPos = true; - } - - // Set trailing position if necessary. - if (needsMainTrailingPos || needsCrossTrailingPos) { - for (i = 0; i < childCount; ++i) { - child = CSSNodeListGet(node->children, i); - - if (needsMainTrailingPos) { - setTrailingPosition(node, child, mainAxis); - } - - if (needsCrossTrailingPos) { - setTrailingPosition(node, child, crossAxis); - } - } - } - } - - // STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN + // STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN currentAbsoluteChild = firstAbsoluteChild; while (currentAbsoluteChild != NULL) { // 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 childWidth = currentAbsoluteChild->style.dimensions[CSSDimensionWidth] + getMarginAxis(currentAbsoluteChild, CSSFlexDirectionRow); } else { // If the child doesn't have a specified width, compute the width based on the left/right offsets if they're defined. - if (isPosDefined(currentAbsoluteChild, CSSPositionLeft) && isPosDefined(currentAbsoluteChild, CSSPositionRight)) { + if (isLeadingPosDefined(currentAbsoluteChild, CSSFlexDirectionRow) && isTrailingPosDefined(currentAbsoluteChild, CSSFlexDirectionRow)) { childWidth = node->layout.measuredDimensions[CSSDimensionWidth] - (getLeadingBorder(node, CSSFlexDirectionRow) + getTrailingBorder(node, CSSFlexDirectionRow)) - - (currentAbsoluteChild->style.position[CSSPositionLeft] + currentAbsoluteChild->style.position[CSSPositionRight]); + (getLeadingPosition(currentAbsoluteChild, CSSFlexDirectionRow) + getTrailingPosition(currentAbsoluteChild, CSSFlexDirectionRow)); childWidth = boundAxis(currentAbsoluteChild, CSSFlexDirectionRow, childWidth); } } @@ -1575,10 +1565,10 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH childHeight = currentAbsoluteChild->style.dimensions[CSSDimensionHeight] + getMarginAxis(currentAbsoluteChild, CSSFlexDirectionColumn); } else { // If the child doesn't have a specified height, compute the height based on the top/bottom offsets if they're defined. - if (isPosDefined(currentAbsoluteChild, CSSPositionTop) && isPosDefined(currentAbsoluteChild, CSSPositionBottom)) { + if (isLeadingPosDefined(currentAbsoluteChild, CSSFlexDirectionColumn) && isTrailingPosDefined(currentAbsoluteChild, CSSFlexDirectionColumn)) { childHeight = node->layout.measuredDimensions[CSSDimensionHeight] - (getLeadingBorder(node, CSSFlexDirectionColumn) + getTrailingBorder(node, CSSFlexDirectionColumn)) - - (currentAbsoluteChild->style.position[CSSPositionTop] + currentAbsoluteChild->style.position[CSSPositionBottom]); + (getLeadingPosition(currentAbsoluteChild, CSSFlexDirectionColumn) + getTrailingPosition(currentAbsoluteChild, CSSFlexDirectionColumn)); childHeight = boundAxis(currentAbsoluteChild, CSSFlexDirectionColumn, childHeight); } } @@ -1613,25 +1603,56 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH layoutNodeInternal(currentAbsoluteChild, childWidth, childHeight, direction, CSSMeasureModeExactly, CSSMeasureModeExactly, true, "abs-layout"); - if (isPosDefined(currentAbsoluteChild, trailing[CSSFlexDirectionRow]) && - !isPosDefined(currentAbsoluteChild, leading[CSSFlexDirectionRow])) { - currentAbsoluteChild->layout.position[leading[CSSFlexDirectionRow]] = - node->layout.measuredDimensions[dim[CSSFlexDirectionRow]] - - currentAbsoluteChild->layout.measuredDimensions[dim[CSSFlexDirectionRow]] - - getPosition(currentAbsoluteChild, trailing[CSSFlexDirectionRow]); + if (isTrailingPosDefined(currentAbsoluteChild, mainAxis) && + !isLeadingPosDefined(currentAbsoluteChild, mainAxis)) { + currentAbsoluteChild->layout.position[leading[mainAxis]] = + node->layout.measuredDimensions[dim[mainAxis]] - + currentAbsoluteChild->layout.measuredDimensions[dim[mainAxis]] - + getTrailingPosition(currentAbsoluteChild, mainAxis); } - if (isPosDefined(currentAbsoluteChild, trailing[CSSFlexDirectionColumn]) && - !isPosDefined(currentAbsoluteChild, leading[CSSFlexDirectionColumn])) { - currentAbsoluteChild->layout.position[leading[CSSFlexDirectionColumn]] = - node->layout.measuredDimensions[dim[CSSFlexDirectionColumn]] - - currentAbsoluteChild->layout.measuredDimensions[dim[CSSFlexDirectionColumn]] - - getPosition(currentAbsoluteChild, trailing[CSSFlexDirectionColumn]); + if (isTrailingPosDefined(currentAbsoluteChild, crossAxis) && + !isLeadingPosDefined(currentAbsoluteChild, crossAxis)) { + currentAbsoluteChild->layout.position[leading[crossAxis]] = + node->layout.measuredDimensions[dim[crossAxis]] - + currentAbsoluteChild->layout.measuredDimensions[dim[crossAxis]] - + getTrailingPosition(currentAbsoluteChild, crossAxis); } } currentAbsoluteChild = currentAbsoluteChild->nextChild; } + + // STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN + if (performLayout) { + bool needsMainTrailingPos = false; + bool needsCrossTrailingPos = false; + + if (mainAxis == CSSFlexDirectionRowReverse || + mainAxis == CSSFlexDirectionColumnReverse) { + needsMainTrailingPos = true; + } + + if (crossAxis == CSSFlexDirectionRowReverse || + crossAxis == CSSFlexDirectionColumnReverse) { + needsCrossTrailingPos = true; + } + + // Set trailing position if necessary. + if (needsMainTrailingPos || needsCrossTrailingPos) { + for (i = 0; i < childCount; ++i) { + child = CSSNodeListGet(node->children, i); + + if (needsMainTrailingPos) { + setTrailingPosition(node, child, mainAxis); + } + + if (needsCrossTrailingPos) { + setTrailingPosition(node, child, crossAxis); + } + } + } + } } int gDepth = 0; diff --git a/CSSLayout/CSSLayout.h b/CSSLayout/CSSLayout.h index 23d38372..7babbd81 100644 --- a/CSSLayout/CSSLayout.h +++ b/CSSLayout/CSSLayout.h @@ -169,6 +169,8 @@ CSS_NODE_STYLE_PROPERTY(float, PositionLeft, positionLeft); CSS_NODE_STYLE_PROPERTY(float, PositionTop, positionTop); CSS_NODE_STYLE_PROPERTY(float, PositionRight, positionRight); CSS_NODE_STYLE_PROPERTY(float, PositionBottom, positionBottom); +CSS_NODE_STYLE_PROPERTY(float, PositionStart, positionStart); +CSS_NODE_STYLE_PROPERTY(float, PositionEnd, positionEnd); CSS_NODE_STYLE_PROPERTY(float, MarginLeft, marginLeft); CSS_NODE_STYLE_PROPERTY(float, MarginTop, marginTop); @@ -204,6 +206,7 @@ CSS_NODE_LAYOUT_PROPERTY(float, Right); CSS_NODE_LAYOUT_PROPERTY(float, Bottom); CSS_NODE_LAYOUT_PROPERTY(float, Width); CSS_NODE_LAYOUT_PROPERTY(float, Height); +CSS_NODE_LAYOUT_PROPERTY(CSSDirection, Direction); CSS_EXTERN_C_END diff --git a/java/com/facebook/csslayout/CSSNode.java b/java/com/facebook/csslayout/CSSNode.java index 6bb7cf66..3bdcba33 100644 --- a/java/com/facebook/csslayout/CSSNode.java +++ b/java/com/facebook/csslayout/CSSNode.java @@ -17,10 +17,12 @@ import com.facebook.infer.annotation.Assertions; import static com.facebook.csslayout.CSSLayout.DIMENSION_HEIGHT; import static com.facebook.csslayout.CSSLayout.DIMENSION_WIDTH; -import static com.facebook.csslayout.CSSLayout.POSITION_BOTTOM; import static com.facebook.csslayout.CSSLayout.POSITION_LEFT; -import static com.facebook.csslayout.CSSLayout.POSITION_RIGHT; import static com.facebook.csslayout.CSSLayout.POSITION_TOP; +import static com.facebook.csslayout.Spacing.BOTTOM; +import static com.facebook.csslayout.Spacing.LEFT; +import static com.facebook.csslayout.Spacing.RIGHT; +import static com.facebook.csslayout.Spacing.TOP; /** * A CSS Node. It has a style object you can manipulate at {@link #style}. After calling @@ -373,16 +375,28 @@ public class CSSNode { } } + /** + * Get this node's position, as defined by style. + */ + public Spacing getPosition() { + return style.position; + } + + public void setPosition(int spacingType, float position) { + if (style.position.set(spacingType, position)) { + dirty(); + } + } + /** * Get this node's position top, as defined by style. */ public float getPositionTop() { - return style.position[POSITION_TOP]; + return style.position.get(TOP); } public void setPositionTop(float positionTop) { - if (!valuesEqual(style.position[POSITION_TOP], positionTop)) { - style.position[POSITION_TOP] = positionTop; + if (style.position.set(TOP, positionTop)) { dirty(); } } @@ -391,12 +405,11 @@ public class CSSNode { * Get this node's position bottom, as defined by style. */ public float getPositionBottom() { - return style.position[POSITION_BOTTOM]; + return style.position.get(BOTTOM); } public void setPositionBottom(float positionBottom) { - if (!valuesEqual(style.position[POSITION_BOTTOM], positionBottom)) { - style.position[POSITION_BOTTOM] = positionBottom; + if (style.position.set(BOTTOM, positionBottom)) { dirty(); } } @@ -405,12 +418,11 @@ public class CSSNode { * Get this node's position left, as defined by style. */ public float getPositionLeft() { - return style.position[POSITION_LEFT]; + return style.position.get(LEFT); } public void setPositionLeft(float positionLeft) { - if (!valuesEqual(style.position[POSITION_LEFT], positionLeft)) { - style.position[POSITION_LEFT] = positionLeft; + if (style.position.set(LEFT, positionLeft)) { dirty(); } } @@ -419,12 +431,11 @@ public class CSSNode { * Get this node's position right, as defined by style. */ public float getPositionRight() { - return style.position[POSITION_RIGHT]; + return style.position.get(RIGHT); } public void setPositionRight(float positionRight) { - if (!valuesEqual(style.position[POSITION_RIGHT], positionRight)) { - style.position[POSITION_RIGHT] = positionRight; + if (style.position.set(RIGHT, positionRight)) { dirty(); } } diff --git a/java/com/facebook/csslayout/CSSStyle.java b/java/com/facebook/csslayout/CSSStyle.java index 8c86149e..b2a8d8b8 100644 --- a/java/com/facebook/csslayout/CSSStyle.java +++ b/java/com/facebook/csslayout/CSSStyle.java @@ -30,8 +30,8 @@ public class CSSStyle { public Spacing margin = new Spacing(); public Spacing padding = new Spacing(); public Spacing border = new Spacing(); + public Spacing position = new Spacing(); - public float[] position = new float[4]; public float[] dimensions = new float[2]; public float minWidth = CSSConstants.UNDEFINED; @@ -56,11 +56,18 @@ public class CSSStyle { overflow = CSSOverflow.VISIBLE; flex = 0f; - margin.reset();; + margin.reset(); padding.reset(); border.reset(); + position.reset(); + + position.setDefault(Spacing.LEFT, CSSConstants.UNDEFINED); + position.setDefault(Spacing.RIGHT, CSSConstants.UNDEFINED); + position.setDefault(Spacing.TOP, CSSConstants.UNDEFINED); + position.setDefault(Spacing.BOTTOM, CSSConstants.UNDEFINED); + position.setDefault(Spacing.START, CSSConstants.UNDEFINED); + position.setDefault(Spacing.END, CSSConstants.UNDEFINED); - Arrays.fill(position, CSSConstants.UNDEFINED); Arrays.fill(dimensions, CSSConstants.UNDEFINED); minWidth = CSSConstants.UNDEFINED; diff --git a/java/com/facebook/csslayout/LayoutEngine.java b/java/com/facebook/csslayout/LayoutEngine.java index bb8e90b6..3f84e66f 100644 --- a/java/com/facebook/csslayout/LayoutEngine.java +++ b/java/com/facebook/csslayout/LayoutEngine.java @@ -149,12 +149,12 @@ public class LayoutEngine { } private static float getRelativePosition(CSSNode node, int axis) { - float lead = node.style.position[leading[axis]]; + float lead = node.style.position.getWithFallback(leadingSpacing[axis], leading[axis]); if (!Float.isNaN(lead)) { return lead; } - float trailingPos = node.style.position[trailing[axis]]; + float trailingPos = node.style.position.getWithFallback(trailingSpacing[axis], trailing[axis]); return Float.isNaN(trailingPos) ? 0 : -trailingPos; } @@ -1069,12 +1069,15 @@ public class LayoutEngine { child = node.getChildAt(i); if (child.style.positionType == CSSPositionType.ABSOLUTE && - !Float.isNaN(child.style.position[leading[mainAxis]])) { + !Float.isNaN(child.style.position.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]))) { if (performLayout) { // In case the child is position absolute and has left/top being // defined, we override the position to whatever the user said // (and margin/border). - child.layout.position[pos[mainAxis]] = (Float.isNaN(child.style.position[leading[mainAxis]]) ? 0 : child.style.position[leading[mainAxis]]) + + child.layout.position[pos[mainAxis]] = + (Float.isNaN(child.style.position.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) ? + 0 : + child.style.position.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + node.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]); } @@ -1136,8 +1139,11 @@ public class LayoutEngine { if (child.style.positionType == CSSPositionType.ABSOLUTE) { // If the child is absolutely positioned and has a top/left/bottom/right // set, override all the previously computed positions to set it correctly. - if (!Float.isNaN(child.style.position[leading[crossAxis]])) { - child.layout.position[pos[crossAxis]] = (Float.isNaN(child.style.position[leading[crossAxis]]) ? 0 : child.style.position[leading[crossAxis]]) + + if (!Float.isNaN(child.style.position.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]))) { + child.layout.position[pos[crossAxis]] = + (Float.isNaN(child.style.position.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis])) ? + 0 : + child.style.position.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis])) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]); } else { @@ -1293,38 +1299,7 @@ public class LayoutEngine { paddingAndBorderAxisCross); } - // STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN - if (performLayout) { - boolean needsMainTrailingPos = false; - boolean needsCrossTrailingPos = false; - - if (mainAxis == CSS_FLEX_DIRECTION_ROW_REVERSE || - mainAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { - needsMainTrailingPos = true; - } - - if (crossAxis == CSS_FLEX_DIRECTION_ROW_REVERSE || - crossAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { - needsCrossTrailingPos = true; - } - - // Set trailing position if necessary. - if (needsMainTrailingPos || needsCrossTrailingPos) { - for (i = 0; i < childCount; ++i) { - child = node.getChildAt(i); - - if (needsMainTrailingPos) { - child.layout.position[trailing[mainAxis]] = node.layout.measuredDimensions[dim[mainAxis]] - (child.style.positionType == CSSPositionType.ABSOLUTE ? 0 : child.layout.measuredDimensions[dim[mainAxis]]) - child.layout.position[pos[mainAxis]]; - } - - if (needsCrossTrailingPos) { - child.layout.position[trailing[crossAxis]] = node.layout.measuredDimensions[dim[crossAxis]] - (child.style.positionType == CSSPositionType.ABSOLUTE ? 0 : child.layout.measuredDimensions[dim[crossAxis]]) - child.layout.position[pos[crossAxis]]; - } - } - } - } - - // STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN + // STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN currentAbsoluteChild = firstAbsoluteChild; while (currentAbsoluteChild != null) { // Now that we know the bounds of the container, perform layout again on the @@ -1338,10 +1313,16 @@ public class LayoutEngine { childWidth = currentAbsoluteChild.style.dimensions[DIMENSION_WIDTH] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW])); } else { // If the child doesn't have a specified width, compute the width based on the left/right offsets if they're defined. - if (!Float.isNaN(currentAbsoluteChild.style.position[POSITION_LEFT]) && !Float.isNaN(currentAbsoluteChild.style.position[POSITION_RIGHT])) { + if (!Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) && + !Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]))) { childWidth = node.layout.measuredDimensions[DIMENSION_WIDTH] - (node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW])) - - (currentAbsoluteChild.style.position[POSITION_LEFT] + currentAbsoluteChild.style.position[POSITION_RIGHT]); + ((Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) ? + 0 : + currentAbsoluteChild.style.position.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) + + (Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW])) ? + 0 : + currentAbsoluteChild.style.position.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]))); childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth); } } @@ -1350,10 +1331,16 @@ public class LayoutEngine { childHeight = currentAbsoluteChild.style.dimensions[DIMENSION_HEIGHT] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])); } else { // If the child doesn't have a specified height, compute the height based on the top/bottom offsets if they're defined. - if (!Float.isNaN(currentAbsoluteChild.style.position[POSITION_TOP]) && !Float.isNaN(currentAbsoluteChild.style.position[POSITION_BOTTOM])) { + if (!Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) && + !Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]))) { childHeight = node.layout.measuredDimensions[DIMENSION_HEIGHT] - (node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])) - - (currentAbsoluteChild.style.position[POSITION_TOP] + currentAbsoluteChild.style.position[POSITION_BOTTOM]); + ((Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) ? + 0 : + currentAbsoluteChild.style.position.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + + (Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])) ? + 0 : + currentAbsoluteChild.style.position.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]))); childHeight = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN, childHeight); } } @@ -1388,24 +1375,61 @@ public class LayoutEngine { layoutNodeInternal(layoutContext, currentAbsoluteChild, childWidth, childHeight, direction, CSSMeasureMode.EXACTLY, CSSMeasureMode.EXACTLY, true, "abs-layout"); - if (!Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]) && - !!Float.isNaN(currentAbsoluteChild.style.position[leading[CSS_FLEX_DIRECTION_ROW]])) { - currentAbsoluteChild.layout.position[leading[CSS_FLEX_DIRECTION_ROW]] = - node.layout.measuredDimensions[dim[CSS_FLEX_DIRECTION_ROW]] - - currentAbsoluteChild.layout.measuredDimensions[dim[CSS_FLEX_DIRECTION_ROW]] - - (Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]) ? 0 : currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]); + if (!Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis])) && + Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]))) { + currentAbsoluteChild.layout.position[leading[mainAxis]] = + node.layout.measuredDimensions[dim[mainAxis]] - + currentAbsoluteChild.layout.measuredDimensions[dim[mainAxis]] - + (Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis])) ? 0 : currentAbsoluteChild.style.position.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis])); } - if (!Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_COLUMN]]) && - !!Float.isNaN(currentAbsoluteChild.style.position[leading[CSS_FLEX_DIRECTION_COLUMN]])) { - currentAbsoluteChild.layout.position[leading[CSS_FLEX_DIRECTION_COLUMN]] = - node.layout.measuredDimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] - - currentAbsoluteChild.layout.measuredDimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] - - (Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_COLUMN]]) ? 0 : currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_COLUMN]]); + if (!Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])) && + Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]))) { + currentAbsoluteChild.layout.position[leading[crossAxis]] = + node.layout.measuredDimensions[dim[crossAxis]] - + currentAbsoluteChild.layout.measuredDimensions[dim[crossAxis]] - + (Float.isNaN(currentAbsoluteChild.style.position.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])) ? 0 : currentAbsoluteChild.style.position.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])); } } currentAbsoluteChild = currentAbsoluteChild.nextChild; } + + // STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN + if (performLayout) { + boolean needsMainTrailingPos = false; + boolean needsCrossTrailingPos = false; + + if (mainAxis == CSS_FLEX_DIRECTION_ROW_REVERSE || + mainAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { + needsMainTrailingPos = true; + } + + if (crossAxis == CSS_FLEX_DIRECTION_ROW_REVERSE || + crossAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) { + needsCrossTrailingPos = true; + } + + // Set trailing position if necessary. + if (needsMainTrailingPos || needsCrossTrailingPos) { + for (i = 0; i < childCount; ++i) { + child = node.getChildAt(i); + + if (needsMainTrailingPos) { + child.layout.position[trailing[mainAxis]] = + node.layout.measuredDimensions[dim[mainAxis]] - + child.layout.measuredDimensions[dim[mainAxis]] - + child.layout.position[pos[mainAxis]]; + } + + if (needsCrossTrailingPos) { + child.layout.position[trailing[crossAxis]] = + node.layout.measuredDimensions[dim[crossAxis]] - + child.layout.measuredDimensions[dim[crossAxis]] - + child.layout.position[pos[crossAxis]]; + } + } + } + } } } diff --git a/tests/java/com/facebook/csslayout/LayoutEngineTest.java b/tests/java/com/facebook/csslayout/LayoutEngineTest.java index f901b3e3..e8cd2506 100644 --- a/tests/java/com/facebook/csslayout/LayoutEngineTest.java +++ b/tests/java/com/facebook/csslayout/LayoutEngineTest.java @@ -2957,8 +2957,8 @@ public class LayoutEngineTest { TestCSSNode root_node = new TestCSSNode(); { TestCSSNode node_0 = root_node; - node_0.style.position[POSITION_LEFT] = 5; - node_0.style.position[POSITION_TOP] = 5; + node_0.setPosition(Spacing.LEFT, 5); + node_0.setPosition(Spacing.TOP, 5); } TestCSSNode root_layout = new TestCSSNode(); @@ -3016,7 +3016,7 @@ public class LayoutEngineTest { TestCSSNode root_node = new TestCSSNode(); { TestCSSNode node_0 = root_node; - node_0.style.position[POSITION_BOTTOM] = 5; + node_0.setPosition(Spacing.BOTTOM, 5); } TestCSSNode root_layout = new TestCSSNode(); @@ -3037,8 +3037,8 @@ public class LayoutEngineTest { TestCSSNode root_node = new TestCSSNode(); { TestCSSNode node_0 = root_node; - node_0.style.position[POSITION_TOP] = 10; - node_0.style.position[POSITION_BOTTOM] = 5; + node_0.setPosition(Spacing.TOP, 10); + node_0.setPosition(Spacing.BOTTOM, 5); } TestCSSNode root_layout = new TestCSSNode(); @@ -3333,8 +3333,8 @@ public class LayoutEngineTest { node_1.style.dimensions[DIMENSION_HEIGHT] = 100; node_1 = node_0.getChildAt(1); node_1.style.positionType = CSSPositionType.ABSOLUTE; - node_1.style.position[POSITION_LEFT] = 10; - node_1.style.position[POSITION_TOP] = 10; + node_1.setPosition(Spacing.LEFT, 10); + node_1.setPosition(Spacing.TOP, 10); } } @@ -3381,7 +3381,7 @@ public class LayoutEngineTest { TestCSSNode node_1; node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; - node_1.style.position[POSITION_LEFT] = 5; + node_1.setPosition(Spacing.LEFT, 5); } } @@ -3418,7 +3418,7 @@ public class LayoutEngineTest { node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; node_1.setMargin(Spacing.TOP, 5); - node_1.style.position[POSITION_TOP] = 5; + node_1.setPosition(Spacing.TOP, 5); } } @@ -3455,7 +3455,7 @@ public class LayoutEngineTest { node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; node_1.setMargin(Spacing.LEFT, 5); - node_1.style.position[POSITION_LEFT] = 5; + node_1.setPosition(Spacing.LEFT, 5); } } @@ -4028,7 +4028,7 @@ public class LayoutEngineTest { TestCSSNode node_1; node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; - node_1.style.position[POSITION_TOP] = -1; + node_1.setPosition(Spacing.TOP, -1); } } @@ -4070,7 +4070,7 @@ public class LayoutEngineTest { TestCSSNode node_1; node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; - node_1.style.position[POSITION_LEFT] = 5; + node_1.setPosition(Spacing.LEFT, 5); } } @@ -5199,10 +5199,10 @@ public class LayoutEngineTest { TestCSSNode node_1; node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; - node_1.style.position[POSITION_LEFT] = 0; - node_1.style.position[POSITION_TOP] = 0; - node_1.style.position[POSITION_RIGHT] = 0; - node_1.style.position[POSITION_BOTTOM] = 0; + node_1.setPosition(Spacing.LEFT, 0); + node_1.setPosition(Spacing.TOP, 0); + node_1.setPosition(Spacing.RIGHT, 0); + node_1.setPosition(Spacing.BOTTOM, 0); } } @@ -5384,8 +5384,8 @@ public class LayoutEngineTest { node_1.style.dimensions[DIMENSION_HEIGHT] = 100; node_1 = node_0.getChildAt(1); node_1.style.positionType = CSSPositionType.ABSOLUTE; - node_1.style.position[POSITION_LEFT] = 0; - node_1.style.position[POSITION_RIGHT] = 0; + node_1.setPosition(Spacing.LEFT, 0); + node_1.setPosition(Spacing.RIGHT, 0); } } @@ -5427,8 +5427,8 @@ public class LayoutEngineTest { TestCSSNode node_1; node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; - node_1.style.position[POSITION_TOP] = 0; - node_1.style.position[POSITION_BOTTOM] = 20; + node_1.setPosition(Spacing.TOP, 0); + node_1.setPosition(Spacing.BOTTOM, 20); } } @@ -5467,10 +5467,10 @@ public class LayoutEngineTest { node_1 = node_0.getChildAt(0); node_1.style.justifyContent = CSSJustify.CENTER; node_1.style.positionType = CSSPositionType.ABSOLUTE; - node_1.style.position[POSITION_LEFT] = 0; - node_1.style.position[POSITION_TOP] = 0; - node_1.style.position[POSITION_RIGHT] = 0; - node_1.style.position[POSITION_BOTTOM] = 0; + node_1.setPosition(Spacing.LEFT, 0); + node_1.setPosition(Spacing.TOP, 0); + node_1.setPosition(Spacing.RIGHT, 0); + node_1.setPosition(Spacing.BOTTOM, 0); addChildren(node_1, 1); { TestCSSNode node_2; @@ -5523,7 +5523,7 @@ public class LayoutEngineTest { TestCSSNode node_1; node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; - node_1.style.position[POSITION_BOTTOM] = 0; + node_1.setPosition(Spacing.BOTTOM, 0); } } @@ -5560,7 +5560,7 @@ public class LayoutEngineTest { TestCSSNode node_1; node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; - node_1.style.position[POSITION_RIGHT] = 0; + node_1.setPosition(Spacing.RIGHT, 0); } } @@ -5598,7 +5598,7 @@ public class LayoutEngineTest { node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; node_1.style.dimensions[DIMENSION_HEIGHT] = 10; - node_1.style.position[POSITION_BOTTOM] = 0; + node_1.setPosition(Spacing.BOTTOM, 0); } } @@ -5636,7 +5636,7 @@ public class LayoutEngineTest { node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; node_1.style.dimensions[DIMENSION_WIDTH] = 10; - node_1.style.position[POSITION_RIGHT] = 0; + node_1.setPosition(Spacing.RIGHT, 0); } } @@ -5673,7 +5673,7 @@ public class LayoutEngineTest { node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; node_1.style.dimensions[DIMENSION_HEIGHT] = 10; - node_1.style.position[POSITION_BOTTOM] = 0; + node_1.setPosition(Spacing.BOTTOM, 0); } } @@ -5710,7 +5710,7 @@ public class LayoutEngineTest { node_1 = node_0.getChildAt(0); node_1.style.positionType = CSSPositionType.ABSOLUTE; node_1.style.dimensions[DIMENSION_WIDTH] = 10; - node_1.style.position[POSITION_RIGHT] = 0; + node_1.setPosition(Spacing.RIGHT, 0); } } @@ -5890,7 +5890,7 @@ public class LayoutEngineTest { { TestCSSNode node_1; node_1 = node_0.getChildAt(0); - node_1.style.position[POSITION_LEFT] = 5; + node_1.setPosition(Spacing.LEFT, 5); addChildren(node_1, 1); { TestCSSNode node_2; @@ -7297,10 +7297,10 @@ public class LayoutEngineTest { node_1.style.positionType = CSSPositionType.ABSOLUTE; node_1.style.maxWidth = 500; node_1.style.maxHeight = 600; - node_1.style.position[POSITION_LEFT] = 100; - node_1.style.position[POSITION_TOP] = 100; - node_1.style.position[POSITION_RIGHT] = 100; - node_1.style.position[POSITION_BOTTOM] = 100; + node_1.setPosition(Spacing.LEFT, 100); + node_1.setPosition(Spacing.TOP, 100); + node_1.setPosition(Spacing.RIGHT, 100); + node_1.setPosition(Spacing.BOTTOM, 100); } } @@ -7340,10 +7340,10 @@ public class LayoutEngineTest { node_1.style.positionType = CSSPositionType.ABSOLUTE; node_1.style.minWidth = 900; node_1.style.minHeight = 1000; - node_1.style.position[POSITION_LEFT] = 100; - node_1.style.position[POSITION_TOP] = 100; - node_1.style.position[POSITION_RIGHT] = 100; - node_1.style.position[POSITION_BOTTOM] = 100; + node_1.setPosition(Spacing.LEFT, 100); + node_1.setPosition(Spacing.TOP, 100); + node_1.setPosition(Spacing.RIGHT, 100); + node_1.setPosition(Spacing.BOTTOM, 100); } } @@ -7478,19 +7478,19 @@ public class LayoutEngineTest { node_1.setPadding(Spacing.BOTTOM, 10); node_1.setPadding(Spacing.START, 10); node_1.setPadding(Spacing.END, 10); - node_1.style.position[POSITION_LEFT] = 100; - node_1.style.position[POSITION_TOP] = 100; - node_1.style.position[POSITION_RIGHT] = 100; - node_1.style.position[POSITION_BOTTOM] = 100; + node_1.setPosition(Spacing.LEFT, 100); + node_1.setPosition(Spacing.TOP, 100); + node_1.setPosition(Spacing.RIGHT, 100); + node_1.setPosition(Spacing.BOTTOM, 100); addChildren(node_1, 1); { TestCSSNode node_2; node_2 = node_1.getChildAt(0); node_2.style.positionType = CSSPositionType.ABSOLUTE; - node_2.style.position[POSITION_LEFT] = 10; - node_2.style.position[POSITION_TOP] = 10; - node_2.style.position[POSITION_RIGHT] = 10; - node_2.style.position[POSITION_BOTTOM] = 10; + node_2.setPosition(Spacing.LEFT, 10); + node_2.setPosition(Spacing.TOP, 10); + node_2.setPosition(Spacing.RIGHT, 10); + node_2.setPosition(Spacing.BOTTOM, 10); } } } @@ -7550,19 +7550,19 @@ public class LayoutEngineTest { node_1.setBorder(Spacing.BOTTOM, 1); node_1.setBorder(Spacing.START, 1); node_1.setBorder(Spacing.END, 1); - node_1.style.position[POSITION_LEFT] = 100; - node_1.style.position[POSITION_TOP] = 100; - node_1.style.position[POSITION_RIGHT] = 100; - node_1.style.position[POSITION_BOTTOM] = 100; + node_1.setPosition(Spacing.LEFT, 100); + node_1.setPosition(Spacing.TOP, 100); + node_1.setPosition(Spacing.RIGHT, 100); + node_1.setPosition(Spacing.BOTTOM, 100); addChildren(node_1, 1); { TestCSSNode node_2; node_2 = node_1.getChildAt(0); node_2.style.positionType = CSSPositionType.ABSOLUTE; - node_2.style.position[POSITION_LEFT] = 10; - node_2.style.position[POSITION_TOP] = 10; - node_2.style.position[POSITION_RIGHT] = 10; - node_2.style.position[POSITION_BOTTOM] = 10; + node_2.setPosition(Spacing.LEFT, 10); + node_2.setPosition(Spacing.TOP, 10); + node_2.setPosition(Spacing.RIGHT, 10); + node_2.setPosition(Spacing.BOTTOM, 10); } } } @@ -7621,10 +7621,10 @@ public class LayoutEngineTest { TestCSSNode node_2; node_2 = node_1.getChildAt(0); node_2.style.positionType = CSSPositionType.ABSOLUTE; - node_2.style.position[POSITION_LEFT] = 10; - node_2.style.position[POSITION_TOP] = 10; - node_2.style.position[POSITION_RIGHT] = 10; - node_2.style.position[POSITION_BOTTOM] = 10; + node_2.setPosition(Spacing.LEFT, 10); + node_2.setPosition(Spacing.TOP, 10); + node_2.setPosition(Spacing.RIGHT, 10); + node_2.setPosition(Spacing.BOTTOM, 10); } } }