Bug 1364525 - Produce scrollbar thumb transforms. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 19 May 2017 10:37:52 -0400
changeset 581198 22d801f9bf5c2877e754f4e85f34f74cbf19061a
parent 581197 933472faa7f42d40241a2a4c321bf9cd4ce52828
child 581199 03ca0bea4d4abeb4853926720777f318f3e4253e
push id59812
push userkgupta@mozilla.com
push dateFri, 19 May 2017 14:38:46 +0000
reviewersbotond
bugs1364525
milestone55.0a1
Bug 1364525 - Produce scrollbar thumb transforms. r?botond This updates PushStateToWR to actually produce the scrollbar thumb transforms and append them into the provided transform array. MozReview-Commit-ID: FN3X7yfTPrT
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/webrender_bindings/WebRenderTypes.h
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -370,16 +370,23 @@ APZCTreeManager::PushStateToWR(wr::WebRe
                                const TimeStamp& aSampleTime,
                                nsTArray<WrTransformProperty>& aTransformArray)
 {
   APZThreadUtils::AssertOnCompositorThread();
   MOZ_ASSERT(aWrApi);
 
   MutexAutoLock lock(mTreeLock);
 
+  // During the first pass through the tree, we build a cache of guid->HTTN so
+  // that we can find the relevant APZC instances quickly in subsequent passes,
+  // such as the one below to generate scrollbar transforms. Without this, perf
+  // could end up being O(n^2) instead of O(n) because we'd have to search the
+  // tree to find the corresponding APZC every time we hit a thumb node.
+  std::map<ScrollableLayerGuid, HitTestingTreeNode*> httnMap;
+
   bool activeAnimations = false;
   uint64_t lastLayersId = -1;
   WrPipelineId lastPipelineId;
 
   // We iterate backwards here because the HitTestingTreeNode is optimized
   // for backwards iteration. The equivalent code in AsyncCompositionManager
   // iterates forwards, but the direction shouldn't really matter in practice
   // so we do what's faster. In the future, if we need to start doing the
@@ -398,30 +405,73 @@ APZCTreeManager::PushStateToWR(wr::WebRe
           // If we walked into or out of a subtree, we need to get the new
           // pipeline id.
           lastLayersId = aNode->GetLayersId();
           const LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(lastLayersId);
           MOZ_ASSERT(state && state->mWrBridge);
           lastPipelineId = state->mWrBridge->PipelineId();
         }
 
+        // Use a 0 presShellId because when we do a lookup in this map for the
+        // scrollbar below we don't have (or care about) the presShellId.
+        ScrollableLayerGuid guid(lastLayersId, 0, apzc->GetGuid().mScrollId);
+        httnMap.insert(std::make_pair(guid, aNode));
+
         ParentLayerPoint layerTranslation = apzc->GetCurrentAsyncTransform(
             AsyncPanZoomController::RESPECT_FORCE_DISABLE).mTranslation;
         // The positive translation means the painted content is supposed to
         // move down (or to the right), and that corresponds to a reduction in
         // the scroll offset. Since we are effectively giving WR the async
         // scroll delta here, we want to negate the translation.
         ParentLayerPoint asyncScrollDelta = -layerTranslation;
         aWrApi->UpdateScrollPosition(lastPipelineId, apzc->GetGuid().mScrollId,
             wr::ToWrPoint(asyncScrollDelta));
 
         apzc->ReportCheckerboard(aSampleTime);
         activeAnimations |= apzc->AdvanceAnimations(aSampleTime);
       });
 
+  // Now we iterate over the nodes again, and generate the transforms needed
+  // for scrollbar thumbs. Although we *could* do this as part of the previous
+  // iteration, it's cleaner and more efficient to do it as a separate pass
+  // because now we have a populated httnMap which allows O(n) runtime here.
+  ForEachNode<ReverseIterator>(mRootNode.get(),
+      [&](HitTestingTreeNode* aNode)
+      {
+        if (!aNode->IsScrollThumbNode()) {
+          return;
+        }
+        ScrollableLayerGuid guid(aNode->GetLayersId(), 0, aNode->GetScrollTargetId());
+        auto it = httnMap.find(guid);
+        if (it == httnMap.end()) {
+          // A scrollbar for content which didn't have an APZC. Possibly the
+          // content isn't layerized. Regardless, we can't async-scroll it so
+          // we can skip the async transform on the scrollbar.
+          return;
+        }
+
+        HitTestingTreeNode* scrollTargetNode = it->second;
+        AsyncPanZoomController* scrollTargetApzc = scrollTargetNode->GetApzc();
+        MOZ_ASSERT(scrollTargetApzc);
+        LayerToParentLayerMatrix4x4 transform = scrollTargetApzc->CallWithLastContentPaintMetrics(
+            [&](const FrameMetrics& aMetrics) {
+                return AsyncCompositionManager::ComputeTransformForScrollThumb(
+                    aNode->GetTransform() * AsyncTransformMatrix(),
+                    scrollTargetNode->GetTransform().ToUnknownMatrix(),
+                    scrollTargetApzc,
+                    aMetrics,
+                    aNode->GetScrollThumbData(),
+                    scrollTargetNode->IsAncestorOf(aNode),
+                    nullptr);
+            });
+        aTransformArray.AppendElement(wr::ToWrTransformProperty(
+            aNode->GetScrollbarAnimationId(),
+            transform));
+      });
+
   return activeAnimations;
 }
 
 // Compute the clip region to be used for a layer with an APZC. This function
 // is only called for layers which actually have scrollable metrics and an APZC.
 template<class ScrollNode> static ParentLayerIntRegion
 ComputeClipRegion(GeckoContentController* aController,
                   const ScrollNode& aLayer)
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -358,17 +358,19 @@ static inline WrRepeatMode ToWrRepeatMod
     return WrRepeatMode::Space;
   default:
     MOZ_ASSERT(false);
   }
 
   return WrRepeatMode::Stretch;
 }
 
-static inline WrTransformProperty ToWrTransformProperty(uint64_t id, gfx::Matrix4x4& transform)
+template<class S, class T>
+static inline WrTransformProperty ToWrTransformProperty(uint64_t id,
+                                                        const gfx::Matrix4x4Typed<S, T>& transform)
 {
   WrTransformProperty prop;
   prop.id = id;
   prop.transform = ToWrMatrix(transform);
   return prop;
 }
 
 static inline WrOpacityProperty ToWrOpacityProperty(uint64_t id, const float opacity)