Absolute positioned items should apear inside padding but outside border

Summary:
Absolute positioned elements were not correctly respecting border / padding.

https://github.com/facebook/css-layout/issues/245
fixes #245

Reviewed By: gkassabli

Differential Revision: D4153332

fbshipit-source-id: 251e29e02018a433f60349b78c03feb121512797
This commit is contained in:
Emil Sjolander
2016-11-09 11:45:18 -08:00
committed by Facebook Github Bot
parent f5912a97e4
commit ff602d4606
5 changed files with 239 additions and 7 deletions

View File

@@ -1115,12 +1115,14 @@ static void absoluteLayoutChild(const CSSNodeRef node,
if (isTrailingPosDefined(child, mainAxis) && !isLeadingPosDefined(child, mainAxis)) { if (isTrailingPosDefined(child, mainAxis) && !isLeadingPosDefined(child, mainAxis)) {
child->layout.position[leading[mainAxis]] = node->layout.measuredDimensions[dim[mainAxis]] - child->layout.position[leading[mainAxis]] = node->layout.measuredDimensions[dim[mainAxis]] -
child->layout.measuredDimensions[dim[mainAxis]] - child->layout.measuredDimensions[dim[mainAxis]] -
getTrailingBorder(node, mainAxis) -
getTrailingPosition(child, mainAxis); getTrailingPosition(child, mainAxis);
} }
if (isTrailingPosDefined(child, crossAxis) && !isLeadingPosDefined(child, crossAxis)) { if (isTrailingPosDefined(child, crossAxis) && !isLeadingPosDefined(child, crossAxis)) {
child->layout.position[leading[crossAxis]] = node->layout.measuredDimensions[dim[crossAxis]] - child->layout.position[leading[crossAxis]] = node->layout.measuredDimensions[dim[crossAxis]] -
child->layout.measuredDimensions[dim[crossAxis]] - child->layout.measuredDimensions[dim[crossAxis]] -
getTrailingBorder(node, crossAxis) -
getTrailingPosition(child, crossAxis); getTrailingPosition(child, crossAxis);
} }
} }
@@ -1830,16 +1832,14 @@ static void layoutNodeImpl(const CSSNodeRef node,
getLeadingMargin(child, mainAxis); getLeadingMargin(child, mainAxis);
} }
} else { } else {
if (performLayout) {
// If the child is position absolute (without top/left) or relative,
// we put it at the current accumulated offset.
child->layout.position[pos[mainAxis]] += mainDim;
}
// Now that we placed the element, we need to update the variables. // Now that we placed the element, we need to update the variables.
// We need to do that only for relative elements. Absolute elements // We need to do that only for relative elements. Absolute elements
// do not take part in that phase. // do not take part in that phase.
if (child->style.positionType == CSSPositionTypeRelative) { if (child->style.positionType == CSSPositionTypeRelative) {
if (performLayout) {
child->layout.position[pos[mainAxis]] += mainDim;
}
if (canSkipFlex) { if (canSkipFlex) {
// If we skipped the flex step, then we can't rely on the // If we skipped the flex step, then we can't rely on the
// measuredDims because // measuredDims because
@@ -1857,6 +1857,8 @@ static void layoutNodeImpl(const CSSNodeRef node,
// can only be one element in that cross dimension. // can only be one element in that cross dimension.
crossDim = fmaxf(crossDim, getDimWithMargin(child, crossAxis)); crossDim = fmaxf(crossDim, getDimWithMargin(child, crossAxis));
} }
} else if (performLayout) {
child->layout.position[pos[mainAxis]] += getLeadingBorder(node, mainAxis) + leadingMainDim;
} }
} }
} }
@@ -1901,7 +1903,7 @@ static void layoutNodeImpl(const CSSNodeRef node,
getLeadingMargin(child, crossAxis); getLeadingMargin(child, crossAxis);
} else { } else {
child->layout.position[pos[crossAxis]] = child->layout.position[pos[crossAxis]] =
leadingPaddingAndBorderCross + getLeadingMargin(child, crossAxis); getLeadingBorder(node, crossAxis) + getLeadingMargin(child, crossAxis);
} }
} else { } else {
float leadingCrossDim = leadingPaddingAndBorderCross; float leadingCrossDim = leadingPaddingAndBorderCross;

View File

@@ -31,6 +31,11 @@
<div style="width: 100px; height: 100px;"></div> <div style="width: 100px; height: 100px;"></div>
</div> </div>
</div> </div>
<div id="absolute_layout_within_border" style="height:100px; width:100px; border-width: 10px; margin: 10px; padding: 10px;">
<div style="position: absolute; width: 50px; height: 50px; left: 0px; top: 0px;"></div>
<div style="position: absolute; width: 50px; height: 50px; right: 0px; bottom: 0px;"></div>
</div>
* *
*/ */
@@ -264,5 +269,76 @@ namespace Facebook.CSSLayout
Assert.AreEqual(100, root_child0_child0.LayoutHeight); Assert.AreEqual(100, root_child0_child0.LayoutHeight);
} }
[Test]
public void Test_absolute_layout_within_border()
{
CSSNode root = new CSSNode();
root.SetMargin(CSSEdge.Left, 10);
root.SetMargin(CSSEdge.Top, 10);
root.SetMargin(CSSEdge.Right, 10);
root.SetMargin(CSSEdge.Bottom, 10);
root.SetPadding(CSSEdge.Left, 10);
root.SetPadding(CSSEdge.Top, 10);
root.SetPadding(CSSEdge.Right, 10);
root.SetPadding(CSSEdge.Bottom, 10);
root.SetBorder(CSSEdge.Left, 10);
root.SetBorder(CSSEdge.Top, 10);
root.SetBorder(CSSEdge.Right, 10);
root.SetBorder(CSSEdge.Bottom, 10);
root.StyleWidth = 100;
root.StyleHeight = 100;
CSSNode root_child0 = new CSSNode();
root_child0.PositionType = CSSPositionType.Absolute;
root_child0.SetPosition(CSSEdge.Left, 0);
root_child0.SetPosition(CSSEdge.Top, 0);
root_child0.StyleWidth = 50;
root_child0.StyleHeight = 50;
root.Insert(0, root_child0);
CSSNode root_child1 = new CSSNode();
root_child1.PositionType = CSSPositionType.Absolute;
root_child1.SetPosition(CSSEdge.Right, 0);
root_child1.SetPosition(CSSEdge.Bottom, 0);
root_child1.StyleWidth = 50;
root_child1.StyleHeight = 50;
root.Insert(1, root_child1);
root.StyleDirection = CSSDirection.LeftToRight;
root.CalculateLayout();
Assert.AreEqual(10, root.LayoutX);
Assert.AreEqual(10, root.LayoutY);
Assert.AreEqual(100, root.LayoutWidth);
Assert.AreEqual(100, root.LayoutHeight);
Assert.AreEqual(10, root_child0.LayoutX);
Assert.AreEqual(10, root_child0.LayoutY);
Assert.AreEqual(50, root_child0.LayoutWidth);
Assert.AreEqual(50, root_child0.LayoutHeight);
Assert.AreEqual(40, root_child1.LayoutX);
Assert.AreEqual(40, root_child1.LayoutY);
Assert.AreEqual(50, root_child1.LayoutWidth);
Assert.AreEqual(50, root_child1.LayoutHeight);
root.StyleDirection = CSSDirection.RightToLeft;
root.CalculateLayout();
Assert.AreEqual(10, root.LayoutX);
Assert.AreEqual(10, root.LayoutY);
Assert.AreEqual(100, root.LayoutWidth);
Assert.AreEqual(100, root.LayoutHeight);
Assert.AreEqual(10, root_child0.LayoutX);
Assert.AreEqual(10, root_child0.LayoutY);
Assert.AreEqual(50, root_child0.LayoutWidth);
Assert.AreEqual(50, root_child0.LayoutHeight);
Assert.AreEqual(40, root_child1.LayoutX);
Assert.AreEqual(40, root_child1.LayoutY);
Assert.AreEqual(50, root_child1.LayoutWidth);
Assert.AreEqual(50, root_child1.LayoutHeight);
}
} }
} }

View File

@@ -19,3 +19,8 @@
<div style="width: 100px; height: 100px;"></div> <div style="width: 100px; height: 100px;"></div>
</div> </div>
</div> </div>
<div id="absolute_layout_within_border" style="height:100px; width:100px; border-width: 10px; margin: 10px; padding: 10px;">
<div style="position: absolute; width: 50px; height: 50px; left: 0px; top: 0px;"></div>
<div style="position: absolute; width: 50px; height: 50px; right: 0px; bottom: 0px;"></div>
</div>

View File

@@ -31,6 +31,11 @@
<div style="width: 100px; height: 100px;"></div> <div style="width: 100px; height: 100px;"></div>
</div> </div>
</div> </div>
<div id="absolute_layout_within_border" style="height:100px; width:100px; border-width: 10px; margin: 10px; padding: 10px;">
<div style="position: absolute; width: 50px; height: 50px; left: 0px; top: 0px;"></div>
<div style="position: absolute; width: 50px; height: 50px; right: 0px; bottom: 0px;"></div>
</div>
* *
*/ */
@@ -258,4 +263,74 @@ public class CSSLayoutAbsolutePositionTest {
assertEquals(100, root_child0_child0.getLayoutHeight(), 0.0f); assertEquals(100, root_child0_child0.getLayoutHeight(), 0.0f);
} }
@Test
public void test_absolute_layout_within_border() {
final CSSNode root = new CSSNode();
root.setMargin(Spacing.LEFT, 10);
root.setMargin(Spacing.TOP, 10);
root.setMargin(Spacing.RIGHT, 10);
root.setMargin(Spacing.BOTTOM, 10);
root.setPadding(Spacing.LEFT, 10);
root.setPadding(Spacing.TOP, 10);
root.setPadding(Spacing.RIGHT, 10);
root.setPadding(Spacing.BOTTOM, 10);
root.setBorder(Spacing.LEFT, 10);
root.setBorder(Spacing.TOP, 10);
root.setBorder(Spacing.RIGHT, 10);
root.setBorder(Spacing.BOTTOM, 10);
root.setStyleWidth(100);
root.setStyleHeight(100);
final CSSNode root_child0 = new CSSNode();
root_child0.setPositionType(CSSPositionType.ABSOLUTE);
root_child0.setPosition(Spacing.LEFT, 0);
root_child0.setPosition(Spacing.TOP, 0);
root_child0.setStyleWidth(50);
root_child0.setStyleHeight(50);
root.addChildAt(root_child0, 0);
final CSSNode root_child1 = new CSSNode();
root_child1.setPositionType(CSSPositionType.ABSOLUTE);
root_child1.setPosition(Spacing.RIGHT, 0);
root_child1.setPosition(Spacing.BOTTOM, 0);
root_child1.setStyleWidth(50);
root_child1.setStyleHeight(50);
root.addChildAt(root_child1, 1);
root.setDirection(CSSDirection.LTR);
root.calculateLayout(null);
assertEquals(10, root.getLayoutX(), 0.0f);
assertEquals(10, root.getLayoutY(), 0.0f);
assertEquals(100, root.getLayoutWidth(), 0.0f);
assertEquals(100, root.getLayoutHeight(), 0.0f);
assertEquals(10, root_child0.getLayoutX(), 0.0f);
assertEquals(10, root_child0.getLayoutY(), 0.0f);
assertEquals(50, root_child0.getLayoutWidth(), 0.0f);
assertEquals(50, root_child0.getLayoutHeight(), 0.0f);
assertEquals(40, root_child1.getLayoutX(), 0.0f);
assertEquals(40, root_child1.getLayoutY(), 0.0f);
assertEquals(50, root_child1.getLayoutWidth(), 0.0f);
assertEquals(50, root_child1.getLayoutHeight(), 0.0f);
root.setDirection(CSSDirection.RTL);
root.calculateLayout(null);
assertEquals(10, root.getLayoutX(), 0.0f);
assertEquals(10, root.getLayoutY(), 0.0f);
assertEquals(100, root.getLayoutWidth(), 0.0f);
assertEquals(100, root.getLayoutHeight(), 0.0f);
assertEquals(10, root_child0.getLayoutX(), 0.0f);
assertEquals(10, root_child0.getLayoutY(), 0.0f);
assertEquals(50, root_child0.getLayoutWidth(), 0.0f);
assertEquals(50, root_child0.getLayoutHeight(), 0.0f);
assertEquals(40, root_child1.getLayoutX(), 0.0f);
assertEquals(40, root_child1.getLayoutY(), 0.0f);
assertEquals(50, root_child1.getLayoutWidth(), 0.0f);
assertEquals(50, root_child1.getLayoutHeight(), 0.0f);
}
} }

View File

@@ -31,6 +31,11 @@
<div style="width: 100px; height: 100px;"></div> <div style="width: 100px; height: 100px;"></div>
</div> </div>
</div> </div>
<div id="absolute_layout_within_border" style="height:100px; width:100px; border-width: 10px; margin: 10px; padding: 10px;">
<div style="position: absolute; width: 50px; height: 50px; left: 0px; top: 0px;"></div>
<div style="position: absolute; width: 50px; height: 50px; right: 0px; bottom: 0px;"></div>
</div>
* *
*/ */
@@ -248,3 +253,72 @@ TEST(CSSLayoutTest, do_not_clamp_height_of_absolute_node_to_height_of_its_overfl
CSSNodeFreeRecursive(root); CSSNodeFreeRecursive(root);
} }
TEST(CSSLayoutTest, absolute_layout_within_border) {
const CSSNodeRef root = CSSNodeNew();
CSSNodeStyleSetMargin(root, CSSEdgeLeft, 10);
CSSNodeStyleSetMargin(root, CSSEdgeTop, 10);
CSSNodeStyleSetMargin(root, CSSEdgeRight, 10);
CSSNodeStyleSetMargin(root, CSSEdgeBottom, 10);
CSSNodeStyleSetPadding(root, CSSEdgeLeft, 10);
CSSNodeStyleSetPadding(root, CSSEdgeTop, 10);
CSSNodeStyleSetPadding(root, CSSEdgeRight, 10);
CSSNodeStyleSetPadding(root, CSSEdgeBottom, 10);
CSSNodeStyleSetBorder(root, CSSEdgeLeft, 10);
CSSNodeStyleSetBorder(root, CSSEdgeTop, 10);
CSSNodeStyleSetBorder(root, CSSEdgeRight, 10);
CSSNodeStyleSetBorder(root, CSSEdgeBottom, 10);
CSSNodeStyleSetWidth(root, 100);
CSSNodeStyleSetHeight(root, 100);
const CSSNodeRef root_child0 = CSSNodeNew();
CSSNodeStyleSetPositionType(root_child0, CSSPositionTypeAbsolute);
CSSNodeStyleSetPosition(root_child0, CSSEdgeLeft, 0);
CSSNodeStyleSetPosition(root_child0, CSSEdgeTop, 0);
CSSNodeStyleSetWidth(root_child0, 50);
CSSNodeStyleSetHeight(root_child0, 50);
CSSNodeInsertChild(root, root_child0, 0);
const CSSNodeRef root_child1 = CSSNodeNew();
CSSNodeStyleSetPositionType(root_child1, CSSPositionTypeAbsolute);
CSSNodeStyleSetPosition(root_child1, CSSEdgeRight, 0);
CSSNodeStyleSetPosition(root_child1, CSSEdgeBottom, 0);
CSSNodeStyleSetWidth(root_child1, 50);
CSSNodeStyleSetHeight(root_child1, 50);
CSSNodeInsertChild(root, root_child1, 1);
CSSNodeCalculateLayout(root, CSSUndefined, CSSUndefined, CSSDirectionLTR);
ASSERT_EQ(10, CSSNodeLayoutGetLeft(root));
ASSERT_EQ(10, CSSNodeLayoutGetTop(root));
ASSERT_EQ(100, CSSNodeLayoutGetWidth(root));
ASSERT_EQ(100, CSSNodeLayoutGetHeight(root));
ASSERT_EQ(10, CSSNodeLayoutGetLeft(root_child0));
ASSERT_EQ(10, CSSNodeLayoutGetTop(root_child0));
ASSERT_EQ(50, CSSNodeLayoutGetWidth(root_child0));
ASSERT_EQ(50, CSSNodeLayoutGetHeight(root_child0));
ASSERT_EQ(40, CSSNodeLayoutGetLeft(root_child1));
ASSERT_EQ(40, CSSNodeLayoutGetTop(root_child1));
ASSERT_EQ(50, CSSNodeLayoutGetWidth(root_child1));
ASSERT_EQ(50, CSSNodeLayoutGetHeight(root_child1));
CSSNodeCalculateLayout(root, CSSUndefined, CSSUndefined, CSSDirectionRTL);
ASSERT_EQ(10, CSSNodeLayoutGetLeft(root));
ASSERT_EQ(10, CSSNodeLayoutGetTop(root));
ASSERT_EQ(100, CSSNodeLayoutGetWidth(root));
ASSERT_EQ(100, CSSNodeLayoutGetHeight(root));
ASSERT_EQ(10, CSSNodeLayoutGetLeft(root_child0));
ASSERT_EQ(10, CSSNodeLayoutGetTop(root_child0));
ASSERT_EQ(50, CSSNodeLayoutGetWidth(root_child0));
ASSERT_EQ(50, CSSNodeLayoutGetHeight(root_child0));
ASSERT_EQ(40, CSSNodeLayoutGetLeft(root_child1));
ASSERT_EQ(40, CSSNodeLayoutGetTop(root_child1));
ASSERT_EQ(50, CSSNodeLayoutGetWidth(root_child1));
ASSERT_EQ(50, CSSNodeLayoutGetHeight(root_child1));
CSSNodeFreeRecursive(root);
}