diff --git a/React/Layout/Layout.c b/React/Layout/Layout.c index 2b168e44a..50d69b522 100644 --- a/React/Layout/Layout.c +++ b/React/Layout/Layout.c @@ -1,21 +1,15 @@ /** - * @generated SignedSource<<24fa633b4dd81b7fb40c2b2b0b7c97d0>> - * - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * !! This file is a check-in from github! !! - * !! !! - * !! You should not modify this file directly. Instead: !! - * !! 1) Go to https://github.com/facebook/css-layout !! - * !! 2) Make a pull request and get it merged !! - * !! 3) Execute ./import.sh to pull in the latest version !! - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * * Copyright (c) 2014, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. + * + * WARNING: You should not modify this file directly. Instead: + * 1) Go to https://github.com/facebook/css-layout + * 2) Make a pull request and get it merged + * 3) Run import.sh to copy Layout.* to react-native-github */ #include @@ -44,6 +38,12 @@ void init_css_node(css_node_t *node) { node->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED; node->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; + node->style.minDimensions[CSS_WIDTH] = CSS_UNDEFINED; + node->style.minDimensions[CSS_HEIGHT] = CSS_UNDEFINED; + + node->style.maxDimensions[CSS_WIDTH] = CSS_UNDEFINED; + node->style.maxDimensions[CSS_HEIGHT] = CSS_UNDEFINED; + node->style.position[CSS_LEFT] = CSS_UNDEFINED; node->style.position[CSS_TOP] = CSS_UNDEFINED; node->style.position[CSS_RIGHT] = CSS_UNDEFINED; @@ -249,6 +249,10 @@ static float getPaddingAndBorder(css_node_t *node, int location) { return getPadding(node, location) + getBorder(node, location); } +static float getBorderAxis(css_node_t *node, css_flex_direction_t axis) { + return getBorder(node, leading[axis]) + getBorder(node, trailing[axis]); +} + static float getMarginAxis(css_node_t *node, css_flex_direction_t axis) { return getMargin(node, leading[axis]) + getMargin(node, trailing[axis]); } @@ -298,7 +302,8 @@ static float getDimWithMargin(css_node_t *node, css_flex_direction_t axis) { } static bool isDimDefined(css_node_t *node, css_flex_direction_t axis) { - return !isUndefined(node->style.dimensions[dim[axis]]); + float value = node->style.dimensions[dim[axis]]; + return !isUndefined(value) && value > 0.0; } static bool isPosDefined(css_node_t *node, css_position_t position) { @@ -317,6 +322,30 @@ static float getPosition(css_node_t *node, css_position_t position) { return 0; } +static float boundAxis(css_node_t *node, css_flex_direction_t axis, float value) { + float min = CSS_UNDEFINED; + float max = CSS_UNDEFINED; + + if (axis == CSS_FLEX_DIRECTION_COLUMN) { + min = node->style.minDimensions[CSS_HEIGHT]; + max = node->style.maxDimensions[CSS_HEIGHT]; + } else if (axis == CSS_FLEX_DIRECTION_ROW) { + min = node->style.minDimensions[CSS_WIDTH]; + max = node->style.maxDimensions[CSS_WIDTH]; + } + + float boundValue = value; + + if (!isUndefined(max) && max >= 0.0 && boundValue > max) { + boundValue = max; + } + if (!isUndefined(min) && min >= 0.0 && boundValue < min) { + boundValue = min; + } + + return boundValue; +} + // 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 @@ -330,7 +359,7 @@ static void setDimensionFromStyle(css_node_t *node, css_flex_direction_t axis) { // The dimensions can never be smaller than the padding and border node->layout.dimensions[dim[axis]] = fmaxf( - node->style.dimensions[dim[axis]], + boundAxis(node, axis, node->style.dimensions[dim[axis]]), getPaddingAndBorderAxis(node, axis) ); } @@ -347,6 +376,7 @@ static float getRelativePosition(css_node_t *node, css_flex_direction_t axis) { static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { /** START_GENERATED **/ + css_flex_direction_t mainAxis = getFlexDirection(node); css_flex_direction_t crossAxis = mainAxis == CSS_FLEX_DIRECTION_ROW ? CSS_FLEX_DIRECTION_COLUMN : @@ -385,25 +415,31 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // Let's not measure the text if we already know both dimensions if (isRowUndefined || isColumnUndefined) { - css_dim_t measure_dim = node->measure( + css_dim_t measureDim = node->measure( node->context, + width ); if (isRowUndefined) { - node->layout.dimensions[CSS_WIDTH] = measure_dim.dimensions[CSS_WIDTH] + + node->layout.dimensions[CSS_WIDTH] = measureDim.dimensions[CSS_WIDTH] + getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW); } if (isColumnUndefined) { - node->layout.dimensions[CSS_HEIGHT] = measure_dim.dimensions[CSS_HEIGHT] + + node->layout.dimensions[CSS_HEIGHT] = measureDim.dimensions[CSS_HEIGHT] + getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN); } } return; } + int i; + int ii; + css_node_t* child; + css_flex_direction_t axis; + // Pre-fill some dimensions straight from the parent - for (int i = 0; i < node->children_count; ++i) { - css_node_t* child = node->get_child(node->context, i); + for (i = 0; i < node->children_count; ++i) { + child = node->get_child(node->context, i); // Pre-fill cross axis dimensions when the child is using stretch before // we call the recursive layout pass if (getAlignItem(node, child) == CSS_ALIGN_STRETCH && @@ -411,27 +447,27 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { !isUndefined(node->layout.dimensions[dim[crossAxis]]) && !isDimDefined(child, crossAxis)) { child->layout.dimensions[dim[crossAxis]] = fmaxf( - node->layout.dimensions[dim[crossAxis]] - + boundAxis(child, crossAxis, node->layout.dimensions[dim[crossAxis]] - getPaddingAndBorderAxis(node, crossAxis) - - getMarginAxis(child, crossAxis), + getMarginAxis(child, crossAxis)), // You never want to go smaller than padding getPaddingAndBorderAxis(child, crossAxis) ); } else if (getPositionType(child) == CSS_POSITION_ABSOLUTE) { // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both // left and right or top and bottom). - for (int ii = 0; ii < 2; ii++) { - css_flex_direction_t axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; + 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) && isPosDefined(child, leading[axis]) && isPosDefined(child, trailing[axis])) { child->layout.dimensions[dim[axis]] = fmaxf( - node->layout.dimensions[dim[axis]] - - getPaddingAndBorderAxis(node, axis) - - getMarginAxis(child, axis) - - getPosition(child, leading[axis]) - - getPosition(child, trailing[axis]), + boundAxis(child, axis, node->layout.dimensions[dim[axis]] - + getPaddingAndBorderAxis(node, axis) - + getMarginAxis(child, axis) - + getPosition(child, leading[axis]) - + getPosition(child, trailing[axis])), // You never want to go smaller than padding getPaddingAndBorderAxis(child, axis) ); @@ -449,11 +485,12 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // We want to execute the next two loops one per line with flex-wrap int startLine = 0; int endLine = 0; - int nextLine = 0; + // int nextOffset = 0; + int alreadyComputedNextLayout = 0; // We aggregate the total dimensions of the container in those two variables float linesCrossDim = 0; float linesMainDim = 0; - while (endLine != node->children_count) { + while (endLine < node->children_count) { // Layout non flexible children and count children by type // mainContentDim is accumulation of the dimensions and margin of all the @@ -467,8 +504,10 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { int flexibleChildrenCount = 0; float totalFlexible = 0; int nonFlexibleChildrenCount = 0; - for (int i = startLine; i < node->children_count; ++i) { - css_node_t* child = node->get_child(node->context, i); + + float maxWidth; + for (i = startLine; i < node->children_count; ++i) { + child = node->get_child(node->context, i); float nextContentDim = 0; // It only makes sense to consider a child flexible if we have a computed @@ -478,26 +517,27 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { totalFlexible += getFlex(child); // Even if we don't know its exact size yet, we already know the padding, - // border and margin. We'll use this partial information to compute the - // remaining space. + // border and margin. We'll use this partial information, which represents + // the smallest possible size for the child, to compute the remaining + // available space. nextContentDim = getPaddingAndBorderAxis(child, mainAxis) + getMarginAxis(child, mainAxis); } else { - float maxWidth = CSS_UNDEFINED; - if (mainAxis == CSS_FLEX_DIRECTION_ROW) { - // do nothing - } else if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) { - maxWidth = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] - - getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW); - } else { + maxWidth = CSS_UNDEFINED; + if (mainAxis != CSS_FLEX_DIRECTION_ROW) { maxWidth = parentMaxWidth - getMarginAxis(node, CSS_FLEX_DIRECTION_ROW) - getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW); + + if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) { + maxWidth = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] - + getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW); + } } // This is the main recursive call. We layout non flexible children. - if (nextLine == 0) { + if (alreadyComputedNextLayout == 0) { layoutNode(child, maxWidth); } @@ -513,11 +553,14 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // The element we are about to add would make us go to the next line if (isFlexWrap(node) && !isUndefined(node->layout.dimensions[dim[mainAxis]]) && - mainContentDim + nextContentDim > definedMainDim) { - nextLine = i + 1; + mainContentDim + nextContentDim > definedMainDim && + // If there's only one element, then it's bigger than the content + // and needs its own line + i != startLine) { + alreadyComputedNextLayout = 1; break; } - nextLine = 0; + alreadyComputedNextLayout = 0; mainContentDim += nextContentDim; endLine = i + 1; } @@ -542,6 +585,26 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // remaining space if (flexibleChildrenCount != 0) { float flexibleMainDim = remainingMainDim / totalFlexible; + float baseMainDim; + float boundMainDim; + + // Iterate over every child in the axis. If the flex share of remaining + // space doesn't meet min/max bounds, remove this child from flex + // calculations. + for (i = startLine; i < endLine; ++i) { + child = node->get_child(node->context, i); + if (isFlex(child)) { + baseMainDim = flexibleMainDim * getFlex(child) + + getPaddingAndBorderAxis(child, mainAxis); + boundMainDim = boundAxis(child, mainAxis, baseMainDim); + + if (baseMainDim != boundMainDim) { + remainingMainDim -= boundMainDim; + totalFlexible -= getFlex(child); + } + } + } + flexibleMainDim = remainingMainDim / totalFlexible; // The non flexible children can overflow the container, in this case // we should just assume that there is no space available. @@ -551,21 +614,20 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // We iterate over the full array and only apply the action on flexible // children. This is faster than actually allocating a new array that // contains only flexible children. - for (int i = startLine; i < endLine; ++i) { - css_node_t* child = node->get_child(node->context, i); + for (i = startLine; i < endLine; ++i) { + child = node->get_child(node->context, i); if (isFlex(child)) { // At this point we know the final size of the element in the main // dimension - child->layout.dimensions[dim[mainAxis]] = flexibleMainDim * getFlex(child) + - getPaddingAndBorderAxis(child, mainAxis); + child->layout.dimensions[dim[mainAxis]] = boundAxis(child, mainAxis, + flexibleMainDim * getFlex(child) + getPaddingAndBorderAxis(child, mainAxis) + ); - float maxWidth = CSS_UNDEFINED; - if (mainAxis == CSS_FLEX_DIRECTION_ROW) { - // do nothing - } else if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) { + maxWidth = CSS_UNDEFINED; + if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) { maxWidth = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] - getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW); - } else { + } else if (mainAxis != CSS_FLEX_DIRECTION_ROW) { maxWidth = parentMaxWidth - getMarginAxis(node, CSS_FLEX_DIRECTION_ROW) - getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW); @@ -580,9 +642,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // space available } else { css_justify_t justifyContent = getJustifyContent(node); - if (justifyContent == CSS_JUSTIFY_FLEX_START) { - // Do nothing - } else if (justifyContent == CSS_JUSTIFY_CENTER) { + if (justifyContent == CSS_JUSTIFY_CENTER) { leadingMainDim = remainingMainDim / 2; } else if (justifyContent == CSS_JUSTIFY_FLEX_END) { leadingMainDim = remainingMainDim; @@ -612,8 +672,8 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { float mainDim = leadingMainDim + getPaddingAndBorder(node, leading[mainAxis]); - for (int i = startLine; i < endLine; ++i) { - css_node_t* child = node->get_child(node->context, i); + for (i = startLine; i < endLine; ++i) { + child = node->get_child(node->context, i); if (getPositionType(child) == CSS_POSITION_ABSOLUTE && isPosDefined(child, leading[mainAxis])) { @@ -638,25 +698,38 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { mainDim += betweenMainDim + getDimWithMargin(child, mainAxis); // The cross dimension is the max of the elements dimension since there // can only be one element in that cross dimension. - crossDim = fmaxf(crossDim, getDimWithMargin(child, crossAxis)); + crossDim = fmaxf(crossDim, boundAxis(child, crossAxis, getDimWithMargin(child, crossAxis))); } } + float containerMainAxis = node->layout.dimensions[dim[mainAxis]]; + // If the user didn't specify a width or height, and it has not been set + // by the container, then we set it via the children. + if (isUndefined(containerMainAxis)) { + containerMainAxis = fmaxf( + // We're missing the last padding at this point to get the final + // dimension + boundAxis(node, mainAxis, mainDim + getPaddingAndBorder(node, trailing[mainAxis])), + // We can never assign a width smaller than the padding and borders + getPaddingAndBorderAxis(node, mainAxis) + ); + } + float containerCrossAxis = node->layout.dimensions[dim[crossAxis]]; if (isUndefined(node->layout.dimensions[dim[crossAxis]])) { containerCrossAxis = fmaxf( // For the cross dim, we add both sides at the end because the value // is aggregate via a max function. Intermediate negative values // can mess this computation otherwise - crossDim + getPaddingAndBorderAxis(node, crossAxis), + boundAxis(node, crossAxis, crossDim + getPaddingAndBorderAxis(node, crossAxis)), getPaddingAndBorderAxis(node, crossAxis) ); } // Position elements in the cross axis - for (int i = startLine; i < endLine; ++i) { - css_node_t* child = node->get_child(node->context, i); + for (i = startLine; i < endLine; ++i) { + child = node->get_child(node->context, i); if (getPositionType(child) == CSS_POSITION_ABSOLUTE && isPosDefined(child, leading[crossAxis])) { @@ -674,21 +747,19 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // alignSelf (child) in order to determine the position in the cross axis if (getPositionType(child) == CSS_POSITION_RELATIVE) { css_align_t alignItem = getAlignItem(node, child); - if (alignItem == CSS_ALIGN_FLEX_START) { - // Do nothing - } else if (alignItem == CSS_ALIGN_STRETCH) { + if (alignItem == CSS_ALIGN_STRETCH) { // You can only stretch if the dimension has not already been set // previously. if (!isDimDefined(child, crossAxis)) { child->layout.dimensions[dim[crossAxis]] = fmaxf( - containerCrossAxis - + boundAxis(child, crossAxis, containerCrossAxis - getPaddingAndBorderAxis(node, crossAxis) - - getMarginAxis(child, crossAxis), + getMarginAxis(child, crossAxis)), // You never want to go smaller than padding getPaddingAndBorderAxis(child, crossAxis) ); } - } else { + } else if (alignItem != CSS_ALIGN_FLEX_START) { // The remaining space between the parent dimensions+padding and child // dimensions+margin. float remainingCrossDim = containerCrossAxis - @@ -719,7 +790,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { node->layout.dimensions[dim[mainAxis]] = fmaxf( // We're missing the last padding at this point to get the final // dimension - linesMainDim + getPaddingAndBorder(node, trailing[mainAxis]), + boundAxis(node, mainAxis, linesMainDim + getPaddingAndBorder(node, trailing[mainAxis])), // We can never assign a width smaller than the padding and borders getPaddingAndBorderAxis(node, mainAxis) ); @@ -730,37 +801,38 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // For the cross dim, we add both sides at the end because the value // is aggregate via a max function. Intermediate negative values // can mess this computation otherwise - linesCrossDim + getPaddingAndBorderAxis(node, crossAxis), + boundAxis(node, crossAxis, linesCrossDim + getPaddingAndBorderAxis(node, crossAxis)), getPaddingAndBorderAxis(node, crossAxis) ); } // Calculate dimensions for absolutely positioned elements - for (int i = 0; i < node->children_count; ++i) { - css_node_t* child = node->get_child(node->context, i); + for (i = 0; i < node->children_count; ++i) { + child = node->get_child(node->context, i); if (getPositionType(child) == CSS_POSITION_ABSOLUTE) { // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both // left and right or top and bottom). - for (int ii = 0; ii < 2; ii++) { - css_flex_direction_t axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; + 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) && isPosDefined(child, leading[axis]) && isPosDefined(child, trailing[axis])) { child->layout.dimensions[dim[axis]] = fmaxf( - node->layout.dimensions[dim[axis]] - - getPaddingAndBorderAxis(node, axis) - - getMarginAxis(child, axis) - - getPosition(child, leading[axis]) - - getPosition(child, trailing[axis]), + boundAxis(child, axis, node->layout.dimensions[dim[axis]] - + getBorderAxis(node, axis) - + getMarginAxis(child, axis) - + getPosition(child, leading[axis]) - + getPosition(child, trailing[axis]) + ), // You never want to go smaller than padding getPaddingAndBorderAxis(child, axis) ); } } - for (int ii = 0; ii < 2; ii++) { - css_flex_direction_t axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; + for (ii = 0; ii < 2; ii++) { + axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; if (isPosDefined(child, trailing[axis]) && !isPosDefined(child, leading[axis])) { child->layout.position[leading[axis]] = diff --git a/React/Layout/Layout.h b/React/Layout/Layout.h index 51f72493b..fe383ea57 100644 --- a/React/Layout/Layout.h +++ b/React/Layout/Layout.h @@ -1,21 +1,15 @@ /** - * @generated SignedSource<<58298c7a8815a8675e970b0347dedfed>> - * - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * !! This file is a check-in from github! !! - * !! !! - * !! You should not modify this file directly. Instead: !! - * !! 1) Go to https://github.com/facebook/css-layout !! - * !! 2) Make a pull request and get it merged !! - * !! 3) Execute ./import.sh to pull in the latest version !! - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * * Copyright (c) 2014, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. + * + * WARNING: You should not modify this file directly. Instead: + * 1) Go to https://github.com/facebook/css-layout + * 2) Make a pull request and get it merged + * 3) Run import.sh to copy Layout.* to react-native-github */ #ifndef __LAYOUT_H @@ -113,6 +107,8 @@ typedef struct { float padding[4]; float border[4]; float dimensions[2]; + float minDimensions[2]; + float maxDimensions[2]; } css_style_t; typedef struct css_node { diff --git a/React/Layout/import.sh b/React/Layout/import.sh new file mode 100755 index 000000000..7e69403f3 --- /dev/null +++ b/React/Layout/import.sh @@ -0,0 +1,15 @@ +LAYOUT_C=`curl https://raw.githubusercontent.com/facebook/css-layout/master/src/Layout.c` +LAYOUT_H=`curl https://raw.githubusercontent.com/facebook/css-layout/master/src/Layout.h` + +REPLACE_STRING="* + * WARNING: You should not modify this file directly. Instead: + * 1) Go to https://github.com/facebook/css-layout + * 2) Make a pull request and get it merged + * 3) Run import.sh to copy Layout.* to react-native-github + */" + +LAYOUT_C=${LAYOUT_C/\*\//$REPLACE_STRING} +LAYOUT_H=${LAYOUT_H/\*\//$REPLACE_STRING} + +echo "$LAYOUT_C" > Layout.c +echo "$LAYOUT_H" > Layout.h