Bug 1417519 - Hook up APZ to use the hit-testing API. r?botond,mstange
This adds the code that APZ needs to use the WR hit-testing API. For now
(if the pref is enabled) it just does the hit-test and compares the
result to the regular hit-test, printing out discrepancies. It also
doesn't yet get the scrollbar result.
MozReview-Commit-ID: 3pjYSWDGeDr
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -2182,33 +2182,109 @@ APZCTreeManager::GetTargetNode(const Scr
return target.forget();
}
already_AddRefed<AsyncPanZoomController>
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint,
HitTestResult* aOutHitResult,
RefPtr<HitTestingTreeNode>* aOutScrollbarNode)
{
- MutexAutoLock lock(mTreeLock);
HitTestResult hitResult = HitNothing;
HitTestingTreeNode* scrollbarNode = nullptr;
- ParentLayerPoint point = ViewAs<ParentLayerPixel>(aPoint,
- PixelCastJustification::ScreenIsParentLayerForRoot);
- RefPtr<AsyncPanZoomController> target = GetAPZCAtPoint(mRootNode, point,
- &hitResult, &scrollbarNode);
+ RefPtr<AsyncPanZoomController> target;
+
+ { // scope mTreeLock
+ MutexAutoLock lock(mTreeLock);
+ target = GetAPZCAtPoint(mRootNode, aPoint, &hitResult, &scrollbarNode);
+ }
+
+ if (gfxPrefs::WebRenderHitTest()) {
+ HitTestResult wrHitResult = HitNothing;
+ RefPtr<AsyncPanZoomController> wrTarget = GetAPZCAtPointWR(aPoint, &wrHitResult);
+ // For now just compare the WR and non-WR results.
+ if (wrHitResult != hitResult) {
+ printf_stderr("WR hit result mismatch at %s: got %d, expected %d\n",
+ Stringify(aPoint).c_str(), (int)wrHitResult, (int)hitResult);
+ // MOZ_RELEASE_ASSERT(false);
+ }
+ if (wrTarget.get() != target.get()) {
+ printf_stderr("WR hit target mismatch at %s: got %s, expected %s\n",
+ Stringify(aPoint).c_str(),
+ wrTarget ? Stringify(wrTarget->GetGuid()).c_str() : "null",
+ target ? Stringify(target->GetGuid()).c_str() : "null");
+ // MOZ_RELEASE_ASSERT(false);
+ }
+ }
if (aOutHitResult) {
*aOutHitResult = hitResult;
}
if (aOutScrollbarNode) {
*aOutScrollbarNode = scrollbarNode;
}
return target.forget();
}
+already_AddRefed<AsyncPanZoomController>
+APZCTreeManager::GetAPZCAtPointWR(const ScreenPoint& aHitTestPoint,
+ HitTestResult* aOutHitResult)
+{
+ MOZ_ASSERT(aOutHitResult);
+
+ RefPtr<AsyncPanZoomController> result;
+ RefPtr<wr::WebRenderAPI> wr = GetWebRenderAPI();
+ if (!wr) {
+ return result.forget();
+ }
+
+ wr::WrPipelineId pipelineId;
+ FrameMetrics::ViewID scrollId;
+ gfx::CompositorHitTestInfo hitInfo;
+ bool hitSomething = wr->HitTest(wr::ToWorldPoint(aHitTestPoint),
+ pipelineId, scrollId, hitInfo);
+ if (!hitSomething) {
+ return result.forget();
+ }
+
+ uint64_t layersId = wr::AsUint64(pipelineId);
+ result = GetTargetAPZC(layersId, scrollId);
+ if (!result) {
+ // It falls back to the root
+ MOZ_ASSERT(scrollId == FrameMetrics::NULL_SCROLL_ID);
+ result = FindRootApzcForLayersId(layersId);
+ MOZ_ASSERT(result);
+ }
+
+ *aOutHitResult = HitLayer;
+ if (hitInfo & gfx::CompositorHitTestInfo::eDispatchToContent) {
+ *aOutHitResult = HitDispatchToContentRegion;
+ return result.forget();
+ }
+
+ auto touchFlags = hitInfo & gfx::CompositorHitTestInfo::eTouchActionMask;
+ if (!touchFlags) {
+ return result.forget();
+ }
+ if (touchFlags == gfx::CompositorHitTestInfo::eTouchActionMask) {
+ *aOutHitResult = HitLayerTouchActionNone;
+ return result.forget();
+ }
+
+ bool panX = !(hitInfo & gfx::CompositorHitTestInfo::eTouchActionPanXDisabled);
+ bool panY = !(hitInfo & gfx::CompositorHitTestInfo::eTouchActionPanYDisabled);
+ if (panX && panY) {
+ *aOutHitResult = HitLayerTouchActionPanXY;
+ } else if (panY) {
+ *aOutHitResult = HitLayerTouchActionPanY;
+ } else if (panX) {
+ *aOutHitResult = HitLayerTouchActionPanX;
+ }
+ return result.forget();
+}
+
RefPtr<const OverscrollHandoffChain>
APZCTreeManager::BuildOverscrollHandoffChain(const RefPtr<AsyncPanZoomController>& aInitialTarget)
{
// Scroll grabbing is a mechanism that allows content to specify that
// the initial target of a pan should be not the innermost scrollable
// frame at the touch point (which is what GetTargetAPZC finds), but
// something higher up in the tree.
// It's not sufficient to just find the initial target, however, as
@@ -2316,28 +2392,30 @@ APZCTreeManager::GetTargetApzcForNode(Hi
return fpNode ? fpNode->GetApzc() : nullptr;
}
}
return nullptr;
}
AsyncPanZoomController*
APZCTreeManager::GetAPZCAtPoint(HitTestingTreeNode* aNode,
- const ParentLayerPoint& aHitTestPoint,
+ const ScreenPoint& aHitTestPoint,
HitTestResult* aOutHitResult,
HitTestingTreeNode** aOutScrollbarNode)
{
mTreeLock.AssertCurrentThreadOwns();
// This walks the tree in depth-first, reverse order, so that it encounters
// APZCs front-to-back on the screen.
HitTestingTreeNode* resultNode;
HitTestingTreeNode* root = aNode;
std::stack<LayerPoint> hitTestPoints;
- hitTestPoints.push(ViewAs<LayerPixel>(aHitTestPoint,
+ ParentLayerPoint point = ViewAs<ParentLayerPixel>(aHitTestPoint,
+ PixelCastJustification::ScreenIsParentLayerForRoot);
+ hitTestPoints.push(ViewAs<LayerPixel>(point,
PixelCastJustification::MovingDownToChildren));
ForEachNode<ReverseIterator>(root,
[&hitTestPoints, this](HitTestingTreeNode* aNode) {
ParentLayerPoint hitTestPointForParent = ViewAs<ParentLayerPixel>(hitTestPoints.top(),
PixelCastJustification::MovingDownToChildren);
if (aNode->IsOutsideClip(hitTestPointForParent)) {
// If the point being tested is outside the clip region for this node
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -515,19 +515,21 @@ private:
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
already_AddRefed<HitTestingTreeNode> GetTargetNode(const ScrollableLayerGuid& aGuid,
GuidComparator aComparator) const;
HitTestingTreeNode* FindTargetNode(HitTestingTreeNode* aNode,
const ScrollableLayerGuid& aGuid,
GuidComparator aComparator);
AsyncPanZoomController* GetTargetApzcForNode(HitTestingTreeNode* aNode);
AsyncPanZoomController* GetAPZCAtPoint(HitTestingTreeNode* aNode,
- const ParentLayerPoint& aHitTestPoint,
+ const ScreenPoint& aHitTestPoint,
HitTestResult* aOutHitResult,
HitTestingTreeNode** aOutScrollbarNode);
+ already_AddRefed<AsyncPanZoomController> GetAPZCAtPointWR(const ScreenPoint& aHitTestPoint,
+ HitTestResult* aOutHitResult);
AsyncPanZoomController* FindRootApzcForLayersId(uint64_t aLayersId) const;
AsyncPanZoomController* FindRootContentApzcForLayersId(uint64_t aLayersId) const;
AsyncPanZoomController* FindRootContentOrRootApzc() const;
already_AddRefed<AsyncPanZoomController> GetMultitouchTarget(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const;
already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const;
/**
* Perform hit testing for a touch-start event.
*
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -278,16 +278,24 @@ static inline wr::LayoutPoint ToLayoutPo
return p;
}
static inline wr::LayoutPoint ToLayoutPoint(const mozilla::LayoutDeviceIntPoint& point)
{
return ToLayoutPoint(LayoutDevicePoint(point));
}
+static inline wr::WorldPoint ToWorldPoint(const mozilla::ScreenPoint& point)
+{
+ wr::WorldPoint p;
+ p.x = point.x;
+ p.y = point.y;
+ return p;
+}
+
static inline wr::LayoutVector2D ToLayoutVector2D(const mozilla::LayoutDevicePoint& point)
{
wr::LayoutVector2D p;
p.x = point.x;
p.y = point.y;
return p;
}