Bug 1298218 - Add a workaround for root scroll frame container layer scrolling. r?tnikkel draft
authorMarkus Stange <mstange@themasta.com>
Fri, 27 Jan 2017 17:38:55 +0100
changeset 469210 e1e215c6bda146c6af317992453883e70316aacd
parent 469209 a36f0f41c2ad9dd1729ec368a0b03ad4b31ff865
child 470448 a621f2dd010c13e80a4515f36579e8ece50277d9
push id43652
push userbmo:mstange@themasta.com
push dateWed, 01 Feb 2017 21:18:30 +0000
reviewerstnikkel
bugs1298218
milestone54.0a1
Bug 1298218 - Add a workaround for root scroll frame container layer scrolling. r?tnikkel Root frame containers really throw a wrench into the whole system. MozReview-Commit-ID: 9066vWMYxxr
layout/generic/nsGfxScrollFrame.cpp
layout/painting/FrameLayerBuilder.cpp
layout/painting/nsDisplayList.cpp
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3287,37 +3287,49 @@ ScrollFrameHelper::BuildDisplayList(nsDi
   // they're not scrolled with the rest of the document. But when both
   // scrollbars are visible, the layer's visible rectangle would be the size
   // of the viewport, so most layer implementations would create a layer buffer
   // that's much larger than necessary. Creating independent layers for each
   // scrollbar works around the problem.
   bool createLayersForScrollbars = mIsRoot &&
     mOuter->PresContext()->IsRootContentDocument();
 
+  nsIScrollableFrame* sf = do_QueryFrame(mOuter);
+  MOZ_ASSERT(sf);
+
   if (ignoringThisScrollFrame) {
     // Root scrollframes have FrameMetrics and clipping on their container
     // layers, so don't apply clipping again.
     mAddClipRectToLayer = false;
 
     // If we are a root scroll frame that has a display port we want to add
     // scrollbars, they will be children of the scrollable layer, but they get
     // adjusted by the APZC automatically.
     bool addScrollBars = mIsRoot && usingDisplayPort && !aBuilder->IsForEventDelivery();
 
     if (addScrollBars) {
       // Add classic scrollbars.
       AppendScrollPartsTo(aBuilder, aDirtyRect, aLists,
                           createLayersForScrollbars, false);
     }
 
-    // Don't clip the scrolled child, and don't paint scrollbars/scrollcorner.
-    // The scrolled frame shouldn't have its own background/border, so we
-    // can just pass aLists directly.
-    mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame,
-                                     dirtyRect, aLists);
+    {
+      nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
+      if (aBuilder->IsPaintingToWindow() &&
+          gfxPrefs::LayoutUseContainersForRootFrames() && mIsRoot) {
+        asrSetter.EnterScrollFrame(sf);
+        aBuilder->SetActiveScrolledRootForRootScrollframe(aBuilder->CurrentActiveScrolledRoot());
+      }
+
+      // Don't clip the scrolled child, and don't paint scrollbars/scrollcorner.
+      // The scrolled frame shouldn't have its own background/border, so we
+      // can just pass aLists directly.
+      mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame,
+                                       dirtyRect, aLists);
+    }
 
     if (addScrollBars) {
       // Add overlay scrollbars.
       AppendScrollPartsTo(aBuilder, aDirtyRect, aLists,
                           createLayersForScrollbars, true);
     }
 
     return;
@@ -3392,19 +3404,16 @@ ScrollFrameHelper::BuildDisplayList(nsDi
         // caret height on the top, and its full width on the right.
         nsRect inflatedClip = clipRect;
         inflatedClip.Inflate(nsMargin(caretRect.height / 2, caretRect.width, 0, 0));
         contentBoxClip = Some(inflatedClip);
       }
     }
   }
 
-  nsIScrollableFrame* sf = do_QueryFrame(mOuter);
-  MOZ_ASSERT(sf);
-
   nsDisplayListCollection scrolledContent;
   {
     // Note that setting the current scroll parent id here means that positioned children
     // of this scroll info layer will pick up the scroll info layer as their scroll handoff
     // parent. This is intentional because that is what happens for positioned children
     // of scroll layers, and we want to maintain consistent behaviour between scroll layers
     // and scroll info layers.
     nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
@@ -3444,16 +3453,20 @@ ScrollFrameHelper::BuildDisplayList(nsDi
       }
     }
 
     nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
     if (mWillBuildScrollableLayer) {
       asrSetter.EnterScrollFrame(sf);
     }
 
+    if (mIsScrollableLayerInRootContainer) {
+      aBuilder->SetActiveScrolledRootForRootScrollframe(aBuilder->CurrentActiveScrolledRoot());
+    }
+
     {
       // Clip our contents to the unsnapped scrolled rect. This makes sure that
       // we don't have display items over the subpixel seam at the edge of the
       // scrolled area.
       DisplayListClipState::AutoSaveRestore scrolledRectClipState(aBuilder);
       nsRect scrolledRectClip =
         GetUnsnappedScrolledRectInternal(mScrolledFrame->GetScrollableOverflowRect(),
                                          mScrollPort.Size()) + mScrolledFrame->GetPosition();
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -4079,17 +4079,18 @@ ContainerState::ProcessDisplayItems(nsDi
       bounds = item->GetBounds(mBuilder, &dummy);
       if (itemClip.HasClip()) {
         bounds.IntersectRect(bounds, itemClip.GetClipRect());
       }
     }
     if (!bounds.IsEmpty()) {
       if (itemASR != mContainerASR) {
         const DisplayItemClip* clip = DisplayItemClipChain::ClipForASR(item->GetClipChain(), mContainerASR);
-        MOZ_ASSERT(clip, "the item should have finite bounds with respect to mContainerASR.");
+        MOZ_ASSERT(clip || gfxPrefs::LayoutUseContainersForRootFrames(),
+                   "the item should have finite bounds with respect to mContainerASR.");
         if (clip) {
           bounds = clip->GetClipRect();
         }
       }
     }
     ((nsRect&)mAccumulatedChildBounds).UnionRect(mAccumulatedChildBounds, bounds);
 #endif
 
@@ -5569,16 +5570,22 @@ FrameLayerBuilder::BuildContainerLayerFo
     NS_ASSERTION(aChildren->IsEmpty(), "Should have no children");
     return containerLayer.forget();
   }
 
   const ActiveScrolledRoot* containerASR = aContainerItem ? aContainerItem->GetActiveScrolledRoot() : nullptr;
   const ActiveScrolledRoot* containerScrollMetadataASR = aParameters.mScrollMetadataASR;
   const ActiveScrolledRoot* containerCompositorASR = aParameters.mCompositorASR;
 
+  if (!aContainerItem && gfxPrefs::LayoutUseContainersForRootFrames()) {
+    containerASR = aBuilder->ActiveScrolledRootForRootScrollframe();
+    containerScrollMetadataASR = containerASR;
+    containerCompositorASR = containerASR;
+  }
+
   ContainerLayerParameters scaleParameters;
   nsRect bounds = aChildren->GetClippedBoundsWithRespectToASR(aBuilder, containerASR);
   nsRect childrenVisible =
       aContainerItem ? aContainerItem->GetVisibleRectForChildren() :
           aContainerFrame->GetVisualOverflowRectRelativeToSelf();
   if (!ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame,
                                   aContainerItem,
                                   bounds.Intersect(childrenVisible),
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -860,16 +860,17 @@ nsDisplayListBuilder::nsDisplayListBuild
       mCurrentFrame(aReferenceFrame),
       mCurrentReferenceFrame(aReferenceFrame),
       mCurrentAGR(&mRootAGR),
       mRootAGR(aReferenceFrame, nullptr),
       mUsedAGRBudget(0),
       mDirtyRect(-1,-1,-1,-1),
       mGlassDisplayItem(nullptr),
       mScrollInfoItemsForHoisting(nullptr),
+      mActiveScrolledRootForRootScrollframe(nullptr),
       mMode(aMode),
       mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
       mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID),
       mCurrentScrollbarFlags(0),
       mPerspectiveItemIndex(0),
       mSVGEffectsBuildingDepth(0),
       mContainsBlendMode(false),
       mIsBuildingScrollbar(false),
@@ -1837,17 +1838,22 @@ nsDisplayList::GetBounds(nsDisplayListBu
 nsRect
 nsDisplayList::GetClippedBoundsWithRespectToASR(nsDisplayListBuilder* aBuilder,
                                                 const ActiveScrolledRoot* aASR) const {
   nsRect bounds;
   for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
     nsRect r = i->GetClippedBounds(aBuilder);
     if (aASR != i->GetActiveScrolledRoot() && !r.IsEmpty()) {
       const DisplayItemClip* clip = DisplayItemClipChain::ClipForASR(i->GetClipChain(), aASR);
-      MOZ_ASSERT(clip, "Need to be clipped wrt aASR. Do not call this function with an ASR that our child items don't have finite bounds wrt.");
+#ifdef DEBUG
+      if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
+        MOZ_ASSERT(clip,
+                   "Need to be clipped wrt aASR. Do not call this function with an ASR that our child items don't have finite bounds wrt.");
+      }
+#endif
       if (clip) {
         r = clip->GetClipRect();
       }
     }
     bounds.UnionRect(bounds, r);
   }
   return bounds;
 }
@@ -1863,17 +1869,21 @@ nsDisplayList::GetVisibleRect() const {
 
 bool
 nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
                                         nsRegion* aVisibleRegion) {
   PROFILER_LABEL("nsDisplayList", "ComputeVisibilityForRoot",
     js::ProfileEntry::Category::GRAPHICS);
 
   nsRegion r;
-  r.And(*aVisibleRegion, GetClippedBoundsWithRespectToASR(aBuilder, nullptr));
+  const ActiveScrolledRoot* rootASR = nullptr;
+  if (gfxPrefs::LayoutUseContainersForRootFrames()) {
+    rootASR = aBuilder->ActiveScrolledRootForRootScrollframe();
+  }
+  r.And(*aVisibleRegion, GetClippedBoundsWithRespectToASR(aBuilder, rootASR));
   return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds());
 }
 
 static nsRegion
 TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
 {
   bool snap;
   nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);