From 7430b1e2b7b58b2413c82bf4712eed4d149aae41 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Wed, 21 Aug 2013 12:03:02 -0400 Subject: [PATCH] Bug 898443 - Ensure that all multitouch events following a START go to the same APZC instance. r=BenWa --- gfx/layers/composite/APZCTreeManager.cpp | 77 ++++++++++++++++-------- gfx/layers/composite/APZCTreeManager.h | 7 ++- 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/gfx/layers/composite/APZCTreeManager.cpp b/gfx/layers/composite/APZCTreeManager.cpp index f07d74e87d0..0712488b670 100644 --- a/gfx/layers/composite/APZCTreeManager.cpp +++ b/gfx/layers/composite/APZCTreeManager.cpp @@ -211,25 +211,37 @@ ApplyTransform(nsIntPoint* aPoint, const gfx3DMatrix& aMatrix) nsEventStatus APZCTreeManager::ReceiveInputEvent(const InputData& aEvent) { - nsRefPtr apzc; gfx3DMatrix transformToApzc; gfx3DMatrix transformToScreen; switch (aEvent.mInputType) { case MULTITOUCH_INPUT: { const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput(); - apzc = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint), - transformToApzc, transformToScreen); - if (apzc) { + if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_START) { + mApzcForInputBlock = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint), + transformToApzc, transformToScreen); + } else { + if (mApzcForInputBlock) { + APZC_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get()); + GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToScreen); + // If we have an mApzcForInputBlock and it's the end of the touch sequence + // then null it out so we don't keep a dangling reference and leak things. + if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_CANCEL || + (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_END && multiTouchInput.mTouches.Length() == 1)) { + mApzcForInputBlock = nullptr; + } + } + } + if (mApzcForInputBlock) { MultiTouchInput inputForApzc(multiTouchInput); for (int i = inputForApzc.mTouches.Length() - 1; i >= 0; i--) { ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc); } - apzc->ReceiveInputEvent(inputForApzc); + mApzcForInputBlock->ReceiveInputEvent(inputForApzc); } break; } case PINCHGESTURE_INPUT: { const PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput(); - apzc = GetTargetAPZC(pinchInput.mFocusPoint, transformToApzc, transformToScreen); + nsRefPtr apzc = GetTargetAPZC(pinchInput.mFocusPoint, transformToApzc, transformToScreen); if (apzc) { PinchGestureInput inputForApzc(pinchInput); ApplyTransform(&(inputForApzc.mFocusPoint), transformToApzc); @@ -238,7 +250,7 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent) break; } case TAPGESTURE_INPUT: { const TapGestureInput& tapInput = aEvent.AsTapGestureInput(); - apzc = GetTargetAPZC(ScreenPoint(tapInput.mPoint), transformToApzc, transformToScreen); + nsRefPtr apzc = GetTargetAPZC(ScreenPoint(tapInput.mPoint), transformToApzc, transformToScreen); if (apzc) { TapGestureInput inputForApzc(tapInput); ApplyTransform(&(inputForApzc.mPoint), transformToApzc); @@ -256,37 +268,50 @@ APZCTreeManager::ReceiveInputEvent(const nsInputEvent& aEvent, { MOZ_ASSERT(NS_IsMainThread()); - nsRefPtr apzc; gfx3DMatrix transformToApzc; gfx3DMatrix transformToScreen; switch (aEvent.eventStructType) { case NS_TOUCH_EVENT: { const nsTouchEvent& touchEvent = static_cast(aEvent); - if (touchEvent.touches.Length() > 0) { + if (touchEvent.touches.Length() == 0) { + break; + } + if (touchEvent.message == NS_TOUCH_START) { nsIntPoint point = touchEvent.touches[0]->mRefPoint; - apzc = GetTargetAPZC(ScreenPoint::FromUnknownPoint(gfx::Point(point.x, point.y)), - transformToApzc, transformToScreen); - if (apzc) { - MultiTouchInput inputForApzc(touchEvent); - for (int i = inputForApzc.mTouches.Length() - 1; i >= 0; i--) { - ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc); + mApzcForInputBlock = GetTargetAPZC(ScreenPoint(point.x, point.y), + transformToApzc, transformToScreen); + } else { + if (mApzcForInputBlock) { + APZC_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get()); + GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToScreen); + // If we have an mApzcForInputBlock and it's the end of the touch sequence + // then null it out so we don't keep a dangling reference and leak things. + if (touchEvent.message == NS_TOUCH_CANCEL || + (touchEvent.message == NS_TOUCH_END && touchEvent.touches.Length() == 1)) { + mApzcForInputBlock = nullptr; } - - gfx3DMatrix outTransform = transformToApzc * transformToScreen; - nsTouchEvent* outEvent = static_cast(aOutEvent); - for (int i = outEvent->touches.Length() - 1; i >= 0; i--) { - ApplyTransform(&(outEvent->touches[i]->mRefPoint), outTransform); - } - - return apzc->ReceiveInputEvent(inputForApzc); } } + if (mApzcForInputBlock) { + MultiTouchInput inputForApzc(touchEvent); + for (int i = inputForApzc.mTouches.Length() - 1; i >= 0; i--) { + ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc); + } + + gfx3DMatrix outTransform = transformToApzc * transformToScreen; + nsTouchEvent* outEvent = static_cast(aOutEvent); + for (int i = outEvent->touches.Length() - 1; i >= 0; i--) { + ApplyTransform(&(outEvent->touches[i]->mRefPoint), outTransform); + } + + return mApzcForInputBlock->ReceiveInputEvent(inputForApzc); + } break; } case NS_MOUSE_EVENT: { const nsMouseEvent& mouseEvent = static_cast(aEvent); - apzc = GetTargetAPZC(ScreenPoint::FromUnknownPoint(gfx::Point(mouseEvent.refPoint.x, - mouseEvent.refPoint.y)), - transformToApzc, transformToScreen); + nsRefPtr apzc = + GetTargetAPZC(ScreenPoint(mouseEvent.refPoint.x, mouseEvent.refPoint.y), + transformToApzc, transformToScreen); if (apzc) { MultiTouchInput inputForApzc(mouseEvent); ApplyTransform(&(inputForApzc.mTouches[0].mScreenPoint), transformToApzc); diff --git a/gfx/layers/composite/APZCTreeManager.h b/gfx/layers/composite/APZCTreeManager.h index c151b5b9eac..4bccae259a8 100644 --- a/gfx/layers/composite/APZCTreeManager.h +++ b/gfx/layers/composite/APZCTreeManager.h @@ -142,7 +142,6 @@ public: * General handler for incoming input events. Manipulates the frame metrics * based on what type of input it is. For example, a PinchGestureEvent will * cause scaling. This should only be called externally to this class. - * HandleInputEvent() should be used internally. */ nsEventStatus ReceiveInputEvent(const InputData& aEvent); @@ -286,6 +285,12 @@ private: * is considered part of the APZC tree management state. */ mozilla::Monitor mTreeLock; nsRefPtr mRootApzc; + /* This tracks the APZC that should receive all inputs for the current input event block. + * This allows touch points to move outside the thing they started on, but still have the + * touch events delivered to the same initial APZC. This will only ever be touched on the + * input delivery thread, and so does not require locking. + */ + nsRefPtr mApzcForInputBlock; }; }