Bug 1022719 - Ignore additional touches when in overscrolled state. r=kats

This commit is contained in:
Botond Ballo 2014-06-10 19:43:20 -04:00
Родитель 39d2cd0d1b
Коммит e8a12a2e30
6 изменённых файлов: 109 добавлений и 0 удалений

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

@ -40,6 +40,7 @@ static bool gPrintApzcTree = false;
APZCTreeManager::APZCTreeManager()
: mTreeLock("APZCTreeLock"),
mInOverscrolledApzc(false),
mRetainedTouchIdentifier(-1),
mTouchCount(0),
mApzcTreeLog("apzctree")
{
@ -379,6 +380,16 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
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();
@ -412,13 +423,43 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
} 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);
}
@ -441,6 +482,7 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
if (mTouchCount == 0) {
mApzcForInputBlock = nullptr;
mInOverscrolledApzc = false;
mRetainedTouchIdentifier = -1;
ClearOverscrollHandoffChain();
}
}
@ -538,6 +580,16 @@ APZCTreeManager::ProcessTouchEvent(WidgetTouchEvent& aEvent,
return nsEventStatus_eIgnore;
}
if (aEvent.message == NS_TOUCH_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;
}
// NS_TOUCH_START event contains all active touches of the current
// session thus resetting mTouchCount.
mTouchCount = aEvent.touches.Length();
@ -553,6 +605,28 @@ APZCTreeManager::ProcessTouchEvent(WidgetTouchEvent& aEvent,
}
}
// 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) {
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
// 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);
--j;
}
}
if (aEvent.touches.IsEmpty()) {
return nsEventStatus_eConsumeNoDefault;
}
}
if (mApzcForInputBlock) {
mApzcForInputBlock->GetGuid(aOutTargetGuid);
// For computing the input for the APZC, used the cached transform.
@ -592,6 +666,7 @@ APZCTreeManager::ProcessTouchEvent(WidgetTouchEvent& aEvent,
if (mTouchCount == 0) {
mApzcForInputBlock = nullptr;
mInOverscrolledApzc = false;
mRetainedTouchIdentifier = -1;
ClearOverscrollHandoffChain();
}
}

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

@ -377,6 +377,11 @@ private:
* was inside an overscrolled APZC.
*/
bool mInOverscrolledApzc;
/* 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.
*/
int32_t mRetainedTouchIdentifier;
/* The number of touch points we are tracking that are currently on the screen. */
uint32_t mTouchCount;
/* The transform from root screen coordinates into mApzcForInputBlock's

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

@ -1842,6 +1842,11 @@ bool AsyncPanZoomController::IsPannable() const {
return mX.CanScroll() || mY.CanScroll();
}
int32_t AsyncPanZoomController::GetLastTouchIdentifier() const {
nsRefPtr<GestureEventListener> listener = GetGestureEventListener();
return listener ? listener->GetLastTouchIdentifier() : -1;
}
void AsyncPanZoomController::RequestContentRepaint() {
RequestContentRepaint(mFrameMetrics);
}

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

@ -318,6 +318,13 @@ public:
*/
bool IsPannable() const;
/**
* Returns the identifier of the touch in the last touch event processed by
* this APZC. This should only be called when the last touch event contained
* only one touch.
*/
int32_t GetLastTouchIdentifier() const;
protected:
enum PanZoomState {
NOTHING, /* no touch-start events received */

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

@ -106,6 +106,16 @@ nsEventStatus GestureEventListener::HandleInputEvent(const MultiTouchInput& aEve
return rv;
}
int32_t GestureEventListener::GetLastTouchIdentifier() const
{
if (mTouches.Length() != 1) {
NS_WARNING("GetLastTouchIdentifier() called when last touch event "
"did not have one touch");
}
return mTouches.IsEmpty() ? -1 : mTouches[0].mIdentifier;
}
nsEventStatus GestureEventListener::HandleInputTouchSingleStart()
{
switch (mState) {

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

@ -53,6 +53,13 @@ public:
*/
nsEventStatus HandleInputEvent(const MultiTouchInput& aEvent);
/**
* Returns the identifier of the touch in the last touch event processed by
* this GestureEventListener. This should only be called when the last touch
* event contained only one touch.
*/
int32_t GetLastTouchIdentifier() const;
private:
// Private destructor, to discourage deletion outside of Release():
~GestureEventListener();