Bug 1030181 - Share code for dealing with WidgetTouchEvent and MultiTouchInput. r=drs r=smaug

This commit is contained in:
Kartikaya Gupta 2014-06-25 20:11:20 -04:00
Родитель d9f8ee7a87
Коммит cb116c4bd1
4 изменённых файлов: 92 добавлений и 161 удалений

Просмотреть файл

@ -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)