From e53bf4974690b3589f91c66e649b74bb40b3e9e2 Mon Sep 17 00:00:00 2001 From: Christopher Chedeau Date: Mon, 19 May 2014 12:39:27 -0700 Subject: [PATCH] fix bug where nested align: stretch were not properly working The way the algorithm work is that you first layout fixed children on the main axis, then compute all the dimensions so that you can layout flexible children. This separation doesn't work anymore if we add the other axis. The solution here is a hacky (but working!) attempt at fixing the issue. We start by doing a pass to set the children dimensions if they are stretch. --- src/Layout.c | 19 ++++++++++++++ src/Layout.js | 19 ++++++++++++++ src/__tests__/Layout-test.c | 49 ++++++++++++++++++++++++++++++++++++ src/__tests__/Layout-test.js | 15 ++++++++++- 4 files changed, 101 insertions(+), 1 deletion(-) diff --git a/src/Layout.c b/src/Layout.c index 069e52c3..fb2cf409 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -364,6 +364,25 @@ void layoutNode(css_node_t *node) { return; } + // Pre-fill cross axis dimensions when the child is using stretch before + // we call the recursive layout pass + for (int i = 0; i < node->children_count; ++i) { + css_node_t* child = &node->children[i]; + if (getAlignItem(node, child) == CSS_ALIGN_STRETCH && + getPositionType(child) == CSS_POSITION_RELATIVE && + !isUndefined(node->layout.dimensions[dim[crossAxis]]) && + !isDimDefined(child, crossAxis) && + !isPosDefined(child, leading[crossAxis])) { + child->layout.dimensions[dim[crossAxis]] = fmaxf( + node->layout.dimensions[dim[crossAxis]] - + getPaddingAndBorderAxis(node, crossAxis) - + getMarginAxis(child, crossAxis), + // You never want to go smaller than padding + getPaddingAndBorderAxis(child, crossAxis) + ); + } + } + // Layout non flexible children and count children by type // mainContentDim is accumulation of the dimensions and margin of all the diff --git a/src/Layout.js b/src/Layout.js index 48803b2a..4627a920 100755 --- a/src/Layout.js +++ b/src/Layout.js @@ -242,6 +242,25 @@ var computeLayout = (function() { return; } + // Pre-fill cross axis dimensions when the child is using stretch before + // we call the recursive layout pass + for (var/*int*/ i = 0; i < node.children.length; ++i) { + var/*css_node_t**/ child = node.children[i]; + if (getAlignItem(node, child) === CSS_ALIGN_STRETCH && + getPositionType(child) === CSS_POSITION_RELATIVE && + !isUndefined(node.layout[dim[crossAxis]]) && + !isDimDefined(child, crossAxis) && + !isPosDefined(child, leading[crossAxis])) { + child.layout[dim[crossAxis]] = fmaxf( + node.layout[dim[crossAxis]] - + getPaddingAndBorderAxis(node, crossAxis) - + getMarginAxis(child, crossAxis), + // You never want to go smaller than padding + getPaddingAndBorderAxis(child, crossAxis) + ); + } + } + // Layout non flexible children and count children by type // mainContentDim is accumulation of the dimensions and margin of all the diff --git a/src/__tests__/Layout-test.c b/src/__tests__/Layout-test.c index a21865eb..958c2937 100644 --- a/src/__tests__/Layout-test.c +++ b/src/__tests__/Layout-test.c @@ -2563,6 +2563,55 @@ int main() test("should layout node with text and position absolute", root_node, root_layout); } + { + css_node_t *root_node = new_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 300; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = &node_0->children[0]; + node_1->style.align_self = CSS_ALIGN_STRETCH; + init_css_node_children(node_1, 1); + { + css_node_t *node_2; + node_2 = &node_1->children[0]; + node_2->style.align_self = CSS_ALIGN_STRETCH; + } + } + } + + css_node_t *root_layout = new_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] = 0; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = &node_0->children[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] = 0; + init_css_node_children(node_1, 1); + { + css_node_t *node_2; + node_2 = &node_1->children[0]; + node_2->layout.position[CSS_TOP] = 0; + node_2->layout.position[CSS_LEFT] = 0; + node_2->layout.dimensions[CSS_WIDTH] = 300; + node_2->layout.dimensions[CSS_HEIGHT] = 0; + } + } + } + + test("should layout node with nested alignSelf: stretch", root_node, root_layout); + } + { css_node_t *root_node = new_css_node(); { diff --git a/src/__tests__/Layout-test.js b/src/__tests__/Layout-test.js index 5134b66d..01f0ff65 100755 --- a/src/__tests__/Layout-test.js +++ b/src/__tests__/Layout-test.js @@ -777,7 +777,20 @@ describe('Layout', function() { ) }); - + it('should layout node with nested alignSelf: stretch', function() { + testLayout( + {style: {width: 300}, children: [ + {style: {alignSelf: 'stretch'}, children: [ + {style: {alignSelf: 'stretch'}} + ]} + ]}, + {width: 300, height: 0, top: 0, left: 0, children: [ + {width: 300, height: 0, top: 0, left: 0, children: [ + {width: 300, height: 0, top: 0, left: 0} + ]} + ]} + ); + }); it('should layout randomly', function() { function RNG(seed) {