/* -*- 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/. */
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XRSystem, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mActiveImmersiveSession)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInlineSessions)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIsSessionSupportedRequests)
NS_IMPL_CYCLE_COLLECTION_UNLINK(
mRequestSessionRequestsWaitingForRuntimeDetection)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequestSessionRequestsWithoutHardware)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequestSessionRequestsWaitingForEnumeration) // Don't need NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER because // DOMEventTargetHelper does it for us.
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
// The document must be a responsible document, active and focused.
nsCOMPtr<Document> responsibleDocument = GetDocumentIfCurrent(); if (!responsibleDocument) { // The document is not trustworthy
promise->MaybeRejectWithSecurityError("This document is not responsible."); return promise.forget();
}
if (immersive || aOptions.mRequiredFeatures.WasPassed() ||
aOptions.mOptionalFeatures.WasPassed()) { if (!responsibleDocument->HasValidTransientUserGestureActivation() &&
aCallerType != CallerType::System &&
StaticPrefs::dom_vr_require_gesture()) { // A user gesture is required.
promise->MaybeRejectWithSecurityError("A user gesture is required."); return promise.forget();
}
}
/** * By default, all sessions will require XRReferenceSpaceType::Viewer * and immersive sessions will require XRReferenceSpaceType::Local. * * https://www.w3.org/TR/webxr/#default-features
*/
requiredReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Viewer); if (immersive) {
requiredReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Local);
}
if (aOptions.mRequiredFeatures.WasPassed()) { for (const nsString& val : aOptions.mRequiredFeatures.Value()) {
Maybe<XRReferenceSpaceType> type =
StringToEnum<XRReferenceSpaceType>(val); if (type.isNothing()) {
promise->MaybeRejectWithNotSupportedError( "A required feature for the XRSession is not available."); return promise.forget();
}
requiredReferenceSpaceTypes.AppendElement(type.value());
}
}
if (aOptions.mOptionalFeatures.WasPassed()) { for (const nsString& val : aOptions.mOptionalFeatures.Value()) {
Maybe<XRReferenceSpaceType> type =
StringToEnum<XRReferenceSpaceType>(val); if (type.isSome()) {
optionalReferenceSpaceTypes.AppendElement(type.value());
}
}
}
if (immersive) { if (mPendingImmersiveSession || mActiveImmersiveSession) {
promise->MaybeRejectWithInvalidStateError( "There can only be one immersive XRSession."); return promise.forget();
}
mPendingImmersiveSession = true;
}
bool XRSystem::CancelHardwareRequest(RequestSessionRequest* aRequest) { if (!aRequest->NeedsHardware()) { // If hardware access was an optional requirement and the user // opted not to provide access, queue the request // to be resolved without hardware.
QueueSessionRequestWithoutEnumeration(aRequest); returnfalse;
}
if (aRequest->IsImmersive()) {
mPendingImmersiveSession = false;
} returntrue;
}
bool XRSystem::OnXRPermissionRequestAllow() { if (!gfx::VRManagerChild::IsCreated()) { // It's possible that this callback returns after // we have already started shutting down. returnfalse;
} if (!mEnumerationInFlight) {
mEnumerationInFlight = true;
gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
Unused << vm->EnumerateVRDisplays();
} return mEnumerationInFlight ||
!mRequestSessionRequestsWaitingForEnumeration.IsEmpty();
}
void XRSystem::OnXRPermissionRequestCancel() {
nsTArray<RefPtr<RequestSessionRequest>> requestSessionRequests(
std::move(mRequestSessionRequestsWaitingForEnumeration)); for (RefPtr<RequestSessionRequest>& request : requestSessionRequests) { if (CancelHardwareRequest(request)) {
request->mPromise->MaybeRejectWithSecurityError( "A device supporting the requested session " "configuration could not be found.");
}
}
}
void XRSystem::ResolveSessionRequestsWithoutHardware() { // Resolve promises returned by RequestSession
nsTArray<RefPtr<gfx::VRDisplayClient>> displays; // Try resolving support without a device, for inline sessions.
displays.AppendElement(nullptr);
void XRSystem::NotifyEnumerationCompleted() { // Enumeration has completed.
mEnumerationInFlight = false;
if (!gfx::VRManagerChild::IsCreated()) { // It's possible that this callback returns after // we have already started shutting down. return;
}
// Resolve promises returned by RequestSession
nsTArray<RefPtr<gfx::VRDisplayClient>> displays;
gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
vm->GetVRDisplays(displays);
void XRSystem::ResolveSessionRequests(
nsTArray<RefPtr<RequestSessionRequest>>& aRequests, const nsTArray<RefPtr<gfx::VRDisplayClient>>& aDisplays) { for (RefPtr<RequestSessionRequest>& request : aRequests) {
RefPtr<XRSession> session; if (request->IsImmersive()) {
mPendingImmersiveSession = false;
} // Select an XR device for (const RefPtr<gfx::VRDisplayClient>& display : aDisplays) {
nsTArray<XRReferenceSpaceType> enabledReferenceSpaceTypes; if (request->ResolveSupport(display, enabledReferenceSpaceTypes)) { if (request->IsImmersive()) {
session = XRSession::CreateImmersiveSession(
GetOwnerWindow(), this, display, request->GetPresentationGroup(),
enabledReferenceSpaceTypes);
mActiveImmersiveSession = session;
} else {
session = XRSession::CreateInlineSession(GetOwnerWindow(), this,
enabledReferenceSpaceTypes);
mInlineSessions.AppendElement(session);
}
request->mPromise->MaybeResolve(session); break;
}
} if (!session) {
request->mPromise->MaybeRejectWithNotSupportedError( "A device supporting the required XRSession configuration " "could not be found.");
}
}
}
void XRSystem::NotifyDetectRuntimesCompleted() {
ResolveIsSessionSupportedRequests(); if (!mRequestSessionRequestsWaitingForRuntimeDetection.IsEmpty()) {
ProcessSessionRequestsWaitingForRuntimeDetection();
}
}
void XRSystem::ResolveIsSessionSupportedRequests() { // Resolve promises returned by IsSessionSupported
gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
nsTArray<RefPtr<IsSessionSupportedRequest>> isSessionSupportedRequests(
std::move(mIsSessionSupportedRequests)); bool featurePolicyBlocked = FeaturePolicyBlocked();
for (RefPtr<IsSessionSupportedRequest>& request :
isSessionSupportedRequests) { if (featurePolicyBlocked) {
request->mPromise->MaybeRejectWithSecurityError( "The xr-spatial-tracking feature policy is required."); continue;
}
for (RefPtr<RequestSessionRequest>& request : sessionRequests) { bool compatibleRuntime = false; switch (request->GetSessionMode()) { case XRSessionMode::Immersive_vr:
compatibleRuntime = vm->RuntimeSupportsVR(); break; case XRSessionMode::Immersive_ar:
compatibleRuntime = vm->RuntimeSupportsAR(); break; case XRSessionMode::Inline:
compatibleRuntime = vm->RuntimeSupportsInline(); break; default: break;
} if (!compatibleRuntime) { // If none of the requested sessions are supported by a // runtime, early exit without showing a permission prompt. if (CancelHardwareRequest(request)) {
request->mPromise->MaybeRejectWithNotSupportedError( "A device supporting the required XRSession configuration " "could not be found.");
} continue;
} if (featurePolicyBlocked) { // Don't show a permission prompt if blocked by feature policy. if (CancelHardwareRequest(request)) {
request->mPromise->MaybeRejectWithSecurityError( "The xr-spatial-tracking feature policy is required.");
} continue;
} // To continue evaluating this request, it must wait for hardware // enumeration and permission request.
mRequestSessionRequestsWaitingForEnumeration.AppendElement(request);
}
if (!mRequestSessionRequestsWaitingForEnumeration.IsEmpty() &&
!alreadyRequestedPermission) { /** * Inline sessions will require only a user gesture * and should not trigger XR permission UI. * This is not a problem currently, as the only platforms * allowing xr-spatial-tracking for inline sessions do not * present a modal XR permission UI. (eg. Android Firefox Reality)
*/
GetOwnerWindow()->RequestXRPermission();
}
}
bool RequestSessionRequest::ResolveSupport( const gfx::VRDisplayClient* aDisplay,
nsTArray<XRReferenceSpaceType>& aEnabledReferenceSpaceTypes) const { if (aDisplay) { if (!aDisplay->GetIsConnected()) { returnfalse;
} if ((aDisplay->GetDisplayInfo().GetPresentingGroups() &
mPresentationGroup) != 0) { returnfalse;
}
const gfx::VRDisplayInfo& info = aDisplay->GetDisplayInfo(); switch (mSessionMode) { case XRSessionMode::Inline: if (!bool(info.mDisplayState.capabilityFlags &
gfx::VRDisplayCapabilityFlags::Cap_Inline)) { returnfalse;
} break; case XRSessionMode::Immersive_vr: if (!bool(info.mDisplayState.capabilityFlags &
gfx::VRDisplayCapabilityFlags::Cap_ImmersiveVR)) { returnfalse;
} break; case XRSessionMode::Immersive_ar: if (!bool(info.mDisplayState.capabilityFlags &
gfx::VRDisplayCapabilityFlags::Cap_ImmersiveAR)) { returnfalse;
} break; default: break;
}
} elseif (mSessionMode != XRSessionMode::Inline) { // If we don't have a device, we can only support inline sessions returnfalse;
}
// All sessions support XRReferenceSpaceType::Viewer by default
aEnabledReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Viewer);
// Immersive sessions support XRReferenceSpaceType::Local by default if (IsImmersive()) {
aEnabledReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Local);
}
for (XRReferenceSpaceType type : mRequiredReferenceSpaceTypes) { if (aDisplay) { if (!aDisplay->IsReferenceSpaceTypeSupported(type)) { returnfalse;
}
} elseif (type != XRReferenceSpaceType::Viewer) { // If we don't have a device, We only support // XRReferenceSpaceType::Viewer returnfalse;
} if (!aEnabledReferenceSpaceTypes.Contains(type)) {
aEnabledReferenceSpaceTypes.AppendElement(type);
}
} if (aDisplay) { for (XRReferenceSpaceType type : mOptionalReferenceSpaceTypes) { if (aDisplay->IsReferenceSpaceTypeSupported(type) &&
!aEnabledReferenceSpaceTypes.Contains(type)) {
aEnabledReferenceSpaceTypes.AppendElement(type);
}
}
} returntrue;
}
bool RequestSessionRequest::WantsHardware() const { for (XRReferenceSpaceType type : mOptionalReferenceSpaceTypes) { // Any XRReferenceSpaceType other than Viewer requires hardware if (type != XRReferenceSpaceType::Viewer) { returntrue;
}
} return NeedsHardware();
}
bool RequestSessionRequest::NeedsHardware() const { for (XRReferenceSpaceType type : mRequiredReferenceSpaceTypes) { // Any XRReferenceSpaceType other than Viewer requires hardware if (type != XRReferenceSpaceType::Viewer) { returntrue;
}
} returnfalse;
}
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.