Bug 1432553 - Fix OOF frame overflow coordinate space
MozReview-Commit-ID: 3VTyAAUM3VR
--- a/layout/painting/RetainedDisplayListBuilder.cpp
+++ b/layout/painting/RetainedDisplayListBuilder.cpp
@@ -659,75 +659,82 @@ HandlePreserve3D(nsIFrame* aFrame, nsRec
nsIFrame* last = aFrame;
while (aFrame->Extend3DContext() ||
aFrame->Combines3DTransformWithAncestors()) {
last = aFrame;
aFrame = aFrame->GetParent();
}
if (last != aFrame) {
aOverflow = last->GetVisualOverflowRectRelativeToParent();
+ CRR_LOG("HandlePreserve3D() Updated overflow rect to: %d %d %d %d\n",
+ aOverflow.x, aOverflow.y, aOverflow.width, aOverflow.height);
}
return aFrame;
}
static void
ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder,
AnimatedGeometryRoot** aAGR, nsRect& aOverflow,
nsIFrame* aStopAtFrame, nsTArray<nsIFrame*>& aOutFramesWithProps,
const bool aStopAtStackingContext)
{
nsIFrame* currentFrame = aFrame;
while (currentFrame != aStopAtFrame) {
- currentFrame = HandlePreserve3D(currentFrame, aOverflow);
+ CRR_LOG("currentFrame: %p (placeholder=%d), aOverflow: %d %d %d %d\n",
+ currentFrame, !aStopAtStackingContext,
+ aOverflow.x, aOverflow.y, aOverflow.width, aOverflow.height);
- // Convert 'aOverflow' into the coordinate space of the nearest stacking context
- // or display port ancestor and update 'currentFrame' to point to that frame.
- nsIFrame* previousFrame = currentFrame;
- aOverflow = nsLayoutUtils::TransformFrameRectToAncestor(currentFrame, aOverflow, aStopAtFrame,
- nullptr, nullptr,
- /* aStopAtStackingContextAndDisplayPortAndOOFFrame = */ true,
- ¤tFrame);
- MOZ_ASSERT(currentFrame);
+ currentFrame = HandlePreserve3D(currentFrame, aOverflow);
// If the current frame is an OOF frame, DisplayListBuildingData needs to be
// set on all the ancestor stacking contexts of the placeholder frame, up
// to the containing block of the OOF frame. This is done to ensure that the
// content that might be behind the OOF frame is built for merging.
- nsIFrame* placeholder = previousFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)
- ? previousFrame->GetPlaceholderFrame()
+ nsIFrame* placeholder = currentFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)
+ ? currentFrame->GetPlaceholderFrame()
: nullptr;
if (placeholder) {
+ // The rect aOverflow is in the coordinate space of the containing block.
+ // Convert it to a coordinate space of the placeholder frame.
nsRect placeholderOverflow =
- aOverflow + previousFrame->GetOffsetTo(placeholder);
+ aOverflow + currentFrame->GetOffsetTo(placeholder);
CRR_LOG("Processing placeholder %p for OOF frame %p\n",
- placeholder, previousFrame);
+ placeholder, currentFrame);
CRR_LOG("OOF frame draw area: %d %d %d %d\n",
placeholderOverflow.x, placeholderOverflow.y,
placeholderOverflow.width, placeholderOverflow.height);
// Tracking AGRs for the placeholder processing is not necessary, as the
// goal is to only modify the DisplayListBuildingData rect.
AnimatedGeometryRoot* dummyAGR = nullptr;
// Find a common ancestor frame to handle frame continuations.
// TODO: It might be possible to write a more specific and efficient
// function for this.
nsIFrame* ancestor =
- nsLayoutUtils::FindNearestCommonAncestorFrame(previousFrame->GetParent(),
+ nsLayoutUtils::FindNearestCommonAncestorFrame(currentFrame->GetParent(),
placeholder->GetParent());
ProcessFrame(placeholder, aBuilder, &dummyAGR, placeholderOverflow,
ancestor, aOutFramesWithProps, false);
}
+ // Convert 'aOverflow' into the coordinate space of the nearest stacking context
+ // or display port ancestor and update 'currentFrame' to point to that frame.
+ aOverflow = nsLayoutUtils::TransformFrameRectToAncestor(currentFrame, aOverflow, aStopAtFrame,
+ nullptr, nullptr,
+ /* aStopAtStackingContextAndDisplayPortAndOOFFrame = */ true,
+ ¤tFrame);
+ MOZ_ASSERT(currentFrame);
+
if (nsLayoutUtils::FrameHasDisplayPort(currentFrame)) {
CRR_LOG("Frame belongs to displayport frame %p\n", currentFrame);
nsIScrollableFrame* sf = do_QueryFrame(currentFrame);
MOZ_ASSERT(sf);
nsRect displayPort;
DebugOnly<bool> hasDisplayPort =
nsLayoutUtils::GetDisplayPort(currentFrame->GetContent(), &displayPort,
RelativeTo::ScrollPort);
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/1432553-1-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="utf-8">
+<title>Retained display list test</title>
+<style type="text/css">
+#parent {
+ position: fixed;
+ top: 0px;
+ left: 300px;
+ width: 200px;
+ height: 200px;
+
+ border: none;
+ background-color: green;
+}
+</style>
+</head>
+<body>
+<div id="parent"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/1432553-1.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="utf-8">
+<title>Retained display list test</title>
+<style type="text/css">
+.back {
+ position: absolute;
+ left: 50px;
+ top: 50px;
+ height: 400px;
+ width: 400px;
+
+ background: white;
+}
+
+#parent {
+ position: fixed;
+ top: 0px;
+ left: 300px;
+ width: 200px;
+ height: 200px;
+
+ border: none;
+ background-color: green;
+}
+
+.translate {
+ transform: translateX(0px);
+}
+
+#child {
+ position: fixed;
+}
+
+.container {
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ width: 600px;
+ height: 600px;
+ z-index: 1;
+}
+</style>
+</head>
+<body>
+<div class="container">
+ <div class="back"></div>
+ <div id="parent">
+ <div id="child"></div>
+ </div>
+</div>
+
+<script type="text/javascript">
+function doTest() {
+ document.getElementById("parent").classList.add("translate");
+ document.documentElement.removeAttribute("class");
+}
+
+window.addEventListener("MozReftestInvalidate", doTest);
+
+// setTimeout(doTest, 1000);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/1432553-2-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="utf-8">
+<title>Retained display list test</title>
+<style type="text/css">
+#parent {
+ position: fixed;
+ top: 300px;
+ left: 300px;
+ width: 200px;
+ height: 200px;
+
+ border: none;
+ background-color: green;
+}
+</style>
+</head>
+<body>
+<div id="parent"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/1432553-2.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="utf-8">
+<title>Retained display list test</title>
+<style type="text/css">
+.back {
+ position: absolute;
+ left: 50px;
+ top: 50px;
+ height: 400px;
+ width: 400px;
+
+ background: white;
+}
+
+#parent {
+ position: fixed;
+ top: 300px;
+ left: 300px;
+ width: 200px;
+ height: 200px;
+
+ border: none;
+ background-color: green;
+}
+
+.translate {
+ transform: translateX(0px);
+}
+
+#child {
+ position: fixed;
+}
+
+.container {
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ width: 600px;
+ height: 600px;
+ z-index: 1;
+}
+</style>
+</head>
+<body>
+<div class="container">
+ <div class="back"></div>
+ <div id="parent">
+ <div id="child"></div>
+ </div>
+</div>
+
+<script type="text/javascript">
+function doTest() {
+ document.getElementById("parent").classList.add("translate");
+ document.documentElement.removeAttribute("class");
+}
+
+window.addEventListener("MozReftestInvalidate", doTest);
+
+// setTimeout(doTest, 1000);
+</script>
+</body>
+</html>
--- a/layout/reftests/display-list/reftest.list
+++ b/layout/reftests/display-list/reftest.list
@@ -12,8 +12,10 @@ skip-if(!retainedDisplayList) == retaine
== retained-dl-zindex-2.html retained-dl-zindex-2-ref.html
fuzzy(1,235200) == 1413073.html 1413073-ref.html
== 1416291.html 1416291-ref.html
== 1417601-1.html 1417601-1-ref.html
== 1418945-1.html 1418945-1-ref.html
skip-if(Android) == 1428993-1.html 1428993-1-ref.html
== 1428993-2.html 1428993-2-ref.html
needs-focus == 1429027-1.html 1429027-1-ref.html
+== 1432553-1.html 1432553-1-ref.html
+== 1432553-2.html 1432553-2-ref.html