зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1030181 - Share code for dealing with WidgetTouchEvent and MultiTouchInput. r=drs r=smaug
This commit is contained in:
Родитель
d9f8ee7a87
Коммит
cb116c4bd1
|
@ -378,122 +378,8 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
|
|||
gfx3DMatrix transformToGecko;
|
||||
switch (aEvent.mInputType) {
|
||||
case MULTITOUCH_INPUT: {
|
||||
const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
|
||||
if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_START) {
|
||||
// If we are in an overscrolled state and a second finger goes down,
|
||||
// ignore that second touch point completely. The touch-start for it is
|
||||
// dropped completely; subsequent touch events until the touch-end for it
|
||||
// will have this touch point filtered out.
|
||||
if (mApzcForInputBlock && mApzcForInputBlock->IsOverscrolled()) {
|
||||
if (mRetainedTouchIdentifier == -1) {
|
||||
mRetainedTouchIdentifier = mApzcForInputBlock->GetLastTouchIdentifier();
|
||||
}
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
// MULTITOUCH_START input contains all active touches of the current
|
||||
// session thus resetting mTouchCount.
|
||||
mTouchCount = multiTouchInput.mTouches.Length();
|
||||
mInOverscrolledApzc = false;
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint),
|
||||
&mInOverscrolledApzc);
|
||||
for (size_t i = 1; i < multiTouchInput.mTouches.Length(); i++) {
|
||||
nsRefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[i].mScreenPoint),
|
||||
&mInOverscrolledApzc);
|
||||
apzc = CommonAncestor(mApzcForInputBlock.get(), apzc2.get());
|
||||
APZCTM_LOG("Using APZC %p as the common ancestor\n", mApzcForInputBlock.get());
|
||||
// For now, we only ever want to do pinching on the root APZC for a given layers id. So
|
||||
// when we find the common ancestor of multiple points, also walk up to the root APZC.
|
||||
apzc = RootAPZCForLayersId(mApzcForInputBlock);
|
||||
APZCTM_LOG("Using APZC %p as the root APZC for multi-touch\n", mApzcForInputBlock.get());
|
||||
}
|
||||
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
|
||||
// in the middle of a panning touch block (for example) and not clean up properly.
|
||||
if (mApzcForInputBlock) {
|
||||
MultiTouchInput cancel(MultiTouchInput::MULTITOUCH_CANCEL, 0, TimeStamp::Now(), 0);
|
||||
mApzcForInputBlock->ReceiveInputEvent(cancel);
|
||||
}
|
||||
mApzcForInputBlock = apzc;
|
||||
}
|
||||
|
||||
// Prepare for possible overscroll handoff.
|
||||
BuildOverscrollHandoffChain(mApzcForInputBlock);
|
||||
|
||||
if (mApzcForInputBlock) {
|
||||
// Cache transformToApzc so it can be used for future events in this block.
|
||||
GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToGecko);
|
||||
mCachedTransformToApzcForInputBlock = transformToApzc;
|
||||
} else {
|
||||
// Reset the cached apz transform
|
||||
mCachedTransformToApzcForInputBlock = gfx3DMatrix();
|
||||
}
|
||||
} else if (mApzcForInputBlock) {
|
||||
APZCTM_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get());
|
||||
}
|
||||
|
||||
// If we receive a touch-cancel, it means all touches are finished, so we
|
||||
// can stop ignoring any that we were ignoring.
|
||||
if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_CANCEL) {
|
||||
mRetainedTouchIdentifier = -1;
|
||||
}
|
||||
|
||||
if (mApzcForInputBlock) {
|
||||
mApzcForInputBlock->GetGuid(aOutTargetGuid);
|
||||
// Use the cached transform to compute the point to send to the APZC.
|
||||
// This ensures that the sequence of touch points an APZC sees in an
|
||||
// input block are all in the same coordinate space.
|
||||
transformToApzc = mCachedTransformToApzcForInputBlock;
|
||||
|
||||
// Make a copy of the input event that we pass, with some modifications,
|
||||
// to the target APZC.
|
||||
MultiTouchInput inputForApzc(multiTouchInput);
|
||||
|
||||
// If we are currently ignoring any touch points, filter them out from
|
||||
// the set of touch points included in this event.
|
||||
if (mRetainedTouchIdentifier != -1) {
|
||||
for (size_t j = 0; j < inputForApzc.mTouches.Length(); ++j) {
|
||||
if (inputForApzc.mTouches[j].mIdentifier != mRetainedTouchIdentifier) {
|
||||
// TODO(botond): Once we get rid of ReceiveInputEvent(WidgetInputEvent),
|
||||
// the signature of this function will change to take the InputData
|
||||
// via non-const reference. We can then remove the touch point from
|
||||
// multiTouchInput rather than the copy (inputForApzc), so that
|
||||
// content doesn't get it either.
|
||||
inputForApzc.mTouches.RemoveElementAt(j);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
if (inputForApzc.mTouches.IsEmpty()) {
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < inputForApzc.mTouches.Length(); i++) {
|
||||
ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
|
||||
}
|
||||
mApzcForInputBlock->ReceiveInputEvent(inputForApzc);
|
||||
}
|
||||
result = mInOverscrolledApzc ? nsEventStatus_eConsumeNoDefault
|
||||
: mApzcForInputBlock ? nsEventStatus_eConsumeDoDefault
|
||||
: nsEventStatus_eIgnore;
|
||||
if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_CANCEL ||
|
||||
multiTouchInput.mType == MultiTouchInput::MULTITOUCH_END) {
|
||||
if (mTouchCount >= multiTouchInput.mTouches.Length()) {
|
||||
// MULTITOUCH_END input contains only released touches thus decrementing.
|
||||
mTouchCount -= multiTouchInput.mTouches.Length();
|
||||
} else {
|
||||
NS_WARNING("Got an unexpected touchend/touchcancel");
|
||||
mTouchCount = 0;
|
||||
}
|
||||
// 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 (mTouchCount == 0) {
|
||||
mApzcForInputBlock = nullptr;
|
||||
mInOverscrolledApzc = false;
|
||||
mRetainedTouchIdentifier = -1;
|
||||
ClearOverscrollHandoffChain();
|
||||
}
|
||||
}
|
||||
MultiTouchInput touchInput = aEvent.AsMultiTouchInput();
|
||||
result = ProcessTouchInput(touchInput, aOutTargetGuid);
|
||||
break;
|
||||
} case PANGESTURE_INPUT: {
|
||||
const PanGestureInput& panInput = aEvent.AsPanGestureInput();
|
||||
|
@ -554,15 +440,17 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
|
|||
}
|
||||
|
||||
already_AddRefed<AsyncPanZoomController>
|
||||
APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
|
||||
APZCTreeManager::GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
|
||||
bool* aOutInOverscrolledApzc)
|
||||
{
|
||||
ScreenPoint point = ScreenPoint(aEvent.touches[0]->mRefPoint.x, aEvent.touches[0]->mRefPoint.y);
|
||||
// Ignore events if any touch hits inside an overscrolled apzc.
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(point, aOutInOverscrolledApzc);
|
||||
for (size_t i = 1; i < aEvent.touches.Length(); i++) {
|
||||
point = ScreenPoint(aEvent.touches[i]->mRefPoint.x, aEvent.touches[i]->mRefPoint.y);
|
||||
nsRefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(point, aOutInOverscrolledApzc);
|
||||
nsRefPtr<AsyncPanZoomController> apzc;
|
||||
if (aEvent.mTouches.Length() == 0) {
|
||||
return apzc.forget();
|
||||
}
|
||||
|
||||
apzc = GetTargetAPZC(aEvent.mTouches[0].mScreenPoint, aOutInOverscrolledApzc);
|
||||
for (size_t i = 1; i < aEvent.mTouches.Length(); i++) {
|
||||
nsRefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(aEvent.mTouches[i].mScreenPoint, aOutInOverscrolledApzc);
|
||||
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
|
||||
|
@ -570,21 +458,18 @@ APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
|
|||
apzc = RootAPZCForLayersId(apzc);
|
||||
APZCTM_LOG("Using APZC %p as the root APZC for multi-touch\n", apzc.get());
|
||||
}
|
||||
|
||||
// Prepare for possible overscroll handoff.
|
||||
BuildOverscrollHandoffChain(apzc);
|
||||
|
||||
return apzc.forget();
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
APZCTreeManager::ProcessTouchEvent(WidgetTouchEvent& aEvent,
|
||||
APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
|
||||
ScrollableLayerGuid* aOutTargetGuid)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!aEvent.touches.Length()) {
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
if (aEvent.message == NS_TOUCH_START) {
|
||||
if (aInput.mType == MultiTouchInput::MULTITOUCH_START) {
|
||||
// If we are in an overscrolled state and a second finger goes down,
|
||||
// ignore that second touch point completely. The touch-start for it is
|
||||
// dropped completely; subsequent touch events until the touch-end for it
|
||||
|
@ -595,12 +480,12 @@ APZCTreeManager::ProcessTouchEvent(WidgetTouchEvent& aEvent,
|
|||
}
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
// NS_TOUCH_START event contains all active touches of the current
|
||||
// session thus resetting mTouchCount.
|
||||
mTouchCount = aEvent.touches.Length();
|
||||
mTouchCount = aInput.mTouches.Length();
|
||||
mInOverscrolledApzc = false;
|
||||
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTouchInputBlockAPZC(aEvent, &mInOverscrolledApzc);
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTouchInputBlockAPZC(aInput, &mInOverscrolledApzc);
|
||||
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
|
||||
|
@ -620,26 +505,28 @@ APZCTreeManager::ProcessTouchEvent(WidgetTouchEvent& aEvent,
|
|||
// Reset the cached apz transform
|
||||
mCachedTransformToApzcForInputBlock = gfx3DMatrix();
|
||||
}
|
||||
} else if (mApzcForInputBlock) {
|
||||
APZCTM_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get());
|
||||
}
|
||||
|
||||
// If we receive a touch-cancel, it means all touches are finished, so we
|
||||
// can stop ignoring any that we were ignoring.
|
||||
if (aEvent.message == NS_TOUCH_CANCEL) {
|
||||
if (aInput.mType == MultiTouchInput::MULTITOUCH_CANCEL) {
|
||||
mRetainedTouchIdentifier = -1;
|
||||
}
|
||||
|
||||
// If we are currently ignoring any touch points, filter them out from the
|
||||
// set of touch points included in this event. Note that we modify aEvent
|
||||
// set of touch points included in this event. Note that we modify aInput
|
||||
// itself, so that the touch points are also filtered out when the caller
|
||||
// passes the event on to content.
|
||||
if (mRetainedTouchIdentifier != -1) {
|
||||
for (size_t j = 0; j < aEvent.touches.Length(); ++j) {
|
||||
if (aEvent.touches[j]->Identifier() != mRetainedTouchIdentifier) {
|
||||
aEvent.touches.RemoveElementAt(j);
|
||||
for (size_t j = 0; j < aInput.mTouches.Length(); ++j) {
|
||||
if (aInput.mTouches[j].mIdentifier != mRetainedTouchIdentifier) {
|
||||
aInput.mTouches.RemoveElementAt(j);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
if (aEvent.touches.IsEmpty()) {
|
||||
if (aInput.mTouches.IsEmpty()) {
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
}
|
||||
|
@ -650,7 +537,7 @@ APZCTreeManager::ProcessTouchEvent(WidgetTouchEvent& aEvent,
|
|||
// This ensures that the sequence of touch points an APZC sees in an
|
||||
// input block are all in the same coordinate space.
|
||||
gfx3DMatrix transformToApzc = mCachedTransformToApzcForInputBlock;
|
||||
MultiTouchInput inputForApzc(aEvent);
|
||||
MultiTouchInput inputForApzc(aInput);
|
||||
for (size_t i = 0; i < inputForApzc.mTouches.Length(); i++) {
|
||||
ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
|
||||
}
|
||||
|
@ -662,31 +549,36 @@ APZCTreeManager::ProcessTouchEvent(WidgetTouchEvent& aEvent,
|
|||
gfx3DMatrix transformToGecko;
|
||||
GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToGecko);
|
||||
gfx3DMatrix outTransform = transformToApzc * transformToGecko;
|
||||
for (size_t i = 0; i < aEvent.touches.Length(); i++) {
|
||||
ApplyTransform(&(aEvent.touches[i]->mRefPoint), outTransform);
|
||||
for (size_t i = 0; i < aInput.mTouches.Length(); i++) {
|
||||
ApplyTransform(&(aInput.mTouches[i].mScreenPoint), outTransform);
|
||||
}
|
||||
}
|
||||
|
||||
nsEventStatus result = mInOverscrolledApzc ? nsEventStatus_eConsumeNoDefault
|
||||
: mApzcForInputBlock ? nsEventStatus_eConsumeDoDefault
|
||||
: nsEventStatus_eIgnore;
|
||||
// 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 (aEvent.message == NS_TOUCH_CANCEL ||
|
||||
aEvent.message == NS_TOUCH_END) {
|
||||
if (mTouchCount >= aEvent.touches.Length()) {
|
||||
|
||||
if (aInput.mType == MultiTouchInput::MULTITOUCH_END) {
|
||||
if (mTouchCount >= aInput.mTouches.Length()) {
|
||||
// NS_TOUCH_END event contains only released touches thus decrementing.
|
||||
mTouchCount -= aEvent.touches.Length();
|
||||
mTouchCount -= aInput.mTouches.Length();
|
||||
} else {
|
||||
NS_WARNING("Got an unexpected touchend/touchcancel");
|
||||
mTouchCount = 0;
|
||||
}
|
||||
if (mTouchCount == 0) {
|
||||
mApzcForInputBlock = nullptr;
|
||||
mInOverscrolledApzc = false;
|
||||
mRetainedTouchIdentifier = -1;
|
||||
ClearOverscrollHandoffChain();
|
||||
}
|
||||
} else if (aInput.mType == MultiTouchInput::MULTITOUCH_CANCEL) {
|
||||
mTouchCount = 0;
|
||||
}
|
||||
|
||||
// If it's the end of the touch sequence then clear out variables so we
|
||||
// keep dangling references and leak things.
|
||||
if (mTouchCount == 0) {
|
||||
mApzcForInputBlock = nullptr;
|
||||
mInOverscrolledApzc = false;
|
||||
mRetainedTouchIdentifier = -1;
|
||||
ClearOverscrollHandoffChain();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -735,12 +627,27 @@ nsEventStatus
|
|||
APZCTreeManager::ReceiveInputEvent(WidgetInputEvent& aEvent,
|
||||
ScrollableLayerGuid* aOutTargetGuid)
|
||||
{
|
||||
// This function will be removed as part of bug 930939.
|
||||
// In general it is preferable to use the version of ReceiveInputEvent
|
||||
// that takes an InputData, as that is usable from off-main-thread.
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
switch (aEvent.eventStructType) {
|
||||
case NS_TOUCH_EVENT: {
|
||||
WidgetTouchEvent& touchEvent = *aEvent.AsTouchEvent();
|
||||
return ProcessTouchEvent(touchEvent, aOutTargetGuid);
|
||||
MultiTouchInput touchInput(touchEvent);
|
||||
nsEventStatus result = ProcessTouchInput(touchInput, aOutTargetGuid);
|
||||
// touchInput was modified in-place to possibly remove some
|
||||
// touch points (if we are overscrolled), and the coordinates were
|
||||
// modified using the APZ untransform. We need to copy these changes
|
||||
// back into the WidgetInputEvent.
|
||||
touchEvent.touches.Clear();
|
||||
touchEvent.touches.SetCapacity(touchInput.mTouches.Length());
|
||||
for (size_t i = 0; i < touchInput.mTouches.Length(); i++) {
|
||||
*touchEvent.touches.AppendElement() = touchInput.mTouches[i].ToNewDOMTouch();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
default: {
|
||||
return ProcessEvent(aEvent, aOutTargetGuid);
|
||||
|
|
|
@ -25,6 +25,7 @@ class gfx3DMatrix;
|
|||
|
||||
namespace mozilla {
|
||||
class InputData;
|
||||
class MultiTouchInput;
|
||||
|
||||
namespace layers {
|
||||
|
||||
|
@ -329,9 +330,9 @@ private:
|
|||
bool* aOutInOverscrolledApzc);
|
||||
already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
|
||||
already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc);
|
||||
already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
|
||||
already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
|
||||
bool* aOutInOverscrolledApzc);
|
||||
nsEventStatus ProcessTouchEvent(WidgetTouchEvent& touchEvent,
|
||||
nsEventStatus ProcessTouchInput(MultiTouchInput& aInput,
|
||||
ScrollableLayerGuid* aOutTargetGuid);
|
||||
nsEventStatus ProcessEvent(WidgetInputEvent& inputEvent,
|
||||
ScrollableLayerGuid* aOutTargetGuid);
|
||||
|
|
|
@ -13,8 +13,13 @@
|
|||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
template<class E> struct already_AddRefed;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class Touch;
|
||||
}
|
||||
|
||||
enum InputType
|
||||
{
|
||||
|
@ -108,14 +113,14 @@ public:
|
|||
mRotationAngle(aRotationAngle),
|
||||
mForce(aForce)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
SingleTouchData()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<dom::Touch> ToNewDOMTouch();
|
||||
|
||||
// A unique number assigned to each SingleTouchData within a MultiTouchInput so
|
||||
// that they can be easily distinguished when handling a touch start/move/end.
|
||||
int32_t mIdentifier;
|
||||
|
@ -165,14 +170,20 @@ public:
|
|||
: InputData(MULTITOUCH_INPUT, aTime, aTimeStamp, aModifiers),
|
||||
mType(aType)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
MultiTouchInput()
|
||||
{
|
||||
}
|
||||
|
||||
MultiTouchInput(const MultiTouchInput& aOther)
|
||||
: InputData(MULTITOUCH_INPUT, aOther.mTime,
|
||||
aOther.mTimeStamp, aOther.modifiers)
|
||||
, mType(aOther.mType)
|
||||
{
|
||||
mTouches.AppendElements(aOther.mTouches);
|
||||
}
|
||||
|
||||
MultiTouchInput(const WidgetTouchEvent& aTouchEvent);
|
||||
|
||||
// This conversion from WidgetMouseEvent to MultiTouchInput is needed because
|
||||
|
|
|
@ -15,6 +15,18 @@ namespace mozilla {
|
|||
|
||||
using namespace dom;
|
||||
|
||||
already_AddRefed<Touch> SingleTouchData::ToNewDOMTouch()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(),
|
||||
"Can only create dom::Touch instances on main thread");
|
||||
nsRefPtr<Touch> touch = new Touch(mIdentifier,
|
||||
nsIntPoint(mScreenPoint.x, mScreenPoint.y),
|
||||
nsIntPoint(mRadius.width, mRadius.height),
|
||||
mRotationAngle,
|
||||
mForce);
|
||||
return touch.forget();
|
||||
}
|
||||
|
||||
MultiTouchInput::MultiTouchInput(const WidgetTouchEvent& aTouchEvent)
|
||||
: InputData(MULTITOUCH_INPUT, aTouchEvent.time, aTouchEvent.timeStamp,
|
||||
aTouchEvent.modifiers)
|
||||
|
|
Загрузка…
Ссылка в новой задаче