Bug 1432553 - Fix OOF frame overflow coordinate space draft
authorMiko Mynttinen <mikokm@gmail.com>
Tue, 23 Jan 2018 20:11:34 +0100
changeset 737850 6b31d037ccb18b837baea498ad1517fcaee4215b
parent 724404 32b850fa28ae1c29039cb7ddcdfd71b324762c05
push id96781
push userbmo:mikokm@gmail.com
push dateThu, 25 Jan 2018 08:02:29 +0000
bugs1432553
milestone60.0a1
Bug 1432553 - Fix OOF frame overflow coordinate space MozReview-Commit-ID: 3VTyAAUM3VR
layout/painting/RetainedDisplayListBuilder.cpp
layout/reftests/display-list/1432553-1-ref.html
layout/reftests/display-list/1432553-1.html
layout/reftests/display-list/1432553-2-ref.html
layout/reftests/display-list/1432553-2.html
layout/reftests/display-list/reftest.list
--- 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,
-                                                           &currentFrame);
-    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,
+                                                           &currentFrame);
+    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