diff --git a/dist/css-layout.h b/dist/css-layout.h index e7a64287..29c08575 100644 --- a/dist/css-layout.h +++ b/dist/css-layout.h @@ -141,8 +141,8 @@ struct css_node { int children_count; int line_index; - css_node_t* next_absolute_child; - css_node_t* next_flex_child; + css_node_t *next_absolute_child; + css_node_t *next_flex_child; css_dim_t (*measure)(void *context, float width, float height); void (*print)(void *context); @@ -151,7 +151,6 @@ struct css_node { void *context; }; - // Lifecycle of nodes and children css_node_t *new_css_node(void); void init_css_node(css_node_t *node); @@ -165,9 +164,13 @@ typedef enum { } css_print_options_t; void print_css_node(css_node_t *node, css_print_options_t options); +bool isUndefined(float value); + // Function that computes the layout! void layoutNode(css_node_t *node, float maxWidth, float maxHeight, css_direction_t parentDirection); -bool isUndefined(float value); + +// Reset the calculated layout values for a given node. You should call this before `layoutNode`. +void resetNodeLayout(css_node_t *node); #endif @@ -1460,6 +1463,10 @@ void layoutNode(css_node_t *node, float parentMaxWidth, float parentMaxHeight, c layout->last_parent_max_height = parentMaxHeight; layout->last_direction = direction; + for (int i = 0, childCount = node->children_count; i < childCount; i++) { + resetNodeLayout(node->get_child(node->context, i)); + } + layoutNodeImpl(node, parentMaxWidth, parentMaxHeight, parentDirection); layout->last_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH]; @@ -1469,4 +1476,11 @@ void layoutNode(css_node_t *node, float parentMaxWidth, float parentMaxHeight, c } } +void resetNodeLayout(css_node_t *node) { + node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED; + node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; + node->layout.position[CSS_LEFT] = 0; + node->layout.position[CSS_TOP] = 0; +} + #endif // CSS_LAYOUT_IMPLEMENTATION \ No newline at end of file diff --git a/dist/css-layout.jar b/dist/css-layout.jar index c9a83c89..9a0a701d 100644 Binary files a/dist/css-layout.jar and b/dist/css-layout.jar differ diff --git a/src/Layout.c b/src/Layout.c index 5d112330..5b2d2636 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -1286,6 +1286,10 @@ void layoutNode(css_node_t *node, float parentMaxWidth, float parentMaxHeight, c layout->last_parent_max_height = parentMaxHeight; layout->last_direction = direction; + for (int i = 0, childCount = node->children_count; i < childCount; i++) { + resetNodeLayout(node->get_child(node->context, i)); + } + layoutNodeImpl(node, parentMaxWidth, parentMaxHeight, parentDirection); layout->last_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH]; @@ -1294,3 +1298,10 @@ void layoutNode(css_node_t *node, float parentMaxWidth, float parentMaxHeight, c layout->last_position[CSS_LEFT] = layout->position[CSS_LEFT]; } } + +void resetNodeLayout(css_node_t *node) { + node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED; + node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; + node->layout.position[CSS_LEFT] = 0; + node->layout.position[CSS_TOP] = 0; +} diff --git a/src/Layout.h b/src/Layout.h index 6ad53e04..0a82e6c7 100644 --- a/src/Layout.h +++ b/src/Layout.h @@ -137,8 +137,8 @@ struct css_node { int children_count; int line_index; - css_node_t* next_absolute_child; - css_node_t* next_flex_child; + css_node_t *next_absolute_child; + css_node_t *next_flex_child; css_dim_t (*measure)(void *context, float width, float height); void (*print)(void *context); @@ -147,7 +147,6 @@ struct css_node { void *context; }; - // Lifecycle of nodes and children css_node_t *new_css_node(void); void init_css_node(css_node_t *node); @@ -161,8 +160,12 @@ typedef enum { } css_print_options_t; void print_css_node(css_node_t *node, css_print_options_t options); -// Function that computes the layout! -void layoutNode(css_node_t *node, float maxWidth, float maxHeight, css_direction_t parentDirection); bool isUndefined(float value); +// Function that computes the layout! +void layoutNode(css_node_t *node, float maxWidth, float maxHeight, css_direction_t parentDirection); + +// Reset the calculated layout values for a given node. You should call this before `layoutNode`. +void resetNodeLayout(css_node_t *node); + #endif diff --git a/src/__tests__/Layout-test.c b/src/__tests__/Layout-test.c index fe31e683..13c449ea 100644 --- a/src/__tests__/Layout-test.c +++ b/src/__tests__/Layout-test.c @@ -7916,6 +7916,94 @@ int main() test("should layout child whose cross axis is undefined and whose alignSelf is stretch", 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; + init_css_node_children(node_0, 2); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + init_css_node_children(node_1, 1); + { + css_node_t *node_2; + node_2 = node_1->get_child(node_1->context, 0); + node_2->style.dimensions[CSS_WIDTH] = 100; + node_2->style.dimensions[CSS_HEIGHT] = 100; + } + node_1 = node_0->get_child(node_0->context, 1); + node_1->style.dimensions[CSS_WIDTH] = 100; + init_css_node_children(node_1, 1); + { + css_node_t *node_2; + node_2 = node_1->get_child(node_1->context, 0); + node_2->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN; + node_2->style.align_items = CSS_ALIGN_CENTER; + init_css_node_children(node_2, 1); + { + css_node_t *node_3; + node_3 = node_2->get_child(node_2->context, 0); + node_3->style.dimensions[CSS_WIDTH] = 50; + node_3->style.dimensions[CSS_HEIGHT] = 50; + } + } + } + } + + 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] = 100; + 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] = 100; + node_1->layout.dimensions[CSS_HEIGHT] = 100; + init_css_node_children(node_1, 1); + { + css_node_t *node_2; + node_2 = node_1->get_child(node_1->context, 0); + node_2->layout.position[CSS_TOP] = 0; + node_2->layout.position[CSS_LEFT] = 0; + node_2->layout.dimensions[CSS_WIDTH] = 100; + node_2->layout.dimensions[CSS_HEIGHT] = 100; + } + 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] = 100; + init_css_node_children(node_1, 1); + { + css_node_t *node_2; + node_2 = node_1->get_child(node_1->context, 0); + node_2->layout.position[CSS_TOP] = 0; + node_2->layout.position[CSS_LEFT] = 0; + node_2->layout.dimensions[CSS_WIDTH] = 100; + node_2->layout.dimensions[CSS_HEIGHT] = 50; + init_css_node_children(node_2, 1); + { + css_node_t *node_3; + node_3 = node_2->get_child(node_2->context, 0); + node_3->layout.position[CSS_TOP] = 0; + node_3->layout.position[CSS_LEFT] = 25; + node_3->layout.dimensions[CSS_WIDTH] = 50; + node_3->layout.dimensions[CSS_HEIGHT] = 50; + } + } + } + } + + test("should center items correctly inside a stretched layout", root_node, root_layout); + } + { css_node_t *root_node = new_test_css_node(); { diff --git a/src/__tests__/Layout-test.js b/src/__tests__/Layout-test.js index aed51c52..a70ce673 100755 --- a/src/__tests__/Layout-test.js +++ b/src/__tests__/Layout-test.js @@ -41,7 +41,6 @@ describe('Javascript Only', function() { }); }); - describe('Layout', function() { it('should layout a single node with width and height', function() { testLayout({ @@ -2459,6 +2458,31 @@ describe('Layout', function() { ]} ); }); + + it('should center items correctly inside a stretched layout', function() { + testLayout( + {style: {flexDirection: 'row'}, children: [ + {style: {}, children: [ + {style: {width: 100, height: 100}} + ]}, + {style: {width: 100}, children: [ + {style: {flexDirection: 'column', alignItems: 'center'}, children: [ + {style: {width: 50, height: 50}}, + ]}, + ]}, + ]}, + {width: 200, height: 100, top: 0, left: 0, children: [ + {width: 100, height: 100, top: 0, left: 0, children: [ + {width: 100, height: 100, top: 0, left: 0} + ]}, + {width: 100, height: 100, top: 0, left: 100, children: [ + {width: 100, height: 50, top: 0, left: 0, children: [ + {width: 50, height: 50, top: 0, left: 25} + ]}, + ]}, + ]} + ); + }); }); describe('Layout alignContent', function() { diff --git a/src/csharp/Facebook.CSSLayout.Tests/LayoutEngineTest.cs b/src/csharp/Facebook.CSSLayout.Tests/LayoutEngineTest.cs index 3b81ed53..e787b508 100644 --- a/src/csharp/Facebook.CSSLayout.Tests/LayoutEngineTest.cs +++ b/src/csharp/Facebook.CSSLayout.Tests/LayoutEngineTest.cs @@ -8387,6 +8387,96 @@ public class LayoutEngineTest [Test] public void TestCase187() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.Row; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.dimensions[DIMENSION_WIDTH] = 100; + node_2.style.dimensions[DIMENSION_HEIGHT] = 100; + } + node_1 = node_0.getChildAt(1); + node_1.style.dimensions[DIMENSION_WIDTH] = 100; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.flexDirection = CSSFlexDirection.Column; + node_2.style.alignItems = CSSAlign.Center; + addChildren(node_2, 1); + { + TestCSSNode node_3; + node_3 = node_2.getChildAt(0); + node_3.style.dimensions[DIMENSION_WIDTH] = 50; + node_3.style.dimensions[DIMENSION_HEIGHT] = 50; + } + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.position[POSITION_TOP] = 0; + node_0.layout.position[POSITION_LEFT] = 0; + node_0.layout.dimensions[DIMENSION_WIDTH] = 200; + node_0.layout.dimensions[DIMENSION_HEIGHT] = 100; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.position[POSITION_TOP] = 0; + node_1.layout.position[POSITION_LEFT] = 0; + node_1.layout.dimensions[DIMENSION_WIDTH] = 100; + node_1.layout.dimensions[DIMENSION_HEIGHT] = 100; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.position[POSITION_TOP] = 0; + node_2.layout.position[POSITION_LEFT] = 0; + node_2.layout.dimensions[DIMENSION_WIDTH] = 100; + node_2.layout.dimensions[DIMENSION_HEIGHT] = 100; + } + node_1 = node_0.getChildAt(1); + node_1.layout.position[POSITION_TOP] = 0; + node_1.layout.position[POSITION_LEFT] = 100; + node_1.layout.dimensions[DIMENSION_WIDTH] = 100; + node_1.layout.dimensions[DIMENSION_HEIGHT] = 100; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.position[POSITION_TOP] = 0; + node_2.layout.position[POSITION_LEFT] = 0; + node_2.layout.dimensions[DIMENSION_WIDTH] = 100; + node_2.layout.dimensions[DIMENSION_HEIGHT] = 50; + addChildren(node_2, 1); + { + TestCSSNode node_3; + node_3 = node_2.getChildAt(0); + node_3.layout.position[POSITION_TOP] = 0; + node_3.layout.position[POSITION_LEFT] = 25; + node_3.layout.dimensions[DIMENSION_WIDTH] = 50; + node_3.layout.dimensions[DIMENSION_HEIGHT] = 50; + } + } + } + } + + test("should center items correctly inside a stretched layout", root_node, root_layout); + } + + [Test] + public void TestCase188() { TestCSSNode root_node = new TestCSSNode(); { diff --git a/src/java/src/com/facebook/csslayout/LayoutEngine.java b/src/java/src/com/facebook/csslayout/LayoutEngine.java index 7106580b..ea1e66c7 100644 --- a/src/java/src/com/facebook/csslayout/LayoutEngine.java +++ b/src/java/src/com/facebook/csslayout/LayoutEngine.java @@ -204,6 +204,10 @@ public class LayoutEngine { node.lastLayout.parentMaxWidth = parentMaxWidth; node.lastLayout.parentMaxHeight = parentMaxHeight; + for (int i = 0, childCount = node.getChildCount(); i < childCount; i++) { + node.getChildAt(i).layout.resetResult(); + } + layoutNodeImpl(layoutContext, node, parentMaxWidth, parentMaxHeight, parentDirection); node.lastLayout.copy(node.layout); } else { @@ -219,10 +223,6 @@ public class LayoutEngine { float parentMaxWidth, float parentMaxHeight, CSSDirection parentDirection) { - for (int i = 0, childCount = node.getChildCount(); i < childCount; i++) { - node.getChildAt(i).layout.resetResult(); - } - /** START_GENERATED **/ CSSDirection direction = resolveDirection(node, parentDirection); diff --git a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java index 66788c50..f44e7642 100644 --- a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java +++ b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java @@ -8390,6 +8390,96 @@ public class LayoutEngineTest { @Test public void testCase187() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.dimensions[DIMENSION_WIDTH] = 100; + node_2.style.dimensions[DIMENSION_HEIGHT] = 100; + } + node_1 = node_0.getChildAt(1); + node_1.style.dimensions[DIMENSION_WIDTH] = 100; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.flexDirection = CSSFlexDirection.COLUMN; + node_2.style.alignItems = CSSAlign.CENTER; + addChildren(node_2, 1); + { + TestCSSNode node_3; + node_3 = node_2.getChildAt(0); + node_3.style.dimensions[DIMENSION_WIDTH] = 50; + node_3.style.dimensions[DIMENSION_HEIGHT] = 50; + } + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.position[POSITION_TOP] = 0; + node_0.layout.position[POSITION_LEFT] = 0; + node_0.layout.dimensions[DIMENSION_WIDTH] = 200; + node_0.layout.dimensions[DIMENSION_HEIGHT] = 100; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.position[POSITION_TOP] = 0; + node_1.layout.position[POSITION_LEFT] = 0; + node_1.layout.dimensions[DIMENSION_WIDTH] = 100; + node_1.layout.dimensions[DIMENSION_HEIGHT] = 100; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.position[POSITION_TOP] = 0; + node_2.layout.position[POSITION_LEFT] = 0; + node_2.layout.dimensions[DIMENSION_WIDTH] = 100; + node_2.layout.dimensions[DIMENSION_HEIGHT] = 100; + } + node_1 = node_0.getChildAt(1); + node_1.layout.position[POSITION_TOP] = 0; + node_1.layout.position[POSITION_LEFT] = 100; + node_1.layout.dimensions[DIMENSION_WIDTH] = 100; + node_1.layout.dimensions[DIMENSION_HEIGHT] = 100; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.position[POSITION_TOP] = 0; + node_2.layout.position[POSITION_LEFT] = 0; + node_2.layout.dimensions[DIMENSION_WIDTH] = 100; + node_2.layout.dimensions[DIMENSION_HEIGHT] = 50; + addChildren(node_2, 1); + { + TestCSSNode node_3; + node_3 = node_2.getChildAt(0); + node_3.layout.position[POSITION_TOP] = 0; + node_3.layout.position[POSITION_LEFT] = 25; + node_3.layout.dimensions[DIMENSION_WIDTH] = 50; + node_3.layout.dimensions[DIMENSION_HEIGHT] = 50; + } + } + } + } + + test("should center items correctly inside a stretched layout", root_node, root_layout); + } + + @Test + public void testCase188() { TestCSSNode root_node = new TestCSSNode(); {