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
--- 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)