Bug 1323983 part 1 - Ensure to release the pointer even if the document has been detached. r=smaug
MozReview-Commit-ID: FY5lDQBYl6U
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -11698,16 +11698,23 @@ nsDocument::SetPointerLock(Element* aEle
do_QueryReferent(EventStateManager::sPointerLockedDoc);
MOZ_ASSERT(pointerLockedDoc == this);
}
#endif
nsIPresShell* shell = GetShell();
if (!shell) {
NS_WARNING("SetPointerLock(): No PresShell");
+ if (!aElement) {
+ // If we are unlocking pointer lock, but for some reason the doc
+ // has already detached from the presshell, just ask the event
+ // state manager to release the pointer.
+ EventStateManager::SetPointerLock(nullptr, nullptr);
+ return true;
+ }
return false;
}
nsPresContext* presContext = shell->GetPresContext();
if (!presContext) {
NS_WARNING("SetPointerLock(): Unable to get PresContext");
return false;
}
@@ -11723,17 +11730,17 @@ nsDocument::SetPointerLock(Element* aEle
return false;
}
}
// Hide the cursor and set pointer lock for future mouse events
RefPtr<EventStateManager> esm = presContext->EventStateManager();
esm->SetCursor(aCursorStyle, nullptr, false,
0.0f, 0.0f, widget, true);
- esm->SetPointerLock(widget, aElement);
+ EventStateManager::SetPointerLock(widget, aElement);
return true;
}
void
nsDocument::UnlockPointer(nsIDocument* aDoc)
{
if (!EventStateManager::sIsPointerLocked) {
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -263,16 +263,17 @@ static uint32_t sESMInstanceCount = 0;
static bool sPointerEventEnabled = false;
uint64_t EventStateManager::sUserInputCounter = 0;
int32_t EventStateManager::sUserInputEventDepth = 0;
bool EventStateManager::sNormalLMouseEventInProcess = false;
EventStateManager* EventStateManager::sActiveESM = nullptr;
nsIDocument* EventStateManager::sMouseOverDocument = nullptr;
nsWeakFrame EventStateManager::sLastDragOverFrame = nullptr;
+LayoutDeviceIntPoint EventStateManager::sPreLockPoint = LayoutDeviceIntPoint(0, 0);
LayoutDeviceIntPoint EventStateManager::sLastRefPoint = kInvalidRefPoint;
CSSIntPoint EventStateManager::sLastScreenPoint = CSSIntPoint(0, 0);
LayoutDeviceIntPoint EventStateManager::sSynthCenteringPoint = kInvalidRefPoint;
CSSIntPoint EventStateManager::sLastClientPoint = CSSIntPoint(0, 0);
bool EventStateManager::sIsPointerLocked = false;
// Reference to the pointer locked element.
nsWeakPtr EventStateManager::sPointerLockedElement;
// Reference to the document which requested pointer lock.
@@ -285,17 +286,16 @@ EventStateManager::WheelPrefs*
EventStateManager::WheelPrefs::sInstance = nullptr;
bool EventStateManager::WheelPrefs::sWheelEventsEnabledOnPlugins = true;
EventStateManager::DeltaAccumulator*
EventStateManager::DeltaAccumulator::sInstance = nullptr;
EventStateManager::EventStateManager()
: mLockCursor(0)
, mLastFrameConsumedSetCursor(false)
- , mPreLockPoint(0,0)
, mCurrentTarget(nullptr)
// init d&d gesture state machine variables
, mGestureDownPoint(0,0)
, mPresContext(nullptr)
, mLClickCount(0)
, mMClickCount(0)
, mRClickCount(0)
, m_haveShutdown(false)
@@ -4348,17 +4348,17 @@ EventStateManager::GetWrapperByEventID(W
if (!mPointersEnterLeaveHelper.Get(pointer->pointerId, getter_AddRefs(helper))) {
helper = new OverOutElementsWrapper();
mPointersEnterLeaveHelper.Put(pointer->pointerId, helper);
}
return helper;
}
-void
+/* static */ void
EventStateManager::SetPointerLock(nsIWidget* aWidget,
nsIContent* aElement)
{
// NOTE: aElement will be nullptr when unlocking.
sIsPointerLocked = !!aElement;
// Reset mouse wheel transaction
WheelTransaction::EndTransaction();
@@ -4366,17 +4366,17 @@ EventStateManager::SetPointerLock(nsIWid
// Deal with DnD events
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (sIsPointerLocked) {
MOZ_ASSERT(aWidget, "Locking pointer requires a widget");
// Store the last known ref point so we can reposition the pointer after unlock.
- mPreLockPoint = sLastRefPoint;
+ sPreLockPoint = sLastRefPoint;
// Fire a synthetic mouse move to ensure event state is updated. We first
// set the mouse to the center of the window, so that the mouse event
// doesn't report any movement.
sLastRefPoint = GetWindowClientRectCenter(aWidget);
aWidget->SynthesizeNativeMouseMove(
sLastRefPoint + aWidget->WidgetToScreenOffset(), nullptr);
@@ -4384,23 +4384,23 @@ EventStateManager::SetPointerLock(nsIWid
if (dragService) {
dragService->Suppress();
}
} else {
// Unlocking, so return pointer to the original position by firing a
// synthetic mouse event. We first reset sLastRefPoint to its
// pre-pointerlock position, so that the synthetic mouse event reports
// no movement.
- sLastRefPoint = mPreLockPoint;
+ sLastRefPoint = sPreLockPoint;
// Reset SynthCenteringPoint to invalid so that next time we start
// locking pointer, it has its initial value.
sSynthCenteringPoint = kInvalidRefPoint;
if (aWidget) {
aWidget->SynthesizeNativeMouseMove(
- mPreLockPoint + aWidget->WidgetToScreenOffset(), nullptr);
+ sPreLockPoint + aWidget->WidgetToScreenOffset(), nullptr);
}
// Unsuppress DnD
if (dragService) {
dragService->Unsuppress();
}
}
}
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -916,17 +916,17 @@ private:
nsIContent* aClosure);
int32_t mLockCursor;
bool mLastFrameConsumedSetCursor;
// Last mouse event mRefPoint (the offset from the widget's origin in
// device pixels) when mouse was locked, used to restore mouse position
// after unlocking.
- LayoutDeviceIntPoint mPreLockPoint;
+ static LayoutDeviceIntPoint sPreLockPoint;
// Stores the mRefPoint of the last synthetic mouse move we dispatched
// to re-center the mouse when we were pointer locked. If this is (-1,-1) it
// means we've not recently dispatched a centering event. We use this to
// detect when we receive the synth event, so we can cancel and not send it
// to content.
static LayoutDeviceIntPoint sSynthCenteringPoint;
@@ -1010,17 +1010,17 @@ public:
// Functions used for click hold context menus
nsCOMPtr<nsITimer> mClickHoldTimer;
void CreateClickHoldTimer(nsPresContext* aPresContext,
nsIFrame* aDownFrame,
WidgetGUIEvent* aMouseDownEvent);
void KillClickHoldTimer();
void FireContextClick();
- void SetPointerLock(nsIWidget* aWidget, nsIContent* aElement) ;
+ static void SetPointerLock(nsIWidget* aWidget, nsIContent* aElement) ;
static void sClickHoldCallback ( nsITimer* aTimer, void* aESM ) ;
};
/**
* This class is used while processing real user input. During this time, popups
* are allowed. For mousedown events, mouse capturing is also permitted.
*/
class AutoHandlingUserInputStatePusher