зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1672330 - Move pointer lock code to PointerLockManager; r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D101054
This commit is contained in:
Родитель
0bd4fa26f2
Коммит
c2c0ea7709
|
@ -13718,7 +13718,7 @@ void Document::ExitFullscreenInDocTree(Document* aMaybeNotARootDoc) {
|
|||
MOZ_ASSERT(aMaybeNotARootDoc);
|
||||
|
||||
// Unlock the pointer
|
||||
UnlockPointer();
|
||||
PointerLockManager::Unlock();
|
||||
|
||||
// Resolve all promises which waiting for exit fullscreen.
|
||||
PendingFullscreenChangeList::Iterator<FullscreenExit> iter(
|
||||
|
@ -13825,7 +13825,7 @@ void Document::RestorePreviousFullscreenState(UniquePtr<FullscreenExit> aExit) {
|
|||
}
|
||||
|
||||
// If fullscreen mode is updated the pointer should be unlocked
|
||||
UnlockPointer();
|
||||
PointerLockManager::Unlock();
|
||||
// All documents listed in the array except the last one are going to
|
||||
// completely exit from the fullscreen state.
|
||||
for (auto i : IntegerRange(exitElements.Length() - 1)) {
|
||||
|
@ -14428,7 +14428,7 @@ bool Document::ApplyFullscreen(UniquePtr<FullscreenRequest> aRequest) {
|
|||
|
||||
// If a document is already in fullscreen, then unlock the mouse pointer
|
||||
// before setting a new document to fullscreen
|
||||
UnlockPointer();
|
||||
PointerLockManager::Unlock();
|
||||
|
||||
// Set the fullscreen element. This sets the fullscreen style on the
|
||||
// element, and the fullscreen-ancestor styles on ancestors of the element
|
||||
|
@ -14534,350 +14534,6 @@ bool Document::SetOrientationPendingPromise(Promise* aPromise) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void DispatchPointerLockChange(Document* aTarget) {
|
||||
if (!aTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(aTarget, u"pointerlockchange"_ns,
|
||||
CanBubble::eYes, ChromeOnlyDispatch::eNo);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
static void DispatchPointerLockError(Document* aTarget, const char* aMessage) {
|
||||
if (!aTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(aTarget, u"pointerlockerror"_ns, CanBubble::eYes,
|
||||
ChromeOnlyDispatch::eNo);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns,
|
||||
aTarget, nsContentUtils::eDOM_PROPERTIES,
|
||||
aMessage);
|
||||
}
|
||||
|
||||
static const char* GetPointerLockError(Element* aElement, Element* aCurrentLock,
|
||||
bool aNoFocusCheck = false) {
|
||||
// Check if pointer lock pref is enabled
|
||||
if (!StaticPrefs::full_screen_api_pointer_lock_enabled()) {
|
||||
return "PointerLockDeniedDisabled";
|
||||
}
|
||||
|
||||
nsCOMPtr<Document> ownerDoc = aElement->OwnerDoc();
|
||||
if (aCurrentLock && aCurrentLock->OwnerDoc() != ownerDoc) {
|
||||
return "PointerLockDeniedInUse";
|
||||
}
|
||||
|
||||
if (!aElement->IsInComposedDoc()) {
|
||||
return "PointerLockDeniedNotInDocument";
|
||||
}
|
||||
|
||||
if (ownerDoc->GetSandboxFlags() & SANDBOXED_POINTER_LOCK) {
|
||||
return "PointerLockDeniedSandboxed";
|
||||
}
|
||||
|
||||
// Check if the element is in a document with a docshell.
|
||||
if (!ownerDoc->GetContainer()) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
nsCOMPtr<nsPIDOMWindowOuter> ownerWindow = ownerDoc->GetWindow();
|
||||
if (!ownerWindow) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
nsCOMPtr<nsPIDOMWindowInner> ownerInnerWindow = ownerDoc->GetInnerWindow();
|
||||
if (!ownerInnerWindow) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
if (ownerWindow->GetCurrentInnerWindow() != ownerInnerWindow) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
|
||||
BrowsingContext* bc = ownerDoc->GetBrowsingContext();
|
||||
BrowsingContext* topBC = bc ? bc->Top() : nullptr;
|
||||
WindowContext* topWC = ownerDoc->GetTopLevelWindowContext();
|
||||
if (!topBC || !topBC->IsActive() || !topWC ||
|
||||
topWC != topBC->GetCurrentWindowContext()) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
|
||||
if (!aNoFocusCheck) {
|
||||
if (!IsInActiveTab(ownerDoc)) {
|
||||
return "PointerLockDeniedNotFocused";
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void ChangePointerLockedElement(Element* aElement, Document* aDocument,
|
||||
Element* aPointerLockedElement) {
|
||||
// aDocument here is not really necessary, as it is the uncomposed
|
||||
// document of both aElement and aPointerLockedElement as far as one
|
||||
// is not nullptr, and they wouldn't both be nullptr in any case.
|
||||
// But since the caller of this function should have known what the
|
||||
// document is, we just don't try to figure out what it should be.
|
||||
MOZ_ASSERT(aDocument);
|
||||
MOZ_ASSERT(aElement != aPointerLockedElement);
|
||||
if (aPointerLockedElement) {
|
||||
MOZ_ASSERT(aPointerLockedElement->GetComposedDoc() == aDocument);
|
||||
aPointerLockedElement->ClearPointerLock();
|
||||
}
|
||||
if (aElement) {
|
||||
MOZ_ASSERT(aElement->GetComposedDoc() == aDocument);
|
||||
aElement->SetPointerLock();
|
||||
EventStateManager::sPointerLockedElement = do_GetWeakReference(aElement);
|
||||
EventStateManager::sPointerLockedDoc = do_GetWeakReference(aDocument);
|
||||
NS_ASSERTION(EventStateManager::sPointerLockedElement &&
|
||||
EventStateManager::sPointerLockedDoc,
|
||||
"aElement and this should support weak references!");
|
||||
} else {
|
||||
EventStateManager::sPointerLockedElement = nullptr;
|
||||
EventStateManager::sPointerLockedDoc = nullptr;
|
||||
}
|
||||
// Retarget all events to aElement via capture or
|
||||
// stop retargeting if aElement is nullptr.
|
||||
PresShell::SetCapturingContent(aElement, CaptureFlags::PointerLock);
|
||||
DispatchPointerLockChange(aDocument);
|
||||
}
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY static bool StartSetPointerLock(
|
||||
Element* aElement, Document* aDocument) {
|
||||
if (!aDocument->SetPointerLock(aElement, StyleCursorKind::None)) {
|
||||
DispatchPointerLockError(aDocument, "PointerLockDeniedFailedToLock");
|
||||
return false;
|
||||
}
|
||||
|
||||
ChangePointerLockedElement(aElement, aDocument, nullptr);
|
||||
nsContentUtils::DispatchEventOnlyToChrome(
|
||||
aDocument, ToSupports(aElement), u"MozDOMPointerLock:Entered"_ns,
|
||||
CanBubble::eYes, Cancelable::eNo, /* DefaultAction */ nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class PointerLockRequest final : public Runnable {
|
||||
public:
|
||||
PointerLockRequest(Element* aElement, bool aUserInputOrChromeCaller)
|
||||
: mozilla::Runnable("PointerLockRequest"),
|
||||
mElement(do_GetWeakReference(aElement)),
|
||||
mDocument(do_GetWeakReference(aElement->OwnerDoc())),
|
||||
mUserInputOrChromeCaller(aUserInputOrChromeCaller) {}
|
||||
|
||||
NS_IMETHOD Run() final {
|
||||
nsCOMPtr<Element> element = do_QueryReferent(mElement);
|
||||
nsCOMPtr<Document> document = do_QueryReferent(mDocument);
|
||||
|
||||
const char* error = nullptr;
|
||||
if (!element || !document || !element->GetComposedDoc()) {
|
||||
error = "PointerLockDeniedNotInDocument";
|
||||
} else if (element->GetComposedDoc() != document) {
|
||||
error = "PointerLockDeniedMovedDocument";
|
||||
}
|
||||
if (!error) {
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
if (element == pointerLockedElement) {
|
||||
DispatchPointerLockChange(document);
|
||||
return NS_OK;
|
||||
}
|
||||
// Note, we must bypass focus change, so pass true as the last parameter!
|
||||
error = GetPointerLockError(element, pointerLockedElement, true);
|
||||
// Another element in the same document is requesting pointer lock,
|
||||
// just grant it without user input check.
|
||||
if (!error && pointerLockedElement) {
|
||||
ChangePointerLockedElement(element, document, pointerLockedElement);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// If it is neither user input initiated, nor requested in fullscreen,
|
||||
// it should be rejected.
|
||||
if (!error && !mUserInputOrChromeCaller &&
|
||||
!document->GetUnretargetedFullScreenElement()) {
|
||||
error = "PointerLockDeniedNotInputDriven";
|
||||
}
|
||||
|
||||
if (error) {
|
||||
DispatchPointerLockError(document, error);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (BrowserChild* browserChild =
|
||||
BrowserChild::GetFrom(document->GetDocShell())) {
|
||||
nsWeakPtr e = do_GetWeakReference(element);
|
||||
nsWeakPtr doc = do_GetWeakReference(element->OwnerDoc());
|
||||
nsWeakPtr bc = do_GetWeakReference(browserChild);
|
||||
browserChild->SendRequestPointerLock(
|
||||
[e, doc, bc](const nsCString& aError) {
|
||||
nsCOMPtr<Document> document = do_QueryReferent(doc);
|
||||
if (!aError.IsEmpty()) {
|
||||
DispatchPointerLockError(document, aError.get());
|
||||
return;
|
||||
}
|
||||
|
||||
const char* error = nullptr;
|
||||
auto autoCleanup = MakeScopeExit([&] {
|
||||
if (error) {
|
||||
DispatchPointerLockError(document, error);
|
||||
// If we are failed to set pointer lock, notify parent to stop
|
||||
// redirect mouse event to this process.
|
||||
if (nsCOMPtr<nsIBrowserChild> browserChild =
|
||||
do_QueryReferent(bc)) {
|
||||
static_cast<BrowserChild*>(browserChild.get())
|
||||
->SendReleasePointerLock();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
nsCOMPtr<Element> element = do_QueryReferent(e);
|
||||
if (!element || !document || !element->GetComposedDoc()) {
|
||||
error = "PointerLockDeniedNotInDocument";
|
||||
return;
|
||||
}
|
||||
|
||||
if (element->GetComposedDoc() != document) {
|
||||
error = "PointerLockDeniedMovedDocument";
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
error = GetPointerLockError(element, pointerLockedElement, true);
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!StartSetPointerLock(element, document)) {
|
||||
error = "PointerLockDeniedFailedToLock";
|
||||
return;
|
||||
}
|
||||
},
|
||||
[doc](mozilla::ipc::ResponseRejectReason) {
|
||||
// IPC layer error
|
||||
nsCOMPtr<Document> document = do_QueryReferent(doc);
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
DispatchPointerLockError(document, "PointerLockDeniedFailedToLock");
|
||||
});
|
||||
} else {
|
||||
StartSetPointerLock(element, document);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
};
|
||||
|
||||
private:
|
||||
nsWeakPtr mElement;
|
||||
nsWeakPtr mDocument;
|
||||
bool mUserInputOrChromeCaller;
|
||||
};
|
||||
|
||||
void Document::RequestPointerLock(Element* aElement, CallerType aCallerType) {
|
||||
NS_ASSERTION(aElement,
|
||||
"Must pass non-null element to Document::RequestPointerLock");
|
||||
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
if (aElement == pointerLockedElement) {
|
||||
DispatchPointerLockChange(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (const char* msg = GetPointerLockError(aElement, pointerLockedElement)) {
|
||||
DispatchPointerLockError(this, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
bool userInputOrSystemCaller = HasValidTransientUserGestureActivation() ||
|
||||
aCallerType == CallerType::System;
|
||||
nsCOMPtr<nsIRunnable> request =
|
||||
new PointerLockRequest(aElement, userInputOrSystemCaller);
|
||||
Dispatch(TaskCategory::Other, request.forget());
|
||||
}
|
||||
|
||||
bool Document::SetPointerLock(Element* aElement, StyleCursorKind aCursorStyle) {
|
||||
MOZ_ASSERT(!aElement || aElement->OwnerDoc() == this,
|
||||
"We should be either unlocking pointer (aElement is nullptr), "
|
||||
"or locking pointer to an element in this document");
|
||||
#ifdef DEBUG
|
||||
if (!aElement) {
|
||||
nsCOMPtr<Document> pointerLockedDoc =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedDoc);
|
||||
MOZ_ASSERT(pointerLockedDoc == this);
|
||||
}
|
||||
#endif
|
||||
|
||||
PresShell* presShell = GetPresShell();
|
||||
if (!presShell) {
|
||||
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 = presShell->GetPresContext();
|
||||
if (!presContext) {
|
||||
NS_WARNING("SetPointerLock(): Unable to get PresContext");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
nsIFrame* rootFrame = presShell->GetRootFrame();
|
||||
if (!NS_WARN_IF(!rootFrame)) {
|
||||
widget = rootFrame->GetNearestWidget();
|
||||
NS_WARNING_ASSERTION(widget,
|
||||
"SetPointerLock(): Unable to find widget in "
|
||||
"presShell->GetRootFrame()->GetNearestWidget();");
|
||||
if (aElement && !widget) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Document::UnlockPointer(Document* aDoc) {
|
||||
if (!EventStateManager::sIsPointerLocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<Document> pointerLockedDoc =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedDoc);
|
||||
if (!pointerLockedDoc || (aDoc && aDoc != pointerLockedDoc)) {
|
||||
return;
|
||||
}
|
||||
if (!pointerLockedDoc->SetPointerLock(nullptr, StyleCursorKind::Auto)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
ChangePointerLockedElement(nullptr, pointerLockedDoc, pointerLockedElement);
|
||||
|
||||
if (BrowserChild* browserChild =
|
||||
BrowserChild::GetFrom(pointerLockedDoc->GetDocShell())) {
|
||||
browserChild->SendReleasePointerLock();
|
||||
}
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
|
||||
pointerLockedElement, u"MozDOMPointerLock:Exited"_ns, CanBubble::eYes,
|
||||
ChromeOnlyDispatch::eYes);
|
||||
asyncDispatcher->RunDOMEventWhenSafe();
|
||||
}
|
||||
|
||||
void Document::UpdateVisibilityState(DispatchVisibilityChange aDispatchEvent) {
|
||||
dom::VisibilityState oldState = mVisibilityState;
|
||||
mVisibilityState = ComputeVisibilityState();
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/NotNull.h"
|
||||
#include "mozilla/PointerLockManager.h"
|
||||
#include "mozilla/PreloadService.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Result.h"
|
||||
|
@ -2008,12 +2009,6 @@ class Document : public nsINode,
|
|||
*/
|
||||
static bool HandlePendingFullscreenRequests(Document* aDocument);
|
||||
|
||||
void RequestPointerLock(Element* aElement, CallerType);
|
||||
MOZ_CAN_RUN_SCRIPT bool SetPointerLock(Element* aElement, StyleCursorKind);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
static void UnlockPointer(Document* aDoc = nullptr);
|
||||
|
||||
// ScreenOrientation related APIs
|
||||
|
||||
void ClearOrientationPendingPromise();
|
||||
|
@ -3407,7 +3402,7 @@ class Document : public nsINode,
|
|||
Element* GetUnretargetedFullScreenElement();
|
||||
bool Fullscreen() { return !!GetFullscreenElement(); }
|
||||
already_AddRefed<Promise> ExitFullscreen(ErrorResult&);
|
||||
void ExitPointerLock() { UnlockPointer(this); }
|
||||
void ExitPointerLock() { PointerLockManager::Unlock(this); }
|
||||
void GetFgColor(nsAString& aFgColor);
|
||||
void SetFgColor(const nsAString& aFgColor);
|
||||
void GetLinkColor(nsAString& aLinkColor);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "DocumentOrShadowRoot.h"
|
||||
#include "mozilla/AnimationComparator.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/PointerLockManager.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/SVGUtils.h"
|
||||
#include "mozilla/dom/AnimatableBinding.h"
|
||||
|
@ -300,7 +301,7 @@ Element* DocumentOrShadowRoot::GetRetargetedFocusedElement() {
|
|||
|
||||
Element* DocumentOrShadowRoot::GetPointerLockElement() {
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
PointerLockManager::GetLockedElement();
|
||||
if (!pointerLockedElement) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/NotNull.h"
|
||||
#include "mozilla/PointerLockManager.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/PresShellForwards.h"
|
||||
#include "mozilla/ReflowOutput.h"
|
||||
|
@ -1830,7 +1831,7 @@ void Element::UnbindFromTree(bool aNullParent) {
|
|||
Document* document = GetComposedDoc();
|
||||
|
||||
if (HasPointerLock()) {
|
||||
Document::UnlockPointer();
|
||||
PointerLockManager::Unlock();
|
||||
}
|
||||
if (mState.HasState(NS_EVENT_STATE_FULLSCREEN)) {
|
||||
// The element being removed is an ancestor of the fullscreen element,
|
||||
|
@ -3339,7 +3340,7 @@ already_AddRefed<Promise> Element::RequestFullscreen(CallerType aCallerType,
|
|||
}
|
||||
|
||||
void Element::RequestPointerLock(CallerType aCallerType) {
|
||||
OwnerDoc()->RequestPointerLock(this, aCallerType);
|
||||
PointerLockManager::RequestLock(this, aCallerType);
|
||||
}
|
||||
|
||||
already_AddRefed<Flex> Element::GetAsFlexContainer() {
|
||||
|
|
|
@ -0,0 +1,443 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "PointerLockManager.h"
|
||||
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/StaticPrefs_full_screen_api.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/WindowContext.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using mozilla::dom::BrowserChild;
|
||||
using mozilla::dom::BrowserParent;
|
||||
using mozilla::dom::BrowsingContext;
|
||||
using mozilla::dom::CallerType;
|
||||
using mozilla::dom::Document;
|
||||
using mozilla::dom::Element;
|
||||
using mozilla::dom::WindowContext;
|
||||
|
||||
// Reference to the pointer locked element.
|
||||
static nsWeakPtr sLockedElement;
|
||||
|
||||
// Reference to the document which requested pointer lock.
|
||||
static nsWeakPtr sLockedDoc;
|
||||
|
||||
// Reference to the BrowserParent requested pointer lock.
|
||||
static BrowserParent* sLockedRemoteTarget = nullptr;
|
||||
|
||||
/* static */
|
||||
bool PointerLockManager::sIsLocked = false;
|
||||
|
||||
/* static */
|
||||
already_AddRefed<dom::Element> PointerLockManager::GetLockedElement() {
|
||||
nsCOMPtr<Element> element = do_QueryReferent(sLockedElement);
|
||||
return element.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<dom::Document> PointerLockManager::GetLockedDocument() {
|
||||
nsCOMPtr<Document> document = do_QueryReferent(sLockedDoc);
|
||||
return document.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
BrowserParent* PointerLockManager::GetLockedRemoteTarget() {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
return sLockedRemoteTarget;
|
||||
}
|
||||
|
||||
static void DispatchPointerLockChange(Document* aTarget) {
|
||||
if (!aTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(aTarget, u"pointerlockchange"_ns,
|
||||
CanBubble::eYes, ChromeOnlyDispatch::eNo);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
static void DispatchPointerLockError(Document* aTarget, const char* aMessage) {
|
||||
if (!aTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(aTarget, u"pointerlockerror"_ns, CanBubble::eYes,
|
||||
ChromeOnlyDispatch::eNo);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns,
|
||||
aTarget, nsContentUtils::eDOM_PROPERTIES,
|
||||
aMessage);
|
||||
}
|
||||
|
||||
static const char* GetPointerLockError(Element* aElement, Element* aCurrentLock,
|
||||
bool aNoFocusCheck = false) {
|
||||
// Check if pointer lock pref is enabled
|
||||
if (!StaticPrefs::full_screen_api_pointer_lock_enabled()) {
|
||||
return "PointerLockDeniedDisabled";
|
||||
}
|
||||
|
||||
nsCOMPtr<Document> ownerDoc = aElement->OwnerDoc();
|
||||
if (aCurrentLock && aCurrentLock->OwnerDoc() != ownerDoc) {
|
||||
return "PointerLockDeniedInUse";
|
||||
}
|
||||
|
||||
if (!aElement->IsInComposedDoc()) {
|
||||
return "PointerLockDeniedNotInDocument";
|
||||
}
|
||||
|
||||
if (ownerDoc->GetSandboxFlags() & SANDBOXED_POINTER_LOCK) {
|
||||
return "PointerLockDeniedSandboxed";
|
||||
}
|
||||
|
||||
// Check if the element is in a document with a docshell.
|
||||
if (!ownerDoc->GetContainer()) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
nsCOMPtr<nsPIDOMWindowOuter> ownerWindow = ownerDoc->GetWindow();
|
||||
if (!ownerWindow) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
nsCOMPtr<nsPIDOMWindowInner> ownerInnerWindow = ownerDoc->GetInnerWindow();
|
||||
if (!ownerInnerWindow) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
if (ownerWindow->GetCurrentInnerWindow() != ownerInnerWindow) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
|
||||
BrowsingContext* bc = ownerDoc->GetBrowsingContext();
|
||||
BrowsingContext* topBC = bc ? bc->Top() : nullptr;
|
||||
WindowContext* topWC = ownerDoc->GetTopLevelWindowContext();
|
||||
if (!topBC || !topBC->IsActive() || !topWC ||
|
||||
topWC != topBC->GetCurrentWindowContext()) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
|
||||
if (!aNoFocusCheck) {
|
||||
if (!IsInActiveTab(ownerDoc)) {
|
||||
return "PointerLockDeniedNotFocused";
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void PointerLockManager::RequestLock(Element* aElement,
|
||||
CallerType aCallerType) {
|
||||
NS_ASSERTION(aElement,
|
||||
"Must pass non-null element to PointerLockManager::RequestLock");
|
||||
|
||||
RefPtr<Document> doc = aElement->OwnerDoc();
|
||||
nsCOMPtr<Element> pointerLockedElement = GetLockedElement();
|
||||
if (aElement == pointerLockedElement) {
|
||||
DispatchPointerLockChange(doc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (const char* msg = GetPointerLockError(aElement, pointerLockedElement)) {
|
||||
DispatchPointerLockError(doc, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
bool userInputOrSystemCaller =
|
||||
doc->HasValidTransientUserGestureActivation() ||
|
||||
aCallerType == CallerType::System;
|
||||
nsCOMPtr<nsIRunnable> request =
|
||||
new PointerLockRequest(aElement, userInputOrSystemCaller);
|
||||
doc->Dispatch(TaskCategory::Other, request.forget());
|
||||
}
|
||||
|
||||
/* static */
|
||||
void PointerLockManager::Unlock(Document* aDoc) {
|
||||
if (!sIsLocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<Document> pointerLockedDoc = GetLockedDocument();
|
||||
if (!pointerLockedDoc || (aDoc && aDoc != pointerLockedDoc)) {
|
||||
return;
|
||||
}
|
||||
if (!SetPointerLock(nullptr, pointerLockedDoc, StyleCursorKind::Auto)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<Element> pointerLockedElement = GetLockedElement();
|
||||
ChangePointerLockedElement(nullptr, pointerLockedDoc, pointerLockedElement);
|
||||
|
||||
if (BrowserChild* browserChild =
|
||||
BrowserChild::GetFrom(pointerLockedDoc->GetDocShell())) {
|
||||
browserChild->SendReleasePointerLock();
|
||||
}
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
|
||||
pointerLockedElement, u"MozDOMPointerLock:Exited"_ns, CanBubble::eYes,
|
||||
ChromeOnlyDispatch::eYes);
|
||||
asyncDispatcher->RunDOMEventWhenSafe();
|
||||
}
|
||||
|
||||
/* static */
|
||||
void PointerLockManager::ChangePointerLockedElement(
|
||||
Element* aElement, Document* aDocument, Element* aPointerLockedElement) {
|
||||
// aDocument here is not really necessary, as it is the uncomposed
|
||||
// document of both aElement and aPointerLockedElement as far as one
|
||||
// is not nullptr, and they wouldn't both be nullptr in any case.
|
||||
// But since the caller of this function should have known what the
|
||||
// document is, we just don't try to figure out what it should be.
|
||||
MOZ_ASSERT(aDocument);
|
||||
MOZ_ASSERT(aElement != aPointerLockedElement);
|
||||
if (aPointerLockedElement) {
|
||||
MOZ_ASSERT(aPointerLockedElement->GetComposedDoc() == aDocument);
|
||||
aPointerLockedElement->ClearPointerLock();
|
||||
}
|
||||
if (aElement) {
|
||||
MOZ_ASSERT(aElement->GetComposedDoc() == aDocument);
|
||||
aElement->SetPointerLock();
|
||||
sLockedElement = do_GetWeakReference(aElement);
|
||||
sLockedDoc = do_GetWeakReference(aDocument);
|
||||
NS_ASSERTION(sLockedElement && sLockedDoc,
|
||||
"aElement and this should support weak references!");
|
||||
} else {
|
||||
sLockedElement = nullptr;
|
||||
sLockedDoc = nullptr;
|
||||
}
|
||||
// Retarget all events to aElement via capture or
|
||||
// stop retargeting if aElement is nullptr.
|
||||
PresShell::SetCapturingContent(aElement, CaptureFlags::PointerLock);
|
||||
DispatchPointerLockChange(aDocument);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool PointerLockManager::StartSetPointerLock(Element* aElement,
|
||||
Document* aDocument) {
|
||||
if (!SetPointerLock(aElement, aDocument, StyleCursorKind::None)) {
|
||||
DispatchPointerLockError(aDocument, "PointerLockDeniedFailedToLock");
|
||||
return false;
|
||||
}
|
||||
|
||||
ChangePointerLockedElement(aElement, aDocument, nullptr);
|
||||
nsContentUtils::DispatchEventOnlyToChrome(
|
||||
aDocument, ToSupports(aElement), u"MozDOMPointerLock:Entered"_ns,
|
||||
CanBubble::eYes, Cancelable::eNo, /* DefaultAction */ nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool PointerLockManager::SetPointerLock(Element* aElement, Document* aDocument,
|
||||
StyleCursorKind aCursorStyle) {
|
||||
MOZ_ASSERT(!aElement || aElement->OwnerDoc() == aDocument,
|
||||
"We should be either unlocking pointer (aElement is nullptr), "
|
||||
"or locking pointer to an element in this document");
|
||||
#ifdef DEBUG
|
||||
if (!aElement) {
|
||||
nsCOMPtr<Document> pointerLockedDoc = GetLockedDocument();
|
||||
MOZ_ASSERT(pointerLockedDoc == aDocument);
|
||||
}
|
||||
#endif
|
||||
|
||||
PresShell* presShell = aDocument->GetPresShell();
|
||||
if (!presShell) {
|
||||
NS_WARNING("SetPointerLock(): No PresShell");
|
||||
if (!aElement) {
|
||||
sIsLocked = false;
|
||||
// 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 = presShell->GetPresContext();
|
||||
if (!presContext) {
|
||||
NS_WARNING("SetPointerLock(): Unable to get PresContext");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
nsIFrame* rootFrame = presShell->GetRootFrame();
|
||||
if (!NS_WARN_IF(!rootFrame)) {
|
||||
widget = rootFrame->GetNearestWidget();
|
||||
NS_WARNING_ASSERTION(widget,
|
||||
"SetPointerLock(): Unable to find widget in "
|
||||
"presShell->GetRootFrame()->GetNearestWidget();");
|
||||
if (aElement && !widget) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sIsLocked = !!aElement;
|
||||
|
||||
// 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);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool PointerLockManager::IsInLockContext(BrowsingContext* aContext) {
|
||||
if (!aContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<Document> pointerLockedDoc = GetLockedDocument();
|
||||
if (!pointerLockedDoc || !pointerLockedDoc->GetBrowsingContext()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BrowsingContext* lockTop = pointerLockedDoc->GetBrowsingContext()->Top();
|
||||
BrowsingContext* top = aContext->Top();
|
||||
|
||||
return top == lockTop;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool PointerLockManager::SetLockedRemoteTarget(BrowserParent* aBrowserParent) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
if (sLockedRemoteTarget) {
|
||||
return sLockedRemoteTarget == aBrowserParent;
|
||||
}
|
||||
|
||||
sLockedRemoteTarget = aBrowserParent;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void PointerLockManager::ReleaseLockedRemoteTarget(
|
||||
BrowserParent* aBrowserParent) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
if (sLockedRemoteTarget == aBrowserParent) {
|
||||
sLockedRemoteTarget = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PointerLockManager::PointerLockRequest::PointerLockRequest(
|
||||
Element* aElement, bool aUserInputOrChromeCaller)
|
||||
: mozilla::Runnable("PointerLockRequest"),
|
||||
mElement(do_GetWeakReference(aElement)),
|
||||
mDocument(do_GetWeakReference(aElement->OwnerDoc())),
|
||||
mUserInputOrChromeCaller(aUserInputOrChromeCaller) {}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PointerLockManager::PointerLockRequest::Run() {
|
||||
nsCOMPtr<Element> element = do_QueryReferent(mElement);
|
||||
nsCOMPtr<Document> document = do_QueryReferent(mDocument);
|
||||
|
||||
const char* error = nullptr;
|
||||
if (!element || !document || !element->GetComposedDoc()) {
|
||||
error = "PointerLockDeniedNotInDocument";
|
||||
} else if (element->GetComposedDoc() != document) {
|
||||
error = "PointerLockDeniedMovedDocument";
|
||||
}
|
||||
if (!error) {
|
||||
nsCOMPtr<Element> pointerLockedElement = do_QueryReferent(sLockedElement);
|
||||
if (element == pointerLockedElement) {
|
||||
DispatchPointerLockChange(document);
|
||||
return NS_OK;
|
||||
}
|
||||
// Note, we must bypass focus change, so pass true as the last parameter!
|
||||
error = GetPointerLockError(element, pointerLockedElement, true);
|
||||
// Another element in the same document is requesting pointer lock,
|
||||
// just grant it without user input check.
|
||||
if (!error && pointerLockedElement) {
|
||||
ChangePointerLockedElement(element, document, pointerLockedElement);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// If it is neither user input initiated, nor requested in fullscreen,
|
||||
// it should be rejected.
|
||||
if (!error && !mUserInputOrChromeCaller &&
|
||||
!document->GetUnretargetedFullScreenElement()) {
|
||||
error = "PointerLockDeniedNotInputDriven";
|
||||
}
|
||||
|
||||
if (error) {
|
||||
DispatchPointerLockError(document, error);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (BrowserChild* browserChild =
|
||||
BrowserChild::GetFrom(document->GetDocShell())) {
|
||||
nsWeakPtr e = do_GetWeakReference(element);
|
||||
nsWeakPtr doc = do_GetWeakReference(element->OwnerDoc());
|
||||
nsWeakPtr bc = do_GetWeakReference(browserChild);
|
||||
browserChild->SendRequestPointerLock(
|
||||
[e, doc, bc](const nsCString& aError) {
|
||||
nsCOMPtr<Document> document = do_QueryReferent(doc);
|
||||
if (!aError.IsEmpty()) {
|
||||
DispatchPointerLockError(document, aError.get());
|
||||
return;
|
||||
}
|
||||
|
||||
const char* error = nullptr;
|
||||
auto autoCleanup = MakeScopeExit([&] {
|
||||
if (error) {
|
||||
DispatchPointerLockError(document, error);
|
||||
// If we are failed to set pointer lock, notify parent to stop
|
||||
// redirect mouse event to this process.
|
||||
if (nsCOMPtr<nsIBrowserChild> browserChild =
|
||||
do_QueryReferent(bc)) {
|
||||
static_cast<BrowserChild*>(browserChild.get())
|
||||
->SendReleasePointerLock();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
nsCOMPtr<Element> element = do_QueryReferent(e);
|
||||
if (!element || !document || !element->GetComposedDoc()) {
|
||||
error = "PointerLockDeniedNotInDocument";
|
||||
return;
|
||||
}
|
||||
|
||||
if (element->GetComposedDoc() != document) {
|
||||
error = "PointerLockDeniedMovedDocument";
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<Element> pointerLockedElement = GetLockedElement();
|
||||
error = GetPointerLockError(element, pointerLockedElement, true);
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!StartSetPointerLock(element, document)) {
|
||||
error = "PointerLockDeniedFailedToLock";
|
||||
return;
|
||||
}
|
||||
},
|
||||
[doc](mozilla::ipc::ResponseRejectReason) {
|
||||
// IPC layer error
|
||||
nsCOMPtr<Document> document = do_QueryReferent(doc);
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
DispatchPointerLockError(document, "PointerLockDeniedFailedToLock");
|
||||
});
|
||||
} else {
|
||||
StartSetPointerLock(element, document);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,82 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_PointerLockManager_h
|
||||
#define mozilla_PointerLockManager_h
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
enum class StyleCursorKind : uint8_t;
|
||||
|
||||
namespace dom {
|
||||
class BrowsingContext;
|
||||
class BrowserParent;
|
||||
enum class CallerType : uint32_t;
|
||||
class Document;
|
||||
class Element;
|
||||
} // namespace dom
|
||||
|
||||
class PointerLockManager final {
|
||||
public:
|
||||
static void RequestLock(dom::Element* aElement, dom::CallerType aCallerType);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
static void Unlock(dom::Document* aDoc = nullptr);
|
||||
|
||||
static bool IsLocked() { return sIsLocked; }
|
||||
|
||||
static already_AddRefed<dom::Element> GetLockedElement();
|
||||
|
||||
static already_AddRefed<dom::Document> GetLockedDocument();
|
||||
|
||||
static dom::BrowserParent* GetLockedRemoteTarget();
|
||||
|
||||
/**
|
||||
* Returns true if aContext and the current pointer locked document
|
||||
* have common top BrowsingContext.
|
||||
* Note that this method returns true only if caller is in the same process
|
||||
* as pointer locked document.
|
||||
*/
|
||||
static bool IsInLockContext(mozilla::dom::BrowsingContext* aContext);
|
||||
|
||||
// Set/release pointer lock remote target. Should only be called in parent
|
||||
// process.
|
||||
static bool SetLockedRemoteTarget(dom::BrowserParent* aBrowserParent);
|
||||
static void ReleaseLockedRemoteTarget(dom::BrowserParent* aBrowserParent);
|
||||
|
||||
private:
|
||||
class PointerLockRequest final : public Runnable {
|
||||
public:
|
||||
PointerLockRequest(dom::Element* aElement, bool aUserInputOrChromeCaller);
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() final;
|
||||
|
||||
private:
|
||||
nsWeakPtr mElement;
|
||||
nsWeakPtr mDocument;
|
||||
bool mUserInputOrChromeCaller;
|
||||
};
|
||||
|
||||
static void ChangePointerLockedElement(dom::Element* aElement,
|
||||
dom::Document* aDocument,
|
||||
dom::Element* aPointerLockedElement);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
static bool StartSetPointerLock(dom::Element* aElement,
|
||||
dom::Document* aDocument);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
static bool SetPointerLock(dom::Element* aElement, dom::Document* aDocument,
|
||||
StyleCursorKind);
|
||||
|
||||
static bool sIsLocked;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_PointerLockManager_h
|
|
@ -124,6 +124,7 @@ EXPORTS.mozilla += [
|
|||
"FlushType.h",
|
||||
"FullscreenChange.h",
|
||||
"IdentifierMapEntry.h",
|
||||
"PointerLockManager.h",
|
||||
"RangeBoundary.h",
|
||||
"RangeUtils.h",
|
||||
"ScriptableContentIterator.h",
|
||||
|
@ -392,6 +393,7 @@ UNIFIED_SOURCES += [
|
|||
"nsWindowRoot.cpp",
|
||||
"nsWrapperCache.cpp",
|
||||
"ParentProcessMessageManager.cpp",
|
||||
"PointerLockManager.cpp",
|
||||
"PopupBlocker.cpp",
|
||||
"Pose.cpp",
|
||||
"PostMessageEvent.cpp",
|
||||
|
|
|
@ -6873,24 +6873,6 @@ Document* nsContentUtils::GetRootDocument(Document* aDoc) {
|
|||
return doc;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool nsContentUtils::IsInPointerLockContext(BrowsingContext* aContext) {
|
||||
if (!aContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<Document> pointerLockedDoc =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedDoc);
|
||||
if (!pointerLockedDoc || !pointerLockedDoc->GetBrowsingContext()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BrowsingContext* lockTop = pointerLockedDoc->GetBrowsingContext()->Top();
|
||||
BrowsingContext* top = aContext->Top();
|
||||
|
||||
return top == lockTop;
|
||||
}
|
||||
|
||||
// static
|
||||
int32_t nsContentUtils::GetAdjustedOffsetInTextControl(nsIFrame* aOffsetFrame,
|
||||
int32_t aOffset) {
|
||||
|
|
|
@ -2445,14 +2445,6 @@ class nsContentUtils {
|
|||
*/
|
||||
static Document* GetRootDocument(Document* aDoc);
|
||||
|
||||
/**
|
||||
* Returns true if aContext and the current pointer lock document
|
||||
* have common top BrowsingContext.
|
||||
* Note that this method returns true only if caller is in the same process
|
||||
* as pointer lock document.
|
||||
*/
|
||||
static bool IsInPointerLockContext(mozilla::dom::BrowsingContext* aContext);
|
||||
|
||||
static void GetShiftText(nsAString& text);
|
||||
static void GetControlText(nsAString& text);
|
||||
static void GetMetaText(nsAString& text);
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include "mozilla/HTMLEditor.h"
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/PointerLockManager.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
@ -4647,11 +4648,8 @@ void nsFocusManager::GetFocusInSelection(nsPIDOMWindowOuter* aWindow,
|
|||
}
|
||||
|
||||
static void MaybeUnlockPointer(BrowsingContext* aCurrentFocusedContext) {
|
||||
nsCOMPtr<Document> pointerLockedDoc =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedDoc);
|
||||
if (pointerLockedDoc &&
|
||||
!nsContentUtils::IsInPointerLockContext(aCurrentFocusedContext)) {
|
||||
Document::UnlockPointer();
|
||||
if (!PointerLockManager::IsInLockContext(aCurrentFocusedContext)) {
|
||||
PointerLockManager::Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4881,8 +4879,8 @@ uint64_t nsFocusManager::GenerateFocusActionId() {
|
|||
}
|
||||
|
||||
static bool IsInPointerLockContext(nsPIDOMWindowOuter* aWin) {
|
||||
return nsContentUtils::IsInPointerLockContext(
|
||||
aWin ? aWin->GetBrowsingContext() : nullptr);
|
||||
return PointerLockManager::IsInLockContext(aWin ? aWin->GetBrowsingContext()
|
||||
: nullptr);
|
||||
}
|
||||
|
||||
void nsFocusManager::SetFocusedWindowInternal(nsPIDOMWindowOuter* aWindow) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/MiscEvents.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/PointerLockManager.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
|
@ -517,7 +518,7 @@ WidgetEvent* Event::WidgetEventPtr() { return mEvent; }
|
|||
CSSIntPoint Event::GetScreenCoords(nsPresContext* aPresContext,
|
||||
WidgetEvent* aEvent,
|
||||
LayoutDeviceIntPoint aPoint) {
|
||||
if (EventStateManager::sIsPointerLocked) {
|
||||
if (PointerLockManager::IsLocked()) {
|
||||
return EventStateManager::sLastScreenPoint;
|
||||
}
|
||||
|
||||
|
@ -587,7 +588,7 @@ CSSIntPoint Event::GetClientCoords(nsPresContext* aPresContext,
|
|||
WidgetEvent* aEvent,
|
||||
LayoutDeviceIntPoint aPoint,
|
||||
CSSIntPoint aDefaultPoint) {
|
||||
if (EventStateManager::sIsPointerLocked) {
|
||||
if (PointerLockManager::IsLocked()) {
|
||||
return EventStateManager::sLastClientPoint;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "mozilla/MiscEvents.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/PointerLockManager.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/ScrollTypes.h"
|
||||
|
@ -223,11 +224,6 @@ 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.
|
||||
nsWeakPtr EventStateManager::sPointerLockedDoc;
|
||||
nsCOMPtr<nsIContent> EventStateManager::sDragOverContent = nullptr;
|
||||
|
||||
EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::sInstance =
|
||||
|
@ -534,11 +530,10 @@ nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (aEvent->HasDragEventMessage() && sIsPointerLocked) {
|
||||
NS_ASSERTION(
|
||||
sIsPointerLocked,
|
||||
"sIsPointerLocked is true. Drag events should be suppressed when "
|
||||
"the pointer is locked.");
|
||||
if (aEvent->HasDragEventMessage() && PointerLockManager::IsLocked()) {
|
||||
NS_ASSERTION(PointerLockManager::IsLocked(),
|
||||
"Pointer is locked. Drag events should be suppressed when "
|
||||
"the pointer is locked.");
|
||||
}
|
||||
#endif
|
||||
// Store last known screenPoint and clientPoint so pointer lock
|
||||
|
@ -546,7 +541,7 @@ nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
if (aEvent->IsTrusted() &&
|
||||
((mouseEvent && mouseEvent->IsReal()) ||
|
||||
aEvent->mClass == eWheelEventClass) &&
|
||||
!sIsPointerLocked) {
|
||||
!PointerLockManager::IsLocked()) {
|
||||
sLastScreenPoint =
|
||||
Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint);
|
||||
sLastClientPoint = Event::GetClientCoords(
|
||||
|
@ -572,7 +567,7 @@ nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
|
||||
switch (aEvent->mMessage) {
|
||||
case eContextMenu:
|
||||
if (sIsPointerLocked) {
|
||||
if (PointerLockManager::IsLocked()) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
break;
|
||||
|
@ -698,7 +693,7 @@ nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
UpdateCursor(aPresContext, aEvent, mCurrentTarget, aStatus);
|
||||
|
||||
UpdateLastRefPointOfMouseEvent(mouseEvent);
|
||||
if (sIsPointerLocked) {
|
||||
if (PointerLockManager::IsLocked()) {
|
||||
ResetPointerToWindowCenterWhilePointerLocked(mouseEvent);
|
||||
}
|
||||
UpdateLastPointerPosition(mouseEvent);
|
||||
|
@ -1383,7 +1378,7 @@ void EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
|
|||
}
|
||||
|
||||
if (BrowserParent* pointerLockedRemote =
|
||||
BrowserParent::GetPointerLockedRemoteTarget()) {
|
||||
PointerLockManager::GetLockedRemoteTarget()) {
|
||||
remote = pointerLockedRemote;
|
||||
} else if (BrowserParent* pointerCapturedRemote =
|
||||
PointerEventHandler::GetPointerCapturingRemoteTarget(
|
||||
|
@ -1577,7 +1572,8 @@ void EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
|
|||
nsIFrame* inDownFrame,
|
||||
WidgetGUIEvent* inMouseDownEvent) {
|
||||
if (!inMouseDownEvent->IsTrusted() ||
|
||||
IsTopLevelRemoteTarget(mGestureDownContent) || sIsPointerLocked) {
|
||||
IsTopLevelRemoteTarget(mGestureDownContent) ||
|
||||
PointerLockManager::IsLocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1644,7 +1640,7 @@ void EventStateManager::sClickHoldCallback(nsITimer* aTimer, void* aESM) {
|
|||
// length of time, which is _not_ what we want.
|
||||
//
|
||||
void EventStateManager::FireContextClick() {
|
||||
if (!mGestureDownContent || !mPresContext || sIsPointerLocked) {
|
||||
if (!mGestureDownContent || !mPresContext || PointerLockManager::IsLocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4251,11 +4247,12 @@ nsIFrame* EventStateManager::DispatchMouseOrPointerEvent(
|
|||
// "[When the mouse is locked on an element...e]vents that require the concept
|
||||
// of a mouse cursor must not be dispatched (for example: mouseover,
|
||||
// mouseout).
|
||||
if (sIsPointerLocked && (aMessage == eMouseLeave || aMessage == eMouseEnter ||
|
||||
aMessage == eMouseOver || aMessage == eMouseOut)) {
|
||||
if (PointerLockManager::IsLocked() &&
|
||||
(aMessage == eMouseLeave || aMessage == eMouseEnter ||
|
||||
aMessage == eMouseOver || aMessage == eMouseOut)) {
|
||||
mCurrentTargetContent = nullptr;
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
PointerLockManager::GetLockedElement();
|
||||
if (!pointerLockedElement) {
|
||||
NS_WARNING("Should have pointer locked element, but didn't.");
|
||||
return nullptr;
|
||||
|
@ -4543,7 +4540,7 @@ void EventStateManager::UpdateLastRefPointOfMouseEvent(
|
|||
// 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) {
|
||||
if (PointerLockManager::IsLocked() && 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
|
||||
|
@ -4567,7 +4564,7 @@ void EventStateManager::UpdateLastRefPointOfMouseEvent(
|
|||
/* static */
|
||||
void EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
|
||||
WidgetMouseEvent* aMouseEvent) {
|
||||
MOZ_ASSERT(sIsPointerLocked);
|
||||
MOZ_ASSERT(PointerLockManager::IsLocked());
|
||||
if ((aMouseEvent->mMessage != eMouseMove &&
|
||||
aMouseEvent->mMessage != ePointerMove) ||
|
||||
!aMouseEvent->mWidget) {
|
||||
|
@ -4705,9 +4702,6 @@ OverOutElementsWrapper* EventStateManager::GetWrapperByEventID(
|
|||
/* static */
|
||||
void EventStateManager::SetPointerLock(nsIWidget* aWidget,
|
||||
nsIContent* aElement) {
|
||||
// NOTE: aElement will be nullptr when unlocking.
|
||||
sIsPointerLocked = !!aElement;
|
||||
|
||||
// Reset mouse wheel transaction
|
||||
WheelTransaction::EndTransaction();
|
||||
|
||||
|
@ -4715,7 +4709,7 @@ void EventStateManager::SetPointerLock(nsIWidget* aWidget,
|
|||
nsCOMPtr<nsIDragService> dragService =
|
||||
do_GetService("@mozilla.org/widget/dragservice;1");
|
||||
|
||||
if (sIsPointerLocked) {
|
||||
if (PointerLockManager::IsLocked()) {
|
||||
MOZ_ASSERT(aWidget, "Locking pointer requires a widget");
|
||||
|
||||
// Release all pointer capture when a pointer lock is successfully applied
|
||||
|
|
|
@ -317,10 +317,6 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
|
|||
// frozen at the last mouse position while the pointer is locked.
|
||||
static CSSIntPoint sLastClientPoint;
|
||||
|
||||
static bool sIsPointerLocked;
|
||||
static nsWeakPtr sPointerLockedElement;
|
||||
static nsWeakPtr sPointerLockedDoc;
|
||||
|
||||
/**
|
||||
* If the absolute values of mMultiplierX and/or mMultiplierY are equal or
|
||||
* larger than this value, the computed scroll amount isn't rounded down to
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "PointerEventHandler.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "PointerEvent.h"
|
||||
#include "PointerLockManager.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
|
@ -195,7 +196,7 @@ bool PointerEventHandler::SetPointerCaptureRemoteTarget(
|
|||
MOZ_ASSERT(sPointerCaptureRemoteTargetTable);
|
||||
MOZ_ASSERT(aBrowserParent);
|
||||
|
||||
if (BrowserParent::GetPointerLockedRemoteTarget()) {
|
||||
if (PointerLockManager::GetLockedRemoteTarget()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/PointerLockManager.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
@ -32,7 +33,7 @@ UIEvent::UIEvent(EventTarget* aOwner, nsPresContext* aPresContext,
|
|||
mLayerPoint(0, 0),
|
||||
mPagePoint(0, 0),
|
||||
mMovementPoint(0, 0),
|
||||
mIsPointerLocked(EventStateManager::sIsPointerLocked),
|
||||
mIsPointerLocked(PointerLockManager::IsLocked()),
|
||||
mLastClientPoint(EventStateManager::sLastClientPoint) {
|
||||
if (aEvent) {
|
||||
mEventIsInternal = false;
|
||||
|
|
|
@ -170,8 +170,6 @@ BrowserParent* BrowserParent::sFocus = nullptr;
|
|||
BrowserParent* BrowserParent::sTopLevelWebFocus = nullptr;
|
||||
/* static */
|
||||
BrowserParent* BrowserParent::sLastMouseRemoteTarget = nullptr;
|
||||
/* static */
|
||||
BrowserParent* BrowserParent::sPointerLockedRemoteTarget = nullptr;
|
||||
|
||||
// The flags passed by the webProgress notifications are 16 bits shifted
|
||||
// from the ones registered by webProgressListeners.
|
||||
|
@ -254,11 +252,6 @@ BrowserParent* BrowserParent::GetLastMouseRemoteTarget() {
|
|||
return sLastMouseRemoteTarget;
|
||||
}
|
||||
|
||||
/* static */
|
||||
BrowserParent* BrowserParent::GetPointerLockedRemoteTarget() {
|
||||
return sPointerLockedRemoteTarget;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
BrowserParent* BrowserParent::GetFrom(nsFrameLoader* aFrameLoader) {
|
||||
if (!aFrameLoader) {
|
||||
|
@ -608,7 +601,7 @@ void BrowserParent::RemoveWindowListeners() {
|
|||
void BrowserParent::DestroyInternal() {
|
||||
UnsetTopLevelWebFocus(this);
|
||||
UnsetLastMouseRemoteTarget(this);
|
||||
UnsetPointerLockedRemoteTarget(this);
|
||||
PointerLockManager::ReleaseLockedRemoteTarget(this);
|
||||
PointerEventHandler::ReleasePointerCaptureRemoteTarget(this);
|
||||
PresShell::ReleaseCapturingRemoteTarget(this);
|
||||
|
||||
|
@ -692,7 +685,7 @@ void BrowserParent::ActorDestroy(ActorDestroyReason why) {
|
|||
// case of a crash.
|
||||
BrowserParent::UnsetTopLevelWebFocus(this);
|
||||
BrowserParent::UnsetLastMouseRemoteTarget(this);
|
||||
BrowserParent::UnsetPointerLockedRemoteTarget(this);
|
||||
PointerLockManager::ReleaseLockedRemoteTarget(this);
|
||||
PointerEventHandler::ReleasePointerCaptureRemoteTarget(this);
|
||||
PresShell::ReleaseCapturingRemoteTarget(this);
|
||||
|
||||
|
@ -3105,14 +3098,6 @@ void BrowserParent::UnsetLastMouseRemoteTarget(BrowserParent* aBrowserParent) {
|
|||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void BrowserParent::UnsetPointerLockedRemoteTarget(
|
||||
BrowserParent* aBrowserParent) {
|
||||
if (sPointerLockedRemoteTarget == aBrowserParent) {
|
||||
sPointerLockedRemoteTarget = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserParent::RecvRequestIMEToCommitComposition(
|
||||
const bool& aCancel, bool* aIsCommitted, nsString* aCommittedString) {
|
||||
nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
|
||||
|
@ -4082,19 +4067,10 @@ mozilla::ipc::IPCResult BrowserParent::RecvIsWindowSupportingWebVR(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool BrowserParent::SetPointerLock() {
|
||||
if (sPointerLockedRemoteTarget) {
|
||||
return sPointerLockedRemoteTarget == this;
|
||||
}
|
||||
|
||||
sPointerLockedRemoteTarget = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserParent::RecvRequestPointerLock(
|
||||
RequestPointerLockResolver&& aResolve) {
|
||||
nsCString error;
|
||||
if (!SetPointerLock()) {
|
||||
if (!PointerLockManager::SetLockedRemoteTarget(this)) {
|
||||
error = "PointerLockDeniedInUse";
|
||||
} else {
|
||||
PointerEventHandler::ReleaseAllPointerCaptureRemoteTarget();
|
||||
|
@ -4104,8 +4080,9 @@ mozilla::ipc::IPCResult BrowserParent::RecvRequestPointerLock(
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserParent::RecvReleasePointerLock() {
|
||||
MOZ_ASSERT_IF(sPointerLockedRemoteTarget, sPointerLockedRemoteTarget == this);
|
||||
UnsetPointerLockedRemoteTarget(this);
|
||||
MOZ_ASSERT_IF(PointerLockManager::GetLockedRemoteTarget(),
|
||||
PointerLockManager::GetLockedRemoteTarget() == this);
|
||||
PointerLockManager::ReleaseLockedRemoteTarget(this);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -117,8 +117,6 @@ class BrowserParent final : public PBrowserParent,
|
|||
|
||||
static BrowserParent* GetLastMouseRemoteTarget();
|
||||
|
||||
static BrowserParent* GetPointerLockedRemoteTarget();
|
||||
|
||||
static BrowserParent* GetFrom(nsFrameLoader* aFrameLoader);
|
||||
|
||||
static BrowserParent* GetFrom(PBrowserParent* aBrowserParent);
|
||||
|
@ -760,7 +758,6 @@ class BrowserParent final : public PBrowserParent,
|
|||
mozilla::ipc::IPCResult RecvMaybeFireEmbedderLoadEvents(
|
||||
EmbedderElementEventType aFireEventAtEmbeddingElement);
|
||||
|
||||
bool SetPointerLock();
|
||||
mozilla::ipc::IPCResult RecvRequestPointerLock(
|
||||
RequestPointerLockResolver&& aResolve);
|
||||
mozilla::ipc::IPCResult RecvReleasePointerLock();
|
||||
|
@ -840,13 +837,6 @@ class BrowserParent final : public PBrowserParent,
|
|||
// current sLastMouseRemoteTarget.
|
||||
static void UnsetLastMouseRemoteTarget(BrowserParent* aBrowserParent);
|
||||
|
||||
// Keeps track of which BrowserParent requested pointer lock.
|
||||
static BrowserParent* sPointerLockedRemoteTarget;
|
||||
|
||||
// Unsetter for sPointerLockedRemoteTarget; only unsets if argument matches
|
||||
// current sPointerLockedRemoteTarget.
|
||||
static void UnsetPointerLockedRemoteTarget(BrowserParent* aBrowserParent);
|
||||
|
||||
struct APZData {
|
||||
bool operator==(const APZData& aOther) {
|
||||
return aOther.guid == guid && aOther.blockId == blockId &&
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--https://bugzilla.mozilla.org/show_bug.cgi?id=1672330-->
|
||||
<head>
|
||||
<title>Bug 1672330</title>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/paint_listener.js"></script>
|
||||
<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
|
||||
<script src="pointerlock_utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<style>
|
||||
#target {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
iframe {
|
||||
width: 400px;
|
||||
height: 300px;
|
||||
border: 1px solid blue;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank"href="https://bugzilla.mozilla.org/show_bug.cgi?id=1672330">Mozilla Bug 1672330</a>
|
||||
<div id="target"></div>
|
||||
<iframe src="https://example.com/tests/dom/tests/mochitest/pointerlock/iframe_differentDOM.html"></iframe>
|
||||
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
/**
|
||||
* Test for Bug 1672330
|
||||
*/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
async function requestPointerLock(aElement, aExpectError = false) {
|
||||
let doc = aElement.ownerDocument;
|
||||
let waitForPointerLockEvent = function() {
|
||||
return new Promise((aResolve) => {
|
||||
let eventHandler = function(aEvent) {
|
||||
is(aEvent.type, aExpectError ? 'pointerlockerror' : 'pointerlockchange',
|
||||
`got ${aEvent.type}`);
|
||||
doc.removeEventListener('pointerlockchange', eventHandler);
|
||||
doc.removeEventListener('pointerlockerror', eventHandler);
|
||||
aResolve();
|
||||
};
|
||||
|
||||
doc.addEventListener('pointerlockchange', eventHandler);
|
||||
doc.addEventListener('pointerlockerror', eventHandler);
|
||||
});
|
||||
};
|
||||
|
||||
aElement.requestPointerLock();
|
||||
await waitForPointerLockEvent();
|
||||
is(doc.pointerLockElement, aExpectError ? null : aElement, "target pointer locked");
|
||||
}
|
||||
|
||||
async function start() {
|
||||
await waitUntilApzStable();
|
||||
|
||||
let target = document.getElementById("target");
|
||||
SpecialPowers.wrap(document).clearUserGestureActivation();
|
||||
// Pointer lock request should be rejected due to the lack of user gesture.
|
||||
await requestPointerLock(target, true);
|
||||
|
||||
// Test mouse event should not be dispatched to document.
|
||||
document.addEventListener("mousemove", function(e) {
|
||||
ok(false, "Got unexpected mousemove");
|
||||
});
|
||||
|
||||
info("test sending mouse event to iframe");
|
||||
let iframe = document.querySelector("iframe");
|
||||
synthesizeMouse(iframe, 10, 10, { type: "mousemove" });
|
||||
await new Promise(resolve => { SimpleTest.executeSoon(resolve); });
|
||||
|
||||
info("test sending mouse event to another window");
|
||||
await new Promise((aResolve) => {
|
||||
let win = window.open("iframe_differentDOM.html");
|
||||
win.addEventListener("load", async function() {
|
||||
info("win onload");
|
||||
await waitUntilApzStable();
|
||||
synthesizeMouse(win.document.body, 10, 10, { type: "mousemove" }, win);
|
||||
win.close();
|
||||
aResolve();
|
||||
});
|
||||
});
|
||||
await new Promise(resolve => { SimpleTest.executeSoon(resolve); });
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -2,6 +2,7 @@
|
|||
support-files =
|
||||
pointerlock_utils.js
|
||||
iframe_differentDOM.html
|
||||
!/gfx/layers/apz/test/mochitest/apz_test_utils.js
|
||||
|
||||
[test_closewindow-with-pointerlock.html]
|
||||
[test_pointerlock_target_not_in_active_document.html]
|
||||
|
@ -32,3 +33,4 @@ support-files =
|
|||
[test_pointerlock_xorigin_iframe.html]
|
||||
support-files =
|
||||
file_pointerlock_xorigin_iframe.html
|
||||
file_pointerlock_xorigin_iframe_no_user_gesture.html
|
||||
|
|
|
@ -22,6 +22,7 @@ SimpleTest.waitForExplicitFinish();
|
|||
|
||||
let gTestFiles = [
|
||||
"file_pointerlock_xorigin_iframe.html",
|
||||
"file_pointerlock_xorigin_iframe_no_user_gesture.html",
|
||||
];
|
||||
|
||||
let gTestWindow = null;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/PerfStats.h"
|
||||
#include "mozilla/PointerLockManager.h"
|
||||
#include "mozilla/PresShellInlines.h"
|
||||
#include "mozilla/RangeUtils.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
|
@ -6960,7 +6961,7 @@ nsresult PresShell::EventHandler::HandleEventUsingCoordinates(
|
|||
EventHandler::GetCapturingContentFor(aGUIEvent);
|
||||
|
||||
if (GetDocument() && aGUIEvent->mClass == eTouchEventClass) {
|
||||
Document::UnlockPointer();
|
||||
PointerLockManager::Unlock();
|
||||
}
|
||||
|
||||
nsIFrame* frameForPresShell = MaybeFlushThrottledStyles(aFrameForPresShell);
|
||||
|
@ -8440,8 +8441,7 @@ void PresShell::EventHandler::MaybeHandleKeyboardEventBeforeDispatch(
|
|||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<Document> pointerLockedDoc =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedDoc);
|
||||
nsCOMPtr<Document> pointerLockedDoc = PointerLockManager::GetLockedDocument();
|
||||
if (!mPresShell->mIsLastChromeOnlyEscapeKeyConsumed && pointerLockedDoc) {
|
||||
// XXX See above comment to understand the reason why this needs
|
||||
// to claim that the Escape key event is consumed by content
|
||||
|
@ -8449,7 +8449,7 @@ void PresShell::EventHandler::MaybeHandleKeyboardEventBeforeDispatch(
|
|||
aKeyboardEvent->PreventDefaultBeforeDispatch(CrossProcessForwarding::eStop);
|
||||
aKeyboardEvent->mFlags.mOnlyChromeDispatch = true;
|
||||
if (aKeyboardEvent->mMessage == eKeyUp) {
|
||||
Document::UnlockPointer();
|
||||
PointerLockManager::Unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче