Bug 1384616 - Allow building a tree structure in WebRenderScrollData for layers-free transactions. r?jrmuizel draft
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 31 Jul 2017 15:27:29 -0400
changeset 618589 71373704ba37440599ed1ab6f66c37650ecb1873
parent 618588 d46ae36f80de189e92de13aac578a57fb6029c5f
child 618590 5cde2c8845f576e8a1ee2c3f8773eb123ac42541
push id71393
push userkgupta@mozilla.com
push dateMon, 31 Jul 2017 19:27:48 +0000
reviewersjrmuizel
bugs1384616
milestone56.0a1
Bug 1384616 - Allow building a tree structure in WebRenderScrollData for layers-free transactions. r?jrmuizel The three main changes in this patch are: (1) Move the code to emplace_back a new WebRenderLayerScrollData to after the display list recursion. This is necessary so that when we empty the temporary mLayerScrollData stack into the final mScrollData structure things end up in the right order. (2) Maintain a stack of ASRs as we recurse so that when we are building a given WebRenderLayerScrollData, we don't add scroll metadatas that are already present on its ancestors. (3) Compute the number of descendants created for each layer scroll data item and record it, so that we can properly reconstruct the shape of the tree. MozReview-Commit-ID: BSdX78AqBNZ
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderLayerManager.h
gfx/layers/wr/WebRenderScrollData.cpp
gfx/layers/wr/WebRenderScrollData.h
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -232,38 +232,61 @@ WebRenderLayerManager::CreateWebRenderCo
     if (item->ShouldFlattenAway(aDisplayListBuilder)) {
       aDisplayList->AppendToBottom(itemSameCoordinateSystemChildren);
       item->~nsDisplayItem();
       continue;
     }
 
     savedItems.AppendToTop(item);
 
+    bool forceNewLayerData = false;
+    size_t layerCountBeforeRecursing = mLayerScrollData.size();
     if (apzEnabled) {
       // For some types of display items we want to force a new
       // WebRenderLayerScrollData object, to ensure we preserve the APZ-relevant
       // data that is in the display item.
-      bool forceNewLayerData = item->UpdateScrollData(nullptr, nullptr);
+      forceNewLayerData = item->UpdateScrollData(nullptr, nullptr);
 
       // Anytime the ASR changes we also want to force a new layer data because
       // the stack of scroll metadata is going to be different for this
       // display item than previously, so we can't squash the display items
       // into the same "layer".
       const ActiveScrolledRoot* asr = item->GetActiveScrolledRoot();
-      if (forceNewLayerData || asr != lastAsr) {
+      if (asr != lastAsr) {
         lastAsr = asr;
-        mLayerScrollData.emplace_back();
-        mLayerScrollData.back().Initialize(mScrollData, item);
+        forceNewLayerData = true;
+      }
+
+      // If we're going to create a new layer data for this item, stash the
+      // ASR so that if we recurse into a sublist they will know where to stop
+      // walking up their ASR chain when building scroll metadata.
+      if (forceNewLayerData) {
+        mAsrStack.push_back(asr);
       }
     }
 
+    // Note: this call to CreateWebRenderCommands can recurse back into
+    // this function if the |item| is a wrapper for a sublist.
     if (!item->CreateWebRenderCommands(aBuilder, aSc, mParentCommands, this,
                                        aDisplayListBuilder)) {
       PushItemAsImage(item, aBuilder, aSc, aDisplayListBuilder);
     }
+
+    if (apzEnabled && forceNewLayerData) {
+      // Pop the thing we pushed before the recursion, so the topmost item on
+      // the stack is enclosing display item's ASR (or the stack is empty)
+      mAsrStack.pop_back();
+      const ActiveScrolledRoot* stopAtAsr =
+          mAsrStack.empty() ? nullptr : mAsrStack.back();
+
+      int32_t descendants = mLayerScrollData.size() - layerCountBeforeRecursing;
+
+      mLayerScrollData.emplace_back();
+      mLayerScrollData.back().Initialize(mScrollData, item, descendants, stopAtAsr);
+    }
   }
   aDisplayList->AppendToTop(&savedItems);
 }
 
 void
 WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
                                                   nsDisplayListBuilder* aDisplayListBuilder)
 {
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -19,16 +19,19 @@
 #include "mozilla/layers/WebRenderUserData.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "nsDisplayList.h"
 
 class nsIWidget;
 
 namespace mozilla {
+
+struct ActiveScrolledRoot;
+
 namespace layers {
 
 class CompositorBridgeChild;
 class KnowsCompositor;
 class PCompositorBridgeChild;
 class WebRenderBridgeChild;
 class WebRenderParentCommand;
 
@@ -240,16 +243,21 @@ private:
   nsTArray<WebRenderParentCommand> mParentCommands;
 
   // This holds the scroll data that we need to send to the compositor for
   // APZ to do it's job
   WebRenderScrollData mScrollData;
   // We use this as a temporary data structure while building the mScrollData
   // inside a layers-free transaction.
   std::vector<WebRenderLayerScrollData> mLayerScrollData;
+  // We use this as a temporary data structure to track the current display
+  // item's ASR as we recurse in CreateWebRenderCommandsFromDisplayList. We
+  // need this so that WebRenderLayerScrollData items that deeper in the
+  // tree don't duplicate scroll metadata that their ancestors already have.
+  std::vector<const ActiveScrolledRoot*> mAsrStack;
 
   // Layers that have been mutated. If we have an empty transaction
   // then a display item layer will no longer be valid
   // if it was a mutated layers.
   void AddMutatedLayer(Layer* aLayer);
   void ClearMutatedLayers();
   LayerRefArray mMutatedLayers;
   bool mTransactionIncomplete;
--- a/gfx/layers/wr/WebRenderScrollData.cpp
+++ b/gfx/layers/wr/WebRenderScrollData.cpp
@@ -64,24 +64,28 @@ WebRenderLayerScrollData::Initialize(Web
 void
 WebRenderLayerScrollData::InitializeRoot(int32_t aDescendantCount)
 {
   mDescendantCount = aDescendantCount;
 }
 
 void
 WebRenderLayerScrollData::Initialize(WebRenderScrollData& aOwner,
-                                     nsDisplayItem* aItem)
+                                     nsDisplayItem* aItem,
+                                     int32_t aDescendantCount,
+                                     const ActiveScrolledRoot* aStopAtAsr)
 {
-  mDescendantCount = 0;
+  MOZ_ASSERT(aDescendantCount >= 0); // Ensure value is valid
+  MOZ_ASSERT(mDescendantCount == -1); // Don't allow re-setting an already set value
+  mDescendantCount = aDescendantCount;
 
   MOZ_ASSERT(aItem);
   aItem->UpdateScrollData(&aOwner, this);
   for (const ActiveScrolledRoot* asr = aItem->GetActiveScrolledRoot();
-       asr;
+       asr && asr != aStopAtAsr;
        asr = asr->mParent) {
     Maybe<ScrollMetadata> metadata = asr->mScrollableFrame->ComputeScrollMetadata(
         nullptr, aItem->ReferenceFrame(), ContainerLayerParameters(), nullptr);
     MOZ_ASSERT(metadata);
     mScrollIds.AppendElement(aOwner.AddMetadata(metadata.ref()));
   }
 }
 
--- a/gfx/layers/wr/WebRenderScrollData.h
+++ b/gfx/layers/wr/WebRenderScrollData.h
@@ -15,16 +15,19 @@
 #include "mozilla/GfxMessageUtils.h"
 #include "mozilla/layers/LayerAttributes.h"
 #include "mozilla/layers/LayersMessageUtils.h"
 #include "mozilla/layers/FocusTarget.h"
 #include "mozilla/Maybe.h"
 #include "nsTArrayForwardDeclare.h"
 
 namespace mozilla {
+
+struct ActiveScrolledRoot;
+
 namespace layers {
 
 class Layer;
 class WebRenderScrollData;
 
 // Data needed by APZ, per layer. One instance of this class is created for
 // each layer in the layer tree and sent over PWebRenderBridge to the APZ code.
 // Each WebRenderLayerScrollData is conceptually associated with an "owning"
@@ -38,17 +41,19 @@ public:
   // Actually initialize the object. This is not done during the constructor
   // for optimization purposes (the call site is hard to write efficiently
   // if we do this in the constructor).
   void Initialize(WebRenderScrollData& aOwner,
                   Layer* aLayer,
                   int32_t aDescendantCount);
   void InitializeRoot(int32_t aDescendantCount);
   void Initialize(WebRenderScrollData& aOwner,
-                  nsDisplayItem* aItem);
+                  nsDisplayItem* aItem,
+                  int32_t aDescendantCount,
+                  const ActiveScrolledRoot* aStopAtAsr);
 
   int32_t GetDescendantCount() const;
   size_t GetScrollMetadataCount() const;
 
   void AppendScrollMetadata(WebRenderScrollData& aOwner,
                             const ScrollMetadata& aData);
   // Return the ScrollMetadata object that used to be on the original Layer
   // at the given index. Since we deduplicate the ScrollMetadata objects into