From 1256250b3f94f8ba95c3b879d24b70938d9f4fbc Mon Sep 17 00:00:00 2001 From: Stone Shih Date: Mon, 18 Sep 2017 15:07:41 +0800 Subject: [PATCH] Bug 1404896 - Separate the pointer lock implementations from GenerateMouseEnterExit to new functions. r=smaug. So that it's easier to reuse the implementation for handling pointer events. MozReview-Commit-ID: LIZoPjuq9ji --- dom/events/EventStateManager.cpp | 129 ++++++++++++++++++++----------- dom/events/EventStateManager.h | 14 ++++ 2 files changed, 98 insertions(+), 45 deletions(-) diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 32e781ae2866..e8104420fa96 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -725,6 +725,13 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, // into UpdateCursor(). GenerateDragGesture(aPresContext, mouseEvent); UpdateCursor(aPresContext, aEvent, mCurrentTarget, aStatus); + + UpdateLastRefPointOfMouseEvent(mouseEvent); + if (sIsPointerLocked) { + ResetPointerToWindowCenterWhilePointerLocked(mouseEvent); + } + UpdateLastPointerPosition(mouseEvent); + GenerateMouseEnterExit(mouseEvent); // Flush pending layout changes, so that later mouse move events // will go to the right nodes. @@ -4266,6 +4273,83 @@ EventStateManager::GeneratePointerEnterExit(EventMessage aMessage, GenerateMouseEnterExit(&pointerEvent); } +/* static */ void +EventStateManager::UpdateLastRefPointOfMouseEvent(WidgetMouseEvent* aMouseEvent) +{ + if (aMouseEvent->mMessage != eMouseMove) { + return; + } + + // Mouse movement is reported on the MouseEvent.movement{X,Y} fields. + // Movement is calculated in UIEvent::GetMovementPoint() as: + // previous_mousemove_mRefPoint - current_mousemove_mRefPoint. + if (sIsPointerLocked && aMouseEvent->mWidget) { + // The pointer is locked. If the pointer is not located at the center of + // the window, dispatch a synthetic mousemove to return the pointer there. + // Doing this between "real" pointer moves gives the impression that the + // (locked) pointer can continue moving and won't stop at the screen + // boundary. We cancel the synthetic event so that we don't end up + // dispatching the centering move event to content. + aMouseEvent->mLastRefPoint = + GetWindowClientRectCenter(aMouseEvent->mWidget); + + } else if (sLastRefPoint == kInvalidRefPoint) { + // We don't have a valid previous mousemove mRefPoint. This is either + // the first move we've encountered, or the mouse has just re-entered + // the application window. We should report (0,0) movement for this + // case, so make the current and previous mRefPoints the same. + aMouseEvent->mLastRefPoint = aMouseEvent->mRefPoint; + } else { + aMouseEvent->mLastRefPoint = sLastRefPoint; + } +} + +/* static */ void +EventStateManager::ResetPointerToWindowCenterWhilePointerLocked( + WidgetMouseEvent* aMouseEvent) +{ + MOZ_ASSERT(sIsPointerLocked); + if (aMouseEvent->mMessage != eMouseMove || !aMouseEvent->mWidget) { + return; + } + + // The pointer is locked. If the pointer is not located at the center of + // the window, dispatch a synthetic mousemove to return the pointer there. + // Doing this between "real" pointer moves gives the impression that the + // (locked) pointer can continue moving and won't stop at the screen + // boundary. We cancel the synthetic event so that we don't end up + // dispatching the centering move event to content. + LayoutDeviceIntPoint center = + GetWindowClientRectCenter(aMouseEvent->mWidget); + + if (aMouseEvent->mRefPoint != center) { + // Mouse move doesn't finish at the center of the window. Dispatch a + // synthetic native mouse event to move the pointer back to the center + // of the window, to faciliate more movement. But first, record that + // we've dispatched a synthetic mouse movement, so we can cancel it + // in the other branch here. + sSynthCenteringPoint = center; + aMouseEvent->mWidget->SynthesizeNativeMouseMove( + center + aMouseEvent->mWidget->WidgetToScreenOffset(), nullptr); + } else if (aMouseEvent->mRefPoint == sSynthCenteringPoint) { + // This is the "synthetic native" event we dispatched to re-center the + // pointer. Cancel it so we don't expose the centering move to content. + aMouseEvent->StopPropagation(); + // Clear sSynthCenteringPoint so we don't cancel other events + // targeted at the center. + sSynthCenteringPoint = kInvalidRefPoint; + } +} + +/* static */ void +EventStateManager::UpdateLastPointerPosition(WidgetMouseEvent* aMouseEvent) +{ + if (aMouseEvent->mMessage != eMouseMove) { + return; + } + sLastRefPoint = aMouseEvent->mRefPoint; +} + void EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent) { @@ -4278,51 +4362,6 @@ EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent) switch(aMouseEvent->mMessage) { case eMouseMove: - { - // Mouse movement is reported on the MouseEvent.movement{X,Y} fields. - // Movement is calculated in UIEvent::GetMovementPoint() as: - // previous_mousemove_mRefPoint - current_mousemove_mRefPoint. - if (sIsPointerLocked && aMouseEvent->mWidget) { - // The pointer is locked. If the pointer is not located at the center of - // the window, dispatch a synthetic mousemove to return the pointer there. - // Doing this between "real" pointer moves gives the impression that the - // (locked) pointer can continue moving and won't stop at the screen - // boundary. We cancel the synthetic event so that we don't end up - // dispatching the centering move event to content. - LayoutDeviceIntPoint center = - GetWindowClientRectCenter(aMouseEvent->mWidget); - aMouseEvent->mLastRefPoint = center; - if (aMouseEvent->mRefPoint != center) { - // Mouse move doesn't finish at the center of the window. Dispatch a - // synthetic native mouse event to move the pointer back to the center - // of the window, to faciliate more movement. But first, record that - // we've dispatched a synthetic mouse movement, so we can cancel it - // in the other branch here. - sSynthCenteringPoint = center; - aMouseEvent->mWidget->SynthesizeNativeMouseMove( - center + aMouseEvent->mWidget->WidgetToScreenOffset(), nullptr); - } else if (aMouseEvent->mRefPoint == sSynthCenteringPoint) { - // This is the "synthetic native" event we dispatched to re-center the - // pointer. Cancel it so we don't expose the centering move to content. - aMouseEvent->StopPropagation(); - // Clear sSynthCenteringPoint so we don't cancel other events - // targeted at the center. - sSynthCenteringPoint = kInvalidRefPoint; - } - } else if (sLastRefPoint == kInvalidRefPoint) { - // We don't have a valid previous mousemove mRefPoint. This is either - // the first move we've encountered, or the mouse has just re-entered - // the application window. We should report (0,0) movement for this - // case, so make the current and previous mRefPoints the same. - aMouseEvent->mLastRefPoint = aMouseEvent->mRefPoint; - } else { - aMouseEvent->mLastRefPoint = sLastRefPoint; - } - - // Update the last known mRefPoint with the current mRefPoint. - sLastRefPoint = aMouseEvent->mRefPoint; - } - MOZ_FALLTHROUGH; case ePointerMove: case ePointerDown: case ePointerGotCapture: diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h index 4a90cc71f79a..5806fbd4cc39 100644 --- a/dom/events/EventStateManager.h +++ b/dom/events/EventStateManager.h @@ -973,6 +973,20 @@ private: RefPtr& aChunk, nsIContent* aClosure); + /** + * Update the attribute mLastRefPoint of the mouse event. It should be + * the center of the window while the pointer is locked. + * the same value as mRefPoint while there is no known last ref point. + * the same value as the last known mRefPoint. + */ + static void UpdateLastRefPointOfMouseEvent(WidgetMouseEvent* aMouseEvent); + + static void ResetPointerToWindowCenterWhilePointerLocked( + WidgetMouseEvent* aMouseEvent); + + // Update the last known ref point to the current event's mRefPoint. + static void UpdateLastPointerPosition(WidgetMouseEvent* aMouseEvent); + int32_t mLockCursor; bool mLastFrameConsumedSetCursor;