Commit 8b143d53 authored by Edgar Chen's avatar Edgar Chen
Browse files

Bug 1684837 - Adjust pointer lock request handling; r=smaug, a=jcristau

Differential Revision: https://phabricator.services.mozilla.com/D100960
parent c801a944
...@@ -14664,64 +14664,130 @@ static void ChangePointerLockedElement(Element* aElement, Document* aDocument, ...@@ -14664,64 +14664,130 @@ static void ChangePointerLockedElement(Element* aElement, Document* aDocument,
DispatchPointerLockChange(aDocument); DispatchPointerLockChange(aDocument);
} }
   
MOZ_CAN_RUN_SCRIPT_BOUNDARY static void StartSetPointerLock( MOZ_CAN_RUN_SCRIPT_BOUNDARY static bool StartSetPointerLock(
Element* aElement, Document* aDocument, bool aUserInputOrChromeCaller) { 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; const char* error = nullptr;
if (!aElement || !aDocument || !aElement->GetComposedDoc()) { if (!element || !document || !element->GetComposedDoc()) {
error = "PointerLockDeniedNotInDocument"; error = "PointerLockDeniedNotInDocument";
} else if (aElement->GetComposedDoc() != aDocument) { } else if (element->GetComposedDoc() != document) {
error = "PointerLockDeniedMovedDocument"; error = "PointerLockDeniedMovedDocument";
} }
if (!error) { if (!error) {
nsCOMPtr<Element> pointerLockedElement = nsCOMPtr<Element> pointerLockedElement =
do_QueryReferent(EventStateManager::sPointerLockedElement); do_QueryReferent(EventStateManager::sPointerLockedElement);
if (aElement == pointerLockedElement) { if (element == pointerLockedElement) {
DispatchPointerLockChange(aDocument); DispatchPointerLockChange(document);
return; return NS_OK;
} }
// Note, we must bypass focus change, so pass true as the last parameter! // Note, we must bypass focus change, so pass true as the last parameter!
error = GetPointerLockError(aElement, pointerLockedElement, true); error = GetPointerLockError(element, pointerLockedElement, true);
// Another element in the same document is requesting pointer lock, // Another element in the same document is requesting pointer lock,
// just grant it without user input check. // just grant it without user input check.
if (!error && pointerLockedElement) { if (!error && pointerLockedElement) {
ChangePointerLockedElement(aElement, aDocument, pointerLockedElement); ChangePointerLockedElement(element, document, pointerLockedElement);
return; return NS_OK;
} }
} }
// If it is neither user input initiated, nor requested in fullscreen, // If it is neither user input initiated, nor requested in fullscreen,
// it should be rejected. // it should be rejected.
if (!error && !aUserInputOrChromeCaller && if (!error && !mUserInputOrChromeCaller &&
!aDocument->GetUnretargetedFullScreenElement()) { !document->GetUnretargetedFullScreenElement()) {
error = "PointerLockDeniedNotInputDriven"; error = "PointerLockDeniedNotInputDriven";
} }
if (!error && !aDocument->SetPointerLock(aElement, StyleCursorKind::None)) {
error = "PointerLockDeniedFailedToLock"; 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) { if (error) {
DispatchPointerLockError(aDocument, 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; return;
} }
   
ChangePointerLockedElement(aElement, aDocument, nullptr); if (element->GetComposedDoc() != document) {
nsContentUtils::DispatchEventOnlyToChrome( error = "PointerLockDeniedMovedDocument";
aDocument, ToSupports(aElement), u"MozDOMPointerLock:Entered"_ns, return;
CanBubble::eYes, Cancelable::eNo, /* DefaultAction */ nullptr); }
}
   
class PointerLockRequest final : public Runnable { nsCOMPtr<Element> pointerLockedElement =
public: do_QueryReferent(EventStateManager::sPointerLockedElement);
PointerLockRequest(Element* aElement, bool aUserInputOrChromeCaller) error = GetPointerLockError(element, pointerLockedElement, true);
: mozilla::Runnable("PointerLockRequest"), if (error) {
mElement(do_GetWeakReference(aElement)), return;
mDocument(do_GetWeakReference(aElement->OwnerDoc())), }
mUserInputOrChromeCaller(aUserInputOrChromeCaller) {
MOZ_ASSERT(XRE_IsParentProcess()); 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);
} }
   
NS_IMETHOD Run() final {
nsCOMPtr<Element> element = do_QueryReferent(mElement);
nsCOMPtr<Document> document = do_QueryReferent(mDocument);
StartSetPointerLock(element, document, mUserInputOrChromeCaller);
return NS_OK; return NS_OK;
}; };
   
...@@ -14749,30 +14815,9 @@ void Document::RequestPointerLock(Element* aElement, CallerType aCallerType) { ...@@ -14749,30 +14815,9 @@ void Document::RequestPointerLock(Element* aElement, CallerType aCallerType) {
   
bool userInputOrSystemCaller = HasValidTransientUserGestureActivation() || bool userInputOrSystemCaller = HasValidTransientUserGestureActivation() ||
aCallerType == CallerType::System; aCallerType == CallerType::System;
if (BrowserChild* browserChild = BrowserChild::GetFrom(GetDocShell())) {
nsWeakPtr e = do_GetWeakReference(aElement);
nsWeakPtr doc = do_GetWeakReference(aElement->OwnerDoc());
browserChild->SendRequestPointerLock(
[e, doc, userInputOrSystemCaller](const nsCString& aError) {
nsCOMPtr<Document> document = do_QueryReferent(doc);
if (!aError.IsEmpty()) {
DispatchPointerLockError(document, aError.get());
return;
}
nsCOMPtr<Element> element = do_QueryReferent(e);
StartSetPointerLock(element, document, userInputOrSystemCaller);
},
[doc](mozilla::ipc::ResponseRejectReason) {
// IPC layer error
nsCOMPtr<Document> document = do_QueryReferent(doc);
DispatchPointerLockError(document, "PointerLockDeniedFailedToLock");
});
} else {
nsCOMPtr<nsIRunnable> request = nsCOMPtr<nsIRunnable> request =
new PointerLockRequest(aElement, userInputOrSystemCaller); new PointerLockRequest(aElement, userInputOrSystemCaller);
Dispatch(TaskCategory::Other, request.forget()); Dispatch(TaskCategory::Other, request.forget());
}
} }
   
bool Document::SetPointerLock(Element* aElement, StyleCursorKind aCursorStyle) { bool Document::SetPointerLock(Element* aElement, StyleCursorKind aCursorStyle) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment