Remove positioned descendants when RenderBlock is no longer a containing block.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 12 Jun 2016 20:45:44 +0000 (20:45 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 12 Jun 2016 20:45:44 +0000 (20:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=158655
<rdar://problem/26510032>

Reviewed by Simon Fraser.

Normally the RenderView is the containing block for fixed positioned renderers.
However when a renderer acquires some transform related properties, it becomes the containing
block for all the fixed positioned renderers in its descendant tree.
When the last transform related property is removed, the renderer is no longer a containing block
and we need to remove all these positioned renderers from the descendant tracker map (gPositionedDescendantsMap).
They will be inserted back into the tracker map during the next layout (either under the RenderView or
under the next transformed renderer in the ancestor chain).

Source/WebCore:

Test: fast/block/fixed-position-reparent-when-transition-is-removed.html

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

LayoutTests:

* fast/block/fixed-position-reparent-when-transition-is-removed-expected.txt: Added.
* fast/block/fixed-position-reparent-when-transition-is-removed.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/block/fixed-position-reparent-when-transition-is-removed-expected.txt [new file with mode: 0644]
LayoutTests/fast/block/fixed-position-reparent-when-transition-is-removed.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderBlock.cpp

index 94abda3..8fd12d4 100644 (file)
@@ -1,3 +1,22 @@
+2016-06-12  Zalan Bujtas  <zalan@apple.com>
+
+        Remove positioned descendants when RenderBlock is no longer a containing block.
+        https://bugs.webkit.org/show_bug.cgi?id=158655
+        <rdar://problem/26510032>
+
+        Reviewed by Simon Fraser.
+
+        Normally the RenderView is the containing block for fixed positioned renderers.
+        However when a renderer acquires some transform related properties, it becomes the containing
+        block for all the fixed positioned renderers in its descendant tree.
+        When the last transform related property is removed, the renderer is no longer a containing block
+        and we need to remove all these positioned renderers from the descendant tracker map (gPositionedDescendantsMap).
+        They will be inserted back into the tracker map during the next layout (either under the RenderView or
+        under the next transformed renderer in the ancestor chain).
+
+        * fast/block/fixed-position-reparent-when-transition-is-removed-expected.txt: Added.
+        * fast/block/fixed-position-reparent-when-transition-is-removed.html: Added.
+
 2016-06-11  Myles C. Maxfield  <mmaxfield@apple.com>
 
         [Cocoa] Map commonly used Chinese Windows font names to names present on Cocoa operating systems
diff --git a/LayoutTests/fast/block/fixed-position-reparent-when-transition-is-removed-expected.txt b/LayoutTests/fast/block/fixed-position-reparent-when-transition-is-removed-expected.txt
new file mode 100644 (file)
index 0000000..3cd69de
--- /dev/null
@@ -0,0 +1,2 @@
+PASS if no crash or assert.
+
diff --git a/LayoutTests/fast/block/fixed-position-reparent-when-transition-is-removed.html b/LayoutTests/fast/block/fixed-position-reparent-when-transition-is-removed.html
new file mode 100644 (file)
index 0000000..39d86dc
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests the case when fixed positioned elements has a new containing block.</title>
+<style>
+div {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+</head>
+<body>
+PASS if no crash or assert.
+<div id=container style="position: absolute; transform: rotate(10deg);">
+  <div id=fixedChild style="position: fixed;"></div>
+</div>
+<script>
+if (window.testRunner) {
+  testRunner.waitUntilDone();
+  testRunner.dumpAsText();
+}
+var container = document.getElementById("container"); 
+setTimeout(function() {
+  container.style.transform = "";
+  setTimeout(function() {
+    var removeThis = document.getElementById("fixedChild");
+    removeThis.parentNode.removeChild(removeThis);
+      setTimeout(function() {
+        var newChild = document.createElement("div");
+        newChild.style.positioned = "absolute";
+        container.appendChild(newChild);
+        if (window.testRunner)
+          testRunner.notifyDone();
+    }, 0);
+  }, 0);
+}, 0);
+</script>
+</body>
+</html>
\ No newline at end of file
index cc2fc0a..3fbda33 100644 (file)
@@ -1,3 +1,24 @@
+2016-06-12  Zalan Bujtas  <zalan@apple.com>
+
+        Remove positioned descendants when RenderBlock is no longer a containing block.
+        https://bugs.webkit.org/show_bug.cgi?id=158655
+        <rdar://problem/26510032>
+
+        Reviewed by Simon Fraser.
+
+        Normally the RenderView is the containing block for fixed positioned renderers.
+        However when a renderer acquires some transform related properties, it becomes the containing
+        block for all the fixed positioned renderers in its descendant tree.
+        When the last transform related property is removed, the renderer is no longer a containing block
+        and we need to remove all these positioned renderers from the descendant tracker map (gPositionedDescendantsMap).
+        They will be inserted back into the tracker map during the next layout (either under the RenderView or
+        under the next transformed renderer in the ancestor chain).
+
+        Test: fast/block/fixed-position-reparent-when-transition-is-removed.html
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::removePositionedObjectsIfNeeded):
+
 2016-06-11  Myles C. Maxfield  <mmaxfield@apple.com>
 
         Addressing post-review comments after r201978.
index 4d8e1c3..2d5ac5c 100644 (file)
@@ -244,14 +244,20 @@ void RenderBlock::removePositionedObjectsIfNeeded(const RenderStyle& oldStyle, c
     if (oldStyle.position() == newStyle.position() && hadTransform == willHaveTransform)
         return;
 
-    // We are no longer a containing block.
+    // We are no longer the containing block for fixed descendants.
+    if (hadTransform && !willHaveTransform) {
+        // Our positioned descendants will be inserted into a new containing block's positioned objects list during the next layout.
+        removePositionedObjects(nullptr, NewContainingBlock);
+        return;
+    }
+
+    // We are no longer the containing block for absolute positioned descendants.
     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.
+        // Our positioned descendants will be inserted into a new containing block's positioned objects list during the next layout.
         removePositionedObjects(nullptr, NewContainingBlock);
         return;
     }
-    
+
     // We are a new containing block.
     if (oldStyle.position() == StaticPosition && !hadTransform) {
         // Remove our absolutely positioned descendants from their current containing block.