diff --git a/dom/base/PointerLockManager.cpp b/dom/base/PointerLockManager.cpp
index 78f1d600afe0b80a41ad1aaa3a29d4c03d4b1d66..4ec9d76abf97c5b537414a654c778a7ea9b9d168 100644
--- a/dom/base/PointerLockManager.cpp
+++ b/dom/base/PointerLockManager.cpp
@@ -265,7 +265,7 @@ bool PointerLockManager::SetPointerLock(Element* aElement, Document* aDocument,
     }
     return false;
   }
-  nsPresContext* presContext = presShell->GetPresContext();
+  RefPtr<nsPresContext> presContext = presShell->GetPresContext();
   if (!presContext) {
     NS_WARNING("SetPointerLock(): Unable to get PresContext");
     return false;
@@ -288,7 +288,7 @@ bool PointerLockManager::SetPointerLock(Element* aElement, Document* aDocument,
   // Hide the cursor and set pointer lock for future mouse events
   RefPtr<EventStateManager> esm = presContext->EventStateManager();
   esm->SetCursor(aCursorStyle, nullptr, {}, Nothing(), widget, true);
-  EventStateManager::SetPointerLock(widget, aElement);
+  EventStateManager::SetPointerLock(widget, presContext);
 
   return true;
 }
diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp
index b633821d8b84aed99dd2dae2a7a8a93135ecf9a2..1ba56447dc97c7e31c69c2d32fb5ce7102999561 100644
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -247,7 +247,7 @@ int16_t EventStateManager::sCurrentMouseBtn = MouseButton::eNotPressed;
 EventStateManager* EventStateManager::sActiveESM = nullptr;
 Document* EventStateManager::sMouseOverDocument = nullptr;
 AutoWeakFrame EventStateManager::sLastDragOverFrame = nullptr;
-LayoutDeviceIntPoint EventStateManager::sPreLockPoint =
+LayoutDeviceIntPoint EventStateManager::sPreLockScreenPoint =
     LayoutDeviceIntPoint(0, 0);
 LayoutDeviceIntPoint EventStateManager::sLastRefPoint = kInvalidRefPoint;
 CSSIntPoint EventStateManager::sLastScreenPoint = CSSIntPoint(0, 0);
@@ -4927,7 +4927,7 @@ OverOutElementsWrapper* EventStateManager::GetWrapperByEventID(
 
 /* static */
 void EventStateManager::SetPointerLock(nsIWidget* aWidget,
-                                       nsIContent* aElement) {
+                                       nsPresContext* aPresContext) {
   // Reset mouse wheel transaction
   WheelTransaction::EndTransaction();
 
@@ -4937,6 +4937,7 @@ void EventStateManager::SetPointerLock(nsIWidget* aWidget,
 
   if (PointerLockManager::IsLocked()) {
     MOZ_ASSERT(aWidget, "Locking pointer requires a widget");
+    MOZ_ASSERT(aPresContext, "Locking pointer requires a presContext");
 
     // Release all pointer capture when a pointer lock is successfully applied
     // on an element.
@@ -4944,7 +4945,8 @@ void EventStateManager::SetPointerLock(nsIWidget* aWidget,
 
     // Store the last known ref point so we can reposition the pointer after
     // unlock.
-    sPreLockPoint = sLastRefPoint;
+    sPreLockScreenPoint = LayoutDeviceIntPoint::Round(
+        sLastScreenPoint * aPresContext->CSSToDevPixelScale());
 
     // 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
@@ -4969,20 +4971,19 @@ void EventStateManager::SetPointerLock(nsIWidget* aWidget,
       aWidget->UnlockNativePointer();
     }
 
-    // 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 = sPreLockPoint;
     // Reset SynthCenteringPoint to invalid so that next time we start
     // locking pointer, it has its initial value.
     sSynthCenteringPoint = kInvalidRefPoint;
     if (aWidget) {
+      // 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 = sPreLockScreenPoint - aWidget->WidgetToScreenOffset();
       // XXX Cannot we do synthesize the native mousemove in the parent process
       //     with calling `UnlockNativePointer` above?  Then, we could make this
       //     API work only in the automation mode.
-      aWidget->SynthesizeNativeMouseMove(
-          sPreLockPoint + aWidget->WidgetToScreenOffset(), nullptr);
+      aWidget->SynthesizeNativeMouseMove(sPreLockScreenPoint, nullptr);
     }
 
     // Unsuppress DnD
diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h
index 7a43ade7a44c523778a6b9d3eded22668385d6fb..8d2ce6797e2cc4602ded8be3c5bb004bb23ea40a 100644
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -1152,10 +1152,9 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
   StyleCursorKind 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.
-  static LayoutDeviceIntPoint sPreLockPoint;
+  // Last mouse event screen point (in device pixel) when mouse was locked, used
+  // to restore mouse position after unlocking.
+  static LayoutDeviceIntPoint sPreLockScreenPoint;
 
   // 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
@@ -1240,7 +1239,7 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
   MOZ_CAN_RUN_SCRIPT_BOUNDARY void FireContextClick();
 
   MOZ_CAN_RUN_SCRIPT static void SetPointerLock(nsIWidget* aWidget,
-                                                nsIContent* aElement);
+                                                nsPresContext* aPresContext);
   static void sClickHoldCallback(nsITimer* aTimer, void* aESM);
 };