From 2163ba09785784d32cc56d771d671b33645d0009 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 14 Nov 2014 07:40:15 -0500 Subject: [PATCH] Bug 1090398 - Distinguish the various outcomes of APZ hit testing more explicitly. r=botond Previously we output of APZ hit testing was an APZC instance and an "in overscroll" flag. Now we need to also distinguish between the hit region and the dispatch-to-content region for an APZC, so this patch introduces an enum that makes this more explicit. --- gfx/layers/apz/src/APZCTreeManager.cpp | 74 ++++++++++++--------- gfx/layers/apz/src/APZCTreeManager.h | 19 ++++-- gfx/layers/apz/src/AsyncPanZoomController.h | 5 ++ 3 files changed, 60 insertions(+), 38 deletions(-) diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 347f378cd5f9..a0b92a271652 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -75,7 +75,7 @@ APZCTreeManager::CalculatePendingDisplayPort( APZCTreeManager::APZCTreeManager() : mInputQueue(new InputQueue()), mTreeLock("APZCTreeLock"), - mInOverscrolledApzc(false), + mHitResultForInputBlock(NoApzcHit), mRetainedTouchIdentifier(-1), mTouchCount(0), mApzcTreeLog("apzctree") @@ -605,7 +605,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, } nsEventStatus result = nsEventStatus_eIgnore; Matrix4x4 transformToApzc; - bool inOverscrolledApzc = false; + HitTestResult hitResult = NoApzcHit; switch (aEvent.mInputType) { case MULTITOUCH_INPUT: { MultiTouchInput& touchInput = aEvent.AsMultiTouchInput(); @@ -614,8 +614,9 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, } case PANGESTURE_INPUT: { PanGestureInput& panInput = aEvent.AsPanGestureInput(); nsRefPtr apzc = GetTargetAPZC(panInput.mPanStartPoint, - &inOverscrolledApzc); + &hitResult); if (apzc) { + MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion); transformToApzc = GetScreenToApzcTransform(apzc); panInput.mLocalPanStartPoint = TransformTo( transformToApzc, panInput.mPanStartPoint); @@ -635,8 +636,9 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, } case PINCHGESTURE_INPUT: { // note: no one currently sends these PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput(); nsRefPtr apzc = GetTargetAPZC(pinchInput.mFocusPoint, - &inOverscrolledApzc); + &hitResult); if (apzc) { + MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion); transformToApzc = GetScreenToApzcTransform(apzc); pinchInput.mLocalFocusPoint = TransformTo( transformToApzc, pinchInput.mFocusPoint); @@ -652,8 +654,9 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, } case TAPGESTURE_INPUT: { // note: no one currently sends these TapGestureInput& tapInput = aEvent.AsTapGestureInput(); nsRefPtr apzc = GetTargetAPZC(tapInput.mPoint, - &inOverscrolledApzc); + &hitResult); if (apzc) { + MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion); transformToApzc = GetScreenToApzcTransform(apzc); tapInput.mLocalPoint = TransformTo( transformToApzc, tapInput.mPoint); @@ -667,7 +670,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, break; } } - if (inOverscrolledApzc) { + if (hitResult == OverscrolledApzc) { result = nsEventStatus_eConsumeNoDefault; } return result; @@ -675,7 +678,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, already_AddRefed APZCTreeManager::GetTouchInputBlockAPZC(const MultiTouchInput& aEvent, - bool* aOutInOverscrolledApzc) + HitTestResult* aOutHitResult) { nsRefPtr apzc; if (aEvent.mTouches.Length() == 0) { @@ -696,9 +699,9 @@ APZCTreeManager::GetTouchInputBlockAPZC(const MultiTouchInput& aEvent, } } - apzc = GetTargetAPZC(aEvent.mTouches[0].mScreenPoint, aOutInOverscrolledApzc); + apzc = GetTargetAPZC(aEvent.mTouches[0].mScreenPoint, aOutHitResult); for (size_t i = 1; i < aEvent.mTouches.Length(); i++) { - nsRefPtr apzc2 = GetTargetAPZC(aEvent.mTouches[i].mScreenPoint, aOutInOverscrolledApzc); + nsRefPtr apzc2 = GetTargetAPZC(aEvent.mTouches[i].mScreenPoint, aOutHitResult); apzc = CommonAncestor(apzc.get(), apzc2.get()); APZCTM_LOG("Using APZC %p as the common ancestor\n", apzc.get()); // For now, we only ever want to do pinching on the root APZC for a given layers id. So @@ -730,8 +733,8 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput, // NS_TOUCH_START event contains all active touches of the current // session thus resetting mTouchCount. mTouchCount = aInput.mTouches.Length(); - mInOverscrolledApzc = false; - nsRefPtr apzc = GetTouchInputBlockAPZC(aInput, &mInOverscrolledApzc); + mHitResultForInputBlock = NoApzcHit; + nsRefPtr apzc = GetTouchInputBlockAPZC(aInput, &mHitResultForInputBlock); if (apzc != mApzcForInputBlock) { // If we're moving to a different APZC as our input target, then send a cancel event // to the old one so that it clears its internal state. Otherwise it could get left @@ -778,6 +781,8 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput, nsEventStatus result = nsEventStatus_eIgnore; if (mApzcForInputBlock) { + MOZ_ASSERT(mHitResultForInputBlock == ApzcHitRegion || mHitResultForInputBlock == ApzcContentRegion); + mApzcForInputBlock->GetGuid(aOutTargetGuid); // For computing the input for the APZC, used the cached transform. // This ensures that the sequence of touch points an APZC sees in an @@ -802,7 +807,7 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput, outTransform, touchData.mScreenPoint); } } - if (mInOverscrolledApzc) { + if (mHitResultForInputBlock == OverscrolledApzc) { result = nsEventStatus_eConsumeNoDefault; } @@ -822,7 +827,7 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput, // don't keep dangling references and leak things. if (mTouchCount == 0) { mApzcForInputBlock = nullptr; - mInOverscrolledApzc = false; + mHitResultForInputBlock = NoApzcHit; mRetainedTouchIdentifier = -1; } @@ -853,17 +858,18 @@ APZCTreeManager::ProcessEvent(WidgetInputEvent& aEvent, // Transform the refPoint. // If the event hits an overscrolled APZC, instruct the caller to ignore it. - bool inOverscrolledApzc = false; + HitTestResult hitResult = NoApzcHit; nsRefPtr apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y), - &inOverscrolledApzc); + &hitResult); if (apzc) { + MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion); apzc->GetGuid(aOutTargetGuid); Matrix4x4 transformToApzc = GetScreenToApzcTransform(apzc); Matrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc); Matrix4x4 outTransform = transformToApzc * transformToGecko; aEvent.refPoint = TransformTo(outTransform, aEvent.refPoint); } - if (inOverscrolledApzc) { + if (hitResult == OverscrolledApzc) { result = nsEventStatus_eConsumeNoDefault; } return result; @@ -1140,24 +1146,24 @@ APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid) } already_AddRefed -APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint, bool* aOutInOverscrolledApzc) +APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint, HitTestResult* aOutHitResult) { MonitorAutoLock lock(mTreeLock); nsRefPtr target; // The root may have siblings, so check those too - bool inOverscrolledApzc = false; + HitTestResult hitResult = NoApzcHit; for (AsyncPanZoomController* apzc = mRootApzc; apzc; apzc = apzc->GetPrevSibling()) { - target = GetAPZCAtPoint(apzc, aPoint.ToUnknownPoint(), &inOverscrolledApzc); + target = GetAPZCAtPoint(apzc, aPoint.ToUnknownPoint(), &hitResult); // If we hit an overscrolled APZC, 'target' will be nullptr but it's still // a hit so we don't search further siblings. - if (target || inOverscrolledApzc) { + if (target || (hitResult == OverscrolledApzc)) { break; } } // If we are in an overscrolled APZC, we should be returning nullptr. - MOZ_ASSERT(!(target && inOverscrolledApzc)); - if (aOutInOverscrolledApzc) { - *aOutInOverscrolledApzc = inOverscrolledApzc; + MOZ_ASSERT(!(target && (hitResult == OverscrolledApzc))); + if (aOutHitResult) { + *aOutHitResult = hitResult; } return target.forget(); } @@ -1278,7 +1284,7 @@ APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableL AsyncPanZoomController* APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, const Point& aHitTestPoint, - bool* aOutInOverscrolledApzc) + HitTestResult* aOutHitResult) { mTreeLock.AssertCurrentThreadOwns(); @@ -1316,8 +1322,8 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, // APZCs front-to-back on the screen. if (hitTestPointForChildLayers.HasPositiveWCoord()) { for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) { - AsyncPanZoomController* match = GetAPZCAtPoint(child, hitTestPointForChildLayers.As2DPoint(), aOutInOverscrolledApzc); - if (*aOutInOverscrolledApzc) { + AsyncPanZoomController* match = GetAPZCAtPoint(child, hitTestPointForChildLayers.As2DPoint(), aOutHitResult); + if (*aOutHitResult == OverscrolledApzc) { // We matched an overscrolled APZC, abort. return nullptr; } @@ -1327,18 +1333,22 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, } } } - if (!result && hitTestPointForThisLayer.HasPositiveWCoord() && - aApzc->HitRegionContains(ParentLayerPoint::FromUnknownPoint(hitTestPointForThisLayer.As2DPoint()))) { - APZCTM_LOG("Successfully matched untransformed point %f %f to visible region for APZC %p\n", - hitTestPointForThisLayer.x, hitTestPointForThisLayer.y, aApzc); - result = aApzc; + if (!result && hitTestPointForThisLayer.HasPositiveWCoord()) { + ParentLayerPoint point = ParentLayerPoint::FromUnknownPoint(hitTestPointForThisLayer.As2DPoint()); + if (aApzc->HitRegionContains(point)) { + APZCTM_LOG("Successfully matched untransformed point %f %f to visible region for APZC %p\n", + hitTestPointForThisLayer.x, hitTestPointForThisLayer.y, aApzc); + result = aApzc; + // If event regions are disabled, *aOutHitResult will be ApzcHitRegion + *aOutHitResult = (aApzc->DispatchToContentRegionContains(point) ? ApzcContentRegion : ApzcHitRegion); + } } // If we are overscrolled, and the point matches us or one of our children, // the result is inside an overscrolled APZC, inform our caller of this // (callers typically ignore events targeted at overscrolled APZCs). if (result && aApzc->IsOverscrolled()) { - *aOutInOverscrolledApzc = true; + *aOutHitResult = OverscrolledApzc; result = nullptr; } diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h index d6776267c7f5..8a4d6c2a9a56 100644 --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -373,9 +373,16 @@ public: about it going away. These are public for testing code and generally should not be used by other production code. */ + enum HitTestResult { + NoApzcHit, + ApzcHitRegion, + ApzcContentRegion, + OverscrolledApzc, + }; + already_AddRefed GetTargetAPZC(const ScrollableLayerGuid& aGuid); already_AddRefed GetTargetAPZC(const ScreenPoint& aPoint, - bool* aOutInOverscrolledApzc); + HitTestResult* aOutHitResult); gfx::Matrix4x4 GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) const; gfx::Matrix4x4 GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const; private: @@ -384,11 +391,11 @@ private: AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid); AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfx::Point& aHitTestPoint, - bool* aOutInOverscrolledApzc); + HitTestResult* aOutHitResult); already_AddRefed CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2); already_AddRefed RootAPZCForLayersId(AsyncPanZoomController* aApzc); already_AddRefed GetTouchInputBlockAPZC(const MultiTouchInput& aEvent, - bool* aOutInOverscrolledApzc); + HitTestResult* aOutHitResult); nsEventStatus ProcessTouchInput(MultiTouchInput& aInput, ScrollableLayerGuid* aOutTargetGuid, uint64_t* aOutInputBlockId); @@ -450,10 +457,10 @@ private: * input delivery thread, and so does not require locking. */ nsRefPtr mApzcForInputBlock; - /* Whether the current input event block is being ignored because the touch-start - * was inside an overscrolled APZC. + /* The hit result for the current input event block; this should always be in + * sync with mApzcForInputBlock. */ - bool mInOverscrolledApzc; + HitTestResult mHitResultForInputBlock; /* Sometimes we want to ignore all touches except one. In such cases, this * is set to the identifier of the touch we are not ignoring; in other cases, * this is set to -1. diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index 725bc71eb631..3301f6019930 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -1016,6 +1016,11 @@ public: return mEventRegions.mHitRegion.Contains(point.x, point.y); } + bool DispatchToContentRegionContains(const ParentLayerPoint& aPoint) const { + ParentLayerIntPoint point = RoundedToInt(aPoint); + return mEventRegions.mDispatchToContentHitRegion.Contains(point.x, point.y); + } + bool IsOverscrolled() const { return mX.IsOverscrolled() || mY.IsOverscrolled(); }