/* -*- 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/. */
using mozilla::dom::BrowserChild; using mozilla::dom::BrowserParent; using mozilla::dom::BrowsingContext; using mozilla::dom::CallerType; using mozilla::dom::CanonicalBrowsingContext; using mozilla::dom::Document; using mozilla::dom::Element; using mozilla::dom::WindowContext;
// Reference to the pointer locked element.
MOZ_RUNINIT static nsWeakPtr sLockedElement;
// Reference to the document which requested pointer lock.
MOZ_RUNINIT static nsWeakPtr sLockedDoc;
// Reference to the BrowserParent requested pointer lock. static BrowserParent* sLockedRemoteTarget = nullptr;
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";
}
}
if (IsPopupOpened()) { return"PointerLockDeniedFailedToLock";
}
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();
MOZ_POINTERLOCK_LOG("Request lock on element 0x%p [document=0x%p]", aElement,
doc.get());
if (aElement == pointerLockedElement) {
DispatchPointerLockChange(doc); return;
}
/* 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);
MOZ_POINTERLOCK_LOG("Change locked element from 0x%p to 0x%p [document=0x%p]",
aPointerLockedElement, aElement, aDocument); 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::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); returntrue;
} returnfalse;
}
RefPtr<nsPresContext> presContext = presShell->GetPresContext(); if (!presContext) {
NS_WARNING("SetPointerLock(): Unable to get PresContext"); returnfalse;
}
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) { returnfalse;
}
}
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, presContext);
constchar* error = nullptr; if (!element || !document || !element->GetComposedDoc()) {
error = "PointerLockDeniedNotInDocument";
} elseif (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->Fullscreen()) {
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;
}
constchar* 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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.