From 6c5195fb3aa175ea416eb53e2c10720089dd8c85 Mon Sep 17 00:00:00 2001 From: Oleg Lokhvitsky Date: Tue, 15 Mar 2016 14:32:58 -0700 Subject: [PATCH] =?UTF-8?q?Update=20Layout.c=20to=20fix=20flexbox=20layout?= =?UTF-8?q?=20bug=E2=80=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Differential Revision: D3049303 fb-gh-sync-id: 14a8c290bb874ab3e954b45f6fb29d71d019adc2 shipit-source-id: 14a8c290bb874ab3e954b45f6fb29d71d019adc2 --- React/Layout/Layout.c | 75 +++++++++++++++++++++++++++---------------- React/Layout/Layout.h | 2 +- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/React/Layout/Layout.c b/React/Layout/Layout.c index 317f69bb6dfbdd..e2804777512e29 100644 --- a/React/Layout/Layout.c +++ b/React/Layout/Layout.c @@ -451,11 +451,16 @@ static float getDimWithMargin(css_node_t *node, css_flex_direction_t axis) { getTrailingMargin(node, axis); } -static bool isDimDefined(css_node_t *node, css_flex_direction_t axis) { +static bool isStyleDimDefined(css_node_t *node, css_flex_direction_t axis) { float value = node->style.dimensions[dim[axis]]; return !isUndefined(value) && value >= 0.0; } +static bool isLayoutDimDefined(css_node_t *node, css_flex_direction_t axis) { + float value = node->layout.dimensions[dim[axis]]; + return !isUndefined(value) && value >= 0.0; +} + static bool isPosDefined(css_node_t *node, css_position_t position) { return !isUndefined(node->style.position[position]); } @@ -499,11 +504,11 @@ static float boundAxis(css_node_t *node, css_flex_direction_t axis, float value) // When the user specifically sets a value for width or height static void setDimensionFromStyle(css_node_t *node, css_flex_direction_t axis) { // The parent already computed us a width or height. We just skip it - if (!isUndefined(node->layout.dimensions[dim[axis]])) { + if (isLayoutDimDefined(node, axis)) { return; } // We only run if there's a width or height defined - if (!isDimDefined(node, axis)) { + if (!isStyleDimDefined(node, axis)) { return; } @@ -561,10 +566,10 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM float paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN); if (isMeasureDefined(node)) { - bool isResolvedRowDimDefined = !isUndefined(node->layout.dimensions[dim[resolvedRowAxis]]); + bool isResolvedRowDimDefined = isLayoutDimDefined(node, resolvedRowAxis); float width = CSS_UNDEFINED; - if (isDimDefined(node, resolvedRowAxis)) { + if (isStyleDimDefined(node, resolvedRowAxis)) { width = node->style.dimensions[CSS_WIDTH]; } else if (isResolvedRowDimDefined) { width = node->layout.dimensions[dim[resolvedRowAxis]]; @@ -575,9 +580,9 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM width -= paddingAndBorderAxisResolvedRow; float height = CSS_UNDEFINED; - if (isDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { + if (isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { height = node->style.dimensions[CSS_HEIGHT]; - } else if (!isUndefined(node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]])) { + } else if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { height = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]; } else { height = parentMaxHeight - @@ -588,15 +593,15 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM // We only need to give a dimension for the text if we haven't got any // for it computed yet. It can either be from the style attribute or because // the element is flexible. - bool isRowUndefined = !isDimDefined(node, resolvedRowAxis) && !isResolvedRowDimDefined; - bool isColumnUndefined = !isDimDefined(node, CSS_FLEX_DIRECTION_COLUMN) && + bool isRowUndefined = !isStyleDimDefined(node, resolvedRowAxis) && !isResolvedRowDimDefined; + bool isColumnUndefined = !isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN) && isUndefined(node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]); // Let's not measure the text if we already know both dimensions if (isRowUndefined || isColumnUndefined) { css_dim_t measureDim = node->measure( node->context, - + width, height ); @@ -623,8 +628,8 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM float paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis); float paddingAndBorderAxisCross = getPaddingAndBorderAxis(node, crossAxis); - bool isMainDimDefined = !isUndefined(node->layout.dimensions[dim[mainAxis]]); - bool isCrossDimDefined = !isUndefined(node->layout.dimensions[dim[crossAxis]]); + bool isMainDimDefined = isLayoutDimDefined(node, mainAxis); + bool isCrossDimDefined = isLayoutDimDefined(node, crossAxis); bool isMainRowDirection = isRowDirection(mainAxis); int i; @@ -686,8 +691,8 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM float mainDim = leadingPaddingAndBorderMain; float crossDim = 0; - float maxWidth; - float maxHeight; + float maxWidth = CSS_UNDEFINED; + float maxHeight = CSS_UNDEFINED; for (i = startLine; i < childCount; ++i) { child = node->get_child(node->context, i); child->line_index = linesCount; @@ -702,7 +707,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM if (alignItem == CSS_ALIGN_STRETCH && child->style.position_type == CSS_POSITION_RELATIVE && isCrossDimDefined && - !isDimDefined(child, crossAxis)) { + !isStyleDimDefined(child, crossAxis)) { child->layout.dimensions[dim[crossAxis]] = fmaxf( boundAxis(child, crossAxis, node->layout.dimensions[dim[crossAxis]] - paddingAndBorderAxisCross - getMarginAxis(child, crossAxis)), @@ -724,8 +729,8 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM // left and right or top and bottom). for (ii = 0; ii < 2; ii++) { axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; - if (!isUndefined(node->layout.dimensions[dim[axis]]) && - !isDimDefined(child, axis) && + if (isLayoutDimDefined(node, axis) && + !isStyleDimDefined(child, axis) && isPosDefined(child, leading[axis]) && isPosDefined(child, trailing[axis])) { child->layout.dimensions[dim[axis]] = fmaxf( @@ -771,7 +776,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM maxHeight = CSS_UNDEFINED; if (!isMainRowDirection) { - if (isDimDefined(node, resolvedRowAxis)) { + if (isLayoutDimDefined(node, resolvedRowAxis)) { maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] - paddingAndBorderAxisResolvedRow; } else { @@ -780,7 +785,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM paddingAndBorderAxisResolvedRow; } } else { - if (isDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { + if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { maxHeight = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] - paddingAndBorderAxisColumn; } else { @@ -831,7 +836,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM if (isSimpleStackCross && (child->style.position_type != CSS_POSITION_RELATIVE || (alignItem != CSS_ALIGN_STRETCH && alignItem != CSS_ALIGN_FLEX_START) || - isUndefined(child->layout.dimensions[dim[crossAxis]]))) { + (alignItem == CSS_ALIGN_STRETCH && !isCrossDimDefined))) { isSimpleStackCross = false; firstComplexCross = i; } @@ -914,7 +919,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM ); maxWidth = CSS_UNDEFINED; - if (isDimDefined(node, resolvedRowAxis)) { + if (isLayoutDimDefined(node, resolvedRowAxis)) { maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] - paddingAndBorderAxisResolvedRow; } else if (!isMainRowDirection) { @@ -923,7 +928,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM paddingAndBorderAxisResolvedRow; } maxHeight = CSS_UNDEFINED; - if (isDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { + if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) { maxHeight = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] - paddingAndBorderAxisColumn; } else if (isMainRowDirection) { @@ -1041,15 +1046,31 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM css_align_t alignItem = getAlignItem(node, child); /*eslint-enable */ if (alignItem == CSS_ALIGN_STRETCH) { - // You can only stretch if the dimension has not already been set + // You can only stretch if the dimension has not already been defined // previously. - if (isUndefined(child->layout.dimensions[dim[crossAxis]])) { + if (!isStyleDimDefined(child, crossAxis)) { + float dimCrossAxis = child->layout.dimensions[dim[crossAxis]]; child->layout.dimensions[dim[crossAxis]] = fmaxf( boundAxis(child, crossAxis, containerCrossAxis - paddingAndBorderAxisCross - getMarginAxis(child, crossAxis)), // You never want to go smaller than padding getPaddingAndBorderAxis(child, crossAxis) ); + + // If the size has changed, and this child has children we need to re-layout this child + if (dimCrossAxis != child->layout.dimensions[dim[crossAxis]] && child->children_count > 0) { + // Reset child margins before re-layout as they are added back in layoutNode and would be doubled + child->layout.position[leading[mainAxis]] -= getLeadingMargin(child, mainAxis) + + getRelativePosition(child, mainAxis); + child->layout.position[trailing[mainAxis]] -= getTrailingMargin(child, mainAxis) + + getRelativePosition(child, mainAxis); + child->layout.position[leading[crossAxis]] -= getLeadingMargin(child, crossAxis) + + getRelativePosition(child, crossAxis); + child->layout.position[trailing[crossAxis]] -= getTrailingMargin(child, crossAxis) + + getRelativePosition(child, crossAxis); + + layoutNode(child, maxWidth, maxHeight, direction); + } } } else if (alignItem != CSS_ALIGN_FLEX_START) { // The remaining space between the parent dimensions+padding and child @@ -1127,7 +1148,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM if (child->line_index != i) { break; } - if (!isUndefined(child->layout.dimensions[dim[crossAxis]])) { + if (isLayoutDimDefined(child, crossAxis)) { lineHeight = fmaxf( lineHeight, child->layout.dimensions[dim[crossAxis]] + getMarginAxis(child, crossAxis) @@ -1220,8 +1241,8 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM for (ii = 0; ii < 2; ii++) { axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; - if (!isUndefined(node->layout.dimensions[dim[axis]]) && - !isDimDefined(currentAbsoluteChild, axis) && + if (isLayoutDimDefined(node, axis) && + !isStyleDimDefined(currentAbsoluteChild, axis) && isPosDefined(currentAbsoluteChild, leading[axis]) && isPosDefined(currentAbsoluteChild, trailing[axis])) { currentAbsoluteChild->layout.dimensions[dim[axis]] = fmaxf( diff --git a/React/Layout/Layout.h b/React/Layout/Layout.h index be37c93939666e..2bcde084d5ea94 100644 --- a/React/Layout/Layout.h +++ b/React/Layout/Layout.h @@ -9,7 +9,7 @@ * !! 3) Copy the file from github to here !! * !! (don't forget to keep this header) !! * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * @generated + * @generated * * Copyright (c) 2014, Facebook, Inc. * All rights reserved.