Bug 1357754 - Implement the traversal functions of WebRenderScrollDataWrapper. r=botond
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 20 Apr 2017 10:38:05 -0400
changeset 403277 1f032699c9c56e3364757db13f25a05f688932df
parent 403276 2a256d666481fd2f38e1c4c4eace9c0c0adf0b56
child 403278 e8979e2cb9b7214fcbeb8b29730554c494d53003
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)
reviewersbotond
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 - Implement the traversal functions of WebRenderScrollDataWrapper. r=botond This mainly implements the GetLastChild and GetPreviousSibling functions in the WebRenderScrollDataWrapper, and adds helper functions that are needed to make that possible. This allows the WebRenderScrollDataWrapper to simulate a full "LayerMetrics" tree using the information in the underlying WebRenderScrollData object. MozReview-Commit-ID: K82Ud2gAo8K
gfx/layers/wr/WebRenderScrollData.cpp
gfx/layers/wr/WebRenderScrollData.h
gfx/layers/wr/WebRenderScrollDataWrapper.h
--- a/gfx/layers/wr/WebRenderScrollData.cpp
+++ b/gfx/layers/wr/WebRenderScrollData.cpp
@@ -29,16 +29,37 @@ WebRenderLayerScrollData::Initialize(Web
   mDescendantCount = aDescendantCount;
 
   MOZ_ASSERT(aLayer);
   for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) {
     mScrollIds.AppendElement(aOwner.AddMetadata(aLayer->GetScrollMetadata(i)));
   }
 }
 
+int32_t
+WebRenderLayerScrollData::GetDescendantCount() const
+{
+  MOZ_ASSERT(mDescendantCount >= 0); // check that it was set
+  return mDescendantCount;
+}
+
+size_t
+WebRenderLayerScrollData::GetScrollMetadataCount() const
+{
+  return mScrollIds.Length();
+}
+
+const ScrollMetadata&
+WebRenderLayerScrollData::GetScrollMetadata(const WebRenderScrollData& aOwner,
+                                            size_t aIndex) const
+{
+  MOZ_ASSERT(aIndex < mScrollIds.Length());
+  return aOwner.GetScrollMetadata(mScrollIds[aIndex]);
+}
+
 WebRenderScrollData::WebRenderScrollData()
 {
 }
 
 WebRenderScrollData::~WebRenderScrollData()
 {
 }
 
@@ -58,19 +79,41 @@ WebRenderScrollData::AddMetadata(const S
 size_t
 WebRenderScrollData::AddNewLayerData()
 {
   size_t len = mLayerScrollData.Length();
   Unused << mLayerScrollData.AppendElement();
   return len;
 }
 
+size_t
+WebRenderScrollData::GetLayerCount() const
+{
+  return mLayerScrollData.Length();
+}
+
 WebRenderLayerScrollData*
 WebRenderScrollData::GetLayerDataMutable(size_t aIndex)
 {
   if (aIndex >= mLayerScrollData.Length()) {
     return nullptr;
   }
   return &(mLayerScrollData.ElementAt(aIndex));
 }
 
+const WebRenderLayerScrollData*
+WebRenderScrollData::GetLayerData(size_t aIndex) const
+{
+  if (aIndex >= mLayerScrollData.Length()) {
+    return nullptr;
+  }
+  return &(mLayerScrollData.ElementAt(aIndex));
+}
+
+const ScrollMetadata&
+WebRenderScrollData::GetScrollMetadata(size_t aIndex) const
+{
+  MOZ_ASSERT(aIndex < mScrollMetadatas.Length());
+  return mScrollMetadatas[aIndex];
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderScrollData.h
+++ b/gfx/layers/wr/WebRenderScrollData.h
@@ -31,16 +31,26 @@ 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);
 
+  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.
+  const ScrollMetadata& GetScrollMetadata(const WebRenderScrollData& aOwner,
+                                          size_t aIndex) const;
+
   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;
 
@@ -64,19 +74,24 @@ public:
 
   // 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();
 
+  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;
+
+  const ScrollMetadata& GetScrollMetadata(size_t aIndex) const;
 
   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.
--- a/gfx/layers/wr/WebRenderScrollDataWrapper.h
+++ b/gfx/layers/wr/WebRenderScrollDataWrapper.h
@@ -15,58 +15,180 @@ namespace layers {
 /*
  * This class is a wrapper to walk through a WebRenderScrollData object, with
  * an exposed API that is template-compatible to LayerMetricsWrapper. This allows
  * APZ to walk through both layer trees and WebRender scroll metadata structures
  * without a lot of code duplication.
  * (Note that not all functions from LayerMetricsWrapper are implemented here,
  * only the ones we've needed in APZ code so far.)
  *
+ * A WebRenderScrollData object is basically a flattened layer tree, with a
+ * number of WebRenderLayerScrollData objects that have a 1:1 correspondence
+ * to layers in a layer tree. Therefore the mLayer pointer in this class can
+ * be considered equivalent to the mLayer pointer in the LayerMetricsWrapper.
+ * There are some extra fields (mData, mLayerIndex, mContainingSubtreeLastIndex)
+ * to move around between these "layers" given the flattened representation.
+ * The mMetadataIndex field in this class corresponds to the mIndex field in
+ * LayerMetricsWrapper, as both classes also need to manage walking through
+ * "virtual" container layers implied by the list of ScrollMetadata objects.
+ *
  * One important note here is that this class holds a pointer to the "owning"
  * WebRenderScrollData. The caller must ensure that this class does not outlive
  * the owning WebRenderScrollData, or this may result in use-after-free errors.
  * This class being declared a MOZ_STACK_CLASS should help with that.
  *
  * Refer to LayerMetricsWrapper.h for actual documentation on the exposed API.
  */
 class MOZ_STACK_CLASS WebRenderScrollDataWrapper {
 public:
-  explicit WebRenderScrollDataWrapper(const WebRenderScrollData* aData)
+  // Basic constructor for external callers. Starts the walker at the root of
+  // the tree.
+  explicit WebRenderScrollDataWrapper(const WebRenderScrollData* aData = nullptr)
+    : mData(aData)
+    , mLayerIndex(0)
+    , mContainingSubtreeLastIndex(0)
+    , mLayer(nullptr)
+    , mMetadataIndex(0)
+  {
+    if (!mData) {
+      return;
+    }
+    mLayer = mData->GetLayerData(mLayerIndex);
+    if (!mLayer) {
+      return;
+    }
+
+    // sanity check on the data
+    MOZ_ASSERT(mData->GetLayerCount() == (size_t)(1 + mLayer->GetDescendantCount()));
+    mContainingSubtreeLastIndex = mData->GetLayerCount();
+
+    // See documentation in LayerMetricsWrapper.h about this. mMetadataIndex
+    // in this class is equivalent to mIndex in that class.
+    mMetadataIndex = mLayer->GetScrollMetadataCount();
+    if (mMetadataIndex > 0) {
+      mMetadataIndex--;
+    }
+  }
+
+private:
+  // Internal constructor for walking from one WebRenderLayerScrollData to
+  // another. In this case we need to recompute the mMetadataIndex to be the
+  // "topmost" scroll metadata on the new layer.
+  WebRenderScrollDataWrapper(const WebRenderScrollData* aData,
+                             size_t aLayerIndex,
+                             size_t aContainingSubtreeLastIndex)
     : mData(aData)
+    , mLayerIndex(aLayerIndex)
+    , mContainingSubtreeLastIndex(aContainingSubtreeLastIndex)
+    , mLayer(nullptr)
+    , mMetadataIndex(0)
   {
+    MOZ_ASSERT(mData);
+    mLayer = mData->GetLayerData(mLayerIndex);
+    MOZ_ASSERT(mLayer);
+
+    // See documentation in LayerMetricsWrapper.h about this. mMetadataIndex
+    // in this class is equivalent to mIndex in that class.
+    mMetadataIndex = mLayer->GetScrollMetadataCount();
+    if (mMetadataIndex > 0) {
+      mMetadataIndex--;
+    }
+  }
+
+  // Internal constructor for walking from one metadata to another metadata on
+  // the same WebRenderLayerScrollData.
+  WebRenderScrollDataWrapper(const WebRenderScrollData* aData,
+                             size_t aLayerIndex,
+                             size_t aContainingSubtreeLastIndex,
+                             const WebRenderLayerScrollData* aLayer,
+                             uint32_t aMetadataIndex)
+    : mData(aData)
+    , mLayerIndex(aLayerIndex)
+    , mContainingSubtreeLastIndex(aContainingSubtreeLastIndex)
+    , mLayer(aLayer)
+    , mMetadataIndex(aMetadataIndex)
+  {
+    MOZ_ASSERT(mData);
+    MOZ_ASSERT(mLayer);
+    MOZ_ASSERT(mLayer == mData->GetLayerData(mLayerIndex));
+    MOZ_ASSERT(mMetadataIndex == 0 || mMetadataIndex < mLayer->GetScrollMetadataCount());
+  }
+
+public:
+  bool IsValid() const
+  {
+    return mLayer != nullptr;
   }
 
   explicit operator bool() const
   {
-    // TODO
-    return false;
+    return IsValid();
   }
 
   bool IsScrollInfoLayer() const
   {
     // TODO
     return false;
   }
 
   WebRenderScrollDataWrapper GetLastChild() const
   {
-    // TODO
-    return WebRenderScrollDataWrapper(nullptr);
+    MOZ_ASSERT(IsValid());
+
+    if (!AtBottomLayer()) {
+      // If we're still walking around in the virtual container layers created
+      // by the ScrollMetadata array, we just need to update the metadata index
+      // and that's it.
+      return WebRenderScrollDataWrapper(mData, mLayerIndex,
+          mContainingSubtreeLastIndex, mLayer, mMetadataIndex - 1);
+    }
+
+    // Otherwise, we need to walk to a different WebRenderLayerScrollData in
+    // mData.
+
+    // Since mData contains the layer in depth-first, last-to-first order,
+    // the index after mLayerIndex must be mLayerIndex's last child, if it
+    // has any children (indicated by GetDescendantCount() > 0). Furthermore
+    // we compute the first index outside the subtree rooted at this node
+    // (in |subtreeLastIndex|) and pass that in to the child wrapper to use as
+    // its mContainingSubtreeLastIndex.
+    if (mLayer->GetDescendantCount() > 0) {
+      size_t prevSiblingIndex = mLayerIndex + 1 + mLayer->GetDescendantCount();
+      size_t subtreeLastIndex = std::min(mContainingSubtreeLastIndex, prevSiblingIndex);
+      return WebRenderScrollDataWrapper(mData, mLayerIndex + 1, subtreeLastIndex);
+    }
+    return WebRenderScrollDataWrapper();
   }
 
   WebRenderScrollDataWrapper GetPrevSibling() const
   {
-    // TODO
-    return WebRenderScrollDataWrapper(nullptr);
+    MOZ_ASSERT(IsValid());
+
+    if (!AtTopLayer()) {
+      // The virtual container layers don't have siblings
+      return WebRenderScrollDataWrapper();
+    }
+
+    // Skip past the descendants to get to the previous sibling. However, we
+    // might be at the last sibling already.
+    size_t prevSiblingIndex = mLayerIndex + 1 + mLayer->GetDescendantCount();
+    if (prevSiblingIndex < mContainingSubtreeLastIndex) {
+      return WebRenderScrollDataWrapper(mData, prevSiblingIndex, mContainingSubtreeLastIndex);
+    }
+    return WebRenderScrollDataWrapper();
   }
 
   const ScrollMetadata& Metadata() const
   {
-    // TODO
-    return *ScrollMetadata::sNullMetadata;
+    MOZ_ASSERT(IsValid());
+
+    if (mMetadataIndex >= mLayer->GetScrollMetadataCount()) {
+      return *ScrollMetadata::sNullMetadata;
+    }
+    return mLayer->GetScrollMetadata(*mData, mMetadataIndex);
   }
 
   const FrameMetrics& Metrics() const
   {
     return Metadata().GetMetrics();
   }
 
   AsyncPanZoomController* GetApzc() const
@@ -159,15 +281,41 @@ public:
 
   const void* GetLayer() const
   {
     // TODO
     return nullptr;
   }
 
 private:
+  bool AtBottomLayer() const
+  {
+    return mMetadataIndex == 0;
+  }
+
+  bool AtTopLayer() const
+  {
+    return mLayer->GetScrollMetadataCount() == 0 || mMetadataIndex == mLayer->GetScrollMetadataCount() - 1;
+  }
+
+private:
   const WebRenderScrollData* mData;
+  // The index (in mData->mLayerScrollData) of the WebRenderLayerScrollData this
+  // wrapper is pointing to.
+  size_t mLayerIndex;
+  // The upper bound on the set of valid indices inside the subtree rooted at
+  // the parent of this "layer". That is, any layer index |i| in the range
+  // mLayerIndex <= i < mContainingSubtreeLastIndex is guaranteed to point to
+  // a layer that is a descendant of "parent", where "parent" is the parent
+  // layer of the layer at mLayerIndex. This is needed in order to implement
+  // GetPrevSibling() correctly.
+  size_t mContainingSubtreeLastIndex;
+  // The WebRenderLayerScrollData this wrapper is pointing to.
+  const WebRenderLayerScrollData* mLayer;
+  // The index of the scroll metadata within mLayer that this wrapper is
+  // pointing to.
+  uint32_t mMetadataIndex;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* GFX_WEBRENDERSCROLLDATAWRAPPER_H */