Bug 1468124 - Don't calculate overflow area if there is any frames in preserve-3d context. r=mattwoodrow
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Tue, 19 Jun 2018 14:49:47 +0900
changeset 479671 245c6fe9938cd895ea56194c34d0bde72bfd995d
parent 479670 ef06853a18a59002945d9ebb29944296f9da2dcc
child 479672 9941588e63261810b56446113d8fe9c07116b185
push id1757
push userffxbld-merge
push dateFri, 24 Aug 2018 17:02:43 +0000
treeherdermozilla-release@736023aebdb1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1468124
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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