nsEventStatus GestureEventListener::HandlePinchGestureEvent(const MultiTouchInput& aEvent, bool aClearTouches) { nsEventStatus rv = nsEventStatus_eIgnore; if (mTouches.Length() > 1 && !aClearTouches) { const nsIntPoint& firstTouch = mTouches[0].mScreenPoint, secondTouch = mTouches[mTouches.Length() - 1].mScreenPoint; nsIntPoint focusPoint = nsIntPoint((firstTouch.x + secondTouch.x)/2, (firstTouch.y + secondTouch.y)/2); float currentSpan = float(NS_hypot(firstTouch.x - secondTouch.x, firstTouch.y - secondTouch.y)); if (mState == NoGesture) { PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_START, aEvent.mTime, focusPoint, currentSpan, currentSpan); mAsyncPanZoomController->HandleInputEvent(pinchEvent); mState = InPinchGesture; } else { PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_SCALE, aEvent.mTime, focusPoint, currentSpan, mPreviousSpan); mAsyncPanZoomController->HandleInputEvent(pinchEvent); } mPreviousSpan = currentSpan; rv = nsEventStatus_eConsumeNoDefault; } else if (mState == InPinchGesture) { PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_END, aEvent.mTime, mTouches[0].mScreenPoint, 1.0f, 1.0f); mAsyncPanZoomController->HandleInputEvent(pinchEvent); mState = NoGesture; rv = nsEventStatus_eConsumeNoDefault; } if (aClearTouches) { mTouches.Clear(); } return rv; }
nsEventStatus GestureEventListener::HandlePinchGestureEvent(const MultiTouchInput& aEvent) { nsEventStatus rv = nsEventStatus_eIgnore; if (aEvent.mType == MultiTouchInput::MULTITOUCH_CANCEL) { mTouches.Clear(); mState = GESTURE_NONE; return rv; } if (mTouches.Length() > 1) { const ScreenIntPoint& firstTouch = mTouches[0].mScreenPoint, secondTouch = mTouches[1].mScreenPoint; ScreenPoint focusPoint = ScreenPoint(firstTouch + secondTouch) / 2; ScreenIntPoint delta = secondTouch - firstTouch; float currentSpan = float(NS_hypot(delta.x, delta.y)); 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, aEvent.modifiers); mAsyncPanZoomController->HandleInputEvent(pinchEvent); mState = GESTURE_PINCH; } break; } case GESTURE_PINCH: { PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_SCALE, aEvent.mTime, focusPoint, currentSpan, mPreviousSpan, aEvent.modifiers); mAsyncPanZoomController->HandleInputEvent(pinchEvent); break; } default: // What? break; } mPreviousSpan = currentSpan; rv = nsEventStatus_eConsumeNoDefault; } else if (mState == GESTURE_PINCH) { PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_END, aEvent.mTime, ScreenPoint(), 1.0f, 1.0f, aEvent.modifiers); mAsyncPanZoomController->HandleInputEvent(pinchEvent); mState = GESTURE_NONE; // If the user left a finger on the screen, spoof a touch start event and // send it to APZC so that they can continue panning from that point. if (mTouches.Length() == 1) { MultiTouchInput touchEvent(MultiTouchInput::MULTITOUCH_START, aEvent.mTime, aEvent.modifiers); touchEvent.mTouches.AppendElement(mTouches[0]); mAsyncPanZoomController->HandleInputEvent(touchEvent); // The spoofed touch start will get back to GEL and make us enter the // GESTURE_WAITING_SINGLE_TAP state, but this isn't a new touch, so there // is no condition under which this touch should turn into any tap. mState = GESTURE_NONE; } rv = nsEventStatus_eConsumeNoDefault; } else if (mState == GESTURE_WAITING_PINCH) { mState = GESTURE_NONE; } return rv; }
nsEventStatus GestureEventListener::HandleInputTouchEnd() { // We intentionally do not pass apzc return statuses up since // it may cause apzc stay in the touching state even after // gestures are completed (please see Bug 1013378 for reference). nsEventStatus rv = nsEventStatus_eIgnore; switch (mState) { case GESTURE_NONE: // GEL doesn't have a dedicated state for PANNING handled in APZC thus ignore. break; case GESTURE_FIRST_SINGLE_TOUCH_DOWN: { CancelLongTapTimeoutTask(); CancelMaxTapTimeoutTask(); nsEventStatus tapupStatus = mAsyncPanZoomController->HandleGestureEvent( CreateTapEvent(mLastTouchInput, TapGestureInput::TAPGESTURE_UP)); if (tapupStatus == nsEventStatus_eIgnore) { SetState(GESTURE_FIRST_SINGLE_TOUCH_UP); CreateMaxTapTimeoutTask(); } else { // We sent the tapup into content without waiting for a double tap SetState(GESTURE_NONE); } break; } case GESTURE_SECOND_SINGLE_TOUCH_DOWN: { CancelMaxTapTimeoutTask(); SetState(GESTURE_NONE); mAsyncPanZoomController->HandleGestureEvent( CreateTapEvent(mLastTouchInput, TapGestureInput::TAPGESTURE_DOUBLE)); break; } case GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN: CancelLongTapTimeoutTask(); SetState(GESTURE_NONE); TriggerSingleTapConfirmedEvent(); break; case GESTURE_LONG_TOUCH_DOWN: { SetState(GESTURE_NONE); mAsyncPanZoomController->HandleGestureEvent( CreateTapEvent(mLastTouchInput, TapGestureInput::TAPGESTURE_LONG_UP)); break; } case GESTURE_MULTI_TOUCH_DOWN: if (mTouches.Length() < 2) { SetState(GESTURE_NONE); } break; case GESTURE_PINCH: if (mTouches.Length() < 2) { SetState(GESTURE_NONE); PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_END, mLastTouchInput.mTime, mLastTouchInput.mTimeStamp, ScreenPoint(), 1.0f, 1.0f, mLastTouchInput.modifiers); mAsyncPanZoomController->HandleGestureEvent(pinchEvent); } rv = nsEventStatus_eConsumeNoDefault; break; default: NS_WARNING("Unhandled state upon touch end"); SetState(GESTURE_NONE); break; } return rv; }
nsEventStatus GestureEventListener::HandleInputTouchMove() { nsEventStatus rv = nsEventStatus_eIgnore; switch (mState) { case GESTURE_NONE: // Ignore this input signal as the corresponding events get handled by APZC break; case GESTURE_LONG_TOUCH_DOWN: if (MoveDistanceIsLarge()) { // So that we don't fire a long-tap-up if the user moves around after a // long-tap SetState(GESTURE_NONE); } break; case GESTURE_FIRST_SINGLE_TOUCH_DOWN: case GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN: case GESTURE_SECOND_SINGLE_TOUCH_DOWN: { // If we move too much, bail out of the tap. if (MoveDistanceIsLarge()) { CancelLongTapTimeoutTask(); CancelMaxTapTimeoutTask(); SetState(GESTURE_NONE); } break; } case GESTURE_MULTI_TOUCH_DOWN: { if (mLastTouchInput.mTouches.Length() < 2) { NS_WARNING("Wrong input: less than 2 moving points in GESTURE_MULTI_TOUCH_DOWN state"); break; } float currentSpan = GetCurrentSpan(mLastTouchInput); mSpanChange += fabsf(currentSpan - mPreviousSpan); if (mSpanChange > PINCH_START_THRESHOLD) { SetState(GESTURE_PINCH); PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_START, mLastTouchInput.mTime, mLastTouchInput.mTimeStamp, GetCurrentFocus(mLastTouchInput), currentSpan, currentSpan, mLastTouchInput.modifiers); rv = mAsyncPanZoomController->HandleGestureEvent(pinchEvent); } else { // Prevent APZC::OnTouchMove from processing a move event when two // touches are active rv = nsEventStatus_eConsumeNoDefault; } mPreviousSpan = currentSpan; break; } case GESTURE_PINCH: { if (mLastTouchInput.mTouches.Length() < 2) { NS_WARNING("Wrong input: less than 2 moving points in GESTURE_PINCH state"); // Prevent APZC::OnTouchMove() from handling this wrong input rv = nsEventStatus_eConsumeNoDefault; break; } float currentSpan = GetCurrentSpan(mLastTouchInput); PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_SCALE, mLastTouchInput.mTime, mLastTouchInput.mTimeStamp, GetCurrentFocus(mLastTouchInput), currentSpan, mPreviousSpan, mLastTouchInput.modifiers); rv = mAsyncPanZoomController->HandleGestureEvent(pinchEvent); mPreviousSpan = currentSpan; break; } default: NS_WARNING("Unhandled state upon touch move"); SetState(GESTURE_NONE); break; } return rv; }
nsEventStatus GestureEventListener::HandleInputTouchEnd() { nsEventStatus rv = nsEventStatus_eIgnore; switch (mState) { case GESTURE_NONE: // GEL doesn't have a dedicated state for PANNING handled in APZC thus ignore. break; case GESTURE_FIRST_SINGLE_TOUCH_DOWN: { CancelLongTapTimeoutTask(); CancelMaxTapTimeoutTask(); TapGestureInput tapEvent(TapGestureInput::TAPGESTURE_UP, mLastTouchInput.mTime, mLastTouchInput.mTouches[0].mScreenPoint, mLastTouchInput.modifiers); nsEventStatus tapupStatus = mAsyncPanZoomController->HandleGestureEvent(tapEvent); if (tapupStatus == nsEventStatus_eIgnore) { SetState(GESTURE_FIRST_SINGLE_TOUCH_UP); CreateMaxTapTimeoutTask(); } else { // We sent the tapup into content without waiting for a double tap SetState(GESTURE_NONE); } break; } case GESTURE_SECOND_SINGLE_TOUCH_DOWN: { CancelMaxTapTimeoutTask(); SetState(GESTURE_NONE); TapGestureInput tapEvent(TapGestureInput::TAPGESTURE_DOUBLE, mLastTouchInput.mTime, mLastTouchInput.mTouches[0].mScreenPoint, mLastTouchInput.modifiers); mAsyncPanZoomController->HandleGestureEvent(tapEvent); break; } case GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN: CancelLongTapTimeoutTask(); SetState(GESTURE_NONE); TriggerSingleTapConfirmedEvent(); break; case GESTURE_LONG_TOUCH_DOWN: { SetState(GESTURE_NONE); TapGestureInput tapEvent(TapGestureInput::TAPGESTURE_LONG_UP, mLastTouchInput.mTime, mLastTouchInput.mTouches[0].mScreenPoint, mLastTouchInput.modifiers); mAsyncPanZoomController->HandleGestureEvent(tapEvent); break; } case GESTURE_MULTI_TOUCH_DOWN: if (mTouches.Length() < 2) { SetState(GESTURE_NONE); } break; case GESTURE_PINCH: if (mTouches.Length() < 2) { SetState(GESTURE_NONE); PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_END, mLastTouchInput.mTime, ScreenPoint(), 1.0f, 1.0f, mLastTouchInput.modifiers); mAsyncPanZoomController->HandleGestureEvent(pinchEvent); } rv = nsEventStatus_eConsumeNoDefault; break; default: NS_WARNING("Unhandled state upon touch end"); SetState(GESTURE_NONE); break; } return rv; }
nsEventStatus GestureEventListener::HandleInputTouchMove() { nsEventStatus rv = nsEventStatus_eIgnore; switch (mState) { case GESTURE_NONE: case GESTURE_LONG_TOUCH_DOWN: // Ignore this input signal as the corresponding events get handled by APZC break; case GESTURE_FIRST_SINGLE_TOUCH_DOWN: case GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN: case GESTURE_SECOND_SINGLE_TOUCH_DOWN: { // If we move too much, bail out of the tap. ScreenIntPoint delta = mLastTouchInput.mTouches[0].mScreenPoint - mTouchStartPosition; if (NS_hypot(delta.x, delta.y) > AsyncPanZoomController::GetTouchStartTolerance()) { CancelLongTapTimeoutTask(); CancelMaxTapTimeoutTask(); SetState(GESTURE_NONE); } break; } case GESTURE_MULTI_TOUCH_DOWN: { if (mLastTouchInput.mTouches.Length() < 2) { NS_WARNING("Wrong input: less than 2 moving points in GESTURE_MULTI_TOUCH_DOWN state"); break; } float currentSpan = GetCurrentSpan(mLastTouchInput); mSpanChange += fabsf(currentSpan - mPreviousSpan); if (mSpanChange > PINCH_START_THRESHOLD) { SetState(GESTURE_PINCH); PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_START, mLastTouchInput.mTime, GetCurrentFocus(mLastTouchInput), currentSpan, currentSpan, mLastTouchInput.modifiers); mAsyncPanZoomController->HandleGestureEvent(pinchEvent); } rv = nsEventStatus_eConsumeNoDefault; mPreviousSpan = currentSpan; break; } case GESTURE_PINCH: { if (mLastTouchInput.mTouches.Length() < 2) { NS_WARNING("Wrong input: less than 2 moving points in GESTURE_PINCH state"); // Prevent APZC::OnTouchMove() from handling this wrong input rv = nsEventStatus_eConsumeNoDefault; break; } float currentSpan = GetCurrentSpan(mLastTouchInput); PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_SCALE, mLastTouchInput.mTime, GetCurrentFocus(mLastTouchInput), currentSpan, mPreviousSpan, mLastTouchInput.modifiers); mAsyncPanZoomController->HandleGestureEvent(pinchEvent); rv = nsEventStatus_eConsumeNoDefault; mPreviousSpan = currentSpan; break; } default: NS_WARNING("Unhandled state upon touch move"); SetState(GESTURE_NONE); break; } return rv; }
nsEventStatus GestureEventListener::HandlePinchGestureEvent(const MultiTouchInput& aEvent, bool aClearTouches) { nsEventStatus rv = nsEventStatus_eIgnore; if (mTouches.Length() > 1 && !aClearTouches) { const nsIntPoint& firstTouch = mTouches[0].mScreenPoint, secondTouch = mTouches[mTouches.Length() - 1].mScreenPoint; nsIntPoint focusPoint = nsIntPoint((firstTouch.x + secondTouch.x)/2, (firstTouch.y + secondTouch.y)/2); float currentSpan = float(NS_hypot(firstTouch.x - secondTouch.x, firstTouch.y - secondTouch.y)); 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->ReceiveInputEvent(pinchEvent); mState = GESTURE_PINCH; } break; } case GESTURE_PINCH: { PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_SCALE, aEvent.mTime, focusPoint, currentSpan, mPreviousSpan); mAsyncPanZoomController->ReceiveInputEvent(pinchEvent); break; } default: // What? break; } mPreviousSpan = currentSpan; rv = nsEventStatus_eConsumeNoDefault; } else if (mState == GESTURE_PINCH) { PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_END, aEvent.mTime, mTouches[0].mScreenPoint, 1.0f, 1.0f); mAsyncPanZoomController->ReceiveInputEvent(pinchEvent); mState = GESTURE_NONE; rv = nsEventStatus_eConsumeNoDefault; } if (aClearTouches) { mTouches.Clear(); } return rv; }