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.
This commit is contained in:
Kartikaya Gupta 2014-11-14 07:40:15 -05:00
parent 9a09468407
commit 2163ba0978
3 changed files with 60 additions and 38 deletions

View File

@ -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<AsyncPanZoomController> apzc = GetTargetAPZC(panInput.mPanStartPoint,
&inOverscrolledApzc);
&hitResult);
if (apzc) {
MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
transformToApzc = GetScreenToApzcTransform(apzc);
panInput.mLocalPanStartPoint = TransformTo<ParentLayerPixel>(
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<AsyncPanZoomController> apzc = GetTargetAPZC(pinchInput.mFocusPoint,
&inOverscrolledApzc);
&hitResult);
if (apzc) {
MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
transformToApzc = GetScreenToApzcTransform(apzc);
pinchInput.mLocalFocusPoint = TransformTo<ParentLayerPixel>(
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<AsyncPanZoomController> apzc = GetTargetAPZC(tapInput.mPoint,
&inOverscrolledApzc);
&hitResult);
if (apzc) {
MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
transformToApzc = GetScreenToApzcTransform(apzc);
tapInput.mLocalPoint = TransformTo<ParentLayerPixel>(
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<AsyncPanZoomController>
APZCTreeManager::GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
bool* aOutInOverscrolledApzc)
HitTestResult* aOutHitResult)
{
nsRefPtr<AsyncPanZoomController> 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<AsyncPanZoomController> apzc2 = GetTargetAPZC(aEvent.mTouches[i].mScreenPoint, aOutInOverscrolledApzc);
nsRefPtr<AsyncPanZoomController> 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<AsyncPanZoomController> apzc = GetTouchInputBlockAPZC(aInput, &mInOverscrolledApzc);
mHitResultForInputBlock = NoApzcHit;
nsRefPtr<AsyncPanZoomController> 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<AsyncPanZoomController> 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<LayoutDevicePixel>(outTransform, aEvent.refPoint);
}
if (inOverscrolledApzc) {
if (hitResult == OverscrolledApzc) {
result = nsEventStatus_eConsumeNoDefault;
}
return result;
@ -1140,24 +1146,24 @@ APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid)
}
already_AddRefed<AsyncPanZoomController>
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint, bool* aOutInOverscrolledApzc)
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint, HitTestResult* aOutHitResult)
{
MonitorAutoLock lock(mTreeLock);
nsRefPtr<AsyncPanZoomController> 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;
}

View File

@ -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<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
already_AddRefed<AsyncPanZoomController> 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<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc);
already_AddRefed<AsyncPanZoomController> 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<AsyncPanZoomController> 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.

View File

@ -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();
}