Bug 1359584 - Part 4: Refactor FrameLayerBuilder::ProcessDisplayItems() to be recursive r=mstange
authorMiko Mynttinen <mikokm@gmail.com>
Fri, 25 Aug 2017 12:34:40 +0200
changeset 430238 575c0a07f75d96d5ca64202bffdc351601a889ae
parent 430237 0b9b457392d5381a1be4ec8ac2200b4a8b50f8cb
child 430239 7bdf8f58bb8b0d18ea7a20bd58a1c26aed07f58d
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1359584
milestone57.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 1359584 - Part 4: Refactor FrameLayerBuilder::ProcessDisplayItems() to be recursive r=mstange MozReview-Commit-ID: JaC3SFGcpzK
layout/painting/FrameLayerBuilder.cpp
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -1101,16 +1101,23 @@ public:
     CollectOldLayers();
   }
 
   /**
    * This is the method that actually walks a display list and builds
    * the child layers.
    */
   void ProcessDisplayItems(nsDisplayList* aList);
+  void ProcessDisplayItems(nsDisplayList* aList,
+                           AnimatedGeometryRoot* aLastAnimatedGeometryRoot,
+                           const ActiveScrolledRoot* aLastASR,
+                           const nsPoint& aLastAGRTopLeft,
+                           nsPoint& aTopLeft,
+                           int32_t aMaxLayers,
+                           int& aLayerCount);
   /**
    * This finalizes all the open PaintedLayers by popping every element off
    * mPaintedLayerDataStack, 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
    */
@@ -3989,28 +3996,41 @@ ContainerState::ProcessDisplayItems(nsDi
     if (ChooseAnimatedGeometryRoot(*aList, &lastAnimatedGeometryRoot, &lastASR)) {
       lastAGRTopLeft = (*lastAnimatedGeometryRoot)->GetOffsetToCrossDoc(mContainerReferenceFrame);
     }
   }
 
   int32_t maxLayers = gfxPrefs::MaxActiveLayers();
   int layerCount = 0;
 
-  nsDisplayList savedItems;
-  nsDisplayItem* item;
-  while ((item = aList->RemoveBottom()) != nullptr) {
+  ProcessDisplayItems(aList, lastAnimatedGeometryRoot, lastASR,
+                      lastAGRTopLeft, topLeft, maxLayers, layerCount);
+}
+
+void
+ContainerState::ProcessDisplayItems(nsDisplayList* aList,
+                                    AnimatedGeometryRoot* aLastAnimatedGeometryRoot,
+                                    const ActiveScrolledRoot* aLastASR,
+                                    const nsPoint& aLastAGRTopLeft,
+                                    nsPoint& aTopLeft,
+                                    int32_t aMaxLayers,
+                                    int& aLayerCount)
+{
+  for (nsDisplayItem* i = aList->GetBottom(); i; i = i->GetAbove()) {
+    nsDisplayItem* item = i;
+    MOZ_ASSERT(item);
+
     DisplayItemType itemType = item->GetType();
 
     // If the item is a event regions item, but is empty (has no regions in it)
     // then we should just throw it out
     if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
       nsDisplayLayerEventRegions* eventRegions =
         static_cast<nsDisplayLayerEventRegions*>(item);
       if (eventRegions->IsEmpty()) {
-        item->Destroy(mBuilder);
         continue;
       }
     }
 
     // Peek ahead to the next item and try merging with it or swapping with it
     // if necessary.
     nsDisplayItem* aboveItem;
     while ((aboveItem = aList->GetBottom()) != nullptr) {
@@ -4019,25 +4039,26 @@ ContainerState::ProcessDisplayItems(nsDi
         item->Destroy(mBuilder);
         item = aboveItem;
         itemType = item->GetType();
       } else {
         break;
       }
     }
 
-    nsDisplayList* itemSameCoordinateSystemChildren
-      = item->GetSameCoordinateSystemChildren();
+    nsDisplayList* childItems = item->GetSameCoordinateSystemChildren();
+
     if (item->ShouldFlattenAway(mBuilder)) {
-      aList->AppendToBottom(itemSameCoordinateSystemChildren);
-      item->Destroy(mBuilder);
+      MOZ_ASSERT(childItems);
+      ProcessDisplayItems(childItems, aLastAnimatedGeometryRoot, aLastASR,
+                          aLastAGRTopLeft, aTopLeft, aMaxLayers, aLayerCount);
       continue;
     }
 
-    savedItems.AppendToTop(item);
+    MOZ_ASSERT(item->GetType() != DisplayItemType::TYPE_WRAP_LIST);
 
     NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item),
       "items in a container layer should all have the same app units per dev pixel");
 
     if (mBuilder->NeedToForceTransparentSurfaceForItem(item)) {
       aList->SetNeedsTransparentSurface();
     }
 
@@ -4054,19 +4075,19 @@ ContainerState::ProcessDisplayItems(nsDi
     }
 
     bool forceInactive;
     AnimatedGeometryRoot* animatedGeometryRoot;
     const ActiveScrolledRoot* itemASR = nullptr;
     const DisplayItemClipChain* layerClipChain = nullptr;
     if (mFlattenToSingleLayer && layerState != LAYER_ACTIVE_FORCE) {
       forceInactive = true;
-      animatedGeometryRoot = lastAnimatedGeometryRoot;
-      itemASR = lastASR;
-      topLeft = lastAGRTopLeft;
+      animatedGeometryRoot = aLastAnimatedGeometryRoot;
+      itemASR = aLastASR;
+      aTopLeft = aLastAGRTopLeft;
       item->FuseClipChainUpTo(mBuilder, mContainerASR);
     } else {
       forceInactive = false;
       if (mManager->IsWidgetLayerManager()) {
         animatedGeometryRoot = item->GetAnimatedGeometryRoot();
         itemASR = item->GetActiveScrolledRoot();
         const DisplayItemClipChain* itemClipChain = item->GetClipChain();
         if (itemClipChain && itemClipChain->mASR == itemASR &&
@@ -4078,17 +4099,17 @@ ContainerState::ProcessDisplayItems(nsDi
       } else {
         // For inactive layer subtrees, splitting content into PaintedLayers
         // based on animated geometry roots is pointless. It's more efficient
         // to build the minimum number of layers.
         animatedGeometryRoot = mContainerAnimatedGeometryRoot;
         itemASR = mContainerASR;
         item->FuseClipChainUpTo(mBuilder, mContainerASR);
       }
-      topLeft = (*animatedGeometryRoot)->GetOffsetToCrossDoc(mContainerReferenceFrame);
+      aTopLeft = (*animatedGeometryRoot)->GetOffsetToCrossDoc(mContainerReferenceFrame);
     }
 
     const ActiveScrolledRoot* scrollMetadataASR =
         layerClipChain ? ActiveScrolledRoot::PickDescendant(itemASR, layerClipChain->mASR) : itemASR;
 
     bool snap;
     nsRect itemContent = item->GetBounds(mBuilder, &snap);
     if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
@@ -4135,28 +4156,28 @@ ContainerState::ProcessDisplayItems(nsDi
     // We haven't computed visibility at this point, so item->GetVisibleRect()
     // is just the dirty rect that item was initialized with. We intersect it
     // with the clipped item bounds to get a tighter visible rect.
     if (!prerenderedTransform) {
       itemVisibleRect = itemVisibleRect.Intersect(
         ScaleToOutsidePixels(item->GetVisibleRect(), false));
     }
 
-    if (maxLayers != -1 && layerCount >= maxLayers) {
+    if (aMaxLayers != -1 && aLayerCount >= aMaxLayers) {
       forceInactive = true;
     }
 
     // Assign the item to a layer
     if (layerState == LAYER_ACTIVE_FORCE ||
         (layerState == LAYER_INACTIVE && !mManager->IsWidgetLayerManager()) ||
         (!forceInactive &&
          (layerState == LAYER_ACTIVE_EMPTY ||
           layerState == LAYER_ACTIVE))) {
 
-      layerCount++;
+      aLayerCount++;
 
       // LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
       // We should never see an empty layer with any visible content!
       NS_ASSERTION(layerState != LAYER_ACTIVE_EMPTY ||
                    itemVisibleRect.IsEmpty(),
                    "State is LAYER_ACTIVE_EMPTY but visible rect is not.");
 
       // As long as the new layer isn't going to be a PaintedLayer,
@@ -4351,22 +4372,21 @@ ContainerState::ProcessDisplayItems(nsDi
       }
 
       if (item->GetType() == DisplayItemType::TYPE_MASK) {
         MOZ_ASSERT(itemClip.GetRoundedRectCount() == 0);
 
         nsDisplayMask* maskItem = static_cast<nsDisplayMask*>(item);
         SetupMaskLayerForCSSMask(ownLayer, maskItem);
 
-        nsDisplayItem* next = aList->GetBottom();
-        if (next && next->GetType() == DisplayItemType::TYPE_SCROLL_INFO_LAYER) {
+        if (i->GetAbove() &&
+            i->GetAbove()->GetType() == DisplayItemType::TYPE_SCROLL_INFO_LAYER) {
           // Since we do build a layer for mask, there is no need for this
           // scroll info layer anymore.
-          aList->RemoveBottom();
-          next->Destroy(mBuilder);
+          i = i->GetAbove();
         }
       }
 
       // Convert the visible rect to a region and give the item
       // a chance to try restrict it further.
       nsIntRegion itemVisibleRegion = itemVisibleRect;
       nsRegion tightBounds = item->GetTightBounds(mBuilder, &snap);
       if (!tightBounds.IsEmpty()) {
@@ -4465,17 +4485,17 @@ ContainerState::ProcessDisplayItems(nsDi
       mLayerBuilder->AddLayerDisplayItem(ownLayer, item, layerState, nullptr);
     } else {
       PaintedLayerData* paintedLayerData =
         mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, itemASR, layerClipChain,
                                                   itemVisibleRect,
                                                   item->Frame()->In3DContextAndBackfaceIsHidden(),
                                                   [&]() {
           return NewPaintedLayerData(item, animatedGeometryRoot, itemASR, layerClipChain, scrollMetadataASR,
-                                     topLeft);
+                                     aTopLeft);
         });
 
       if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
         nsDisplayLayerEventRegions* eventRegions =
             static_cast<nsDisplayLayerEventRegions*>(item);
         paintedLayerData->AccumulateEventRegions(this, eventRegions);
       } else {
         // check to see if the new item has rounded rect clips in common with
@@ -4483,35 +4503,32 @@ ContainerState::ProcessDisplayItems(nsDi
         if (mManager->IsWidgetLayerManager()) {
           paintedLayerData->UpdateCommonClipCount(itemClip);
         }
         paintedLayerData->Accumulate(this, item, itemVisibleRect, itemClip, layerState, aList);
 
         if (!paintedLayerData->mLayer) {
           // Try to recycle the old layer of this display item.
           RefPtr<PaintedLayer> layer =
-            AttemptToRecyclePaintedLayer(animatedGeometryRoot, item, topLeft);
+            AttemptToRecyclePaintedLayer(animatedGeometryRoot, item, aTopLeft);
           if (layer) {
             paintedLayerData->mLayer = layer;
 
             NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
                          "Layer already in list???");
             mNewChildLayers[paintedLayerData->mNewChildLayersIndex].mLayer = layer.forget();
           }
         }
       }
     }
 
-    if (itemSameCoordinateSystemChildren &&
-        itemSameCoordinateSystemChildren->NeedsTransparentSurface()) {
+    if (childItems && childItems->NeedsTransparentSurface()) {
       aList->SetNeedsTransparentSurface();
     }
   }
-
-  aList->AppendToTop(&savedItems);
 }
 
 void
 ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, PaintedLayer* aNewLayer)
 {
   NS_ASSERTION(aItem->GetPerFrameKey(),
                "Display items that render using Thebes must have a key");
   nsDisplayItemGeometry* oldGeometry = nullptr;