Bug 1384181 - Reorganize the WebRenderScrollData code to work with layers-free transactions. r? draft
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 26 Jul 2017 14:47:48 -0400
changeset 616161 e5e66645b6b77e8f3fb5f2e5772b640ffc0ff29f
parent 615935 388d81ed93fa640f91d155f36254667c734157cf
child 616162 4865a295a312ed83cb2ff92a22bfc277680d0ec3
push id70614
push userkgupta@mozilla.com
push dateWed, 26 Jul 2017 20:00:48 +0000
bugs1384181
milestone56.0a1
Bug 1384181 - Reorganize the WebRenderScrollData code to work with layers-free transactions. r? Until now WebRenderScrollData was only used with "layers" WR transactions, but we want to use it with layers-free transactions as well. As such, we need to allow collecting information from display items instead of layers. This restructures the code a little bit to allow that. This patch should not have any functional effect on the "layers" codepath, but on the "layers-free" codepath it is now actually populating some rudimentary data into the WebRenderScrollData before sending it across. This will be fleshed out in future patches. MozReview-Commit-ID: BROqpsHPRND
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
@@ -233,48 +233,38 @@ WebRenderLayerManager::CreateWebRenderCo
       aDisplayList->AppendToBottom(itemSameCoordinateSystemChildren);
       item->~nsDisplayItem();
       continue;
     }
 
     savedItems.AppendToTop(item);
 
     if (apzEnabled) {
+      bool forceNewLayerData = false;
+
+      // 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.
+      switch (itemType) {
+      case nsDisplayItem::TYPE_SCROLL_INFO_LAYER:
+        forceNewLayerData = true;
+        break;
+      default:
+        break;
+      }
+
+      // 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();
-      // The ASR check here is just an optimization to avoid doing any unnecessary
-      // work in a common case, where adjacent items in the display list have
-      // the same ASR.
-      if (asr && asr != lastAsr) {
+      if (forceNewLayerData || asr != lastAsr) {
         lastAsr = asr;
-        FrameMetrics::ViewID id = nsLayoutUtils::ViewIDForASR(asr);
-        if (mScrollMetadata.find(id) == mScrollMetadata.end()) {
-          // We pass null here for the display item clip because we don't need
-          // the clip to be in the ScrollMetadata here; we will push the clip
-          // information into the WR display list directly.
-          Maybe<ScrollMetadata> metadata = asr->mScrollableFrame->ComputeScrollMetadata(
-              nullptr, item->ReferenceFrame(),
-              ContainerLayerParameters(), nullptr);
-          MOZ_ASSERT(metadata);
-          mScrollMetadata[id] = *metadata;
-        }
-      }
-      if (itemType == nsDisplayItem::TYPE_SCROLL_INFO_LAYER) {
-        // we should only really get one scroll info layer per scroll id, so
-        // it's not worth trying to get the ViewID and checking to see if we
-        // already have it in mScrollMetadata before doing the work of computing
-        // the metadata.
-        nsDisplayScrollInfoLayer* info = static_cast<nsDisplayScrollInfoLayer*>(item);
-        UniquePtr<ScrollMetadata> metadata = info->ComputeScrollMetadata(
-            nullptr, ContainerLayerParameters());
-        MOZ_ASSERT(metadata);
-        MOZ_ASSERT(metadata->GetMetrics().IsScrollInfoLayer());
-        FrameMetrics::ViewID id = metadata->GetMetrics().GetScrollId();
-        if (mScrollMetadata.find(id) == mScrollMetadata.end()) {
-          mScrollMetadata[id] = *metadata;
-        }
+        mLayerScrollData.emplace_back();
+        mLayerScrollData.back().Initialize(mScrollData, item);
       }
     }
 
     if (!item->CreateWebRenderCommands(aBuilder, aSc, mParentCommands, this,
                                        aDisplayListBuilder)) {
       PushItemAsImage(item, aBuilder, aSc, aDisplayListBuilder);
     }
   }
@@ -532,66 +522,77 @@ WebRenderLayerManager::EndTransactionInt
 
   if (mEndTransactionWithoutLayers) {
     // aDisplayList being null here means this is an empty transaction following a layers-free
     // transaction, so we reuse the previously built displaylist and scroll
     // metadata information
     if (aDisplayList && aDisplayListBuilder) {
       StackingContextHelper sc;
       mParentCommands.Clear();
-      mScrollMetadata.clear();
+      mScrollData = WebRenderScrollData();
+      MOZ_ASSERT(mLayerScrollData.empty());
 
       CreateWebRenderCommandsFromDisplayList(aDisplayList, aDisplayListBuilder, sc, builder);
 
       builder.Finalize(contentSize, mBuiltDisplayList);
+
+      // Append the WebRenderLayerScrollData items into WebRenderScrollData
+      // in reverse order, from topmost to bottommost. This is in keeping with
+      // the semantics of WebRenderScrollData.
+      for (auto i = mLayerScrollData.crbegin(); i != mLayerScrollData.crend(); i++) {
+        mScrollData.AddLayerData(*i);
+      }
+      mLayerScrollData.clear();
     }
 
     builder.PushBuiltDisplayList(mBuiltDisplayList);
     WrBridge()->AddWebRenderParentCommands(mParentCommands);
   } else {
+    mScrollData = WebRenderScrollData();
+
     mRoot->StartPendingAnimations(mAnimationReadyTime);
     StackingContextHelper sc;
 
     WebRenderLayer::ToWebRenderLayer(mRoot)->RenderLayer(builder, sc);
+
+    // Need to do this after RenderLayer because the compositor animation IDs
+    // get populated during RenderLayer and we need those.
+    PopulateScrollData(mScrollData, mRoot.get());
   }
 
   mWidget->AddWindowOverlayWebRenderCommands(WrBridge(), builder);
   WrBridge()->ClearReadLocks();
 
   // We can't finish this transaction so return. This usually
   // happens in an empty transaction where we can't repaint a painted layer.
   // In this case, leave the transaction open and let a full transaction happen.
   if (mTransactionIncomplete) {
     DiscardLocalImages();
     WrBridge()->ProcessWebRenderParentCommands();
     return false;
   }
 
-  WebRenderScrollData scrollData;
   if (AsyncPanZoomEnabled()) {
-    scrollData.SetFocusTarget(mFocusTarget);
+    mScrollData.SetFocusTarget(mFocusTarget);
     mFocusTarget = FocusTarget();
 
     if (mIsFirstPaint) {
-      scrollData.SetIsFirstPaint();
+      mScrollData.SetIsFirstPaint();
       mIsFirstPaint = false;
     }
-    scrollData.SetPaintSequenceNumber(mPaintSequenceNumber);
-    if (mRoot) {
-      PopulateScrollData(scrollData, mRoot.get());
-    }
+    mScrollData.SetPaintSequenceNumber(mPaintSequenceNumber);
   }
 
   bool sync = mTarget != nullptr;
   mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true);
 
   {
     AutoProfilerTracing
       tracing("Paint", sync ? "ForwardDPTransactionSync":"ForwardDPTransaction");
-    WrBridge()->DPEnd(builder, size.ToUnknownSize(), sync, mLatestTransactionId, scrollData);
+    WrBridge()->DPEnd(builder, size.ToUnknownSize(), sync, mLatestTransactionId, mScrollData);
   }
 
   MakeSnapshotIfRequired(size);
   mNeedsComposite = false;
 
   ClearDisplayItemLayers();
 
   // this may result in Layers being deleted, which results in
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -1,23 +1,26 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_WEBRENDERLAYERMANAGER_H
 #define GFX_WEBRENDERLAYERMANAGER_H
 
+#include <vector>
+
 #include "gfxPrefs.h"
 #include "Layers.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/layers/APZTestData.h"
 #include "mozilla/layers/FocusTarget.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/TransactionIdAllocator.h"
+#include "mozilla/layers/WebRenderScrollData.h"
 #include "mozilla/layers/WebRenderUserData.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "nsDisplayList.h"
 
 class nsIWidget;
 
 namespace mozilla {
@@ -231,19 +234,22 @@ private:
 
   LayerRefArray mKeepAlive;
 
   // These fields are used to save a copy of the display list for
   // empty transactions in layers-free mode.
   wr::BuiltDisplayList mBuiltDisplayList;
   nsTArray<WebRenderParentCommand> mParentCommands;
 
-  // We need this for building scroll data for the compositor in
-  // layers-free mode
-  std::unordered_map<FrameMetrics::ViewID, ScrollMetadata> mScrollMetadata;
+  // 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;
 
   // 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
@@ -11,16 +11,22 @@
 #include "nsTArray.h"
 #include "UnitTransforms.h"
 
 namespace mozilla {
 namespace layers {
 
 WebRenderLayerScrollData::WebRenderLayerScrollData()
   : mDescendantCount(-1)
+  , mTransformIsPerspective(false)
+  , mEventRegionsOverride(EventRegionsOverride::NoOverride)
+  , mScrollbarAnimationId(0)
+  , mScrollbarTargetContainerId(FrameMetrics::NULL_SCROLL_ID)
+  , mIsScrollbarContainer(false)
+  , mFixedPosScrollContainerId(FrameMetrics::NULL_SCROLL_ID)
 {
 }
 
 WebRenderLayerScrollData::~WebRenderLayerScrollData()
 {
 }
 
 void
@@ -49,16 +55,41 @@ WebRenderLayerScrollData::Initialize(Web
       : EventRegionsOverride::NoOverride;
   mScrollThumbData = aLayer->GetScrollThumbData();
   mScrollbarAnimationId = aLayer->GetCompositorAnimationsId();
   mScrollbarTargetContainerId = aLayer->GetScrollbarTargetContainerId();
   mIsScrollbarContainer = aLayer->IsScrollbarContainer();
   mFixedPosScrollContainerId = aLayer->GetFixedPositionScrollContainerId();
 }
 
+void
+WebRenderLayerScrollData::Initialize(WebRenderScrollData& aOwner,
+                                     nsDisplayItem* aItem)
+{
+  mDescendantCount = 0;
+
+  MOZ_ASSERT(aItem);
+  if (aItem->GetType() == nsDisplayItem::TYPE_SCROLL_INFO_LAYER) {
+    nsDisplayScrollInfoLayer* info = static_cast<nsDisplayScrollInfoLayer*>(aItem);
+    UniquePtr<ScrollMetadata> metadata = info->ComputeScrollMetadata(
+        nullptr, ContainerLayerParameters());
+    MOZ_ASSERT(metadata);
+    MOZ_ASSERT(metadata->GetMetrics().IsScrollInfoLayer());
+    mScrollIds.AppendElement(aOwner.AddMetadata(*metadata));
+  }
+  for (const ActiveScrolledRoot* asr = aItem->GetActiveScrolledRoot();
+       asr;
+       asr = asr->mParent) {
+    Maybe<ScrollMetadata> metadata = asr->mScrollableFrame->ComputeScrollMetadata(
+        nullptr, aItem->ReferenceFrame(), ContainerLayerParameters(), nullptr);
+    MOZ_ASSERT(metadata);
+    mScrollIds.AppendElement(aOwner.AddMetadata(metadata.ref()));
+  }
+}
+
 int32_t
 WebRenderLayerScrollData::GetDescendantCount() const
 {
   MOZ_ASSERT(mDescendantCount >= 0); // check that it was set
   return mDescendantCount;
 }
 
 size_t
@@ -108,16 +139,23 @@ size_t
 WebRenderScrollData::AddNewLayerData()
 {
   size_t len = mLayerScrollData.Length();
   Unused << mLayerScrollData.AppendElement();
   return len;
 }
 
 size_t
+WebRenderScrollData::AddLayerData(const WebRenderLayerScrollData& aData)
+{
+  mLayerScrollData.AppendElement(aData);
+  return mLayerScrollData.Length() - 1;
+}
+
+size_t
 WebRenderScrollData::GetLayerCount() const
 {
   return mLayerScrollData.Length();
 }
 
 WebRenderLayerScrollData*
 WebRenderScrollData::GetLayerDataMutable(size_t aIndex)
 {
--- a/gfx/layers/wr/WebRenderScrollData.h
+++ b/gfx/layers/wr/WebRenderScrollData.h
@@ -36,16 +36,18 @@ public:
   ~WebRenderLayerScrollData();
 
   // 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 Initialize(WebRenderScrollData& aOwner,
+                  nsDisplayItem* aItem);
 
   int32_t GetDescendantCount() const;
   size_t GetScrollMetadataCount() const;
 
   // Return the ScrollMetadata object that used to be on the original Layer
   // at the given index. Since we deduplicate the ScrollMetadata objects into
   // the array in the owning WebRenderScrollData object, we need to be passed
   // in a reference to that owner as well.
@@ -107,16 +109,19 @@ public:
   ~WebRenderScrollData();
 
   // Add the given ScrollMetadata if it doesn't already exist. Return an index
   // that can be used to look up the metadata later.
   size_t AddMetadata(const ScrollMetadata& aMetadata);
   // Add a new empty WebRenderLayerScrollData and return the index that can be
   // used to look it up via GetLayerData.
   size_t AddNewLayerData();
+  // Add the provided WebRenderLayerScrollData and return the index that can
+  // be used to look it up via GetLayerData.
+  size_t AddLayerData(const WebRenderLayerScrollData& aData);
 
   size_t GetLayerCount() const;
 
   // Return a pointer to the scroll data at the given index. Use with caution,
   // as the pointer may be invalidated if this WebRenderScrollData is mutated.
   WebRenderLayerScrollData* GetLayerDataMutable(size_t aIndex);
   const WebRenderLayerScrollData* GetLayerData(size_t aIndex) const;