Title: [200736] trunk
Revision
200736
Author
za...@apple.com
Date
2016-05-11 19:09:59 -0700 (Wed, 11 May 2016)

Log Message

Absolute positioned element is not placed properly when parent becomes the containing block.
https://bugs.webkit.org/show_bug.cgi?id=157455
<rdar://problem/26212568>

Reviewed by Simon Fraser.

When a container becomes a containing block, we need to check if there are any positioned boxes in its subtree
in order to "re-parent" them. It basically means that we remove them from RenderBlock::positionedDescendants map
and they'll get re-inserted during the next layout correctly.
This patch fixes the case when a container becomes the containing block by setting the transform property and its positioned
child gets misplaced.

Source/WebCore:

Test: fast/block/containing-block-changes.html

* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::removePositionedObjectsIfNeeded):
(WebCore::RenderBlock::styleWillChange):
* rendering/RenderBlock.h:

LayoutTests:

* fast/block/containing-block-changes-expected.html: Added.
* fast/block/containing-block-changes.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (200735 => 200736)


--- trunk/LayoutTests/ChangeLog	2016-05-12 01:32:07 UTC (rev 200735)
+++ trunk/LayoutTests/ChangeLog	2016-05-12 02:09:59 UTC (rev 200736)
@@ -1,3 +1,20 @@
+2016-05-11  Zalan Bujtas  <za...@apple.com>
+
+        Absolute positioned element is not placed properly when parent becomes the containing block.
+        https://bugs.webkit.org/show_bug.cgi?id=157455
+        <rdar://problem/26212568>
+
+        Reviewed by Simon Fraser.
+
+        When a container becomes a containing block, we need to check if there are any positioned boxes in its subtree
+        in order to "re-parent" them. It basically means that we remove them from RenderBlock::positionedDescendants map
+        and they'll get re-inserted during the next layout correctly.
+        This patch fixes the case when a container becomes the containing block by setting the transform property and its positioned
+        child gets misplaced.  
+
+        * fast/block/containing-block-changes-expected.html: Added.
+        * fast/block/containing-block-changes.html: Added.
+
 2016-05-11  Ryosuke Niwa  <rn...@webkit.org>
 
         Add a failing expectation on iOS for the test added in r200712

Added: trunk/LayoutTests/fast/block/containing-block-changes-expected.html (0 => 200736)


--- trunk/LayoutTests/fast/block/containing-block-changes-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/block/containing-block-changes-expected.html	2016-05-12 02:09:59 UTC (rev 200736)
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests that we properly reparent containing block descendants.</title>
+<style>
+.container {
+    position: relative;
+    height: 20px;
+    width: 20px;
+    border: 10px solid gray;
+}
+
+.indented {
+  left: 10px;
+}
+
+.box {
+    left: 0px;
+    top: 0px;
+    height: 10px;
+    width: 10px;
+    background-color: blue;
+}
+</style>
+</head>
+<body>
+<div class=box style="position: absolute"></div>
+<div class="container indented"><div class=box></div></div>
+<div class=container><div class=box></div></div>
+<div class="container indented"><div class=box></div></div>
+<div class="container indented"><div class=box></div></div>
+<div class="container indented"><div class=box></div></div>
+<div class=container><div class=box></div></div>
+<div class=container></div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/fast/block/containing-block-changes.html (0 => 200736)


--- trunk/LayoutTests/fast/block/containing-block-changes.html	                        (rev 0)
+++ trunk/LayoutTests/fast/block/containing-block-changes.html	2016-05-12 02:09:59 UTC (rev 200736)
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests that we properly reparent containing block descendants.</title>
+<style>
+    .translate {
+        transform: translateX(10px);
+    }
+
+    .positioned {
+        position: relative;
+    }
+    
+    .container {
+      height: 20px;
+      width: 20px;
+      border: 10px solid gray;
+    }
+    
+    .box {
+      position: absolute;
+      left: 0px;
+      top: 0px;
+      height: 10px;
+      width: 10px;
+      background-color: blue;
+    }
+</style>
+</head>
+<body>
+<div class="container"><div class="box"></div></div>
+<div class="container"><div class="box"></div></div>
+<div class="container"><div class="box"></div></div>
+<div class="container"><div class="box"></div></div>
+<div class="container"><div class="box"></div></div>
+<div class="container"><div class="box"></div></div>
+<div class="container"><div class="box"></div></div>
+<script>
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+setTimeout(function() {
+  document.getElementsByClassName("container")[0].classList.toggle("translate");
+  document.getElementsByClassName("container")[1].classList.toggle("positioned");
+  document.getElementsByClassName("container")[2].classList.toggle("translate");
+  document.getElementsByClassName("container")[3].classList.toggle("positioned");
+  document.getElementsByClassName("container")[4].classList.toggle("positioned");
+  document.getElementsByClassName("container")[5].classList.toggle("translate");
+  document.getElementsByClassName("container")[6].classList.toggle("translate");
+  document.body.offsetHeight;
+  setTimeout(function() {
+    document.getElementsByClassName("container")[2].classList.toggle("positioned"); 
+    document.getElementsByClassName("container")[3].classList.toggle("translate");
+    document.getElementsByClassName("container")[4].classList.toggle("translate"); 
+    document.getElementsByClassName("container")[5].classList.toggle("positioned"); 
+    document.getElementsByClassName("container")[6].classList.toggle("positioned"); 
+    document.body.offsetHeight;
+    setTimeout(function() {
+      document.getElementsByClassName("container")[4].classList.toggle("positioned"); 
+      document.getElementsByClassName("container")[5].classList.toggle("translate"); 
+      document.getElementsByClassName("container")[6].classList.toggle("translate"); 
+      document.body.offsetHeight;
+      setTimeout(function() {
+        document.getElementsByClassName("container")[6].classList.toggle("positioned"); 
+        document.body.offsetHeight;
+        if (window.testRunner)
+          testRunner.notifyDone();
+      }, 0);
+    }, 0);
+  }, 0);
+}, 0);
+</script>
+</body>
+</html>
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (200735 => 200736)


--- trunk/Source/WebCore/ChangeLog	2016-05-12 01:32:07 UTC (rev 200735)
+++ trunk/Source/WebCore/ChangeLog	2016-05-12 02:09:59 UTC (rev 200736)
@@ -1,3 +1,24 @@
+2016-05-11  Zalan Bujtas  <za...@apple.com>
+
+        Absolute positioned element is not placed properly when parent becomes the containing block.
+        https://bugs.webkit.org/show_bug.cgi?id=157455
+        <rdar://problem/26212568>
+
+        Reviewed by Simon Fraser.
+
+        When a container becomes a containing block, we need to check if there are any positioned boxes in its subtree
+        in order to "re-parent" them. It basically means that we remove them from RenderBlock::positionedDescendants map
+        and they'll get re-inserted during the next layout correctly.
+        This patch fixes the case when a container becomes the containing block by setting the transform property and its positioned
+        child gets misplaced.  
+
+        Test: fast/block/containing-block-changes.html
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::removePositionedObjectsIfNeeded):
+        (WebCore::RenderBlock::styleWillChange):
+        * rendering/RenderBlock.h:
+
 2016-05-11  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, rolling out r200700, r200703, and r200713.

Modified: trunk/Source/WebCore/rendering/RenderBlock.cpp (200735 => 200736)


--- trunk/Source/WebCore/rendering/RenderBlock.cpp	2016-05-12 01:32:07 UTC (rev 200735)
+++ trunk/Source/WebCore/rendering/RenderBlock.cpp	2016-05-12 02:09:59 UTC (rev 200736)
@@ -236,38 +236,45 @@
     return gRareDataMap ? gRareDataMap->contains(this) : false;
 }
 
-void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
+void RenderBlock::removePositionedObjectsIfNeeded(const RenderStyle& oldStyle, const RenderStyle& newStyle)
 {
-    const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
+    bool hadTransform = oldStyle.hasTransformRelatedProperty();
+    bool willHaveTransform = newStyle.hasTransformRelatedProperty();
+    if (oldStyle.position() == newStyle.position() && hadTransform == willHaveTransform)
+        return;
 
-    setReplaced(newStyle.isDisplayInlineType());
-
-    if (oldStyle && oldStyle->hasTransformRelatedProperty() && !newStyle.hasTransformRelatedProperty())
+    // We are no longer a containing block.
+    if (newStyle.position() == StaticPosition && !willHaveTransform) {
+        // Clear our positioned objects list. Our absolutely positioned descendants will be
+        // inserted into our containing block's positioned objects list during layout.
         removePositionedObjects(nullptr, NewContainingBlock);
-
-    if (oldStyle && parent() && diff == StyleDifferenceLayout && oldStyle->position() != newStyle.position()) {
-        if (newStyle.position() == StaticPosition)
-            // Clear our positioned objects list. Our absolutely positioned descendants will be
-            // inserted into our containing block's positioned objects list during layout.
-            removePositionedObjects(nullptr, NewContainingBlock);
-        else if (oldStyle->position() == StaticPosition) {
-            // Remove our absolutely positioned descendants from their current containing block.
-            // They will be inserted into our positioned objects list during layout.
-            auto containingBlock = parent();
-            while (containingBlock && !is<RenderView>(*containingBlock)
-                && (containingBlock->style().position() == StaticPosition || (containingBlock->isInline() && !containingBlock->isReplaced()))) {
-                if (containingBlock->style().position() == RelativePosition && containingBlock->isInline() && !containingBlock->isReplaced()) {
-                    containingBlock = containingBlock->containingBlock();
-                    break;
-                }
-                containingBlock = containingBlock->parent();
+        return;
+    }
+    
+    // We are a new containing block.
+    if (oldStyle.position() == StaticPosition && !hadTransform) {
+        // Remove our absolutely positioned descendants from their current containing block.
+        // They will be inserted into our positioned objects list during layout.
+        auto* containingBlock = parent();
+        while (containingBlock && !is<RenderView>(*containingBlock)
+            && (containingBlock->style().position() == StaticPosition || (containingBlock->isInline() && !containingBlock->isReplaced()))) {
+            if (containingBlock->style().position() == RelativePosition && containingBlock->isInline() && !containingBlock->isReplaced()) {
+                containingBlock = containingBlock->containingBlock();
+                break;
             }
-
-            if (is<RenderBlock>(*containingBlock))
-                downcast<RenderBlock>(*containingBlock).removePositionedObjects(this, NewContainingBlock);
+            containingBlock = containingBlock->parent();
         }
+        if (containingBlock && is<RenderBlock>(*containingBlock))
+            downcast<RenderBlock>(*containingBlock).removePositionedObjects(this, NewContainingBlock);
     }
+}
 
+void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
+{
+    const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
+    setReplaced(newStyle.isDisplayInlineType());
+    if (oldStyle)
+        removePositionedObjectsIfNeeded(*oldStyle, newStyle);
     RenderBox::styleWillChange(diff, newStyle);
 }
 

Modified: trunk/Source/WebCore/rendering/RenderBlock.h (200735 => 200736)


--- trunk/Source/WebCore/rendering/RenderBlock.h	2016-05-12 01:32:07 UTC (rev 200735)
+++ trunk/Source/WebCore/rendering/RenderBlock.h	2016-05-12 02:09:59 UTC (rev 200736)
@@ -489,6 +489,8 @@
 
     RenderFlowThread* updateCachedFlowThreadContainingBlock(RenderFlowThread*) const;
 
+    void removePositionedObjectsIfNeeded(const RenderStyle& oldStyle, const RenderStyle& newStyle);
+
 private:
     bool hasRareData() const;
     
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to