Bug 1468124 - Don't calculate overflow area if there is any frames in preserve-3d context. r?mattwoodrow draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Tue, 19 Jun 2018 14:49:47 +0900
changeset 808297 b04e22f98733dc07b6ebea821f4b18cdbee0ee0a
parent 808264 1e2c9151a09e43613a79daa8d4a94dc3e314020c
push id113349
push userhikezoe@mozilla.com
push dateTue, 19 Jun 2018 05:51:50 +0000
reviewersmattwoodrow
bugs1468124
milestone62.0a1
Bug 1468124 - Don't calculate overflow area if there is any frames in preserve-3d context. r?mattwoodrow MozReview-Commit-ID: 2Ts3MzdouB7
layout/painting/RetainedDisplayListBuilder.cpp
layout/painting/crashtests/1468124-1.html
layout/painting/crashtests/crashtests.list
--- a/layout/painting/RetainedDisplayListBuilder.cpp
+++ b/layout/painting/RetainedDisplayListBuilder.cpp
@@ -665,53 +665,36 @@ GetFirstDisplayItemWithChildren(nsIFrame
   for (nsDisplayItem* i : *items) {
     if (i->GetChildren()) {
       return i;
     }
   }
   return nullptr;
 }
 
-static nsIFrame*
-HandlePreserve3D(nsIFrame* aFrame, nsRect& aOverflow)
+static bool
+IsInPreserve3DContext(const nsIFrame* aFrame)
 {
-  // Preserve-3d frames don't have valid overflow areas, and they might
-  // have singular transforms (despite still being visible when combined
-  // with their ancestors). If we're at one, jump up to the root of the
-  // preserve-3d context and use the whole overflow area.
-  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;
+  return aFrame->Extend3DContext() ||
+         aFrame->Combines3DTransformWithAncestors();
 }
 
-static void
+static bool
 ProcessFrameInternal(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder,
                      AnimatedGeometryRoot** aAGR, nsRect& aOverflow,
                      nsIFrame* aStopAtFrame, nsTArray<nsIFrame*>& aOutFramesWithProps,
                      const bool aStopAtStackingContext)
 {
   nsIFrame* currentFrame = aFrame;
 
   while (currentFrame != aStopAtFrame) {
     CRR_LOG("currentFrame: %p (placeholder=%d), aOverflow: %d %d %d %d\n",
              currentFrame, !aStopAtStackingContext,
              aOverflow.x, aOverflow.y, aOverflow.width, aOverflow.height);
 
-    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 = currentFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)
                           ? currentFrame->GetPlaceholderFrame()
                           : nullptr;
 
@@ -734,26 +717,33 @@ ProcessFrameInternal(nsIFrame* aFrame, n
 
       // 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(currentFrame->GetParent(),
                                                       placeholder->GetParent());
 
-      ProcessFrameInternal(placeholder, aBuilder, &dummyAGR, placeholderOverflow,
-                           ancestor, aOutFramesWithProps, false);
+      if (!ProcessFrameInternal(placeholder, aBuilder, &dummyAGR,
+                                placeholderOverflow, ancestor,
+                                aOutFramesWithProps, false)) {
+        return 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);
+    if (IsInPreserve3DContext(currentFrame)) {
+      return false;
+    }
+
     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 =
@@ -851,16 +841,17 @@ ProcessFrameInternal(nsIFrame* aFrame, n
 
       // Don't contribute to the root dirty area at all.
       aOverflow.SetEmpty();
       *aAGR = nullptr;
 
       break;
     }
   }
+  return true;
 }
 
 bool
 RetainedDisplayListBuilder::ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder,
              nsIFrame* aStopAtFrame, nsTArray<nsIFrame*>& aOutFramesWithProps,
              const bool aStopAtStackingContext,
              nsRect* aOutDirty,
              AnimatedGeometryRoot** aOutModifiedAGR)
@@ -891,18 +882,20 @@ RetainedDisplayListBuilder::ProcessFrame
 
   // If the modified frame is also a caret frame, include the caret area.
   // This is needed because some frames (for example text frames without text)
   // might have an empty overflow rect.
   if (aFrame == aBuilder.GetCaretFrame()) {
     overflow.UnionRect(overflow, aBuilder.GetCaretRect());
   }
 
-  ProcessFrameInternal(aFrame, aBuilder, &agr, overflow, aStopAtFrame,
-                       aOutFramesWithProps, aStopAtStackingContext);
+  if (!ProcessFrameInternal(aFrame, aBuilder, &agr, overflow, aStopAtFrame,
+                            aOutFramesWithProps, aStopAtStackingContext)) {
+    return false;
+  }
 
   if (!overflow.IsEmpty()) {
     aOutDirty->UnionRect(*aOutDirty, overflow);
     CRR_LOG("Adding area to root draw area: %d %d %d %d\n",
             overflow.x, overflow.y, overflow.width, overflow.height);
 
     // If we get changed frames from multiple AGRS, then just give up as it gets really complex to
     // track which items would need to be marked in MarkFramesForDifferentAGR.
new file mode 100644
--- /dev/null
+++ b/layout/painting/crashtests/1468124-1.html
@@ -0,0 +1,27 @@
+<html class="reftest-wait">
+<style>
+:not(feFuncB) {
+  position: fixed;
+}
+a:last-child {
+  -webkit-transform-style: preserve-3d;
+}
+* {
+  -webkit-backface-visibility: hidden;
+</style>
+<script>
+window.requestIdleCallback(function() {
+  document.documentElement.getBoundingClientRect();
+});
+function go() {
+  var c = document.createElement("a")
+  c.text = "-";
+  try { c.replaceChild(b, c.childNodes[0]); } catch(e) { }
+  try { document.body.appendChild(c); } catch(e) { }
+  document.documentElement.className = "";
+}
+</script>
+<body onload=go()>
+<d id="b">|
+<audio controls="">
+</html>
--- a/layout/painting/crashtests/crashtests.list
+++ b/layout/painting/crashtests/crashtests.list
@@ -7,9 +7,9 @@ load 1418177-1.html
 load 1418722-1.html
 load 1419917.html
 load 1425271-1.html
 load 1428906-1.html
 skip-if(webrender) load 1430589-1.html # bug 1421825 for webrender
 load 1454105-1.html
 load 1455944-1.html
 load 1465305-1.html
-
+load 1468124-1.html