Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  PointerLockManager.cpp

  Sprache: C
 

/* 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/Logging.h"
#include "mozilla/PresShell.h"
#include "mozilla/ScopeExit.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/CanonicalBrowsingContext.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ElementBinding.h"
#include "mozilla/dom/PointerEventHandler.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/WindowContext.h"
#include "nsCOMPtr.h"
#include "nsIWidget.h"
#include "nsMenuPopupFrame.h"
#include "nsSandboxFlags.h"

mozilla::LazyLogModule gPointerLockLog("PointerLock");

#define MOZ_POINTERLOCK_LOG(...) \
  MOZ_LOG(gPointerLockLog, mozilla::LogLevel::Debug, (__VA_ARGS__))

namespace mozilla {

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::PointerLockOptions;
using mozilla::dom::Promise;
using mozilla::dom::WindowContext;

// Reference to the pointer locked element.
constinit static nsWeakPtr sLockedElement;

// Reference to the document which requested pointer lock.
constinit static nsWeakPtr sLockedDoc;

// Reference to the BrowserParent requested pointer lock.
static BrowserParent* sLockedRemoteTarget = nullptr;

/* static */
bool PointerLockManager::sIsLocked = false;

/* static */
bool PointerLockManager::sIsLockUnadjustedMovement = false;

// Map a Gecko-internal pointer-lock error string to the DOMException defined in
// the spec, https://w3c.github.io/pointerlock/#dom-element-requestpointerlock.
static void RejectPromiseForError(Promise* aPromise, const char* aError) {
  MOZ_ASSERT(aPromise);
  MOZ_ASSERT(aError);

  if (!strcmp(aError, "PointerLockDeniedDisabled")) {
    aPromise->MaybeRejectWithNotSupportedError("Pointer Lock API is disabled.");
    return;
  }
  if (!strcmp(aError, "PointerLockDeniedNotInDocument")) {
    aPromise->MaybeRejectWithInvalidStateError(
        "The requesting element is not in a document.");
    return;
  }
  if (!strcmp(aError, "PointerLockDeniedSandboxed")) {
    aPromise->MaybeRejectWithSecurityError(
        "Pointer Lock API is restricted via sandbox.");
    return;
  }
  // Other browsers allow the hidden document to lock the pointer, but there is
  // a spec issue for that, https://github.com/w3c/pointerlock/issues/93.
  if (!strcmp(aError, "PointerLockDeniedHidden")) {
    aPromise->MaybeRejectWithWrongDocumentError("The document is not visible.");
    return;
  }
  if (!strcmp(aError, "PointerLockDeniedNotFocused")) {
    aPromise->MaybeRejectWithWrongDocumentError("The document is not focused.");
    return;
  }
  if (!strcmp(aError, "PointerLockDeniedFailedToLock")) {
    aPromise->MaybeRejectWithNotSupportedError(
        "The browser failed to lock the pointer.");
    return;
  }
  if (!strcmp(aError, "PointerLockDeniedInUse")) {
    aPromise->MaybeRejectWithInvalidStateError(
        "The pointer is currently locked by a different document.");
    return;
  }
  if (!strcmp(aError, "PointerLockDeniedNotInputDriven")) {
    aPromise->MaybeRejectWithNotAllowedError(
        "Element.requestPointerLock() was not called from inside a short "
        "running user-generated event handler, and the document is not in full "
        "screen.");
    return;
  }
  if (!strcmp(aError, "PointerLockDeniedMovedDocument")) {
    aPromise->MaybeRejectWithInvalidStateError(
        "The requesting element has moved to a different document");
    return;
  }

  MOZ_ASSERT_UNREACHABLE("Unknown pointer lock error");
  aPromise->MaybeRejectWithInvalidStateError("Unknown error.");
}

/* 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;
  }

  MOZ_POINTERLOCK_LOG("Dispatch pointerlockchange event [document=0x%p]",
                      aTarget);
  RefPtr<AsyncEventDispatcher> asyncDispatcher =
      new AsyncEventDispatcher(aTarget, u"pointerlockchange"_ns,
                               CanBubble::eYes, ChromeOnlyDispatch::eNo);
  asyncDispatcher->PostDOMEvent();
}

static void DispatchPointerLockError(Document* aTarget, const char* aMessage) {
  MOZ_ASSERT(aMessage);
  if (!aTarget) {
    return;
  }

  MOZ_POINTERLOCK_LOG(
      "Dispatch pointerlockerror event [document=0x%p, message=%s]", aTarget,
      aMessage);
  RefPtr<AsyncEventDispatcher> asyncDispatcher =
      new AsyncEventDispatcher(aTarget, u"pointerlockerror"_ns, CanBubble::eYes,
                               ChromeOnlyDispatch::eNo);
  asyncDispatcher->PostDOMEvent();
  nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns,
                                  aTarget, PropertiesFile::DOM_PROPERTIES,
                                  aMessage);
}

// Combined error path: fires pointerlockerror for backwards compatibility AND
// rejects the spec-mandated Promise with the appropriate DOMException.
static void FailWith(Document* aTarget, Promise* aPromise, const char* aError) {
  DispatchPointerLockError(aTarget, aError);
  RejectPromiseForError(aPromise, aError);
}

static bool IsPopupOpened() {
  // Check if any popup is open.
  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  if (!pm) {
    return false;
  }

  nsTArray<nsMenuPopupFrame*> popups;
  pm->GetVisiblePopups(popups, true);

  for (nsMenuPopupFrame* popup : popups) {
    if (popup->GetPopupType() != widget::PopupType::Tooltip) {
      return true;
    }
  }

  return false;
}

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";
    }
  }

  if (IsPopupOpened()) {
    return "PointerLockDeniedFailedToLock";
  }

  return nullptr;
}

/* static */
void PointerLockManager::RequestLock(Element* aElement,
                                     const PointerLockOptions& aOptions,
                                     CallerType aCallerType,
                                     Promise* aPromise) {
  MOZ_ASSERT(aPromise);
  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, "
      "unadjustedMovement=%s]",
      aElement, doc.get(), aOptions.mUnadjustedMovement ? "true" : "false");

  // XXX: https://bugzilla.mozilla.org/show_bug.cgi?id=2037874.
  // Spec does this check in queued task instead, see step 6-2 of
  // https://w3c.github.io/pointerlock/#dom-element-requestpointerlock.
  if (aElement == pointerLockedElement &&
      sIsLockUnadjustedMovement == aOptions.mUnadjustedMovement) {
    DispatchPointerLockChange(doc);
    aPromise->MaybeResolveWithUndefined();
    return;
  }

  if (const char* msg = GetPointerLockError(aElement, pointerLockedElement)) {
    FailWith(doc, aPromise, msg);
    return;
  }

  bool userInputOrSystemCaller =
      doc->HasValidTransientUserGestureActivation() ||
      aCallerType == CallerType::System;
  nsCOMPtr<nsIRunnable> request =
      new PointerLockRequest(aElement, userInputOrSystemCaller,
                             aOptions.mUnadjustedMovement, aPromise);
  doc->Dispatch(request.forget());
}

/* static */
void PointerLockManager::Unlock(const char* aReason, Document* aDoc) {
  if (sLockedRemoteTarget) {
    MOZ_ASSERT(XRE_IsParentProcess());
    MOZ_ASSERT(!sIsLocked);

    if (aDoc) {
      CanonicalBrowsingContext* lockedBc =
          sLockedRemoteTarget->GetBrowsingContext();
      if (lockedBc &&
          lockedBc->TopCrossChromeBoundary()->GetExtantDocument() != aDoc) {
        return;
      }
    }

    MOZ_POINTERLOCK_LOG(
        "Unlock document 0x%p [sLockedRemoteTarget=0x%p, reason=%s]", aDoc,
        sLockedRemoteTarget, aReason);

    (void)sLockedRemoteTarget->SendReleasePointerLock();
    PointerLockManager::ReleaseLockedRemoteTarget(sLockedRemoteTarget);
    return;
  }

  if (!sIsLocked) {
    return;
  }

  nsCOMPtr<Document> pointerLockedDoc = GetLockedDocument();
  MOZ_POINTERLOCK_LOG("Unlock document 0x%p [LockedDocument=0x%p, reason=%s]",
                      aDoc, pointerLockedDoc.get(), aReason);

  if (!pointerLockedDoc || (aDoc && aDoc != pointerLockedDoc)) {
    return;
  }
  if (!SetPointerLock(nullptr, pointerLockedDoc, StyleCursorKind::Auto,
                      /* aUnadjustedMovement */ false)) {
    return;
  }

  nsCOMPtr<Element> pointerLockedElement = GetLockedElement();
  ChangePointerLockedElement(nullptr, pointerLockedDoc, pointerLockedElement);

  if (BrowserChild* browserChild =
          BrowserChild::GetFrom(pointerLockedDoc->GetDocShell())) {
    browserChild->SendReleasePointerLock();
  }

  AsyncEventDispatcher::RunDOMEventWhenSafe(
      *pointerLockedElement, u"MozDOMPointerLock:Exited"_ns, CanBubble::eYes,
      ChromeOnlyDispatch::eYes);
}

/* 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::StartSetPointerLock(Element* aElement,
                                             Document* aDocument,
                                             bool aUnadjustedMovement) {
  if (!SetPointerLock(aElement, aDocument, StyleCursorKind::None,
                      aUnadjustedMovement)) {
    DispatchPointerLockError(aDocument, "PointerLockDeniedFailedToLock");
    return false;
  }

  ChangePointerLockedElement(aElement, aDocument, nullptr);
  nsContentUtils::DispatchEventOnlyToChrome(
      aDocument, aElement, u"MozDOMPointerLock:Entered"_ns, CanBubble::eYes,
      Cancelable::eNo, /* DefaultAction */ nullptr);

  return true;
}

/* static */
bool PointerLockManager::SetPointerLock(Element* aElement, Document* aDocument,
                                        StyleCursorKind aCursorStyle,
                                        bool aUnadjustedMovement) {
  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;
      sIsLockUnadjustedMovement = 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,
                                        /* aUnadjustedMovement */ false);
      return true;
    }
    return false;
  }
  RefPtr<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) {
    NS_WARNING("SetPointerLock(): No Widget while requesting pointer lock");
    return false;
  }

  sIsLocked = !!aElement;
  sIsLockUnadjustedMovement = !!aElement && aUnadjustedMovement;

  // 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,
                                    sIsLockUnadjustedMovement);

  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 */
void PointerLockManager::SetLockedRemoteTarget(BrowserParent* aBrowserParent,
                                               const bool& aUnadjustedMovement,
                                               nsACString& aError) {
  MOZ_ASSERT(XRE_IsParentProcess());
  MOZ_ASSERT(aBrowserParent);

  if (sLockedRemoteTarget) {
    if (sLockedRemoteTarget != aBrowserParent) {
      aError = "PointerLockDeniedInUse"_ns;
    }
    return;
  }

  // Check if any popup is open.
  if (IsPopupOpened()) {
    aError = "PointerLockDeniedFailedToLock"_ns;
    return;
  }

  RefPtr<Element> element =
      aBrowserParent->TopLevelBrowserParent()->GetOwnerElement();
  if (NS_WARN_IF(!element)) {
    aError = "PointerLockDeniedFailedToLock"_ns;
    return;
  }

  nsPresContext* presContext = element->OwnerDoc()->GetPresContext();
  if (NS_WARN_IF(!presContext)) {
    aError = "PointerLockDeniedFailedToLock"_ns;
    return;
  }

  nsIWidget* widget = nsContentUtils::WidgetForContent(element);
  if (NS_WARN_IF(!widget)) {
    aError = "PointerLockDeniedFailedToLock"_ns;
    return;
  }

  MOZ_POINTERLOCK_LOG("Set locked remote target to 0x%p", aBrowserParent);
  sLockedRemoteTarget = aBrowserParent;
  PointerEventHandler::ReleaseAllPointerCaptureRemoteTarget();
  if (StaticPrefs::dom_pointer_lock_reset_to_center_from_parent_enabled()) {
    // Capture pointer to the top level browser element, so that mouse event can
    // be always retargeted to the content when pointer lock is active, even if
    // the pointer is out of the content area.
    // XXX Now that we also capture the pointer in the parent process for
    // pointer lock, we could potentially rely on the captured content for
    // cross-process event dispatching instead of tracking the locked remote
    // target separately.
    PresShell::SetCapturingContent(element, CaptureFlags::PointerLock);
    EventStateManager::RequestLockPointer(widget, presContext,
                                          aUnadjustedMovement);
  }
}

/* static */
void PointerLockManager::ReleaseLockedRemoteTarget(
    BrowserParent* aBrowserParent) {
  MOZ_ASSERT(XRE_IsParentProcess());
  if (sLockedRemoteTarget == aBrowserParent) {
    MOZ_POINTERLOCK_LOG("Release locked remote target 0x%p",
                        sLockedRemoteTarget);
    sLockedRemoteTarget = nullptr;
    PresShell::SetCapturingContent(nullptr, CaptureFlags::PointerLock);

    nsCOMPtr<nsIWidget> widget = aBrowserParent->GetTopLevelWidget();
    EventStateManager::ReleaseLockedPointer(widget);
  }
}

/* static */
bool PointerLockManager::ShouldResetPointer() {
  if (!StaticPrefs::dom_pointer_lock_reset_to_center_from_parent_enabled()) {
    return IsLocked();
  }

  // If the pref is enabled, we should reset pointer position to center of the
  // widget in parent process.
  return XRE_IsParentProcess() && (GetLockedRemoteTarget() || IsLocked());
}

static nsIWidget* GetWidgetForDocument(Document* aDocument) {
  if (!aDocument) {
    return nullptr;
  }
  PresShell* presShell = aDocument->GetPresShell();
  if (!presShell) {
    return nullptr;
  }
  return presShell->GetRootWidget();
}

PointerLockManager::PointerLockRequest::PointerLockRequest(
    Element* aElement, bool aUserInputOrChromeCaller, bool aUnadjustedMovement,
    Promise* aPromise)
    : mozilla::Runnable("PointerLockRequest"),
      mElement(do_GetWeakReference(aElement)),
      mDocument(do_GetWeakReference(aElement->OwnerDoc())),
      mUserInputOrChromeCaller(aUserInputOrChromeCaller),
      mUnadjustedMovement(aUnadjustedMovement),
      mPromise(aPromise) {}

NS_IMETHODIMP
PointerLockManager::PointerLockRequest::Run() {
  nsCOMPtr<Element> element = do_QueryReferent(mElement);
  nsCOMPtr<Document> document = do_QueryReferent(mDocument);
  RefPtr<Promise> promise = std::move(mPromise);

  const char* error = nullptr;
  if (!element || !document || !element->GetComposedDoc()) {
    error = "PointerLockDeniedNotInDocument";
  } else if (element->GetComposedDoc() != document) {
    error = "PointerLockDeniedMovedDocument";
  } else if (mUnadjustedMovement) {
    nsCOMPtr<nsIWidget> widget = GetWidgetForDocument(document);
    if (!widget || !widget->SupportsUnadjustedMovement()) {
      // XXX Reuse the existing error code for now, we should have a more
      // specific error code for this case.
      error = "PointerLockDeniedFailedToLock";
    }
  }

  if (!error) {
    nsCOMPtr<Element> pointerLockedElement = do_QueryReferent(sLockedElement);
    // XXX The steps are not exactly the same as in the spec, but they should
    // result in the same behavior.
    if (element == pointerLockedElement &&
        sIsLockUnadjustedMovement == mUnadjustedMovement) {
      DispatchPointerLockChange(document);
      promise->MaybeResolveWithUndefined();
      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) {
      // Apply new options on the existing lock.
      if (sIsLockUnadjustedMovement != mUnadjustedMovement) {
        nsCOMPtr<nsIWidget> widget = GetWidgetForDocument(document);
        if (NS_WARN_IF(!widget)) {
          FailWith(document, promise, "PointerLockDeniedFailedToLock");
          return NS_OK;
        }
        MOZ_ASSERT(widget->SupportsUnadjustedMovement());
        widget->SetNativePointerLockMode(
            mUnadjustedMovement ? nsIWidget::NativePointerLockMode::Unadjusted
                                : nsIWidget::NativePointerLockMode::Regular);
        sIsLockUnadjustedMovement = mUnadjustedMovement;
      }
      if (element != pointerLockedElement) {
        ChangePointerLockedElement(element, document, pointerLockedElement);
      } else {
        DispatchPointerLockChange(document);
      }
      promise->MaybeResolveWithUndefined();
      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) {
    FailWith(document, promise, 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(
        mUnadjustedMovement,
        [e, doc, bc, promise,
         unadjustedMovement = mUnadjustedMovement](const nsCString& aError) {
          nsCOMPtr<Document> document = do_QueryReferent(doc);
          if (!aError.IsEmpty()) {
            FailWith(document, promise, aError.get());
            return;
          }

          const char* error = nullptr;
          auto autoCleanup = MakeScopeExit([&] {
            if (error) {
              FailWith(document, promise, 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, unadjustedMovement)) {
            error = "PointerLockDeniedFailedToLock";
            return;
          }

          promise->MaybeResolveWithUndefined();
        },
        [doc, promise](mozilla::ipc::ResponseRejectReason) {
          // IPC layer error
          nsCOMPtr<Document> document = do_QueryReferent(doc);
          FailWith(document, promise, "PointerLockDeniedFailedToLock");
        });
  } else {
    if (StartSetPointerLock(element, document, mUnadjustedMovement)) {
      promise->MaybeResolveWithUndefined();
    } else {
      FailWith(document, promise, "PointerLockDeniedFailedToLock");
    }
  }

  return NS_OK;
}

}  // namespace mozilla

Messung V0.5 in Prozent
C=90 H=95 G=92

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

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 und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002