Bug 1062100 - Part 2: Assign clip rects to non-async-scrollable scrolled layers, and hide clipped layers if some non-moving layer covers their entire clip rect. r=mattwoodrow, a=lmandel
authorRobert O'Callahan <robert@ocallahan.org>
Sat, 06 Sep 2014 16:16:33 +1200
changeset 218363 231126bd4179a1ba74084c1adf459ed4ee4fe5fc
parent 218362 422d79a278be1ae0573ebcba29f9cdcadada3b3d
child 218364 d261f0165d94ae39023d71d7399635d82be97ebf
push id7100
push userryanvm@gmail.com
push dateSat, 11 Oct 2014 22:05:28 +0000
treeherdermozilla-aurora@e96a7a4f3bbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow, lmandel
bugs1062100
milestone34.0a2
Bug 1062100 - Part 2: Assign clip rects to non-async-scrollable scrolled layers, and hide clipped layers if some non-moving layer covers their entire clip rect. r=mattwoodrow, a=lmandel
layout/base/FrameLayerBuilder.cpp
layout/generic/nsGfxScrollFrame.cpp
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -579,24 +579,26 @@ class ContainerState {
 public:
   ContainerState(nsDisplayListBuilder* aBuilder,
                  LayerManager* aManager,
                  FrameLayerBuilder* aLayerBuilder,
                  nsIFrame* aContainerFrame,
                  nsDisplayItem* aContainerItem,
                  const nsRect& aContainerBounds,
                  ContainerLayer* aContainerLayer,
-                 const ContainerLayerParameters& aParameters) :
+                 const ContainerLayerParameters& aParameters,
+                 bool aFlattenToSingleLayer) :
     mBuilder(aBuilder), mManager(aManager),
     mLayerBuilder(aLayerBuilder),
     mContainerFrame(aContainerFrame),
     mContainerLayer(aContainerLayer),
     mContainerBounds(aContainerBounds),
     mParameters(aParameters),
-    mNextFreeRecycledThebesLayer(0)
+    mNextFreeRecycledThebesLayer(0),
+    mFlattenToSingleLayer(aFlattenToSingleLayer)
   {
     nsPresContext* presContext = aContainerFrame->PresContext();
     mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
     mContainerReferenceFrame =
       const_cast<nsIFrame*>(aContainerItem ? aContainerItem->ReferenceFrameForChildren() :
                                              mBuilder->FindReferenceFrameFor(mContainerFrame));
     mContainerAnimatedGeometryRoot = aContainerItem
       ? nsLayoutUtils::GetAnimatedGeometryRootFor(aContainerItem, aBuilder, aManager)
@@ -608,25 +610,21 @@ public:
     // When AllowResidualTranslation is false, display items will be drawn
     // scaled with a translation by integer pixels, so we know how the snapping
     // will work.
     mSnappingEnabled = aManager->IsSnappingEffectiveTransforms() &&
       !mParameters.AllowResidualTranslation();
     CollectOldLayers();
   }
 
-  enum ProcessDisplayItemsFlags {
-    NO_COMPONENT_ALPHA = 0x01,
-  };
-
   /**
    * This is the method that actually walks a display list and builds
    * the child layers.
    */
-  void ProcessDisplayItems(nsDisplayList* aList, uint32_t aFlags);
+  void ProcessDisplayItems(nsDisplayList* aList);
   /**
    * This finalizes all the open ThebesLayers by popping every element off
    * mThebesLayerDataStack, then sets the children of the container layer
    * to be all the layers in mNewChildLayers in that order and removes any
    * layers as children of the container that aren't in mNewChildLayers.
    * @param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA,
    * set *aTextContentFlags to CONTENT_COMPONENT_ALPHA
    */
@@ -886,16 +884,17 @@ protected:
   typedef nsAutoTArray<NewLayerEntry,1> AutoLayersArray;
   AutoLayersArray                  mNewChildLayers;
   nsTArray<nsRefPtr<ThebesLayer> > mRecycledThebesLayers;
   nsDataHashtable<nsPtrHashKey<Layer>, nsRefPtr<ImageLayer> >
     mRecycledMaskImageLayers;
   uint32_t                         mNextFreeRecycledThebesLayer;
   nscoord                          mAppUnitsPerDevPixel;
   bool                             mSnappingEnabled;
+  bool                             mFlattenToSingleLayer;
 };
 
 class ThebesDisplayItemLayerUserData : public LayerUserData
 {
 public:
   ThebesDisplayItemLayerUserData() :
     mMaskClipCount(0),
     mForcedBackgroundColor(NS_RGBA(0,0,0,0)),
@@ -2728,29 +2727,28 @@ ContainerState::ComputeOpaqueRect(nsDisp
  * create a mask layer to do any rounded rect clipping.
  * (ThebesLayers don't need a clip rect on the layer, we clip the items
  * individually when we draw them.)
  * We set the visible rect for all layers, although the actual setting
  * of visible rects for some ThebesLayers is deferred until the calling
  * of ContainerState::Finish.
  */
 void
-ContainerState::ProcessDisplayItems(nsDisplayList* aList,
-                                    uint32_t aFlags)
+ContainerState::ProcessDisplayItems(nsDisplayList* aList)
 {
   PROFILER_LABEL("ContainerState", "ProcessDisplayItems",
     js::ProfileEntry::Category::GRAPHICS);
 
   const nsIFrame* lastAnimatedGeometryRoot = mContainerReferenceFrame;
   nsPoint topLeft(0,0);
 
   // When NO_COMPONENT_ALPHA is set, items will be flattened into a single
   // layer, so we need to choose which active scrolled root to use for all
   // items.
-  if (aFlags & NO_COMPONENT_ALPHA) {
+  if (mFlattenToSingleLayer) {
     if (ChooseAnimatedGeometryRoot(*aList, &lastAnimatedGeometryRoot)) {
       topLeft = lastAnimatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame);
     }
   }
 
   int32_t maxLayers = nsDisplayItem::MaxActiveLayers();
   int layerCount = 0;
 
@@ -2821,17 +2819,17 @@ ContainerState::ProcessDisplayItems(nsDi
     LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
     if (layerState == LAYER_INACTIVE &&
         nsDisplayItem::ForceActiveLayers()) {
       layerState = LAYER_ACTIVE;
     }
 
     bool forceInactive;
     const nsIFrame* animatedGeometryRoot;
-    if (aFlags & NO_COMPONENT_ALPHA) {
+    if (mFlattenToSingleLayer) {
       forceInactive = true;
       animatedGeometryRoot = lastAnimatedGeometryRoot;
     } else {
       forceInactive = false;
       if (mManager->IsWidgetLayerManager()) {
         animatedGeometryRoot = nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder, mManager);
       } else {
         // For inactive layer subtrees, splitting content into ThebesLayers
@@ -3468,16 +3466,22 @@ FindOpaqueRegionEntry(nsTArray<OpaqueReg
     }
   }
   return nullptr;
 }
 
 void
 ContainerState::SetupScrollingMetadata(NewLayerEntry* aEntry)
 {
+  if (mFlattenToSingleLayer) {
+    // animated geometry roots are forced to all match, so we can't
+    // use them and we don't get async scrolling.
+    return;
+  }
+
   nsAutoTArray<FrameMetrics,2> metricsArray;
   if (aEntry->mBaseFrameMetrics) {
     metricsArray.AppendElement(*aEntry->mBaseFrameMetrics);
   }
   uint32_t baseLength = metricsArray.Length();
 
   nsIntRect tmpClipRect;
   const nsIntRect* layerClip = aEntry->mLayer->GetClipRect();
@@ -3537,25 +3541,32 @@ ContainerState::PostprocessRetainedLayer
     NewLayerEntry* e = &mNewChildLayers.ElementAt(i);
     if (!e->mLayer) {
       continue;
     }
 
     OpaqueRegionEntry* data = FindOpaqueRegionEntry(opaqueRegions,
         e->mAnimatedGeometryRoot, e->mFixedPosFrameForLayerData);
 
+    SetupScrollingMetadata(e);
+
     if (hideAll) {
       e->mVisibleRegion.SetEmpty();
-    } else if (data) {
-      e->mVisibleRegion.Sub(e->mVisibleRegion, data->mOpaqueRegion);
+    } else {
+      const nsIntRect* clipRect = e->mLayer->GetClipRect();
+      if (clipRect && opaqueRegionForContainer >= 0 &&
+          opaqueRegions[opaqueRegionForContainer].mOpaqueRegion.Contains(*clipRect)) {
+        e->mVisibleRegion.SetEmpty();
+      } else if (data) {
+        e->mVisibleRegion.Sub(e->mVisibleRegion, data->mOpaqueRegion);
+      }
     }
 
     SetOuterVisibleRegionForLayer(e->mLayer, e->mVisibleRegion,
       e->mLayerContentsVisibleRect.width >= 0 ? &e->mLayerContentsVisibleRect : nullptr);
-    SetupScrollingMetadata(e);
 
     if (!e->mOpaqueRegion.IsEmpty()) {
       const nsIFrame* animatedGeometryRootToCover = e->mAnimatedGeometryRoot;
       if (e->mOpaqueForAnimatedGeometryRootParent &&
           nsLayoutUtils::GetAnimatedGeometryRootForFrame(e->mAnimatedGeometryRoot->GetParent(),
                                                          mContainerAnimatedGeometryRoot)
             == mContainerAnimatedGeometryRoot) {
         animatedGeometryRootToCover = mContainerAnimatedGeometryRoot;
@@ -3960,47 +3971,47 @@ FrameLayerBuilder::BuildContainerLayerFo
     }
   }
 
   LayerManagerData* data = static_cast<LayerManagerData*>
     (aManager->GetUserData(&gLayerManagerUserData));
 
   nsIntRect pixBounds;
   nscoord appUnitsPerDevPixel;
-  uint32_t stateFlags = 0;
+  bool flattenToSingleLayer = false;
   if ((aContainerFrame->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) &&
       mRetainingManager && mRetainingManager->ShouldAvoidComponentAlphaLayers()) {
-    stateFlags = ContainerState::NO_COMPONENT_ALPHA;
+    flattenToSingleLayer = true;
   }
   uint32_t flags;
   while (true) {
     ContainerState state(aBuilder, aManager, aManager->GetLayerBuilder(),
                          aContainerFrame, aContainerItem, bounds,
-                         containerLayer, scaleParameters);
-
-    state.ProcessDisplayItems(aChildren, stateFlags);
+                         containerLayer, scaleParameters, flattenToSingleLayer);
+
+    state.ProcessDisplayItems(aChildren);
 
     // Set CONTENT_COMPONENT_ALPHA if any of our children have it.
     // This is suboptimal ... a child could have text that's over transparent
     // pixels in its own layer, but over opaque parts of previous siblings.
     bool hasComponentAlphaChildren = false;
     pixBounds = state.ScaleToOutsidePixels(bounds, false);
     appUnitsPerDevPixel = state.GetAppUnitsPerDevPixel();
     state.Finish(&flags, data, pixBounds, aChildren, hasComponentAlphaChildren);
 
     if (hasComponentAlphaChildren &&
         mRetainingManager &&
         mRetainingManager->ShouldAvoidComponentAlphaLayers() &&
         containerLayer->HasMultipleChildren() &&
-        !stateFlags) {
+        !flattenToSingleLayer) {
       // Since we don't want any component alpha layers on BasicLayers, we repeat
       // the layer building process with this explicitely forced off.
       // We restore the previous FrameLayerBuilder state since the first set
       // of layer building will have changed it.
-      stateFlags = ContainerState::NO_COMPONENT_ALPHA;
+      flattenToSingleLayer = true;
       data->mDisplayItems.EnumerateEntries(RestoreDisplayItemData,
                                            &mContainerLayerGeneration);
       mThebesLayerItems.EnumerateEntries(RestoreThebesLayerItemEntries,
                                          &mContainerLayerGeneration);
       aContainerFrame->AddStateBits(NS_FRAME_NO_COMPONENT_ALPHA);
       continue;
     }
     break;
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3023,28 +3023,28 @@ ScrollFrameHelper::BuildDisplayList(nsDi
 
 void
 ScrollFrameHelper::ComputeFrameMetrics(Layer* aLayer,
                                        nsIFrame* aContainerReferenceFrame,
                                        const ContainerLayerParameters& aParameters,
                                        nsRect* aClipRect,
                                        nsTArray<FrameMetrics>* aOutput) const
 {
+  nsRect viewport = mScrollPort +
+    mOuter->GetOffsetToCrossDoc(aContainerReferenceFrame);
+  if (!(mIsRoot && mOuter->PresContext()->PresShell()->GetIsViewportOverridden())) {
+    *aClipRect = viewport;
+  }
+
   if (!mShouldBuildScrollableLayer || BuildScrollContainerLayers()) {
     return;
   }
 
   MOZ_ASSERT(mScrolledFrame->GetContent());
 
-  nsRect viewport = mScrollPort +
-    mOuter->GetOffsetToCrossDoc(aContainerReferenceFrame);
-
-  if (!(mIsRoot && mOuter->PresContext()->PresShell()->GetIsViewportOverridden())) {
-    *aClipRect = viewport;
-  }
   *aOutput->AppendElement() =
       nsDisplayScrollLayer::ComputeFrameMetrics(mScrolledFrame, mOuter,
         aContainerReferenceFrame, aLayer, mScrollParentID,
         viewport, false, false, aParameters);
 }
 
 bool
 ScrollFrameHelper::IsRectNearlyVisible(const nsRect& aRect) const