Incorrect position: fixed; rendering when child of position:relative/sticky.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Jan 2016 20:01:23 +0000 (20:01 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Jan 2016 20:01:23 +0000 (20:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=147284

Reviewed by Simon Fraser and David Hyatt.

Computing logical left for positioned objects should take the relative positioned ancestors' offset
into account.

Source/WebCore:

Tests: fast/block/positioning/fixed-container-with-relative-parent.html
       fast/block/positioning/fixed-container-with-sticky-parent.html

* rendering/RenderBox.cpp:
(WebCore::computeInlineStaticDistance):

LayoutTests:

* fast/block/positioning/fixed-container-with-relative-parent-expected.html: Added.
* fast/block/positioning/fixed-container-with-relative-parent.html: Added.
* fast/block/positioning/fixed-container-with-sticky-parent-expected.html: Added.
* fast/block/positioning/fixed-container-with-sticky-parent.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/block/positioning/fixed-container-with-relative-parent-expected.html [new file with mode: 0644]
LayoutTests/fast/block/positioning/fixed-container-with-relative-parent.html [new file with mode: 0644]
LayoutTests/fast/block/positioning/fixed-container-with-sticky-parent-expected.html [new file with mode: 0644]
LayoutTests/fast/block/positioning/fixed-container-with-sticky-parent.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderBox.cpp

index 4662ba2..045e2f3 100644 (file)
@@ -1,3 +1,18 @@
+2016-01-07  Zalan Bujtas  <zalan@apple.com>
+
+        Incorrect position: fixed; rendering when child of position:relative/sticky.
+        https://bugs.webkit.org/show_bug.cgi?id=147284
+
+        Reviewed by Simon Fraser and David Hyatt.
+
+        Computing logical left for positioned objects should take the relative positioned ancestors' offset
+        into account.
+
+        * fast/block/positioning/fixed-container-with-relative-parent-expected.html: Added.
+        * fast/block/positioning/fixed-container-with-relative-parent.html: Added.
+        * fast/block/positioning/fixed-container-with-sticky-parent-expected.html: Added.
+        * fast/block/positioning/fixed-container-with-sticky-parent.html: Added.
+
 2016-01-07  Chris Dumez  <cdumez@apple.com>
 
         Directly-composited animated GIFs never resume once scrolled offscreen
diff --git a/LayoutTests/fast/block/positioning/fixed-container-with-relative-parent-expected.html b/LayoutTests/fast/block/positioning/fixed-container-with-relative-parent-expected.html
new file mode 100644 (file)
index 0000000..8467aca
--- /dev/null
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>It tests that fixed (auto)positioned element is placed properly when the parent element is relative positioned.</title>
+</head>
+<body>
+<div style="position: relative; left: 10px; width: 22px; height: 22px; background-color: green;"></div>
+<div style="position: relative; left: 10px; margin-top: 1px; width: 22px; height: 22px; background-color: green;"></div>
+<div style="position: relative; left: 10px; margin-top: 1px; width: 22px; height: 22px; background-color: green;"></div>
+<div style="position: relative; left: 10px; margin-top: 1px; width: 22px; height: 22px; background-color: green;"></div>
+<div style="position: relative; left: 10px; margin-top: 1px; width: 22px; height: 22px; background-color: green;"></div>
+<div style="position: relative; left: 10px; margin-top: 1px; width: 22px; height: 22px; background-color: green;"></div>
+<div style="position: relative; left: 10px; margin-top: 1px; width: 22px; height: 22px; background-color: green;"></div>
+<div style="position: relative; left: 10px; margin-top: 1px; width: 22px; height: 22px; background-color: green;"></div>
+
+<div dir=rtl style="position: absolute; right: 8px; top: 99px;">
+  <div style="position: relative; right: 10px; width: 22px; height: 22px; background-color: green;"></div>
+  <div style="position: relative; right: 10px; margin-top: 1px; width: 22px; height: 22px; background-color: green;"></div>
+  <div style="position: relative; right: 10px; margin-top: 1px; width: 22px; height: 22px; background-color: green;"></div>
+  <div style="position: relative; right: 10px; margin-top: 1px; width: 22px; height: 22px; background-color: green;"></div>
+  <div style="position: relative; right: 10px; margin-top: 1px; width: 22px; height: 22px; background-color: green;"></div>
+  <div style="position: relative; right: 10px; margin-top: 1px; width: 22px; height: 22px; background-color: green;"></div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/block/positioning/fixed-container-with-relative-parent.html b/LayoutTests/fast/block/positioning/fixed-container-with-relative-parent.html
new file mode 100644 (file)
index 0000000..b9e0ed5
--- /dev/null
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>It tests that fixed (auto)positioned element is placed properly when the parent element is relative positioned.</title>
+<script>
+    if (window.testRunner)
+           testRunner.waitUntilDone();
+</script>
+</head>
+<body>
+<div style="position: relative; left: 10px; width: 20px; height: 20px; border: 1px solid green;">
+  <div class=fixed style="width: 20px; height: 20px; background-color: green;"></div>
+</div>
+
+<div style="-webkit-writing-mode: vertical-lr; margin-top: 1px; position: relative; left: 10px; width: 20px; height: 20px; border: 1px solid green;">
+  <div class=fixed style="width: 20px; height: 20px; background-color: green;"></div>
+</div>
+
+<div style="position: relative; left: 10px; width: 20px; height: 20px; margin-top: 1px; border: 1px solid green;">
+  <div class=fixed style="width: 20px; height: 20px; background-color: green;"></div>
+</div>
+
+<div style="-webkit-writing-mode: vertical-lr; position: relative; left: 10px; width: 20px; height: 20px; margin-top: 1px; border: 1px solid green;">
+  <div class=fixed style="width: 20px; height: 20px; background-color: green;"></div>
+</div>
+
+<div style="position: absolute; left: 13px; margin-top: 1px;">
+  <div style="position: relative; left: 5px; width: 20px; height: 20px; border: 1px solid green;">
+    <div class=fixed style="width: 20px; height: 20px; background-color: green;"></div>
+  </div>
+</div>
+
+<div style="position: absolute; margin-top: 24px; left: 8px;">
+  <span style="position: relative; left: 10px;">
+    <div class=fixed style="width: 22px; height: 22px; background-color: green;"></div>
+  </span>
+  <span style="position: relative; left: 10px; margin: 1px;">
+    <div class=fixed style="width: 22px; height: 22px; background-color: green; margin-top: 5px;"></div>
+  </span>
+  <div style="position: absolute; left: 5px;">
+    <span style="position: relative; left: 5px;">
+      <div class=fixed style="width: 22px; height: 22px; margin-top: 10px; background-color: green;"></div>
+    </span>
+  </div>
+</div>
+
+<div dir=rtl>
+  <div style="position: relative; top: 0px; right: 10px; width: 20px; height: 20px; border: 1px solid green;">
+    <div class=fixed style="width: 20px; height: 20px; background-color: green;"></div>
+  </div>
+
+  <div style="position: relative; right: 10px; width: 20px; height: 20px; margin-top: 1px; border: 1px solid green;">
+    <div class=fixed style="width: 20px; height: 20px; background-color: green;"></div>
+  </div>
+
+  <div style="position: absolute; margin-top: 1px;">
+    <div style="position: relative; right: 10px; width: 20px; height: 20px; border: 1px solid green;">
+      <div class=fixed style="width: 20px; height: 20px; background-color: green;"></div>
+    </div>
+  </div>
+  <span style="position: relative; right: 10px; top: 24px;">
+      <div class=fixed style="width: 22px; height: 22px; background-color: green;"></div>
+  </span>
+
+  <span style="position: relative; right: 10px; top: 47px">
+      <div class=fixed style="width: 22px; height: 22px; background-color: green;"></div>
+  </span>
+
+  <div style="position: absolute; right: 13px;">
+    <span style="position: relative; right: 5px; top: 70px;">
+      <div class=fixed style="width: 22px; height: 22px; background-color: green;"></div>
+    </span>
+  </div>
+</div>
+<script>
+setTimeout(function() {
+    var elements = document.getElementsByClassName("fixed");
+    for (var i = 0; i < elements.length; ++i)
+        elements[i].style.position = "fixed";
+    if (window.testRunner)
+        testRunner.notifyDone();
+}, 0);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/block/positioning/fixed-container-with-sticky-parent-expected.html b/LayoutTests/fast/block/positioning/fixed-container-with-sticky-parent-expected.html
new file mode 100644 (file)
index 0000000..1b1d2ee
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>It tests that fixed (auto)positioned element is placed properly when the parent element is sticky positioned.</title>
+</head>
+<body>
+<div style="position: relative; left: 42px; width: 22px; height: 22px; background-color: green;"></div>
+<div style="position: relative; left: 42px; margin-top: 5px; width: 22px; height: 22px; background-color: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/block/positioning/fixed-container-with-sticky-parent.html b/LayoutTests/fast/block/positioning/fixed-container-with-sticky-parent.html
new file mode 100644 (file)
index 0000000..effa958
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>It tests that fixed (auto)positioned element is placed properly when the parent element is sticky positioned.</title>
+<script>
+    if (window.testRunner)
+           testRunner.waitUntilDone();
+</script>
+</head>
+<body>
+<div style="position: -webkit-sticky; left: 50px; width: 20px; height: 20px; border: 1px solid green;">
+  <div class=fixed style="width: 20px; height: 20px; background-color: green;"></div>
+</div>
+<div style="position: -webkit-sticky; left: 50px; width: 20px; height: 20px; margin: 5px; border: 1px solid green;">
+  <div class=fixed style="width: 20px; height: 20px; background-color: green;"></div>
+</div>
+
+<script>
+setTimeout(function() {
+    var elements = document.getElementsByClassName("fixed");
+    for (var i = 0; i < elements.length; ++i)
+        elements[i].style.position = "fixed";
+    if (window.testRunner)
+        testRunner.notifyDone();
+}, 0);
+</script>
+</body>
+</html>
index d9bcf36..b38163e 100644 (file)
@@ -1,3 +1,19 @@
+2016-01-07  Zalan Bujtas  <zalan@apple.com>
+
+        Incorrect position: fixed; rendering when child of position:relative/sticky.
+        https://bugs.webkit.org/show_bug.cgi?id=147284
+
+        Reviewed by Simon Fraser and David Hyatt.
+
+        Computing logical left for positioned objects should take the relative positioned ancestors' offset
+        into account.
+
+        Tests: fast/block/positioning/fixed-container-with-relative-parent.html
+               fast/block/positioning/fixed-container-with-sticky-parent.html
+
+        * rendering/RenderBox.cpp:
+        (WebCore::computeInlineStaticDistance):
+
 2016-01-06  Simon Fraser  <simon.fraser@apple.com>
 
         Initial implementation files for display-list recording and playback
index 335ee66..7ebf811 100644 (file)
@@ -3331,25 +3331,32 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh
     if (child->parent()->style().direction() == LTR) {
         LayoutUnit staticPosition = child->layer()->staticInlinePosition() - containerBlock->borderLogicalLeft();
         for (auto* current = child->parent(); current && current != containerBlock; current = current->container()) {
-            if (is<RenderBox>(*current)) {
-                staticPosition += downcast<RenderBox>(*current).logicalLeft();
-                if (region && is<RenderBlock>(*current)) {
-                    const RenderBlock& currentBlock = downcast<RenderBlock>(*current);
-                    region = currentBlock.clampToStartAndEndRegions(region);
-                    RenderBoxRegionInfo* boxInfo = currentBlock.renderBoxRegionInfo(region);
-                    if (boxInfo)
-                        staticPosition += boxInfo->logicalLeft();
-                }
+            if (!is<RenderBox>(*current))
+                continue;
+            const auto& renderBox = downcast<RenderBox>(*current);
+            staticPosition += renderBox.logicalLeft();
+            if (renderBox.isInFlowPositioned())
+                staticPosition += renderBox.isHorizontalWritingMode() ? renderBox.offsetForInFlowPosition().width() : renderBox.offsetForInFlowPosition().height();
+            if (region && is<RenderBlock>(*current)) {
+                const RenderBlock& currentBlock = downcast<RenderBlock>(*current);
+                region = currentBlock.clampToStartAndEndRegions(region);
+                RenderBoxRegionInfo* boxInfo = currentBlock.renderBoxRegionInfo(region);
+                if (boxInfo)
+                    staticPosition += boxInfo->logicalLeft();
             }
         }
         logicalLeft.setValue(Fixed, staticPosition);
     } else {
-        RenderBox& enclosingBox = child->parent()->enclosingBox();
+        const RenderBox& enclosingBox = child->parent()->enclosingBox();
         LayoutUnit staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock->borderLogicalLeft();
-        for (RenderElement* current = &enclosingBox; current; current = current->container()) {
+        for (const RenderElement* current = &enclosingBox; current; current = current->container()) {
             if (is<RenderBox>(*current)) {
-                if (current != containerBlock)
-                    staticPosition -= downcast<RenderBox>(*current).logicalLeft();
+                if (current != containerBlock) {
+                    const auto& renderBox = downcast<RenderBox>(*current);
+                    staticPosition -= renderBox.logicalLeft();
+                    if (renderBox.isInFlowPositioned())
+                        staticPosition -= renderBox.isHorizontalWritingMode() ? renderBox.offsetForInFlowPosition().width() : renderBox.offsetForInFlowPosition().height();
+                }
                 if (current == &enclosingBox)
                     staticPosition -= enclosingBox.logicalWidth();
                 if (region && is<RenderBlock>(*current)) {
@@ -3713,8 +3720,13 @@ static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom
     // FIXME: The static distance computation has not been patched for mixed writing modes.
     LayoutUnit staticLogicalTop = child->layer()->staticBlockPosition() - containerBlock->borderBefore();
     for (RenderElement* container = child->parent(); container && container != containerBlock; container = container->container()) {
-        if (is<RenderBox>(*container) && !is<RenderTableRow>(*container))
-            staticLogicalTop += downcast<RenderBox>(*container).logicalTop();
+        if (!is<RenderBox>(*container))
+            continue;
+        const auto& renderBox = downcast<RenderBox>(*container);
+        if (!is<RenderTableRow>(renderBox))
+            staticLogicalTop += renderBox.logicalTop();
+        if (renderBox.isInFlowPositioned())
+            staticLogicalTop += renderBox.isHorizontalWritingMode() ? renderBox.offsetForInFlowPosition().height() : renderBox.offsetForInFlowPosition().width();
     }
     logicalTop.setValue(Fixed, staticLogicalTop);
 }