diff --git a/gfx/layers/ipc/GestureEventListener.cpp b/gfx/layers/ipc/GestureEventListener.cpp index 3bc50b1f51e8..c0e45721943c 100644 --- a/gfx/layers/ipc/GestureEventListener.cpp +++ b/gfx/layers/ipc/GestureEventListener.cpp @@ -20,9 +20,18 @@ namespace layers { */ static const int MAX_TAP_TIME = 300; +/** + * Amount of change in span needed to take us from the GESTURE_WAITING_PINCH + * state to the GESTURE_PINCH state. This is measured as a change in distance + * between the fingers used to compute the span ratio. Note that it is a + * distance, not a displacement. + */ +static const float PINCH_START_THRESHOLD = 35.0f; + GestureEventListener::GestureEventListener(AsyncPanZoomController* aAsyncPanZoomController) : mAsyncPanZoomController(aAsyncPanZoomController), mState(GESTURE_NONE), + mSpanChange(0.0f), mLastTouchInput(MultiTouchInput::MULTITOUCH_START, 0) { } @@ -145,6 +154,10 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent) mState = GESTURE_NONE; } + if (!mTouches.Length()) { + mSpanChange = 0.0f; + } + break; } case MultiTouchInput::MULTITOUCH_CANCEL: @@ -172,17 +185,31 @@ nsEventStatus GestureEventListener::HandlePinchGestureEvent(const MultiTouchInpu float(NS_hypot(firstTouch.x - secondTouch.x, firstTouch.y - secondTouch.y)); - if (mState == GESTURE_NONE) { - PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_START, - aEvent.mTime, - focusPoint, - currentSpan, - currentSpan); + switch (mState) { + case GESTURE_NONE: + mPreviousSpan = currentSpan; + mState = GESTURE_WAITING_PINCH; + // Deliberately fall through. If the user pinched and took their fingers + // off the screen such that they still had 1 left on it, we want there to + // be no resistance. We should only reset |mSpanChange| once all fingers + // are off the screen. + case GESTURE_WAITING_PINCH: { + mSpanChange += fabsf(currentSpan - mPreviousSpan); + if (mSpanChange > PINCH_START_THRESHOLD) { + PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_START, + aEvent.mTime, + focusPoint, + currentSpan, + currentSpan); - mAsyncPanZoomController->HandleInputEvent(pinchEvent); + mAsyncPanZoomController->HandleInputEvent(pinchEvent); - mState = GESTURE_PINCH; - } else { + mState = GESTURE_PINCH; + } + + break; + } + case GESTURE_PINCH: { PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_SCALE, aEvent.mTime, focusPoint, @@ -190,6 +217,11 @@ nsEventStatus GestureEventListener::HandlePinchGestureEvent(const MultiTouchInpu mPreviousSpan); mAsyncPanZoomController->HandleInputEvent(pinchEvent); + break; + } + default: + // What? + break; } mPreviousSpan = currentSpan; diff --git a/gfx/layers/ipc/GestureEventListener.h b/gfx/layers/ipc/GestureEventListener.h index f1fced0f046d..2051bf5e0fed 100644 --- a/gfx/layers/ipc/GestureEventListener.h +++ b/gfx/layers/ipc/GestureEventListener.h @@ -61,7 +61,12 @@ protected: enum GestureState { // There's no gesture going on, and we don't think we're about to enter one. GESTURE_NONE, - // There's a pinch happening, which occurs when there are two touch inputs. + // We have detected that two or more fingers are on the screen, but there + // hasn't been enough movement yet to make us start actually zooming the + // screen. + GESTURE_WAITING_PINCH, + // There are two or more fingers on the screen, and the user has already + // pinched enough for us to start zooming the screen. GESTURE_PINCH, // A touch start has happened and it may turn into a tap. We use this // because, if we put down two fingers and then lift them very quickly, this @@ -137,6 +142,14 @@ protected: */ GestureState mState; + /** + * Total change in span since we detected a pinch gesture. Only used when we + * are in the |GESTURE_WAITING_PINCH| state and need to know how far zoomed + * out we are compared to our original pinch span. Note that this does _not_ + * continue to be updated once we jump into the |GESTURE_PINCH| state. + */ + float mSpanChange; + /** * Previous span calculated for the purposes of setting inside a * PinchGestureInput.