Bug 1357754 - Implement the traversal functions of WebRenderScrollDataWrapper. r=botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 20 Apr 2017 10:04:49 -0400
changeset 565810 5e15a2ac61f5cdff8a1e3e55f18e4eeb14ca3c12
parent 565809 eae70e8480e05ff2746b6796ba4d086a415da0db
child 565811 b407a61a019fb665c309c9b40fc8e2945157161a
push id55024
push userkgupta@mozilla.com
push dateThu, 20 Apr 2017 14:05:27 +0000
reviewersbotond
bugs1357754
milestone55.0a1
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 had (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 */