From 5f52e947cb6538a4313eefab225fcbdee48a66c2 Mon Sep 17 00:00:00 2001 From: Andrew Rasmussen Date: Thu, 30 Apr 2015 14:35:59 -0700 Subject: [PATCH] Fix layout for absolutely positioned nodes with absolutely positioned parents that have border and/or padding --- src/Layout.c | 6 +- src/Layout.js | 6 +- src/__tests__/Layout-test.c | 128 +++++++++++++++++ src/__tests__/Layout-test.js | 45 ++++++ .../com/facebook/csslayout/LayoutEngine.java | 6 +- .../facebook/csslayout/LayoutEngineTest.java | 132 ++++++++++++++++++ 6 files changed, 320 insertions(+), 3 deletions(-) diff --git a/src/Layout.c b/src/Layout.c index 5fbbd594..ffb376cd 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -244,6 +244,10 @@ static float getPaddingAndBorder(css_node_t *node, int location) { return getPadding(node, location) + getBorder(node, location); } +static float getBorderAxis(css_node_t *node, css_flex_direction_t axis) { + return getBorder(node, leading[axis]) + getBorder(node, trailing[axis]); +} + static float getMarginAxis(css_node_t *node, css_flex_direction_t axis) { return getMargin(node, leading[axis]) + getMargin(node, trailing[axis]); } @@ -812,7 +816,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { isPosDefined(child, trailing[axis])) { child->layout.dimensions[dim[axis]] = fmaxf( boundAxis(child, axis, node->layout.dimensions[dim[axis]] - - getPaddingAndBorderAxis(node, axis) - + getBorderAxis(node, axis) - getMarginAxis(child, axis) - getPosition(child, leading[axis]) - getPosition(child, trailing[axis]) diff --git a/src/Layout.js b/src/Layout.js index 652dc891..34505c1e 100755 --- a/src/Layout.js +++ b/src/Layout.js @@ -125,6 +125,10 @@ var computeLayout = (function() { return getPadding(node, location) + getBorder(node, location); } + function getBorderAxis(node, axis) { + return getBorder(node, leading[axis]) + getBorder(node, trailing[axis]); + } + function getMarginAxis(node, axis) { return getMargin(node, leading[axis]) + getMargin(node, trailing[axis]); } @@ -703,7 +707,7 @@ var computeLayout = (function() { isPosDefined(child, trailing[axis])) { child.layout[dim[axis]] = fmaxf( boundAxis(child, axis, node.layout[dim[axis]] - - getPaddingAndBorderAxis(node, axis) - + getBorderAxis(node, axis) - getMarginAxis(child, axis) - getPosition(child, leading[axis]) - getPosition(child, trailing[axis]) diff --git a/src/__tests__/Layout-test.c b/src/__tests__/Layout-test.c index 667c0586..7f860c75 100644 --- a/src/__tests__/Layout-test.c +++ b/src/__tests__/Layout-test.c @@ -4754,6 +4754,134 @@ int main() test("should layout minHeight without a flex child", 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] = 400; + node_0->style.dimensions[CSS_HEIGHT] = 400; + 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.padding[CSS_LEFT] = 10; + node_1->style.padding[CSS_TOP] = 10; + node_1->style.padding[CSS_RIGHT] = 10; + node_1->style.padding[CSS_BOTTOM] = 10; + 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; + 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.position_type = CSS_POSITION_ABSOLUTE; + node_2->style.position[CSS_LEFT] = 10; + node_2->style.position[CSS_TOP] = 10; + node_2->style.position[CSS_RIGHT] = 10; + node_2->style.position[CSS_BOTTOM] = 10; + } + } + } + + 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] = 400; + node_0->layout.dimensions[CSS_HEIGHT] = 400; + 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] = 200; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + 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] = 10; + node_2->layout.position[CSS_LEFT] = 10; + node_2->layout.dimensions[CSS_WIDTH] = 180; + node_2->layout.dimensions[CSS_HEIGHT] = 180; + } + } + } + + test("should layout absolutely positioned node with absolutely positioned padded parent", 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] = 400; + node_0->style.dimensions[CSS_HEIGHT] = 400; + 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.padding[CSS_LEFT] = 10; + node_1->style.padding[CSS_TOP] = 10; + node_1->style.padding[CSS_RIGHT] = 10; + node_1->style.padding[CSS_BOTTOM] = 10; + node_1->style.border[CSS_LEFT] = 1; + node_1->style.border[CSS_TOP] = 1; + node_1->style.border[CSS_RIGHT] = 1; + node_1->style.border[CSS_BOTTOM] = 1; + 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; + 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.position_type = CSS_POSITION_ABSOLUTE; + node_2->style.position[CSS_LEFT] = 10; + node_2->style.position[CSS_TOP] = 10; + node_2->style.position[CSS_RIGHT] = 10; + node_2->style.position[CSS_BOTTOM] = 10; + } + } + } + + 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] = 400; + node_0->layout.dimensions[CSS_HEIGHT] = 400; + 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] = 200; + node_1->layout.dimensions[CSS_HEIGHT] = 200; + 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] = 11; + node_2->layout.position[CSS_LEFT] = 11; + node_2->layout.dimensions[CSS_WIDTH] = 178; + node_2->layout.dimensions[CSS_HEIGHT] = 178; + } + } + } + + test("should layout absolutely positioned node with absolutely positioned padded and bordered parent", root_node, root_layout); + } /** END_GENERATED **/ return tests_finished(); } diff --git a/src/__tests__/Layout-test.js b/src/__tests__/Layout-test.js index a86550bb..a44044dc 100755 --- a/src/__tests__/Layout-test.js +++ b/src/__tests__/Layout-test.js @@ -1552,5 +1552,50 @@ describe('Layout', function() { ); }); + it('should layout absolutely positioned node with absolutely positioned padded parent', function() { + testLayout( + {style: {width: 400, height: 400}, children: [ + {style: {position: 'absolute', top: 100, left: 100, right: 100, bottom: 100, padding: 10}, children: [ + {style: {position: 'absolute', top: 10, left: 10, right: 10, bottom: 10}} + ]}, + ]}, + {width: 400, height: 400, top: 0, left: 0, children: [ + {width: 200, height: 200, top: 100, left: 100, children: [ + {width: 180, height: 180, top: 10, left: 10} + ]} + ]} + ); + }); + + it('should layout absolutely positioned node with absolutely positioned padded and bordered parent', function() { + testLayout( + {style: {width: 400, height: 400}, children: [ + {style: {position: 'absolute', top: 100, left: 100, right: 100, bottom: 100, padding: 10, borderWidth: 1}, children: [ + {style: {position: 'absolute', top: 10, left: 10, right: 10, bottom: 10}} + ]}, + ]}, + {width: 400, height: 400, top: 0, left: 0, children: [ + {width: 200, height: 200, top: 100, left: 100, children: [ + {width: 178, height: 178, top: 11, left: 11} + ]} + ]} + ); + }); + + it('should layout absolutely positioned node with padded flex 1 parent', function() { + testLayout( + {style: {width: 400, height: 400}, children: [ + {style: {flex: 1, padding: 10}, children: [ + {style: {position: 'absolute', top: 10, left: 10, right: 10, bottom: 10}} + ]}, + ]}, + {width: 400, height: 400, top: 0, left: 0, children: [ + {width: 400, height: 400, top: 0, left: 0, children: [ + {width: 380, height: 380, top: 10, left: 10} + ]} + ]} + ); + }); + }); diff --git a/src/java/src/com/facebook/csslayout/LayoutEngine.java b/src/java/src/com/facebook/csslayout/LayoutEngine.java index 2518bb00..623d024a 100644 --- a/src/java/src/com/facebook/csslayout/LayoutEngine.java +++ b/src/java/src/com/facebook/csslayout/LayoutEngine.java @@ -178,6 +178,10 @@ public class LayoutEngine { return getPadding(node, position) + getBorder(node, position); } + private static float getBorderAxis(CSSNode node, CSSFlexDirection axis) { + return getBorder(node, getLeading(axis)) + getBorder(node, getTrailing(axis)); + } + private static float getMarginAxis(CSSNode node, CSSFlexDirection axis) { return getMargin(node, getLeading(axis)) + getMargin(node, getTrailing(axis)); } @@ -757,7 +761,7 @@ public class LayoutEngine { isPosDefined(child, getTrailing(axis))) { setLayoutDimension(child, getDim(axis), Math.max( boundAxis(child, axis, getLayoutDimension(node, getDim(axis)) - - getPaddingAndBorderAxis(node, axis) - + getBorderAxis(node, axis) - getMarginAxis(child, axis) - getPosition(child, getLeading(axis)) - getPosition(child, getTrailing(axis)) diff --git a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java index cc2f6917..52ba50b2 100644 --- a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java +++ b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java @@ -5073,5 +5073,137 @@ public class LayoutEngineTest { test("should layout minHeight without a flex child", root_node, root_layout); } + + @Test + public void testCase122() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 400; + node_0.style.height = 400; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.padding[Spacing.LEFT] = 10; + node_1.style.padding[Spacing.TOP] = 10; + node_1.style.padding[Spacing.RIGHT] = 10; + node_1.style.padding[Spacing.BOTTOM] = 10; + node_1.style.positionLeft = 100; + node_1.style.positionTop = 100; + node_1.style.positionRight = 100; + node_1.style.positionBottom = 100; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.positionType = CSSPositionType.ABSOLUTE; + node_2.style.positionLeft = 10; + node_2.style.positionTop = 10; + node_2.style.positionRight = 10; + node_2.style.positionBottom = 10; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 400; + node_0.layout.height = 400; + 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 = 200; + node_1.layout.height = 200; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 10; + node_2.layout.x = 10; + node_2.layout.width = 180; + node_2.layout.height = 180; + } + } + } + + test("should layout absolutely positioned node with absolutely positioned padded parent", root_node, root_layout); + } + + @Test + public void testCase123() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 400; + node_0.style.height = 400; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.padding[Spacing.LEFT] = 10; + node_1.style.padding[Spacing.TOP] = 10; + node_1.style.padding[Spacing.RIGHT] = 10; + node_1.style.padding[Spacing.BOTTOM] = 10; + node_1.style.border[Spacing.LEFT] = 1; + node_1.style.border[Spacing.TOP] = 1; + node_1.style.border[Spacing.RIGHT] = 1; + node_1.style.border[Spacing.BOTTOM] = 1; + node_1.style.positionLeft = 100; + node_1.style.positionTop = 100; + node_1.style.positionRight = 100; + node_1.style.positionBottom = 100; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.positionType = CSSPositionType.ABSOLUTE; + node_2.style.positionLeft = 10; + node_2.style.positionTop = 10; + node_2.style.positionRight = 10; + node_2.style.positionBottom = 10; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 400; + node_0.layout.height = 400; + 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 = 200; + node_1.layout.height = 200; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 11; + node_2.layout.x = 11; + node_2.layout.width = 178; + node_2.layout.height = 178; + } + } + } + + test("should layout absolutely positioned node with absolutely positioned padded and bordered parent", root_node, root_layout); + } /** END_GENERATED **/ }