Bug 1373378 - Do a better job tracking the ancestor scrollids in DisplayListBuilder. r?jrmuizel draft
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 16 Jun 2017 15:12:24 -0400
changeset 595716 5c7a264dad4cf98fc87b25ae60b3664d4657b84a
parent 595715 75ca2ddcc36a06b4730663504e89d490de7014be
child 633790 473c9492dd73f687ba3d543b783512256556bcc2
push id64431
push userkgupta@mozilla.com
push dateFri, 16 Jun 2017 19:12:55 +0000
reviewersjrmuizel
bugs1373378
milestone56.0a1
Bug 1373378 - Do a better job tracking the ancestor scrollids in DisplayListBuilder. r?jrmuizel In some cases we need to know the ancestor scrollid of a scrollid that we had previously pushed onto the stack and then subsequently popped off. Since that scrollid is no longer actually on the stack at the time of the query, we would return Nothing(). Instead, this patch adds a map to "remember" previously encountered scrollids and their ancestors, so that these queries can be correctly handled. MozReview-Commit-ID: BrtEv88ZysX
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -609,16 +609,23 @@ DisplayListBuilder::PushBuiltDisplayList
 void
 DisplayListBuilder::PushScrollLayer(const layers::FrameMetrics::ViewID& aScrollId,
                                     const WrRect& aContentRect,
                                     const WrRect& aClipRect)
 {
   WRDL_LOG("PushScrollLayer id=%" PRIu64 " co=%s cl=%s\n",
       aScrollId, Stringify(aContentRect).c_str(), Stringify(aClipRect).c_str());
   wr_dp_push_scroll_layer(mWrState, aScrollId, aContentRect, aClipRect);
+  if (!mScrollIdStack.empty()) {
+    auto it = mScrollParents.insert({aScrollId, mScrollIdStack.back()});
+    if (!it.second) { // aScrollId was already a key in mScrollParents
+                      // so check that the parent value is the same.
+      MOZ_ASSERT(it.first->second == mScrollIdStack.back());
+    }
+  }
   mScrollIdStack.push_back(aScrollId);
 }
 
 void
 DisplayListBuilder::PopScrollLayer()
 {
   WRDL_LOG("PopScrollLayer id=%" PRIu64 "\n", mScrollIdStack.back());
   mScrollIdStack.pop_back();
@@ -899,21 +906,14 @@ DisplayListBuilder::TopmostClipId()
     return Nothing();
   }
   return Some(mClipIdStack.back());
 }
 
 Maybe<layers::FrameMetrics::ViewID>
 DisplayListBuilder::ParentScrollIdFor(layers::FrameMetrics::ViewID aScrollId)
 {
-  // Finds the scrollId in mScrollIdStack immediately before aScrollId, or
-  // returns Nothing() if it can't find one
-  for (auto it = mScrollIdStack.rbegin(); it != mScrollIdStack.rend(); it++) {
-    if (*it == aScrollId) {
-      it++;
-      return (it == mScrollIdStack.rend() ? Nothing() : Some(*it));
-    }
-  }
-  return Nothing();
+  auto it = mScrollParents.find(aScrollId);
+  return (it == mScrollParents.end() ? Nothing() : Some(it->second));
 }
 
 } // namespace wr
 } // namespace mozilla
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -3,16 +3,17 @@
 /* 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 MOZILLA_LAYERS_WEBRENDERAPI_H
 #define MOZILLA_LAYERS_WEBRENDERAPI_H
 
 #include <vector>
+#include <unordered_map>
 
 #include "mozilla/AlreadyAddRefed.h"
 #include "mozilla/Range.h"
 #include "mozilla/webrender/webrender_ffi.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "FrameMetrics.h"
 #include "GLTypes.h"
 #include "Units.h"
@@ -288,34 +289,36 @@ public:
   WrClipRegionToken PushClipRegion(const WrRect& aMain,
                                    const nsTArray<WrComplexClipRegion>& aComplex,
                                    const WrImageMask* aMask = nullptr);
 
   // Returns the clip id that was most recently pushed with PushClip and that
   // has not yet been popped with PopClip. Return Nothing() if the clip stack
   // is empty.
   Maybe<WrClipId> TopmostClipId();
-  // Returns the scroll id that was pushed just before the given scroll id.
-  // If the given scroll id is not in the stack of active scrolled layers, or if
-  // it is the rootmost scroll id (and therefore has no ancestor), this function
-  // returns Nothing().
+  // Returns the scroll id that was pushed just before the given scroll id. This
+  // function returns Nothing() if the given scrollid has not been encountered,
+  // or if it is the rootmost scroll id (and therefore has no ancestor).
   Maybe<layers::FrameMetrics::ViewID> ParentScrollIdFor(layers::FrameMetrics::ViewID aScrollId);
 
   // Try to avoid using this when possible.
   WrState* Raw() { return mWrState; }
 protected:
   WrState* mWrState;
 
   // Track the stack of clip ids and scroll layer ids that have been pushed
   // (by PushClip and PushScrollLayer, respectively) and are still active.
   // This is helpful for knowing e.g. what the ancestor scroll id of a particular
   // scroll id is, and doing other "queries" of current state.
   std::vector<WrClipId> mClipIdStack;
   std::vector<layers::FrameMetrics::ViewID> mScrollIdStack;
 
+  // Track the parent scroll id of each scroll id that we encountered.
+  std::unordered_map<layers::FrameMetrics::ViewID, layers::FrameMetrics::ViewID> mScrollParents;
+
   friend class WebRenderAPI;
 };
 
 Maybe<WrImageFormat>
 SurfaceFormatToWrImageFormat(gfx::SurfaceFormat aFormat);
 
 } // namespace wr
 } // namespace mozilla