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