Bug 1412112 - Cache the view id on the ASR to speed up the ViewIDForASR operation. r?mstange draft
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 23 Nov 2017 12:22:22 -0500
changeset 702697 4063bf80f86ef951ad2b9ad479efadfb9baa95d7
parent 702588 b6bed1b710c3e22cab49f22f1b5f44d80286bcb9
child 741571 2463ed92c984e6dc1f7bdec4ace095d66f276eb3
push id90599
push userkgupta@mozilla.com
push dateThu, 23 Nov 2017 17:22:47 +0000
reviewersmstange
bugs1412112
milestone59.0a1
Bug 1412112 - Cache the view id on the ASR to speed up the ViewIDForASR operation. r?mstange This also moves the function from nsLayoutUtils to be a function on the ASR itself, which seems more appropriate. MozReview-Commit-ID: 88lUmYi80P0
gfx/layers/wr/ScrollingLayersHelper.cpp
gfx/layers/wr/WebRenderScrollData.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/painting/FrameLayerBuilder.cpp
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/gfx/layers/wr/ScrollingLayersHelper.cpp
+++ b/gfx/layers/wr/ScrollingLayersHelper.cpp
@@ -104,17 +104,17 @@ ScrollingLayersHelper::BeginItem(nsDispl
   // would only need to push one thing here and we would be done. However, we
   // also care about the ScrollingLayersHelper instance that might be created
   // for nested display items, in the case where aItem is a wrapper item. The
   // nested ScrollingLayersHelper may rely on things like TopmostScrollId and
   // TopmostClipId, so now we need to push at most two things onto the stack.
 
   FrameMetrics::ViewID leafmostId = ids.first.valueOr(FrameMetrics::NULL_SCROLL_ID);
   FrameMetrics::ViewID scrollId = aItem->GetActiveScrolledRoot()
-      ? nsLayoutUtils::ViewIDForASR(aItem->GetActiveScrolledRoot())
+      ? aItem->GetActiveScrolledRoot()->GetViewId()
       : FrameMetrics::NULL_SCROLL_ID;
   // If the leafmost ASR is not the same as the item's ASR then we are dealing
   // with a case where the item's clip chain is scrolled by something other than
   // the item's ASR. So for those cases we need to use the ClipAndScroll API.
   bool needClipAndScroll = (leafmostId != scrollId);
 
   // The other scenario where we need to push a ClipAndScroll is when we are
   // in a nested display item where the enclosing item pushed a ClipAndScroll,
@@ -232,17 +232,17 @@ ScrollingLayersHelper::RecurseAndDefineC
     auto it = mCache.find(aChain);
     if (it != mCache.end()) {
       ids.second = Some(it->second);
     }
   }
   if (ids.second) {
     // If we've already got an id for this clip, we can early-exit
     if (aAsr) {
-      FrameMetrics::ViewID scrollId = nsLayoutUtils::ViewIDForASR(aAsr);
+      FrameMetrics::ViewID scrollId = aAsr->GetViewId();
       MOZ_ASSERT(mBuilder->IsScrollLayerDefined(scrollId));
       ids.first = Some(scrollId);
     }
     return ids;
   }
 
   // If not, recurse to ensure all the ancestors are defined
   auto ancestorIds = DefineClipChain(
@@ -271,17 +271,17 @@ ScrollingLayersHelper::RecurseAndDefineC
     } else {
       // But if the ASRs are different, this is the outermost clip that's
       // still inside aAsr, and we need to make it a child of aAsr rather
       // than aChain->mParent.
       ancestorIds.second = Nothing();
     }
   } else {
     MOZ_ASSERT(!ancestorIds.second);
-    FrameMetrics::ViewID scrollId = aChain->mASR ? nsLayoutUtils::ViewIDForASR(aChain->mASR) : FrameMetrics::NULL_SCROLL_ID;
+    FrameMetrics::ViewID scrollId = aChain->mASR ? aChain->mASR->GetViewId() : FrameMetrics::NULL_SCROLL_ID;
     if (mBuilder->TopmostScrollId() == scrollId) {
       if (mBuilder->TopmostIsClip()) {
         // If aChain->mASR is already the topmost scroll layer on the stack, but
         // but there was another clip pushed *on top* of that ASR, then that clip
         // shares the ASR, and we need to make our clip a child of that clip, which
         // in turn will already be a descendant of the correct ASR.
         // This covers the cases where e.g. the Gecko display list has nested items,
         // and the clip chain on the nested item implicitly extends from the clip
@@ -339,17 +339,17 @@ ScrollingLayersHelper::RecurseAndDefineA
                                            int32_t aAppUnitsPerDevPixel,
                                            const StackingContextHelper& aSc)
 {
   MOZ_ASSERT(aAsr);
 
   // This will hold our return value
   std::pair<Maybe<FrameMetrics::ViewID>, Maybe<wr::WrClipId>> ids;
 
-  FrameMetrics::ViewID scrollId = nsLayoutUtils::ViewIDForASR(aAsr);
+  FrameMetrics::ViewID scrollId = aAsr->GetViewId();
   if (mBuilder->IsScrollLayerDefined(scrollId)) {
     // If we've already defined this scroll layer before, we can early-exit
     ids.first = Some(scrollId);
     if (aChain) {
       if (mBuilder->HasExtraClip()) {
         ids.second = mBuilder->GetCacheOverride(aChain);
       } else {
         auto it = mCache.find(aChain);
--- a/gfx/layers/wr/WebRenderScrollData.cpp
+++ b/gfx/layers/wr/WebRenderScrollData.cpp
@@ -49,17 +49,17 @@ WebRenderLayerScrollData::Initialize(Web
   mDescendantCount = aDescendantCount;
 
   MOZ_ASSERT(aItem);
   aItem->UpdateScrollData(&aOwner, this);
   for (const ActiveScrolledRoot* asr = aItem->GetActiveScrolledRoot();
        asr && asr != aStopAtAsr;
        asr = asr->mParent) {
     MOZ_ASSERT(aOwner.GetManager());
-    FrameMetrics::ViewID scrollId = nsLayoutUtils::ViewIDForASR(asr);
+    FrameMetrics::ViewID scrollId = asr->GetViewId();
     if (Maybe<size_t> index = aOwner.HasMetadataFor(scrollId)) {
       mScrollIds.AppendElement(index.ref());
     } else {
       Maybe<ScrollMetadata> metadata = asr->mScrollableFrame->ComputeScrollMetadata(
           nullptr, aOwner.GetManager(), aItem->ReferenceFrame(),
           ContainerLayerParameters(), nullptr);
       MOZ_ASSERT(metadata);
       MOZ_ASSERT(metadata->GetMetrics().GetScrollId() == scrollId);
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -863,23 +863,16 @@ nsLayoutUtils::FindContentFor(ViewID aId
 
   if (exists) {
     return content;
   } else {
     return nullptr;
   }
 }
 
-ViewID
-nsLayoutUtils::ViewIDForASR(const mozilla::ActiveScrolledRoot* aASR)
-{
-  nsIContent* content = aASR->mScrollableFrame->GetScrolledFrame()->GetContent();
-  return nsLayoutUtils::FindOrCreateIDFor(content);
-}
-
 nsIFrame*
 GetScrollFrameFromContent(nsIContent* aContent)
 {
   nsIFrame* frame = aContent->GetPrimaryFrame();
   if (aContent->OwnerDoc()->GetRootElement() == aContent) {
     nsIPresShell* presShell = frame ? frame->PresShell() : nullptr;
     if (!presShell) {
       presShell = aContent->OwnerDoc()->GetShell();
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -182,22 +182,16 @@ public:
   static ViewID FindOrCreateIDFor(nsIContent* aContent);
 
   /**
    * Find content for given ID.
    */
   static nsIContent* FindContentFor(ViewID aId);
 
   /**
-   * Find the view ID (or generate a new one) for the content element
-   * corresponding to the ASR.
-   */
-  static ViewID ViewIDForASR(const mozilla::ActiveScrolledRoot* aASR);
-
-  /**
    * Find the scrollable frame for a given ID.
    */
   static nsIScrollableFrame* FindScrollableFrameFor(ViewID aId);
 
   /**
    * Find the ID for a given scrollable frame.
    */
   static ViewID FindIDForScrollableFrame(nsIScrollableFrame* aScrollable);
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -5032,17 +5032,17 @@ FixUpFixedPositionLayer(Layer* aLayer,
     aLeafScrollMetadataASR == aContainerScrollMetadataASR
       ? aContainerCompositorASR
       : aLeafScrollMetadataASR;
 
   // The goal of the annotation is to have the layer move with aTargetASR.
   if (compositorASR && aTargetASR != compositorASR) {
     // Mark this layer as fixed with respect to the child scroll frame of aTargetASR.
     aLayer->SetFixedPositionData(
-      nsLayoutUtils::ViewIDForASR(FindDirectChildASR(aTargetASR, compositorASR)),
+      FindDirectChildASR(aTargetASR, compositorASR)->GetViewId(),
       aLayer->GetFixedPositionAnchor(),
       aLayer->GetFixedPositionSides());
   } else {
     // Remove the fixed annotation from the layer, unless this layers is fixed
     // to the document's root scroll frame - in that case, the annotation is
     // needed for hit testing, because fixed layers in iframes should scroll
     // the iframe, even though their position is not affected by scrolling in
     // the iframe. (The APZ hit testing code has a special case for this.)
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4900,17 +4900,17 @@ nsDisplayCompositorHitTestInfo::CreateWe
 
   // XXX: eventually this scrollId computation and the SetHitTestInfo
   // call will get moved out into the WR display item iteration code so that
   // we don't need to do it as often, and so that we can do it for other
   // display item types as well (reducing the need for as many instances of
   // this display item).
   FrameMetrics::ViewID scrollId = FrameMetrics::NULL_SCROLL_ID;
   if (const ActiveScrolledRoot* asr = GetActiveScrolledRoot()) {
-    scrollId = nsLayoutUtils::ViewIDForASR(asr);
+    scrollId = asr->GetViewId();
   }
 
   // Insert a transparent rectangle with the hit-test info
   aBuilder.SetHitTestInfo(scrollId, mHitTestInfo);
   aBuilder.PushRect(rect, rect, true, wr::ToColorF(gfx::Color()));
   aBuilder.ClearHitTestInfo();
 
   return true;
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -257,16 +257,17 @@ struct ActiveScrolledRoot {
 
       if (aIsRetained) {
         RefPtr<ActiveScrolledRoot> ref = asr;
         f->SetProperty(ActiveScrolledRootCache(), ref.forget().take());
       }
     }
     asr->mParent = aParent;
     asr->mScrollableFrame = aScrollableFrame;
+    asr->mViewId = Nothing();
     asr->mDepth = aParent ? aParent->mDepth + 1 : 1;
     asr->mRetained = aIsRetained;
 
     return asr.forget();
   }
 
   static const ActiveScrolledRoot* PickAncestor(const ActiveScrolledRoot* aOne,
                                                 const ActiveScrolledRoot* aTwo)
@@ -285,16 +286,28 @@ struct ActiveScrolledRoot {
   static bool IsAncestor(const ActiveScrolledRoot* aAncestor,
                          const ActiveScrolledRoot* aDescendant);
 
   static nsCString ToString(const mozilla::ActiveScrolledRoot* aActiveScrolledRoot);
 
   // Call this when inserting an ancestor.
   void IncrementDepth() { mDepth++; }
 
+  /**
+   * Find the view ID (or generate a new one) for the content element
+   * corresponding to the ASR.
+   */
+  mozilla::layers::FrameMetrics::ViewID GetViewId() const {
+    if (!mViewId.isSome()) {
+      nsIContent* content = mScrollableFrame->GetScrolledFrame()->GetContent();
+      mViewId = Some(nsLayoutUtils::FindOrCreateIDFor(content));
+    }
+    return *mViewId;
+  }
+
   RefPtr<const ActiveScrolledRoot> mParent;
   nsIScrollableFrame* mScrollableFrame;
 
   NS_INLINE_DECL_REFCOUNTING(ActiveScrolledRoot)
 
 private:
   ActiveScrolledRoot()
   {
@@ -314,16 +327,21 @@ private:
     NS_RELEASE(aASR);
   }
   NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(ActiveScrolledRootCache, ActiveScrolledRoot, DetachASR)
 
   static uint32_t Depth(const ActiveScrolledRoot* aActiveScrolledRoot) {
     return aActiveScrolledRoot ? aActiveScrolledRoot->mDepth : 0;
   }
 
+  // This field is lazily populated in GetViewId(). We don't want to do the
+  // work of populating if webrender is disabled, because it is often not
+  // needed.
+  mutable Maybe<mozilla::layers::FrameMetrics::ViewID> mViewId;
+
   uint32_t mDepth;
   bool mRetained;
 };
 
 }
 
 enum class nsDisplayListBuilderMode : uint8_t {
   PAINTING,