[LFC] Use the containing block's padding box to position out-of-flow elements.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 15 Jan 2019 14:48:54 +0000 (14:48 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 15 Jan 2019 14:48:54 +0000 (14:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=193431

Reviewed by Antti Koivisto.

Source/WebCore:

If the element has 'position: absolute', the containing block is established by the nearest ancestor
with a 'position' of 'absolute', 'relative' or 'fixed', in the following way:

1. In the case that the ancestor is an inline element, the containing block is the bounding box around the padding
boxes of the first and the last inline boxes generated for that element. In CSS 2.2, if the inline element is split
across multiple lines, the containing block is undefined.

2. Otherwise, the containing block is formed by the padding edge of the ancestor.

This patch covers #2.

Test: fast/block/block-only/out-of-flow-with-containing-block-border-padding.html

* layout/displaytree/DisplayBox.h:
(WebCore::Display::Box::width const):
(WebCore::Display::Box::height const):
(WebCore::Display::Box::contentBoxTop const):
(WebCore::Display::Box::contentBoxLeft const):
(WebCore::Display::Box::paddingBoxTop const):
(WebCore::Display::Box::paddingBoxLeft const):
(WebCore::Display::Box::paddingBoxBottom const):
(WebCore::Display::Box::paddingBoxRight const):
(WebCore::Display::Box::paddingBoxHeight const):
(WebCore::Display::Box::paddingBoxWidth const):
* page/FrameViewLayoutContext.cpp:
(WebCore::layoutUsingFormattingContext):

Tools:

* LayoutReloaded/misc/LFC-passing-tests.txt:

LayoutTests:

* fast/block/block-only/out-of-flow-with-containing-block-border-padding-expected.txt: Added.
* fast/block/block-only/out-of-flow-with-containing-block-border-padding.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@239983 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/block/block-only/out-of-flow-with-containing-block-border-padding-expected.txt [new file with mode: 0644]
LayoutTests/fast/block/block-only/out-of-flow-with-containing-block-border-padding.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/layout/FormattingContextGeometry.cpp
Source/WebCore/layout/displaytree/DisplayBox.h
Tools/ChangeLog
Tools/LayoutReloaded/misc/LFC-passing-tests.txt

index cabc101..400c6bd 100644 (file)
@@ -1,3 +1,13 @@
+2019-01-15  Zalan Bujtas  <zalan@apple.com>
+
+        [LFC] Use the containing block's padding box to position out-of-flow elements.
+        https://bugs.webkit.org/show_bug.cgi?id=193431
+
+        Reviewed by Antti Koivisto.
+
+        * fast/block/block-only/out-of-flow-with-containing-block-border-padding-expected.txt: Added.
+        * fast/block/block-only/out-of-flow-with-containing-block-border-padding.html: Added.
+
 2019-01-15  Guillaume Emont  <guijemont@igalia.com>
 
         Skip a slow test and a flakey test on arm
diff --git a/LayoutTests/fast/block/block-only/out-of-flow-with-containing-block-border-padding-expected.txt b/LayoutTests/fast/block/block-only/out-of-flow-with-containing-block-border-padding-expected.txt
new file mode 100644 (file)
index 0000000..cf325a4
--- /dev/null
@@ -0,0 +1,33 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+layer at (8,8) size 56x56
+  RenderBlock (relative positioned) {DIV} at (0,0) size 56x56 [border: (3px solid #008000)]
+layer at (21,13) size 10x10
+  RenderBlock (positioned) {DIV} at (13,5) size 10x10 [bgcolor=#0000FF]
+layer at (8,64) size 56x56
+  RenderBlock (relative positioned) {DIV} at (0,56) size 56x56 [border: (3px solid #008000)]
+layer at (21,105) size 10x10
+  RenderBlock (positioned) {DIV} at (13,41) size 10x10 [bgcolor=#0000FF]
+layer at (8,120) size 56x56
+  RenderBlock (relative positioned) {DIV} at (0,112) size 56x56 [border: (3px solid #008000)]
+layer at (21,125) size 10x46
+  RenderBlock (positioned) {DIV} at (13,5) size 10x46 [bgcolor=#0000FF]
+layer at (8,176) size 56x56
+  RenderBlock (relative positioned) {DIV} at (0,168) size 56x56 [border: (3px solid #008000)]
+layer at (13,189) size 10x10
+  RenderBlock (positioned) {DIV} at (5,13) size 10x10 [bgcolor=#0000FF]
+layer at (8,232) size 56x56
+  RenderBlock (relative positioned) {DIV} at (0,224) size 56x56 [border: (3px solid #008000)]
+layer at (49,245) size 10x10
+  RenderBlock (positioned) {DIV} at (41,13) size 10x10 [bgcolor=#0000FF]
+layer at (8,288) size 56x56
+  RenderBlock (relative positioned) {DIV} at (0,280) size 56x56 [border: (3px solid #008000)]
+layer at (13,301) size 46x10
+  RenderBlock (positioned) {DIV} at (5,13) size 46x10 [bgcolor=#0000FF]
+layer at (8,344) size 56x56
+  RenderBlock (relative positioned) {DIV} at (0,336) size 56x56 [border: (3px solid #008000)]
+layer at (13,349) size 46x46
+  RenderBlock (positioned) {DIV} at (5,5) size 46x46 [bgcolor=#0000FF]
diff --git a/LayoutTests/fast/block/block-only/out-of-flow-with-containing-block-border-padding.html b/LayoutTests/fast/block/block-only/out-of-flow-with-containing-block-border-padding.html
new file mode 100644 (file)
index 0000000..f65db93
--- /dev/null
@@ -0,0 +1,35 @@
+<style>
+.container {
+       border: 3px solid green;
+       padding: 10px;
+    height: 30px;
+    width: 30px;
+    position: relative;
+}
+
+div div {
+       background: blue;
+    position: absolute;
+}
+</style>
+<div class=container>
+    <div style="top: 2px; width: 10px; height: 10px"></div>
+</div>
+<div class=container>
+    <div style="bottom: 2px; width: 10px; height: 10px"></div>
+</div>
+<div class=container>
+    <div style="top: 2px; bottom: 2px; width: 10px;"></div>
+</div>
+<div class=container>
+    <div style="left: 2px; width: 10px; height: 10px"></div>
+</div>
+<div class=container>
+    <div style="right: 2px; width: 10px; height: 10px"></div>
+</div>
+<div class=container>
+    <div style="left: 2px; right: 2px; height: 10px;"></div>
+</div>
+<div class=container>
+    <div style="top: 2px; left: 2px; right: 2px; bottom: 2px;"></div>
+</div>
index 7df1688..c3f185d 100644 (file)
@@ -1,3 +1,37 @@
+2019-01-15  Zalan Bujtas  <zalan@apple.com>
+
+        [LFC] Use the containing block's padding box to position out-of-flow elements.
+        https://bugs.webkit.org/show_bug.cgi?id=193431
+
+        Reviewed by Antti Koivisto.
+
+        If the element has 'position: absolute', the containing block is established by the nearest ancestor
+        with a 'position' of 'absolute', 'relative' or 'fixed', in the following way:
+
+        1. In the case that the ancestor is an inline element, the containing block is the bounding box around the padding
+        boxes of the first and the last inline boxes generated for that element. In CSS 2.2, if the inline element is split
+        across multiple lines, the containing block is undefined.
+
+        2. Otherwise, the containing block is formed by the padding edge of the ancestor.
+
+        This patch covers #2. 
+
+        Test: fast/block/block-only/out-of-flow-with-containing-block-border-padding.html
+
+        * layout/displaytree/DisplayBox.h:
+        (WebCore::Display::Box::width const):
+        (WebCore::Display::Box::height const):
+        (WebCore::Display::Box::contentBoxTop const):
+        (WebCore::Display::Box::contentBoxLeft const):
+        (WebCore::Display::Box::paddingBoxTop const):
+        (WebCore::Display::Box::paddingBoxLeft const):
+        (WebCore::Display::Box::paddingBoxBottom const):
+        (WebCore::Display::Box::paddingBoxRight const):
+        (WebCore::Display::Box::paddingBoxHeight const):
+        (WebCore::Display::Box::paddingBoxWidth const):
+        * page/FrameViewLayoutContext.cpp:
+        (WebCore::layoutUsingFormattingContext):
+
 2019-01-11  Antoine Quint  <graouts@apple.com>
 
         Support parsing of additional values for the touch-action property
index 6643c14..cc38f18 100644 (file)
@@ -273,11 +273,12 @@ VerticalGeometry FormattingContext::Geometry::outOfFlowNonReplacedVerticalGeomet
     auto& style = layoutBox.style();
     auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox);
     auto& containingBlockDisplayBox = layoutState.displayBoxForLayoutBox(*layoutBox.containingBlock());
-    auto containingBlockHeight = containingBlockDisplayBox.height();
-    auto containingBlockWidth = containingBlockDisplayBox.width();
+    auto containingBlockHeight = containingBlockDisplayBox.paddingBoxHeight();
+    auto containingBlockWidth = containingBlockDisplayBox.paddingBoxWidth();
 
     auto top = computedValueIfNotAuto(style.logicalTop(), containingBlockWidth);
     auto bottom = computedValueIfNotAuto(style.logicalBottom(), containingBlockWidth);
+    auto isStaticallyPositioned = !top && !bottom;
     auto height = usedHeight ? usedHeight.value() : computedHeightValue(layoutState, layoutBox, HeightType::Normal);
     auto computedVerticalMargin = Geometry::computedVerticalMargin(layoutState, layoutBox);
     UsedVerticalMargin::NonCollapsedValues usedVerticalMargin; 
@@ -353,6 +354,14 @@ VerticalGeometry FormattingContext::Geometry::outOfFlowNonReplacedVerticalGeomet
     ASSERT(bottom);
     ASSERT(height);
 
+    // For out-of-flow elements the containing block is formed by the padding edge of the ancestor.
+    // At this point the non-statically positioned value is in the coordinate system of the padding box. Let's convert it to border box coordinate system.
+    if (!isStaticallyPositioned) {
+        auto containingBlockPaddingVerticalEdge = containingBlockDisplayBox.paddingBoxTop();
+        *top += containingBlockPaddingVerticalEdge;
+        *bottom += containingBlockPaddingVerticalEdge;
+    }
+
     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Position][Height][Margin] -> out-of-flow non-replaced -> top(" << *top << "px) bottom("  << *bottom << "px) height(" << *height << "px) margin(" << usedVerticalMargin.before << "px, "  << usedVerticalMargin.after << "px) layoutBox(" << &layoutBox << ")");
     return { *top, *bottom, { contentHeight(), usedVerticalMargin } };
 }
@@ -390,11 +399,13 @@ HorizontalGeometry FormattingContext::Geometry::outOfFlowNonReplacedHorizontalGe
     auto& style = layoutBox.style();
     auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox);
     auto& containingBlock = *layoutBox.containingBlock();
-    auto containingBlockWidth = layoutState.displayBoxForLayoutBox(containingBlock).contentBoxWidth();
+    auto& containingBlockDisplayBox = layoutState.displayBoxForLayoutBox(containingBlock);
+    auto containingBlockWidth = containingBlockDisplayBox.paddingBoxWidth();
     auto isLeftToRightDirection = containingBlock.style().isLeftToRightDirection();
     
     auto left = computedValueIfNotAuto(style.logicalLeft(), containingBlockWidth);
     auto right = computedValueIfNotAuto(style.logicalRight(), containingBlockWidth);
+    auto isStaticallyPositioned = !left && !right;
     auto width = computedValueIfNotAuto(usedWidth ? Length { usedWidth.value(), Fixed } : style.logicalWidth(), containingBlockWidth);
     auto computedHorizontalMargin = Geometry::computedHorizontalMargin(layoutState, layoutBox);
     UsedHorizontalMargin usedHorizontalMargin;
@@ -496,6 +507,14 @@ HorizontalGeometry FormattingContext::Geometry::outOfFlowNonReplacedHorizontalGe
     ASSERT(right);
     ASSERT(width);
 
+    // For out-of-flow elements the containing block is formed by the padding edge of the ancestor.
+    // At this point the non-statically positioned value is in the coordinate system of the padding box. Let's convert it to border box coordinate system.
+    if (!isStaticallyPositioned) {
+        auto containingBlockPaddingVerticalEdge = containingBlockDisplayBox.paddingBoxLeft();
+        *left += containingBlockPaddingVerticalEdge;
+        *right += containingBlockPaddingVerticalEdge;
+    }
+
     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Position][Width][Margin] -> out-of-flow non-replaced -> left(" << *left << "px) right("  << *right << "px) width(" << *width << "px) margin(" << usedHorizontalMargin.start << "px, "  << usedHorizontalMargin.end << "px) layoutBox(" << &layoutBox << ")");
     return { *left, *right, { contentWidth(), usedHorizontalMargin, computedHorizontalMargin } };
 }
@@ -517,11 +536,12 @@ VerticalGeometry FormattingContext::Geometry::outOfFlowReplacedVerticalGeometry(
     auto& style = layoutBox.style();
     auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox);
     auto& containingBlockDisplayBox = layoutState.displayBoxForLayoutBox(*layoutBox.containingBlock());
-    auto containingBlockHeight = containingBlockDisplayBox.height();
-    auto containingBlockWidth = containingBlockDisplayBox.width();
+    auto containingBlockHeight = containingBlockDisplayBox.paddingBoxHeight();
+    auto containingBlockWidth = containingBlockDisplayBox.paddingBoxWidth();
 
     auto top = computedValueIfNotAuto(style.logicalTop(), containingBlockWidth);
     auto bottom = computedValueIfNotAuto(style.logicalBottom(), containingBlockWidth);
+    auto isStaticallyPositioned = !top && !bottom;
     auto height = inlineReplacedHeightAndMargin(layoutState, layoutBox, usedHeight).height;
     auto computedVerticalMargin = Geometry::computedVerticalMargin(layoutState, layoutBox);
     UsedVerticalMargin::NonCollapsedValues usedVerticalMargin; 
@@ -564,6 +584,14 @@ VerticalGeometry FormattingContext::Geometry::outOfFlowReplacedVerticalGeometry(
     if (boxHeight > containingBlockHeight)
         bottom = containingBlockHeight - (*top + usedVerticalMargin.before + borderTop + paddingTop + height + paddingBottom + borderBottom + usedVerticalMargin.after); 
 
+    // For out-of-flow elements the containing block is formed by the padding edge of the ancestor.
+    // At this point the non-statically positioned value is in the coordinate system of the padding box. Let's convert it to border box coordinate system.
+    if (!isStaticallyPositioned) {
+        auto containingBlockPaddingVerticalEdge = containingBlockDisplayBox.paddingBoxTop();
+        *top += containingBlockPaddingVerticalEdge;
+        *bottom += containingBlockPaddingVerticalEdge;
+    }
+
     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Position][Height][Margin] -> out-of-flow replaced -> top(" << *top << "px) bottom("  << *bottom << "px) height(" << height << "px) margin(" << usedVerticalMargin.before << "px, "  << usedVerticalMargin.after << "px) layoutBox(" << &layoutBox << ")");
     return { *top, *bottom, { height, usedVerticalMargin } };
 }
@@ -589,11 +617,13 @@ HorizontalGeometry FormattingContext::Geometry::outOfFlowReplacedHorizontalGeome
     auto& style = layoutBox.style();
     auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox);
     auto& containingBlock = *layoutBox.containingBlock();
-    auto containingBlockWidth = layoutState.displayBoxForLayoutBox(containingBlock).contentBoxWidth();
+    auto& containingBlockDisplayBox = layoutState.displayBoxForLayoutBox(containingBlock);
+    auto containingBlockWidth = containingBlockDisplayBox.paddingBoxWidth();
     auto isLeftToRightDirection = containingBlock.style().isLeftToRightDirection();
 
     auto left = computedValueIfNotAuto(style.logicalLeft(), containingBlockWidth);
     auto right = computedValueIfNotAuto(style.logicalRight(), containingBlockWidth);
+    auto isStaticallyPositioned = !left && !right;
     auto computedHorizontalMargin = Geometry::computedHorizontalMargin(layoutState, layoutBox);
     UsedHorizontalMargin usedHorizontalMargin;
     auto width = inlineReplacedWidthAndMargin(layoutState, layoutBox, usedWidth).width;
@@ -657,6 +687,14 @@ HorizontalGeometry FormattingContext::Geometry::outOfFlowReplacedHorizontalGeome
     ASSERT(left);
     ASSERT(right);
 
+    // For out-of-flow elements the containing block is formed by the padding edge of the ancestor.
+    // At this point the non-statically positioned value is in the coordinate system of the padding box. Let's convert it to border box coordinate system.
+    if (isStaticallyPositioned) {
+        auto containingBlockPaddingVerticalEdge = containingBlockDisplayBox.paddingBoxLeft();
+        *left += containingBlockPaddingVerticalEdge;
+        *right += containingBlockPaddingVerticalEdge;
+    }
+
     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Position][Width][Margin] -> out-of-flow replaced -> left(" << *left << "px) right("  << *right << "px) width(" << width << "px) margin(" << usedHorizontalMargin.start << "px, "  << usedHorizontalMargin.end << "px) layoutBox(" << &layoutBox << ")");
     return { *left, *right, { width, usedHorizontalMargin, computedHorizontalMargin } };
 }
index 16782c4..1d45aa3 100644 (file)
@@ -133,8 +133,8 @@ public:
     LayoutPoint bottomRight() const { return { right(), bottom() }; }
 
     LayoutSize size() const { return { width(), height() }; }
-    LayoutUnit width() const { return borderLeft() + paddingLeft().valueOr(0) + contentBoxWidth() + paddingRight().valueOr(0) + borderRight(); }
-    LayoutUnit height() const { return borderTop() + paddingTop().valueOr(0) + contentBoxHeight() + paddingBottom().valueOr(0) + borderBottom(); }
+    LayoutUnit width() const { return borderLeft() + paddingBoxWidth() + borderRight(); }
+    LayoutUnit height() const { return borderTop() + paddingBoxHeight() + borderBottom(); }
     Rect rect() const { return { top(), left(), width(), height() }; }
     Rect rectWithMargin() const;
 
@@ -160,13 +160,20 @@ public:
     Optional<LayoutUnit> paddingBottom() const;
     Optional<LayoutUnit> paddingRight() const;
 
-    LayoutUnit contentBoxTop() const { return borderTop() + paddingTop().valueOr(0); }
-    LayoutUnit contentBoxLeft() const { return borderLeft() + paddingLeft().valueOr(0); }
+    LayoutUnit contentBoxTop() const { return paddingBoxTop() + paddingTop().valueOr(0); }
+    LayoutUnit contentBoxLeft() const { return paddingBoxLeft() + paddingLeft().valueOr(0); }
     LayoutUnit contentBoxBottom() const { return contentBoxTop() + contentBoxHeight(); }
     LayoutUnit contentBoxRight() const { return contentBoxLeft() + contentBoxWidth(); }
     LayoutUnit contentBoxHeight() const;
     LayoutUnit contentBoxWidth() const;
 
+    LayoutUnit paddingBoxTop() const { return borderTop(); }
+    LayoutUnit paddingBoxLeft() const { return borderLeft(); }
+    LayoutUnit paddingBoxBottom() const { return paddingBoxTop() + paddingBoxHeight(); }
+    LayoutUnit paddingBoxRight() const { return paddingBoxLeft() + paddingBoxWidth(); }
+    LayoutUnit paddingBoxHeight() const { return paddingTop().valueOr(0) + contentBoxHeight() + paddingBottom().valueOr(0); }
+    LayoutUnit paddingBoxWidth() const { return paddingLeft().valueOr(0) + contentBoxWidth() + paddingRight().valueOr(0); }
+
     Rect marginBox() const;
     Rect nonCollapsedMarginBox() const;
 
index 97b2720..9a26240 100644 (file)
@@ -1,3 +1,12 @@
+2019-01-15  Zalan Bujtas  <zalan@apple.com>
+
+        [LFC] Use the containing block's padding box to position out-of-flow elements.
+        https://bugs.webkit.org/show_bug.cgi?id=193431
+
+        Reviewed by Antti Koivisto.
+
+        * LayoutReloaded/misc/LFC-passing-tests.txt:
+
 2019-01-14  Tim Horton  <timothy_horton@apple.com>
 
         Move a test implementation file that got misplaced in the Xcode project
index 2826337..4ec9d76 100644 (file)
@@ -77,6 +77,7 @@ fast/block/block-only/relative-right.html
 fast/block/block-only/relative-siblings.html
 fast/block/block-only/relative-simple.html
 fast/block/block-only/box-sizing-inflow-out-of-flow-simple.html
+fast/block/block-only/out-of-flow-with-containing-block-border-padding.html
 fast/block/basic/002.html
 fast/block/basic/003.html
 fast/block/basic/006.html