Bug 1357754 - Add a mechanism to send scroll data to APZ over PWebRenderBridge. r=jrmuizel
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 20 Apr 2017 10:38:04 -0400
changeset 403273 9801b8ad5dc2d77edd387c7b508f2bffdb409a5b
parent 403272 fd86020ac35ec57f249afd2db9831d533cc541ae
child 403274 022304bf1ad7b528403ec843cc96777767b8141a
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1357754
milestone55.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 1357754 - Add a mechanism to send scroll data to APZ over PWebRenderBridge. r=jrmuizel This adds a WebRenderScrollData class (which contains a list of WebRenderLayerScrollData objects, among other things), and adds it to the DPEnd/DPSyncEnd messages sent across PWebRenderBridge. These classes are skeletons for now (more stuff will be added to them in future patches). MozReview-Commit-ID: 9duxwlUpdu7
gfx/layers/ipc/PWebRenderBridge.ipdl
gfx/layers/moz.build
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderBridgeChild.h
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderScrollData.cpp
gfx/layers/wr/WebRenderScrollData.h
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -17,16 +17,17 @@ include protocol PTexture;
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
 using mozilla::wr::ByteBuffer from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::wr::ExternalImageId from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::wr::FontKey from "mozilla/webrender/WebRenderTypes.h";
 using WrBuiltDisplayListDescriptor from "mozilla/webrender/webrender_ffi.h";
 using WrAuxiliaryListsDescriptor from "mozilla/webrender/webrender_ffi.h";
+using mozilla::layers::WebRenderScrollData from "mozilla/layers/WebRenderScrollData.h";
 
 namespace mozilla {
 namespace layers {
 
 sync protocol PWebRenderBridge
 {
   manager PCompositorBridge;
 
@@ -46,19 +47,21 @@ parent:
                      SurfaceFormat aFormat, ByteBuffer aBytes);
   sync UpdateImage(ImageKey aImageKey, IntSize aSize,
                    SurfaceFormat aFormat, ByteBuffer aBytes);
   sync DeleteImage(ImageKey aImageKey);
   async AddRawFont(FontKey aFontKey, ByteBuffer aBytes, uint32_t aFontIndex);
   async DeleteFont(FontKey aFontKey);
   async DPBegin(IntSize aSize);
   async DPEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
-              ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc);
+              ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc,
+              WebRenderScrollData aScrollData);
   sync DPSyncEnd(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
-                 ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc);
+                 ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc,
+                 WebRenderScrollData aScrollData);
   sync DPGetSnapshot(PTexture texture);
   async AddExternalImageId(ExternalImageId aImageId, CompositableHandle aHandle);
   async AddExternalImageIdForCompositable(ExternalImageId aImageId, CompositableHandle aHandle);
   async RemoveExternalImageId(ExternalImageId aImageId);
   async SetLayerObserverEpoch(uint64_t layerObserverEpoch);
   async ClearCachedResources();
   // Schedule a composite if one isn't already scheduled.
   async ForceComposite();
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -201,16 +201,17 @@ EXPORTS.mozilla.layers += [
     'wr/WebRenderBridgeChild.h',
     'wr/WebRenderBridgeParent.h',
     'wr/WebRenderCompositableHolder.h',
     'wr/WebRenderDisplayItemLayer.h',
     'wr/WebRenderImageHost.h',
     'wr/WebRenderLayerManager.h',
     'wr/WebRenderLayersLogging.h',
     'wr/WebRenderMessageUtils.h',
+    'wr/WebRenderScrollData.h',
     'wr/WebRenderTextureHost.h',
 ]
 
 if CONFIG['MOZ_X11']:
     EXPORTS.mozilla.layers += [
         'basic/TextureClientX11.h',
         'basic/X11TextureSourceBasic.h',
         'composite/X11TextureHost.h',
@@ -392,16 +393,17 @@ UNIFIED_SOURCES += [
     'wr/WebRenderCompositableHolder.cpp',
     'wr/WebRenderContainerLayer.cpp',
     'wr/WebRenderDisplayItemLayer.cpp',
     'wr/WebRenderImageHost.cpp',
     'wr/WebRenderImageLayer.cpp',
     'wr/WebRenderLayerManager.cpp',
     'wr/WebRenderLayersLogging.cpp',
     'wr/WebRenderPaintedLayer.cpp',
+    'wr/WebRenderScrollData.cpp',
     'wr/WebRenderTextLayer.cpp',
     # XXX here are some unified build error.
     #'wr/WebRenderTextureHost.cpp'
 ]
 
 SOURCES += [
     'basic/BasicImageLayer.cpp',
     'ImageContainer.cpp',
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -85,31 +85,35 @@ WebRenderBridgeChild::ClearReadLocks()
       }
     }
   }
 
   mReadLocks.Clear();
 }
 
 void
-WebRenderBridgeChild::DPEnd(wr::DisplayListBuilder &aBuilder, const gfx::IntSize& aSize, bool aIsSync, uint64_t aTransactionId)
+WebRenderBridgeChild::DPEnd(wr::DisplayListBuilder &aBuilder,
+                            const gfx::IntSize& aSize,
+                            bool aIsSync,
+                            uint64_t aTransactionId,
+                            const WebRenderScrollData& aScrollData)
 {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(mIsInTransaction);
 
   wr::BuiltDisplayList dl = aBuilder.Finalize();
   ByteBuffer dlData(Move(dl.dl));
   ByteBuffer auxData(Move(dl.aux));
 
   if (aIsSync) {
     this->SendDPSyncEnd(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId,
-                        dlData, dl.dl_desc, auxData, dl.aux_desc);
+                        dlData, dl.dl_desc, auxData, dl.aux_desc, aScrollData);
   } else {
     this->SendDPEnd(aSize, mParentCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId,
-                    dlData, dl.dl_desc, auxData, dl.aux_desc);
+                    dlData, dl.dl_desc, auxData, dl.aux_desc, aScrollData);
   }
 
   mParentCommands.Clear();
   mDestroyedActors.Clear();
   mIsInTransaction = false;
 }
 
 wr::ExternalImageId
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -55,17 +55,19 @@ class WebRenderBridgeChild final : publi
 
 public:
   explicit WebRenderBridgeChild(const wr::PipelineId& aPipelineId);
 
   void AddWebRenderParentCommand(const WebRenderParentCommand& aCmd);
   void AddWebRenderParentCommands(const nsTArray<WebRenderParentCommand>& aCommands);
 
   bool DPBegin(const  gfx::IntSize& aSize);
-  void DPEnd(wr::DisplayListBuilder &aBuilder, const gfx::IntSize& aSize, bool aIsSync, uint64_t aTransactionId);
+  void DPEnd(wr::DisplayListBuilder &aBuilder, const gfx::IntSize& aSize,
+             bool aIsSync, uint64_t aTransactionId,
+             const WebRenderScrollData& aScrollData);
 
   CompositorBridgeChild* GetCompositorBridgeChild();
 
   wr::PipelineId GetPipeline() { return mPipelineId; }
 
   // KnowsCompositor
   TextureForwarder* GetTextureForwarder() override;
   LayersIPCActor* GetLayersIPCActor() override;
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -281,17 +281,18 @@ void
 WebRenderBridgeParent::HandleDPEnd(const gfx::IntSize& aSize,
                                  InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                  InfallibleTArray<OpDestroy>&& aToDestroy,
                                  const uint64_t& aFwdTransactionId,
                                  const uint64_t& aTransactionId,
                                  const ByteBuffer& dl,
                                  const WrBuiltDisplayListDescriptor& dlDesc,
                                  const ByteBuffer& aux,
-                                 const WrAuxiliaryListsDescriptor& auxDesc)
+                                 const WrAuxiliaryListsDescriptor& auxDesc,
+                                 const WebRenderScrollData& aScrollData)
 {
   UpdateFwdTransactionId(aFwdTransactionId);
   AutoClearReadLocks clearLocks(mReadLocks);
 
   if (mDestroyed) {
     for (const auto& op : aToDestroy) {
       DestroyActor(op);
     }
@@ -300,47 +301,52 @@ WebRenderBridgeParent::HandleDPEnd(const
   // This ensures that destroy operations are always processed. It is not safe
   // to early-return from RecvDPEnd without doing so.
   AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
 
   ++mWrEpoch; // Update webrender epoch
   ProcessWebRenderCommands(aSize, aCommands, wr::NewEpoch(mWrEpoch),
                            dl, dlDesc, aux, auxDesc);
   HoldPendingTransactionId(mWrEpoch, aTransactionId);
+
+  // TODO: pass the WebRenderScrollData to APZ (this will happen in a future
+  // patch)
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvDPEnd(const gfx::IntSize& aSize,
                                  InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                  InfallibleTArray<OpDestroy>&& aToDestroy,
                                  const uint64_t& aFwdTransactionId,
                                  const uint64_t& aTransactionId,
                                  const ByteBuffer& dl,
                                  const WrBuiltDisplayListDescriptor& dlDesc,
                                  const ByteBuffer& aux,
-                                 const WrAuxiliaryListsDescriptor& auxDesc)
+                                 const WrAuxiliaryListsDescriptor& auxDesc,
+                                 const WebRenderScrollData& aScrollData)
 {
   HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
-              dl, dlDesc, aux, auxDesc);
+              dl, dlDesc, aux, auxDesc, aScrollData);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvDPSyncEnd(const gfx::IntSize &aSize,
                                      InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                      InfallibleTArray<OpDestroy>&& aToDestroy,
                                      const uint64_t& aFwdTransactionId,
                                      const uint64_t& aTransactionId,
                                      const ByteBuffer& dl,
                                      const WrBuiltDisplayListDescriptor& dlDesc,
                                      const ByteBuffer& aux,
-                                     const WrAuxiliaryListsDescriptor& auxDesc)
+                                     const WrAuxiliaryListsDescriptor& auxDesc,
+                                     const WebRenderScrollData& aScrollData)
 {
   HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
-              dl, dlDesc, aux, auxDesc);
+              dl, dlDesc, aux, auxDesc, aScrollData);
   return IPC_OK();
 }
 
 void
 WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize,
                                                 InfallibleTArray<WebRenderParentCommand>& aCommands, const wr::Epoch& aEpoch,
                                                 const ByteBuffer& dl,
                                                 const WrBuiltDisplayListDescriptor& dlDesc,
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -86,26 +86,28 @@ public:
   mozilla::ipc::IPCResult RecvDPEnd(const gfx::IntSize& aSize,
                                     InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                     InfallibleTArray<OpDestroy>&& aToDestroy,
                                     const uint64_t& aFwdTransactionId,
                                     const uint64_t& aTransactionId,
                                     const ByteBuffer& dl,
                                     const WrBuiltDisplayListDescriptor& dlDesc,
                                     const ByteBuffer& aux,
-                                    const WrAuxiliaryListsDescriptor& auxDesc) override;
+                                    const WrAuxiliaryListsDescriptor& auxDesc,
+                                    const WebRenderScrollData& aScrollData) override;
   mozilla::ipc::IPCResult RecvDPSyncEnd(const gfx::IntSize& aSize,
                                         InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                         InfallibleTArray<OpDestroy>&& aToDestroy,
                                         const uint64_t& aFwdTransactionId,
                                         const uint64_t& aTransactionId,
                                         const ByteBuffer& dl,
                                         const WrBuiltDisplayListDescriptor& dlDesc,
                                         const ByteBuffer& aux,
-                                        const WrAuxiliaryListsDescriptor& auxDesc) override;
+                                        const WrAuxiliaryListsDescriptor& auxDesc,
+                                        const WebRenderScrollData& aScrollData) override;
   mozilla::ipc::IPCResult RecvDPGetSnapshot(PTextureParent* aTexture) override;
 
   mozilla::ipc::IPCResult RecvAddExternalImageId(const ExternalImageId& aImageId,
                                                  const CompositableHandle& aHandle) override;
   mozilla::ipc::IPCResult RecvAddExternalImageIdForCompositable(const ExternalImageId& aImageId,
                                                                 const CompositableHandle& aHandle) override;
   mozilla::ipc::IPCResult RecvRemoveExternalImageId(const ExternalImageId& aImageId) override;
   mozilla::ipc::IPCResult RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch) override;
@@ -174,17 +176,18 @@ private:
   void HandleDPEnd(const gfx::IntSize& aSize,
                    InfallibleTArray<WebRenderParentCommand>&& aCommands,
                    InfallibleTArray<OpDestroy>&& aToDestroy,
                    const uint64_t& aFwdTransactionId,
                    const uint64_t& aTransactionId,
                    const ByteBuffer& dl,
                    const WrBuiltDisplayListDescriptor& dlDesc,
                    const ByteBuffer& aux,
-                   const WrAuxiliaryListsDescriptor& auxDesc);
+                   const WrAuxiliaryListsDescriptor& auxDesc,
+                   const WebRenderScrollData& aScrollData);
 
   void SampleAnimations(nsTArray<WrOpacityProperty>& aOpacityArray,
                         nsTArray<WrTransformProperty>& aTransformArray);
 
 private:
   struct PendingTransactionId {
     PendingTransactionId(wr::Epoch aEpoch, uint64_t aId)
       : mEpoch(aEpoch)
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -334,16 +334,34 @@ WebRenderLayerManager::EndEmptyTransacti
   if (!mRoot) {
     return false;
   }
 
   // We might used painted layer images so don't delete them yet.
   return EndTransactionInternal(nullptr, nullptr, aFlags);
 }
 
+/*static*/ int32_t
+PopulateScrollData(WebRenderScrollData& aTarget, Layer* aLayer)
+{
+  MOZ_ASSERT(aLayer);
+
+  // We want to allocate a WebRenderLayerScrollData object for this layer,
+  // but don't keep a pointer to it since it might get memmove'd during the
+  // recursion below. Instead keep the index and get the pointer later.
+  size_t index = aTarget.AddNewLayerData();
+
+  int32_t descendants = 0;
+  for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
+    descendants += PopulateScrollData(aTarget, child);
+  }
+  aTarget.GetLayerDataMutable(index)->Initialize(aTarget, aLayer, descendants);
+  return descendants + 1;
+}
+
 void
 WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
                                       void* aCallbackData,
                                       EndTransactionFlags aFlags)
 {
   DiscardImages();
   WrBridge()->RemoveExpiredFontKeys();
   EndTransactionInternal(aCallback, aCallbackData, aFlags);
@@ -379,20 +397,25 @@ WebRenderLayerManager::EndTransactionInt
   // 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();
     return false;
   }
 
+  WebRenderScrollData scrollData;
+  if (mRoot && mWidget->AsyncPanZoomEnabled()) {
+    PopulateScrollData(scrollData, mRoot.get());
+  }
+
   bool sync = mTarget != nullptr;
   mLatestTransactionId = mTransactionIdAllocator->GetTransactionId();
 
-  WrBridge()->DPEnd(builder, size.ToUnknownSize(), sync, mLatestTransactionId);
+  WrBridge()->DPEnd(builder, size.ToUnknownSize(), sync, mLatestTransactionId, scrollData);
 
   MakeSnapshotIfRequired(size);
   mNeedsComposite = false;
 
   ClearDisplayItemLayers();
 
   // this may result in Layers being deleted, which results in
   // PLayer::Send__delete__() and DeallocShmem()
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderScrollData.cpp
@@ -0,0 +1,76 @@
+/* -*- 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/. */
+
+#include "mozilla/layers/WebRenderScrollData.h"
+#include "mozilla/Unused.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace layers {
+
+WebRenderLayerScrollData::WebRenderLayerScrollData()
+  : mDescendantCount(-1)
+{
+}
+
+WebRenderLayerScrollData::~WebRenderLayerScrollData()
+{
+}
+
+void
+WebRenderLayerScrollData::Initialize(WebRenderScrollData& aOwner,
+                                     Layer* aLayer,
+                                     int32_t aDescendantCount)
+{
+  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(aLayer);
+  for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) {
+    mScrollIds.AppendElement(aOwner.AddMetadata(aLayer->GetScrollMetadata(i)));
+  }
+}
+
+WebRenderScrollData::WebRenderScrollData()
+{
+}
+
+WebRenderScrollData::~WebRenderScrollData()
+{
+}
+
+size_t
+WebRenderScrollData::AddMetadata(const ScrollMetadata& aMetadata)
+{
+  FrameMetrics::ViewID scrollId = aMetadata.GetMetrics().GetScrollId();
+  auto insertResult = mScrollIdMap.insert(std::make_pair(scrollId, 0));
+  if (insertResult.second) {
+    // Insertion took place, therefore it's a scrollId we hadn't seen before
+    insertResult.first->second = mScrollMetadatas.Length();
+    mScrollMetadatas.AppendElement(aMetadata);
+  } // else we didn't insert, because it already existed
+  return insertResult.first->second;
+}
+
+size_t
+WebRenderScrollData::AddNewLayerData()
+{
+  size_t len = mLayerScrollData.Length();
+  Unused << mLayerScrollData.AppendElement();
+  return len;
+}
+
+WebRenderLayerScrollData*
+WebRenderScrollData::GetLayerDataMutable(size_t aIndex)
+{
+  if (aIndex >= mLayerScrollData.Length()) {
+    return nullptr;
+  }
+  return &(mLayerScrollData.ElementAt(aIndex));
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderScrollData.h
@@ -0,0 +1,147 @@
+/* -*- 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_WEBRENDERSCROLLDATA_H
+#define GFX_WEBRENDERSCROLLDATA_H
+
+#include <map>
+
+#include "chrome/common/ipc_message_utils.h"
+#include "FrameMetrics.h"
+#include "mozilla/Maybe.h"
+#include "nsTArrayForwardDeclare.h"
+
+namespace mozilla {
+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"
+// WebRenderScrollData.
+class WebRenderLayerScrollData
+{
+public:
+  WebRenderLayerScrollData(); // needed for IPC purposes
+  ~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);
+
+  friend struct IPC::ParamTraits<WebRenderLayerScrollData>;
+
+private:
+  // The number of descendants this layer has (not including the layer itself).
+  // This is needed to reconstruct the depth-first layer tree traversal
+  // efficiently. Leaf layers should always have 0 descendants.
+  int32_t mDescendantCount;
+
+  // Handles to the ScrollMetadata objects that were on this layer. The values
+  // stored in this array are indices into the owning WebRenderScrollData's
+  // mScrollMetadatas array. This indirection is used to deduplicate the
+  // ScrollMetadata objects, since there is usually heavy duplication of them
+  // within a layer tree.
+  nsTArray<size_t> mScrollIds;
+};
+
+// Data needed by APZ, for the whole layer tree. One instance of this class
+// is created for each transaction sent over PWebRenderBridge. It is populated
+// with information from the WebRender layer tree on the client side and the
+// information is used by APZ on the parent side.
+class WebRenderScrollData
+{
+public:
+  WebRenderScrollData();
+  ~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();
+
+  // 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);
+
+  friend struct IPC::ParamTraits<WebRenderScrollData>;
+
+private:
+  // Internal data structure used to maintain uniqueness of mScrollMetadatas.
+  // This is not serialized/deserialized over IPC because there's no need for it,
+  // as the parent side doesn't need this at all. Also because we don't have any
+  // IPC-friendly hashtable implementation lying around.
+  // The key into this map is the scrollId of a ScrollMetadata, and the value is
+  // an index into the mScrollMetadatas array.
+  std::map<FrameMetrics::ViewID, size_t> mScrollIdMap;
+
+  // A list of all the unique ScrollMetadata objects from the layer tree. Each
+  // ScrollMetadata in this list must have a unique scroll id.
+  nsTArray<ScrollMetadata> mScrollMetadatas;
+
+  // A list of per-layer scroll data objects, generated via a depth-first,
+  // pre-order, last-to-first traversal of the layer tree (i.e. a recursive
+  // traversal where a node N first pushes itself, followed by its children in
+  // last-to-first order). Each layer's scroll data object knows how many
+  // descendants that layer had, which allows reconstructing the traversal on the
+  // other side.
+  nsTArray<WebRenderLayerScrollData> mLayerScrollData;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+namespace IPC {
+
+template<>
+struct ParamTraits<mozilla::layers::WebRenderLayerScrollData>
+{
+  typedef mozilla::layers::WebRenderLayerScrollData paramType;
+
+  static void
+  Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mDescendantCount);
+    WriteParam(aMsg, aParam.mScrollIds);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->mDescendantCount)
+        && ReadParam(aMsg, aIter, &aResult->mScrollIds);
+  }
+};
+
+template<>
+struct ParamTraits<mozilla::layers::WebRenderScrollData>
+{
+  typedef mozilla::layers::WebRenderScrollData paramType;
+
+  static void
+  Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mScrollMetadatas);
+    WriteParam(aMsg, aParam.mLayerScrollData);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->mScrollMetadatas)
+        && ReadParam(aMsg, aIter, &aResult->mLayerScrollData);
+  }
+};
+
+} // namespace IPC
+
+#endif /* GFX_WEBRENDERSCROLLDATA_H */