diff --git a/README.md b/README.md index a8529cbe..45963d35 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ Supported Attributes Name | Value ----:|------ width, height | positive number +minWidth, minHeight | positive number +maxWidth, maxHeight | positive number left, right, top, bottom | number margin, marginLeft, marginRight, marginTop, marginBottom | number padding, paddingLeft, paddingRight, paddingTop, paddingBottom | positive number diff --git a/src/JavaTranspiler.js b/src/JavaTranspiler.js index 8239bc1c..56ce90fd 100644 --- a/src/JavaTranspiler.js +++ b/src/JavaTranspiler.js @@ -50,6 +50,16 @@ function __transpileSingleTestToJava(code) { function (str, match1, match2) { return match1 + '.' + match2.toLowerCase(); }) + .replace( // style.maxDimensions[CSS_WIDTH] => style.maxWidth + /(style|layout)\.maxDimensions\[CSS_(WIDTH|HEIGHT)\]/g, + function (str, match1, match2) { + return match1 + '.max' + match2.substr(0, 1).toUpperCase() + match2.substr(1).toLowerCase(); + }) + .replace( // style.minDimensions[CSS_WIDTH] => style.minWidth + /(style|layout)\.minDimensions\[CSS_(WIDTH|HEIGHT)\]/g, + function (str, match1, match2) { + return match1 + '.min' + match2.substr(0, 1).toUpperCase() + match2.substr(1).toLowerCase(); + }) .replace( // layout.position[CSS_TOP] => layout.y /layout\.position\[CSS_(TOP|LEFT)\]/g, function (str, match1) { diff --git a/src/Layout-test-utils.js b/src/Layout-test-utils.js index dbea07a9..fce33b01 100644 --- a/src/Layout-test-utils.js +++ b/src/Layout-test-utils.js @@ -172,6 +172,10 @@ var layoutTestUtils = (function() { var div = document.createElement('div'); transfer(div, node, 'width', 'px'); transfer(div, node, 'height', 'px'); + transfer(div, node, 'minWidth', 'px'); + transfer(div, node, 'minHeight', 'px'); + transfer(div, node, 'maxWidth', 'px'); + transfer(div, node, 'maxHeight', 'px'); transfer(div, node, 'top', 'px'); transfer(div, node, 'left', 'px'); transfer(div, node, 'right', 'px'); diff --git a/src/Layout.c b/src/Layout.c index 21980c5a..ed1f5695 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -33,6 +33,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; @@ -307,6 +313,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 @@ -320,7 +350,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) ); } @@ -408,9 +438,9 @@ 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) ); @@ -424,11 +454,11 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { 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) ); @@ -478,8 +508,9 @@ 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); @@ -545,6 +576,25 @@ 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-> 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. @@ -559,8 +609,15 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { 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); + baseMainDim = flexibleMainDim * getFlex(child) + + getPaddingAndBorderAxis(child, mainAxis); + boundMainDim = boundAxis(child, mainAxis, baseMainDim); + + if (baseMainDim == boundMainDim) { + child->layout.dimensions[dim[mainAxis]] = baseMainDim; + } else { + child->layout.dimensions[dim[mainAxis]] = boundMainDim; + } maxWidth = CSS_UNDEFINED; if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) { @@ -637,7 +694,7 @@ 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))); } } @@ -648,7 +705,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { containerMainAxis = fmaxf( // We're missing the last padding at this point to get the final // dimension - mainDim + getPaddingAndBorder(node, trailing[mainAxis]), + boundAxis(node, mainAxis, mainDim + getPaddingAndBorder(node, trailing[mainAxis])), // We can never assign a width smaller than the padding and borders getPaddingAndBorderAxis(node, mainAxis) ); @@ -660,7 +717,7 @@ 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 - crossDim + getPaddingAndBorderAxis(node, crossAxis), + boundAxis(node, crossAxis, crossDim + getPaddingAndBorderAxis(node, crossAxis)), getPaddingAndBorderAxis(node, crossAxis) ); } @@ -691,9 +748,9 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // 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) ); @@ -729,7 +786,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) ); @@ -740,7 +797,7 @@ 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) ); } @@ -759,11 +816,12 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { 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) ); diff --git a/src/Layout.h b/src/Layout.h index d5a815ce..53840947 100644 --- a/src/Layout.h +++ b/src/Layout.h @@ -102,6 +102,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/src/Layout.js b/src/Layout.js index d60e9e9c..366adae5 100755 --- a/src/Layout.js +++ b/src/Layout.js @@ -202,6 +202,27 @@ var computeLayout = (function() { return 0; } + function boundAxis(node, axis, value) { + var min = { + row: node.style['minWidth'], + column: node.style['minHeight'] + }[axis]; + + var max = { + row: node.style['maxWidth'], + column: node.style['maxHeight'] + }[axis]; + + var boundValue = value; + if (!isUndefined(max) && max >= 0 && boundValue > max) { + boundValue = max; + } + if (!isUndefined(min) && min >= 0 && boundValue < min) { + boundValue = min; + } + return boundValue; + } + function fmaxf(a, b) { if (a > b) { return a; @@ -222,7 +243,7 @@ var computeLayout = (function() { // The dimensions can never be smaller than the padding and border node.layout[dim[axis]] = fmaxf( - node.style[dim[axis]], + boundAxis(node, axis, node.style[dim[axis]]), getPaddingAndBorderAxis(node, axis) ); } @@ -308,9 +329,9 @@ var computeLayout = (function() { !isUndefined(node.layout[dim[crossAxis]]) && !isDimDefined(child, crossAxis)) { child.layout[dim[crossAxis]] = fmaxf( - node.layout[dim[crossAxis]] - + boundAxis(child, crossAxis, node.layout[dim[crossAxis]] - getPaddingAndBorderAxis(node, crossAxis) - - getMarginAxis(child, crossAxis), + getMarginAxis(child, crossAxis)), // You never want to go smaller than padding getPaddingAndBorderAxis(child, crossAxis) ); @@ -324,11 +345,11 @@ var computeLayout = (function() { isPosDefined(child, leading[axis]) && isPosDefined(child, trailing[axis])) { child.layout[dim[axis]] = fmaxf( - node.layout[dim[axis]] - - getPaddingAndBorderAxis(node, axis) - - getMarginAxis(child, axis) - - getPosition(child, leading[axis]) - - getPosition(child, trailing[axis]), + boundAxis(child, axis, node.layout[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) ); @@ -378,8 +399,9 @@ var computeLayout = (function() { 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); @@ -445,6 +467,26 @@ var computeLayout = (function() { // remaining space if (flexibleChildrenCount !== 0) { var/*float*/ flexibleMainDim = remainingMainDim / totalFlexible; + var/*float*/ baseMainDim; + var/*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.children[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. @@ -459,8 +501,15 @@ var computeLayout = (function() { if (isFlex(child)) { // At this point we know the final size of the element in the main // dimension - child.layout[dim[mainAxis]] = flexibleMainDim * getFlex(child) + - getPaddingAndBorderAxis(child, mainAxis); + baseMainDim = flexibleMainDim * getFlex(child) + + getPaddingAndBorderAxis(child, mainAxis); + boundMainDim = boundAxis(child, mainAxis, baseMainDim); + + if (baseMainDim === boundMainDim) { + child.layout[dim[mainAxis]] = baseMainDim; + } else { + child.layout[dim[mainAxis]] = boundMainDim; + } maxWidth = CSS_UNDEFINED; if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) { @@ -537,7 +586,7 @@ var computeLayout = (function() { 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))); } } @@ -548,7 +597,7 @@ var computeLayout = (function() { containerMainAxis = fmaxf( // We're missing the last padding at this point to get the final // dimension - mainDim + getPaddingAndBorder(node, trailing[mainAxis]), + boundAxis(node, mainAxis, mainDim + getPaddingAndBorder(node, trailing[mainAxis])), // We can never assign a width smaller than the padding and borders getPaddingAndBorderAxis(node, mainAxis) ); @@ -560,7 +609,7 @@ var computeLayout = (function() { // 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) ); } @@ -591,9 +640,9 @@ var computeLayout = (function() { // previously. if (!isDimDefined(child, crossAxis)) { child.layout[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) ); @@ -629,7 +678,7 @@ var computeLayout = (function() { node.layout[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) ); @@ -640,7 +689,7 @@ var computeLayout = (function() { // 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) ); } @@ -659,11 +708,12 @@ var computeLayout = (function() { isPosDefined(child, leading[axis]) && isPosDefined(child, trailing[axis])) { child.layout[dim[axis]] = fmaxf( - node.layout[dim[axis]] - - getPaddingAndBorderAxis(node, axis) - - getMarginAxis(child, axis) - - getPosition(child, leading[axis]) - - getPosition(child, trailing[axis]), + boundAxis(child, axis, node.layout[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) ); diff --git a/src/__tests__/Layout-random-test.js b/src/__tests__/Layout-random-test.js index 40d9004c..e552cdbe 100644 --- a/src/__tests__/Layout-random-test.js +++ b/src/__tests__/Layout-random-test.js @@ -49,6 +49,10 @@ describe('Random layout', function() { var node = {style: {}}; randMinMax(node, 0.5, 'width', -100, 1000); randMinMax(node, 0.5, 'height', -100, 1000); + randMinMax(node, 0.5, 'minWidth', -100, 1000); + randMinMax(node, 0.5, 'minHeight', -100, 1000); + randMinMax(node, 0.5, 'maxWidth', -100, 1000); + randMinMax(node, 0.5, 'maxHeight', -100, 1000); randMinMax(node, 0.5, 'top', -10, 10); randMinMax(node, 0.5, 'left', -10, 10); randMinMax(node, 0.5, 'right', -10, 10); diff --git a/src/__tests__/Layout-test.c b/src/__tests__/Layout-test.c index 65558774..f36e5410 100644 --- a/src/__tests__/Layout-test.c +++ b/src/__tests__/Layout-test.c @@ -3768,6 +3768,819 @@ int main() test("should layout flex wrap with a line bigger than container", root_node, root_layout); } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 100; + node_0->style.dimensions[CSS_HEIGHT] = 200; + node_0->style.maxDimensions[CSS_WIDTH] = 90; + node_0->style.maxDimensions[CSS_HEIGHT] = 190; + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 90; + node_0->layout.dimensions[CSS_HEIGHT] = 190; + } + + test("should use max bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 100; + node_0->style.dimensions[CSS_HEIGHT] = 200; + node_0->style.minDimensions[CSS_WIDTH] = 110; + node_0->style.minDimensions[CSS_HEIGHT] = 210; + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 110; + node_0->layout.dimensions[CSS_HEIGHT] = 210; + } + + test("should use min bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 100; + node_0->style.dimensions[CSS_HEIGHT] = 200; + node_0->style.maxDimensions[CSS_WIDTH] = 90; + node_0->style.maxDimensions[CSS_HEIGHT] = 190; + node_0->style.minDimensions[CSS_WIDTH] = 110; + node_0->style.minDimensions[CSS_HEIGHT] = 210; + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 110; + node_0->layout.dimensions[CSS_HEIGHT] = 210; + } + + test("should use min bounds over max bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 100; + node_0->style.dimensions[CSS_HEIGHT] = 200; + node_0->style.maxDimensions[CSS_WIDTH] = 80; + node_0->style.maxDimensions[CSS_HEIGHT] = 180; + node_0->style.minDimensions[CSS_WIDTH] = 90; + node_0->style.minDimensions[CSS_HEIGHT] = 190; + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 90; + node_0->layout.dimensions[CSS_HEIGHT] = 190; + } + + test("should use min bounds over max bounds and natural width", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 100; + node_0->style.dimensions[CSS_HEIGHT] = 200; + node_0->style.minDimensions[CSS_WIDTH] = -10; + node_0->style.minDimensions[CSS_HEIGHT] = -20; + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 100; + node_0->layout.dimensions[CSS_HEIGHT] = 200; + } + + test("should ignore negative min bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 100; + node_0->style.dimensions[CSS_HEIGHT] = 200; + node_0->style.maxDimensions[CSS_WIDTH] = -10; + node_0->style.maxDimensions[CSS_HEIGHT] = -20; + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 100; + node_0->layout.dimensions[CSS_HEIGHT] = 200; + } + + test("should ignore negative max bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.maxDimensions[CSS_WIDTH] = 30; + node_0->style.maxDimensions[CSS_HEIGHT] = 10; + node_0->style.padding[CSS_LEFT] = 20; + node_0->style.padding[CSS_TOP] = 15; + node_0->style.padding[CSS_RIGHT] = 20; + node_0->style.padding[CSS_BOTTOM] = 15; + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 40; + node_0->layout.dimensions[CSS_HEIGHT] = 30; + } + + test("should use padded size over max bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.minDimensions[CSS_WIDTH] = 50; + node_0->style.minDimensions[CSS_HEIGHT] = 40; + node_0->style.padding[CSS_LEFT] = 20; + node_0->style.padding[CSS_TOP] = 15; + node_0->style.padding[CSS_RIGHT] = 20; + node_0->style.padding[CSS_BOTTOM] = 15; + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 50; + node_0->layout.dimensions[CSS_HEIGHT] = 40; + } + + test("should use min size over padded size", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW; + node_0->style.dimensions[CSS_WIDTH] = 300; + node_0->style.dimensions[CSS_HEIGHT] = 200; + init_css_node_children(node_0, 3); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.flex = 1; + node_1 = node_0->get_child(node_0->context, 1); + node_1->style.flex = 1; + node_1->style.minDimensions[CSS_WIDTH] = 200; + node_1 = node_0->get_child(node_0->context, 2); + node_1->style.flex = 1; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 300; + node_0->layout.dimensions[CSS_HEIGHT] = 200; + init_css_node_children(node_0, 3); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + node_1 = node_0->get_child(node_0->context, 1); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 50; + node_1->layout.dimensions[CSS_WIDTH] = 200; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + node_1 = node_0->get_child(node_0->context, 2); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 250; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + } + } + + test("should override flex direction size with min bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW; + node_0->style.dimensions[CSS_WIDTH] = 300; + node_0->style.dimensions[CSS_HEIGHT] = 200; + init_css_node_children(node_0, 3); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.flex = 1; + node_1 = node_0->get_child(node_0->context, 1); + node_1->style.flex = 1; + node_1->style.maxDimensions[CSS_WIDTH] = 110; + node_1->style.minDimensions[CSS_WIDTH] = 90; + node_1 = node_0->get_child(node_0->context, 2); + node_1->style.flex = 1; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 300; + node_0->layout.dimensions[CSS_HEIGHT] = 200; + init_css_node_children(node_0, 3); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 100; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + node_1 = node_0->get_child(node_0->context, 1); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 100; + node_1->layout.dimensions[CSS_WIDTH] = 100; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + node_1 = node_0->get_child(node_0->context, 2); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 200; + node_1->layout.dimensions[CSS_WIDTH] = 100; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + } + } + + test("should not override flex direction size within bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW; + node_0->style.dimensions[CSS_WIDTH] = 300; + node_0->style.dimensions[CSS_HEIGHT] = 200; + init_css_node_children(node_0, 3); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.flex = 1; + node_1 = node_0->get_child(node_0->context, 1); + node_1->style.flex = 1; + node_1->style.maxDimensions[CSS_WIDTH] = 60; + node_1 = node_0->get_child(node_0->context, 2); + node_1->style.flex = 1; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 300; + node_0->layout.dimensions[CSS_HEIGHT] = 200; + init_css_node_children(node_0, 3); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 120; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + node_1 = node_0->get_child(node_0->context, 1); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 120; + node_1->layout.dimensions[CSS_WIDTH] = 60; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + node_1 = node_0->get_child(node_0->context, 2); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 180; + node_1->layout.dimensions[CSS_WIDTH] = 120; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + } + } + + test("should override flex direction size with max bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 300; + node_0->style.dimensions[CSS_HEIGHT] = 200; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.flex = 1; + node_1->style.maxDimensions[CSS_WIDTH] = 310; + node_1->style.minDimensions[CSS_WIDTH] = 290; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 300; + node_0->layout.dimensions[CSS_HEIGHT] = 200; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 300; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + } + } + + test("should pre-fill child size within bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 300; + node_0->style.dimensions[CSS_HEIGHT] = 200; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.flex = 1; + node_1->style.maxDimensions[CSS_WIDTH] = 290; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 300; + node_0->layout.dimensions[CSS_HEIGHT] = 200; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 290; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + } + } + + test("should pre-fill child size within max bound", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 300; + node_0->style.dimensions[CSS_HEIGHT] = 200; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.flex = 1; + node_1->style.minDimensions[CSS_WIDTH] = 310; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 300; + node_0->layout.dimensions[CSS_HEIGHT] = 200; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 310; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + } + } + + test("should pre-fill child size within min bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.maxDimensions[CSS_WIDTH] = 300; + node_0->style.maxDimensions[CSS_HEIGHT] = 700; + node_0->style.minDimensions[CSS_WIDTH] = 100; + node_0->style.minDimensions[CSS_HEIGHT] = 500; + init_css_node_children(node_0, 2); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_WIDTH] = 200; + node_1->style.dimensions[CSS_HEIGHT] = 300; + node_1 = node_0->get_child(node_0->context, 1); + node_1->style.dimensions[CSS_WIDTH] = 200; + node_1->style.dimensions[CSS_HEIGHT] = 300; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 200; + node_0->layout.dimensions[CSS_HEIGHT] = 600; + init_css_node_children(node_0, 2); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 200; + node_1->layout.dimensions[CSS_HEIGHT] = 300; + node_1 = node_0->get_child(node_0->context, 1); + node_1->layout.position[CSS_TOP] = 300; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 200; + node_1->layout.dimensions[CSS_HEIGHT] = 300; + } + } + + test("should set parents size based on bounded children", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.maxDimensions[CSS_WIDTH] = 100; + node_0->style.maxDimensions[CSS_HEIGHT] = 500; + init_css_node_children(node_0, 2); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_WIDTH] = 200; + node_1->style.dimensions[CSS_HEIGHT] = 300; + node_1 = node_0->get_child(node_0->context, 1); + node_1->style.dimensions[CSS_WIDTH] = 200; + node_1->style.dimensions[CSS_HEIGHT] = 300; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 100; + node_0->layout.dimensions[CSS_HEIGHT] = 500; + init_css_node_children(node_0, 2); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 200; + node_1->layout.dimensions[CSS_HEIGHT] = 300; + node_1 = node_0->get_child(node_0->context, 1); + node_1->layout.position[CSS_TOP] = 300; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 200; + node_1->layout.dimensions[CSS_HEIGHT] = 300; + } + } + + test("should set parents size based on max bounded children", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.minDimensions[CSS_WIDTH] = 300; + node_0->style.minDimensions[CSS_HEIGHT] = 700; + init_css_node_children(node_0, 2); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_WIDTH] = 200; + node_1->style.dimensions[CSS_HEIGHT] = 300; + node_1 = node_0->get_child(node_0->context, 1); + node_1->style.dimensions[CSS_WIDTH] = 200; + node_1->style.dimensions[CSS_HEIGHT] = 300; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 300; + node_0->layout.dimensions[CSS_HEIGHT] = 700; + init_css_node_children(node_0, 2); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 200; + node_1->layout.dimensions[CSS_HEIGHT] = 300; + node_1 = node_0->get_child(node_0->context, 1); + node_1->layout.position[CSS_TOP] = 300; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 200; + node_1->layout.dimensions[CSS_HEIGHT] = 300; + } + } + + test("should set parents size based on min bounded children", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.align_items = CSS_ALIGN_STRETCH; + node_0->style.dimensions[CSS_WIDTH] = 1000; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_HEIGHT] = 100; + node_1->style.maxDimensions[CSS_WIDTH] = 1100; + node_1->style.maxDimensions[CSS_HEIGHT] = 110; + node_1->style.minDimensions[CSS_WIDTH] = 900; + node_1->style.minDimensions[CSS_HEIGHT] = 90; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 1000; + node_0->layout.dimensions[CSS_HEIGHT] = 100; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 1000; + node_1->layout.dimensions[CSS_HEIGHT] = 100; + } + } + + test("should keep stretched size within bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.align_items = CSS_ALIGN_STRETCH; + node_0->style.dimensions[CSS_WIDTH] = 1000; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_HEIGHT] = 100; + node_1->style.maxDimensions[CSS_WIDTH] = 900; + node_1->style.maxDimensions[CSS_HEIGHT] = 90; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 1000; + node_0->layout.dimensions[CSS_HEIGHT] = 90; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 900; + node_1->layout.dimensions[CSS_HEIGHT] = 90; + } + } + + test("should keep stretched size within max bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.align_items = CSS_ALIGN_STRETCH; + node_0->style.dimensions[CSS_WIDTH] = 1000; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_HEIGHT] = 100; + node_1->style.minDimensions[CSS_WIDTH] = 1100; + node_1->style.minDimensions[CSS_HEIGHT] = 110; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 1000; + node_0->layout.dimensions[CSS_HEIGHT] = 110; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 1100; + node_1->layout.dimensions[CSS_HEIGHT] = 110; + } + } + + test("should keep stretched size within min bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW; + node_0->style.dimensions[CSS_WIDTH] = 1000; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_HEIGHT] = 100; + node_1->style.minDimensions[CSS_WIDTH] = 100; + node_1->style.minDimensions[CSS_HEIGHT] = 110; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 1000; + node_0->layout.dimensions[CSS_HEIGHT] = 110; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 0; + node_1->layout.dimensions[CSS_WIDTH] = 100; + node_1->layout.dimensions[CSS_HEIGHT] = 110; + } + } + + test("should keep cross axis size within min bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 1000; + node_0->style.dimensions[CSS_HEIGHT] = 1000; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.position_type = CSS_POSITION_ABSOLUTE; + node_1->style.maxDimensions[CSS_WIDTH] = 500; + node_1->style.maxDimensions[CSS_HEIGHT] = 600; + node_1->style.position[CSS_LEFT] = 100; + node_1->style.position[CSS_TOP] = 100; + node_1->style.position[CSS_RIGHT] = 100; + node_1->style.position[CSS_BOTTOM] = 100; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 1000; + node_0->layout.dimensions[CSS_HEIGHT] = 1000; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 100; + node_1->layout.position[CSS_LEFT] = 100; + node_1->layout.dimensions[CSS_WIDTH] = 500; + node_1->layout.dimensions[CSS_HEIGHT] = 600; + } + } + + test("should layout node with position absolute, top and left and max bounds", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 1000; + node_0->style.dimensions[CSS_HEIGHT] = 1000; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.position_type = CSS_POSITION_ABSOLUTE; + node_1->style.minDimensions[CSS_WIDTH] = 900; + node_1->style.minDimensions[CSS_HEIGHT] = 1000; + node_1->style.position[CSS_LEFT] = 100; + node_1->style.position[CSS_TOP] = 100; + node_1->style.position[CSS_RIGHT] = 100; + node_1->style.position[CSS_BOTTOM] = 100; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 1000; + node_0->layout.dimensions[CSS_HEIGHT] = 1000; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 100; + node_1->layout.position[CSS_LEFT] = 100; + node_1->layout.dimensions[CSS_WIDTH] = 900; + node_1->layout.dimensions[CSS_HEIGHT] = 1000; + } + } + + test("should layout node with position absolute, top and left and min bounds", root_node, root_layout); + } /** END_GENERATED **/ return tests_finished(); } diff --git a/src/__tests__/Layout-test.js b/src/__tests__/Layout-test.js index 6f766a2a..893fd53c 100755 --- a/src/__tests__/Layout-test.js +++ b/src/__tests__/Layout-test.js @@ -1244,4 +1244,243 @@ describe('Layout', function() { ); }); + it('should use max bounds', function() { + testLayout( + {style: {width: 100, height: 200, maxWidth: 90, maxHeight: 190}}, + {width: 90, height: 190, top: 0, left: 0} + ); + }); + + it('should use min bounds', function() { + testLayout( + {style: {width: 100, height: 200, minWidth: 110, minHeight: 210}}, + {width: 110, height: 210, top: 0, left: 0} + ); + }); + + it('should use min bounds over max bounds', function() { + testLayout( + {style: {width: 100, height: 200, minWidth: 110, maxWidth: 90, minHeight: 210, maxHeight: 190}}, + {width: 110, height: 210, top: 0, left: 0} + ); + }); + + it('should use min bounds over max bounds and natural width', function() { + testLayout( + {style: {width: 100, height: 200, minWidth: 90, maxWidth: 80, minHeight: 190, maxHeight: 180}}, + {width: 90, height: 190, top: 0, left: 0} + ); + }); + + it('should ignore negative min bounds', function() { + testLayout( + {style: {width: 100, height: 200, minWidth: -10, minHeight: -20}}, + {width: 100, height: 200, top: 0, left: 0} + ); + }); + + it('should ignore negative max bounds', function() { + testLayout( + {style: {width: 100, height: 200, maxWidth: -10, maxHeight: -20}}, + {width: 100, height: 200, top: 0, left: 0} + ); + }); + + it('should use padded size over max bounds', function() { + testLayout( + {style: {paddingTop: 15, paddingBottom: 15, paddingLeft: 20, paddingRight: 20, maxWidth: 30, maxHeight: 10}}, + {width: 40, height: 30, top: 0, left: 0} + ); + }); + + it('should use min size over padded size', function() { + testLayout( + {style: {paddingTop: 15, paddingBottom: 15, paddingLeft: 20, paddingRight: 20, minWidth: 50, minHeight: 40}}, + {width: 50, height: 40, top: 0, left: 0} + ); + }); + + it('should override flex direction size with min bounds', function() { + testLayout( + {style: {width: 300, height: 200, flexDirection:'row'}, children: [ + {style: {flex: 1}}, + {style: {flex: 1, minWidth: 200}}, + {style: {flex: 1}} + ]}, + {width: 300, height: 200, top: 0, left: 0, children: [ + {width: 50, height: 200, top: 0, left: 0}, + {width: 200, height: 200, top: 0, left: 50}, + {width: 50, height: 200, top: 0, left: 250} + ]} + ); + }); + + it('should not override flex direction size within bounds', function() { + testLayout( + {style: {width: 300, height: 200, flexDirection:'row'}, children: [ + {style: {flex: 1}}, + {style: {flex: 1, minWidth: 90, maxWidth: 110}}, + {style: {flex: 1}} + ]}, + {width: 300, height: 200, top: 0, left: 0, children: [ + {width: 100, height: 200, top: 0, left: 0}, + {width: 100, height: 200, top: 0, left: 100}, + {width: 100, height: 200, top: 0, left: 200} + ]} + ); + }); + + it('should override flex direction size with max bounds', function() { + testLayout( + {style: {width: 300, height: 200, flexDirection:'row'}, children: [ + {style: {flex: 1}}, + {style: {flex: 1, maxWidth: 60}}, + {style: {flex: 1}} + ]}, + {width: 300, height: 200, top: 0, left: 0, children: [ + {width: 120, height: 200, top: 0, left: 0}, + {width: 60, height: 200, top: 0, left: 120}, + {width: 120, height: 200, top: 0, left: 180} + ]} + ); + }); + + it('should pre-fill child size within bounds', function() { + testLayout( + {style: {width: 300, height: 200}, children: [ + {style: {flex: 1, minWidth: 290, maxWidth: 310}}, + ]}, + {width: 300, height: 200, top: 0, left: 0, children: [ + {width: 300, height: 200, top: 0, left: 0}, + ]} + ); + }); + + it('should pre-fill child size within max bound', function() { + testLayout( + {style: {width: 300, height: 200}, children: [ + {style: {flex: 1, maxWidth: 290}}, + ]}, + {width: 300, height: 200, top: 0, left: 0, children: [ + {width: 290, height: 200, top: 0, left: 0}, + ]} + ); + }); + + it('should pre-fill child size within min bounds', function() { + testLayout( + {style: {width: 300, height: 200}, children: [ + {style: {flex: 1, minWidth: 310}}, + ]}, + {width: 300, height: 200, top: 0, left: 0, children: [ + {width: 310, height: 200, top: 0, left: 0}, + ]} + ); + }); + + it('should set parents size based on bounded children', function() { + testLayout( + {style: {minWidth: 100, maxWidth: 300, minHeight: 500, maxHeight: 700}, children: [ + {style: {width: 200, height: 300}}, + {style: {width: 200, height: 300}}, + ]}, + {width: 200, height: 600, top: 0, left: 0, children: [ + {width: 200, height: 300, top: 0, left: 0}, + {width: 200, height: 300, top: 300, left: 0}, + ]} + ); + }); + + it('should set parents size based on max bounded children', function() { + testLayout( + {style: {maxWidth: 100, maxHeight: 500}, children: [ + {style: {width: 200, height: 300}}, + {style: {width: 200, height: 300}}, + ]}, + {width: 100, height: 500, top: 0, left: 0, children: [ + {width: 200, height: 300, top: 0, left: 0}, + {width: 200, height: 300, top: 300, left: 0}, + ]} + ); + }); + + it('should set parents size based on min bounded children', function() { + testLayout( + {style: {minWidth: 300, minHeight: 700}, children: [ + {style: {width: 200, height: 300}}, + {style: {width: 200, height: 300}}, + ]}, + {width: 300, height: 700, top: 0, left: 0, children: [ + {width: 200, height: 300, top: 0, left: 0}, + {width: 200, height: 300, top: 300, left: 0}, + ]} + ); + }); + + it('should keep stretched size within bounds', function() { + testLayout( + {style: {width: 1000, alignItems: 'stretch'}, children: [ + {style: {height: 100, minHeight: 90, maxHeight: 110, minWidth: 900, maxWidth: 1100}} + ]}, + {width: 1000, height: 100, top: 0, left: 0, children: [ + {width: 1000, height: 100, top: 0, left: 0} + ]} + ); + }); + + it('should keep stretched size within max bounds', function() { + testLayout( + {style: {width: 1000, alignItems: 'stretch'}, children: [ + {style: {height: 100, maxHeight: 90, maxWidth: 900}} + ]}, + {width: 1000, height: 90, top: 0, left: 0, children: [ + {width: 900, height: 90, top: 0, left: 0} + ]} + ); + }); + + it('should keep stretched size within min bounds', function() { + testLayout( + {style: {width: 1000, alignItems: 'stretch'}, children: [ + {style: {height: 100, minHeight: 110, minWidth: 1100}} + ]}, + {width: 1000, height: 110, top: 0, left: 0, children: [ + {width: 1100, height: 110, top: 0, left: 0} + ]} + ); + }); + + it('should keep cross axis size within min bounds', function() { + testLayout( + {style: {width: 1000, flexDirection: 'row'}, children: [ + {style: {height: 100, minHeight: 110, minWidth: 100}} + ]}, + {width: 1000, height: 110, top: 0, left: 0, children: [ + {width: 100, height: 110, top: 0, left: 0} + ]} + ); + }); + + it('should layout node with position absolute, top and left and max bounds', function() { + testLayout( + {style: {width: 1000, height: 1000}, children: [ + {style: {position: 'absolute', top: 100, left: 100, bottom: 100, right: 100, maxWidth: 500, maxHeight: 600}} + ]}, + {width: 1000, height: 1000, top: 0, left: 0, children: [ + {width: 500, height: 600, top: 100, left: 100}, + ]} + ); + }); + + it('should layout node with position absolute, top and left and min bounds', function() { + testLayout( + {style: {width: 1000, height: 1000}, children: [ + {style: {position: 'absolute', top: 100, left: 100, bottom: 100, right: 100, minWidth: 900, minHeight: 1000}} + ]}, + {width: 1000, height: 1000, top: 0, left: 0, children: [ + {width: 900, height: 1000, top: 100, left: 100}, + ]} + ); + }); + }); diff --git a/src/java/src/com/facebook/csslayout/CSSStyle.java b/src/java/src/com/facebook/csslayout/CSSStyle.java index bd66db97..602de3ed 100644 --- a/src/java/src/com/facebook/csslayout/CSSStyle.java +++ b/src/java/src/com/facebook/csslayout/CSSStyle.java @@ -32,4 +32,10 @@ public class CSSStyle { public float width = CSSConstants.UNDEFINED; public float height = CSSConstants.UNDEFINED; + + public float minWidth = CSSConstants.UNDEFINED; + public float minHeight = CSSConstants.UNDEFINED; + + public float maxWidth = CSSConstants.UNDEFINED; + public float maxHeight = CSSConstants.UNDEFINED; } diff --git a/src/java/src/com/facebook/csslayout/LayoutEngine.java b/src/java/src/com/facebook/csslayout/LayoutEngine.java index 5b72b39c..e214db17 100644 --- a/src/java/src/com/facebook/csslayout/LayoutEngine.java +++ b/src/java/src/com/facebook/csslayout/LayoutEngine.java @@ -188,6 +188,30 @@ public class LayoutEngine { getLeading(axis)) + getPaddingAndBorder(node, getTrailing(axis)); } + private static float boundAxis(CSSNode node, CSSFlexDirection axis, float value) { + float min = CSSConstants.UNDEFINED; + float max = CSSConstants.UNDEFINED; + + if (axis == CSSFlexDirection.COLUMN) { + min = node.style.minHeight; + max = node.style.maxHeight; + } else if (axis == CSSFlexDirection.ROW) { + min = node.style.minWidth; + max = node.style.maxWidth; + } + + float boundValue = value; + + if (!CSSConstants.isUndefined(max) && max >= 0.0 && boundValue > max) { + boundValue = max; + } + if (!CSSConstants.isUndefined(min) && min >= 0.0 && boundValue < min) { + boundValue = min; + } + + return boundValue; + } + private static void setDimensionFromStyle(CSSNode node, CSSFlexDirection axis) { // The parent already computed us a width or height. We just skip it if (!CSSConstants.isUndefined(getLayoutDimension(node, getDim(axis)))) { @@ -200,7 +224,7 @@ public class LayoutEngine { // The dimensions can never be smaller than the padding and border float maxLayoutDimension = Math.max( - getStyleDimension(node, getDim(axis)), + boundAxis(node, axis, getStyleDimension(node, getDim(axis))), getPaddingAndBorderAxis(node, axis)); setLayoutDimension(node, getDim(axis), maxLayoutDimension); } @@ -283,7 +307,6 @@ public class LayoutEngine { CSSLayoutContext layoutContext, CSSNode node, float parentMaxWidth) { - for (int i = 0; i < node.getChildCount(); i++) { node.getChildAt(i).layout.resetResult(); } @@ -360,9 +383,9 @@ public class LayoutEngine { !CSSConstants.isUndefined(getLayoutDimension(node, getDim(crossAxis))) && !isDimDefined(child, crossAxis)) { setLayoutDimension(child, getDim(crossAxis), Math.max( - getLayoutDimension(node, getDim(crossAxis)) - + boundAxis(child, crossAxis, getLayoutDimension(node, getDim(crossAxis)) - getPaddingAndBorderAxis(node, crossAxis) - - getMarginAxis(child, crossAxis), + getMarginAxis(child, crossAxis)), // You never want to go smaller than padding getPaddingAndBorderAxis(child, crossAxis) )); @@ -376,11 +399,11 @@ public class LayoutEngine { isPosDefined(child, getLeading(axis)) && isPosDefined(child, getTrailing(axis))) { setLayoutDimension(child, getDim(axis), Math.max( - getLayoutDimension(node, getDim(axis)) - - getPaddingAndBorderAxis(node, axis) - - getMarginAxis(child, axis) - - getPosition(child, getLeading(axis)) - - getPosition(child, getTrailing(axis)), + boundAxis(child, axis, getLayoutDimension(node, getDim(axis)) - + getPaddingAndBorderAxis(node, axis) - + getMarginAxis(child, axis) - + getPosition(child, getLeading(axis)) - + getPosition(child, getTrailing(axis))), // You never want to go smaller than padding getPaddingAndBorderAxis(child, axis) )); @@ -430,8 +453,9 @@ public class LayoutEngine { totalFlexible = 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); @@ -497,6 +521,25 @@ public class LayoutEngine { // remaining space if (flexibleChildrenCount != 0) { float flexibleMainDim = remainingMainDim / totalFlexible; + float baseMainDim; + float boundMainDim; + + // Iterate over every child. 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.getChildAt(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. @@ -511,8 +554,15 @@ public class LayoutEngine { if (isFlex(child)) { // At this point we know the final size of the element in the main // dimension - setLayoutDimension(child, getDim(mainAxis), flexibleMainDim * getFlex(child) + - getPaddingAndBorderAxis(child, mainAxis)); + baseMainDim = flexibleMainDim * getFlex(child) + + getPaddingAndBorderAxis(child, mainAxis); + boundMainDim = boundAxis(child, mainAxis, baseMainDim); + + if (baseMainDim == boundMainDim) { + setLayoutDimension(child, getDim(mainAxis), baseMainDim); + } else { + setLayoutDimension(child, getDim(mainAxis), boundMainDim); + } maxWidth = CSSConstants.UNDEFINED; if (isDimDefined(node, CSSFlexDirection.ROW)) { @@ -589,7 +639,7 @@ public class LayoutEngine { mainDim = 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 = Math.max(crossDim, getDimWithMargin(child, crossAxis)); + crossDim = Math.max(crossDim, boundAxis(child, crossAxis, getDimWithMargin(child, crossAxis))); } } @@ -600,7 +650,7 @@ public class LayoutEngine { containerMainAxis = Math.max( // We're missing the last padding at this point to get the final // dimension - mainDim + getPaddingAndBorder(node, getTrailing(mainAxis)), + boundAxis(node, mainAxis, mainDim + getPaddingAndBorder(node, getTrailing(mainAxis))), // We can never assign a width smaller than the padding and borders getPaddingAndBorderAxis(node, mainAxis) ); @@ -612,7 +662,7 @@ public class LayoutEngine { // 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) ); } @@ -643,9 +693,9 @@ public class LayoutEngine { // previously. if (!isDimDefined(child, crossAxis)) { setLayoutDimension(child, getDim(crossAxis), Math.max( - 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) )); @@ -681,7 +731,7 @@ public class LayoutEngine { setLayoutDimension(node, getDim(mainAxis), Math.max( // We're missing the last padding at this point to get the final // dimension - linesMainDim + getPaddingAndBorder(node, getTrailing(mainAxis)), + boundAxis(node, mainAxis, linesMainDim + getPaddingAndBorder(node, getTrailing(mainAxis))), // We can never assign a width smaller than the padding and borders getPaddingAndBorderAxis(node, mainAxis) )); @@ -692,7 +742,7 @@ public class LayoutEngine { // 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) )); } @@ -711,11 +761,12 @@ public class LayoutEngine { isPosDefined(child, getLeading(axis)) && isPosDefined(child, getTrailing(axis))) { setLayoutDimension(child, getDim(axis), Math.max( - getLayoutDimension(node, getDim(axis)) - - getPaddingAndBorderAxis(node, axis) - - getMarginAxis(child, axis) - - getPosition(child, getLeading(axis)) - - getPosition(child, getTrailing(axis)), + boundAxis(child, axis, getLayoutDimension(node, getDim(axis)) - + getPaddingAndBorderAxis(node, axis) - + getMarginAxis(child, axis) - + getPosition(child, getLeading(axis)) - + getPosition(child, getTrailing(axis)) + ), // You never want to go smaller than padding getPaddingAndBorderAxis(child, axis) )); diff --git a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java index 71b109af..9e050e5e 100644 --- a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java +++ b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java @@ -4033,5 +4033,864 @@ public class LayoutEngineTest { test("should layout flex wrap with a line bigger than container", root_node, root_layout); } + + @Test + public void testCase95() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.height = 200; + node_0.style.maxWidth = 90; + node_0.style.maxHeight = 190; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 90; + node_0.layout.height = 190; + } + + test("should use max bounds", root_node, root_layout); + } + + @Test + public void testCase96() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.height = 200; + node_0.style.minWidth = 110; + node_0.style.minHeight = 210; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 110; + node_0.layout.height = 210; + } + + test("should use min bounds", root_node, root_layout); + } + + @Test + public void testCase97() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.height = 200; + node_0.style.maxWidth = 90; + node_0.style.maxHeight = 190; + node_0.style.minWidth = 110; + node_0.style.minHeight = 210; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 110; + node_0.layout.height = 210; + } + + test("should use min bounds over max bounds", root_node, root_layout); + } + + @Test + public void testCase98() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.height = 200; + node_0.style.maxWidth = 80; + node_0.style.maxHeight = 180; + node_0.style.minWidth = 90; + node_0.style.minHeight = 190; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 90; + node_0.layout.height = 190; + } + + test("should use min bounds over max bounds and natural width", root_node, root_layout); + } + + @Test + public void testCase99() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.height = 200; + node_0.style.minWidth = -10; + node_0.style.minHeight = -20; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 100; + node_0.layout.height = 200; + } + + test("should ignore negative min bounds", root_node, root_layout); + } + + @Test + public void testCase100() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.height = 200; + node_0.style.maxWidth = -10; + node_0.style.maxHeight = -20; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 100; + node_0.layout.height = 200; + } + + test("should ignore negative max bounds", root_node, root_layout); + } + + @Test + public void testCase101() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.maxWidth = 30; + node_0.style.maxHeight = 10; + node_0.style.padding[Spacing.LEFT] = 20; + node_0.style.padding[Spacing.TOP] = 15; + node_0.style.padding[Spacing.RIGHT] = 20; + node_0.style.padding[Spacing.BOTTOM] = 15; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 40; + node_0.layout.height = 30; + } + + test("should use padded size over max bounds", root_node, root_layout); + } + + @Test + public void testCase102() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.minWidth = 50; + node_0.style.minHeight = 40; + node_0.style.padding[Spacing.LEFT] = 20; + node_0.style.padding[Spacing.TOP] = 15; + node_0.style.padding[Spacing.RIGHT] = 20; + node_0.style.padding[Spacing.BOTTOM] = 15; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 50; + node_0.layout.height = 40; + } + + test("should use min size over padded size", root_node, root_layout); + } + + @Test + public void testCase103() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 300; + node_0.style.height = 200; + addChildren(node_0, 3); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1 = node_0.getChildAt(1); + node_1.style.flex = 1; + node_1.style.minWidth = 200; + node_1 = node_0.getChildAt(2); + node_1.style.flex = 1; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 300; + node_0.layout.height = 200; + addChildren(node_0, 3); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 50; + node_1.layout.height = 200; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 0; + node_1.layout.x = 50; + node_1.layout.width = 200; + node_1.layout.height = 200; + node_1 = node_0.getChildAt(2); + node_1.layout.y = 0; + node_1.layout.x = 250; + node_1.layout.width = 50; + node_1.layout.height = 200; + } + } + + test("should override flex direction size with min bounds", root_node, root_layout); + } + + @Test + public void testCase104() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 300; + node_0.style.height = 200; + addChildren(node_0, 3); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1 = node_0.getChildAt(1); + node_1.style.flex = 1; + node_1.style.maxWidth = 110; + node_1.style.minWidth = 90; + node_1 = node_0.getChildAt(2); + node_1.style.flex = 1; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 300; + node_0.layout.height = 200; + addChildren(node_0, 3); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 200; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 0; + node_1.layout.x = 100; + node_1.layout.width = 100; + node_1.layout.height = 200; + node_1 = node_0.getChildAt(2); + node_1.layout.y = 0; + node_1.layout.x = 200; + node_1.layout.width = 100; + node_1.layout.height = 200; + } + } + + test("should not override flex direction size within bounds", root_node, root_layout); + } + + @Test + public void testCase105() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 300; + node_0.style.height = 200; + addChildren(node_0, 3); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1 = node_0.getChildAt(1); + node_1.style.flex = 1; + node_1.style.maxWidth = 60; + node_1 = node_0.getChildAt(2); + node_1.style.flex = 1; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 300; + node_0.layout.height = 200; + addChildren(node_0, 3); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 120; + node_1.layout.height = 200; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 0; + node_1.layout.x = 120; + node_1.layout.width = 60; + node_1.layout.height = 200; + node_1 = node_0.getChildAt(2); + node_1.layout.y = 0; + node_1.layout.x = 180; + node_1.layout.width = 120; + node_1.layout.height = 200; + } + } + + test("should override flex direction size with max bounds", root_node, root_layout); + } + + @Test + public void testCase106() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 300; + node_0.style.height = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1.style.maxWidth = 310; + node_1.style.minWidth = 290; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 300; + node_0.layout.height = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 300; + node_1.layout.height = 200; + } + } + + test("should pre-fill child size within bounds", root_node, root_layout); + } + + @Test + public void testCase107() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 300; + node_0.style.height = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1.style.maxWidth = 290; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 300; + node_0.layout.height = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 290; + node_1.layout.height = 200; + } + } + + test("should pre-fill child size within max bound", root_node, root_layout); + } + + @Test + public void testCase108() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 300; + node_0.style.height = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1.style.minWidth = 310; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 300; + node_0.layout.height = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 310; + node_1.layout.height = 200; + } + } + + test("should pre-fill child size within min bounds", root_node, root_layout); + } + + @Test + public void testCase109() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.maxWidth = 300; + node_0.style.maxHeight = 700; + node_0.style.minWidth = 100; + node_0.style.minHeight = 500; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 200; + node_1.style.height = 300; + node_1 = node_0.getChildAt(1); + node_1.style.width = 200; + node_1.style.height = 300; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 200; + node_0.layout.height = 600; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 200; + node_1.layout.height = 300; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 300; + node_1.layout.x = 0; + node_1.layout.width = 200; + node_1.layout.height = 300; + } + } + + test("should set parents size based on bounded children", root_node, root_layout); + } + + @Test + public void testCase110() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.maxWidth = 100; + node_0.style.maxHeight = 500; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 200; + node_1.style.height = 300; + node_1 = node_0.getChildAt(1); + node_1.style.width = 200; + node_1.style.height = 300; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 100; + node_0.layout.height = 500; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 200; + node_1.layout.height = 300; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 300; + node_1.layout.x = 0; + node_1.layout.width = 200; + node_1.layout.height = 300; + } + } + + test("should set parents size based on max bounded children", root_node, root_layout); + } + + @Test + public void testCase111() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.minWidth = 300; + node_0.style.minHeight = 700; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 200; + node_1.style.height = 300; + node_1 = node_0.getChildAt(1); + node_1.style.width = 200; + node_1.style.height = 300; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 300; + node_0.layout.height = 700; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 200; + node_1.layout.height = 300; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 300; + node_1.layout.x = 0; + node_1.layout.width = 200; + node_1.layout.height = 300; + } + } + + test("should set parents size based on min bounded children", root_node, root_layout); + } + + @Test + public void testCase112() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.alignItems = CSSAlign.STRETCH; + node_0.style.width = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 100; + node_1.style.maxWidth = 1100; + node_1.style.maxHeight = 110; + node_1.style.minWidth = 900; + node_1.style.minHeight = 90; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 1000; + node_1.layout.height = 100; + } + } + + test("should keep stretched size within bounds", root_node, root_layout); + } + + @Test + public void testCase113() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.alignItems = CSSAlign.STRETCH; + node_0.style.width = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 100; + node_1.style.maxWidth = 900; + node_1.style.maxHeight = 90; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 90; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 900; + node_1.layout.height = 90; + } + } + + test("should keep stretched size within max bounds", root_node, root_layout); + } + + @Test + public void testCase114() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.alignItems = CSSAlign.STRETCH; + node_0.style.width = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 100; + node_1.style.minWidth = 1100; + node_1.style.minHeight = 110; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 110; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 1100; + node_1.layout.height = 110; + } + } + + test("should keep stretched size within min bounds", root_node, root_layout); + } + + @Test + public void testCase115() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 100; + node_1.style.minWidth = 100; + node_1.style.minHeight = 110; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 110; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 110; + } + } + + test("should keep cross axis size within min bounds", root_node, root_layout); + } + + @Test + public void testCase116() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.maxWidth = 500; + node_1.style.maxHeight = 600; + node_1.style.positionLeft = 100; + node_1.style.positionTop = 100; + node_1.style.positionRight = 100; + node_1.style.positionBottom = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 100; + node_1.layout.x = 100; + node_1.layout.width = 500; + node_1.layout.height = 600; + } + } + + test("should layout node with position absolute, top and left and max bounds", root_node, root_layout); + } + + @Test + public void testCase117() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.minWidth = 900; + node_1.style.minHeight = 1000; + node_1.style.positionLeft = 100; + node_1.style.positionTop = 100; + node_1.style.positionRight = 100; + node_1.style.positionBottom = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 100; + node_1.layout.x = 100; + node_1.layout.width = 900; + node_1.layout.height = 1000; + } + } + + test("should layout node with position absolute, top and left and min bounds", root_node, root_layout); + } /** END_GENERATED **/ } diff --git a/src/transpile.js b/src/transpile.js index d649df3c..193631dc 100644 --- a/src/transpile.js +++ b/src/transpile.js @@ -145,6 +145,10 @@ function printLayout(test) { addFloat(node, 'flex', 'flex'); addFloat(node, 'width', 'dimensions[CSS_WIDTH]'); addFloat(node, 'height', 'dimensions[CSS_HEIGHT]'); + addFloat(node, 'maxWidth', 'maxDimensions[CSS_WIDTH]'); + addFloat(node, 'maxHeight', 'maxDimensions[CSS_HEIGHT]'); + addFloat(node, 'minWidth', 'minDimensions[CSS_WIDTH]'); + addFloat(node, 'minHeight', 'minDimensions[CSS_HEIGHT]'); addSpacing(node, 'margin', ''); addSpacing(node, 'padding', ''); addSpacing(node, 'border', 'Width'); @@ -223,6 +227,10 @@ function transpileAnnotatedJStoC(jsCode) { .replace(/\.children\.length/g, '.children_count') .replace(/\.width/g, '.dimensions[CSS_WIDTH]') .replace(/\.height/g, '.dimensions[CSS_HEIGHT]') + .replace(/\.maxWidth/g, '.maxDimensions[CSS_WIDTH]') + .replace(/\.maxHeight/g, '.maxDimensions[CSS_HEIGHT]') + .replace(/\.minWidth/g, '.minDimensions[CSS_WIDTH]') + .replace(/\.minHeight/g, '.minDimensions[CSS_HEIGHT]') .replace(/layout\[dim/g, 'layout.dimensions[dim') .replace(/layout\[pos/g, 'layout.position[pos') .replace(/layout\[leading/g, 'layout.position[leading')