Bug 1860712 [wpt PR 42705] - Port popover test to WPT and adjust for close requests...
[gecko.git] / dom / vr / XRSystem.cpp
blob09b9e074763a1386a05f246db87f4bfb7629c5ee
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/XRSystem.h"
9 #include "mozilla/StaticPrefs_dom.h"
10 #include "mozilla/dom/XRPermissionRequest.h"
11 #include "mozilla/dom/XRSession.h"
12 #include "mozilla/dom/BindingCallContext.h"
13 #include "mozilla/dom/Document.h"
14 #include "mozilla/dom/Promise.h"
15 #include "mozilla/dom/FeaturePolicyUtils.h"
16 #include "mozilla/dom/PermissionMessageUtils.h"
17 #include "nsGlobalWindowInner.h"
18 #include "nsThreadUtils.h"
19 #include "gfxVR.h"
20 #include "VRDisplayClient.h"
21 #include "VRManagerChild.h"
23 namespace mozilla::dom {
25 using namespace gfx;
27 ////////////////////////////////////////////////////////////////////////////////
28 // XRSystem cycle collection
29 NS_IMPL_CYCLE_COLLECTION_CLASS(XRSystem)
31 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XRSystem,
32 DOMEventTargetHelper)
33 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mActiveImmersiveSession)
34 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInlineSessions)
35 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIsSessionSupportedRequests)
36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
37 mRequestSessionRequestsWaitingForRuntimeDetection)
38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequestSessionRequestsWithoutHardware)
39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
40 mRequestSessionRequestsWaitingForEnumeration)
41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
43 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XRSystem, DOMEventTargetHelper)
44 NS_IMPL_CYCLE_COLLECTION_UNLINK(mActiveImmersiveSession)
45 NS_IMPL_CYCLE_COLLECTION_UNLINK(mInlineSessions)
46 NS_IMPL_CYCLE_COLLECTION_UNLINK(mIsSessionSupportedRequests)
47 NS_IMPL_CYCLE_COLLECTION_UNLINK(
48 mRequestSessionRequestsWaitingForRuntimeDetection)
49 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequestSessionRequestsWithoutHardware)
50 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequestSessionRequestsWaitingForEnumeration)
51 // Don't need NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER because
52 // DOMEventTargetHelper does it for us.
53 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
55 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(XRSystem, DOMEventTargetHelper)
57 JSObject* XRSystem::WrapObject(JSContext* aCx,
58 JS::Handle<JSObject*> aGivenProto) {
59 return XRSystem_Binding::Wrap(aCx, this, aGivenProto);
62 // static
63 already_AddRefed<XRSystem> XRSystem::Create(nsPIDOMWindowInner* aWindow) {
64 MOZ_ASSERT(aWindow);
66 RefPtr<XRSystem> service = new XRSystem(aWindow);
67 return service.forget();
70 XRSystem::XRSystem(nsPIDOMWindowInner* aWindow)
71 : DOMEventTargetHelper(aWindow),
72 mShuttingDown(false),
73 mPendingImmersiveSession(false),
74 mEnumerationInFlight(false) {
75 // Unregister with VRManagerChild
76 VRManagerChild* vmc = VRManagerChild::Get();
77 if (vmc) {
78 vmc->AddListener(this);
82 void XRSystem::Shutdown() {
83 MOZ_ASSERT(!mShuttingDown);
84 mShuttingDown = true;
86 // Unregister from VRManagerChild
87 if (VRManagerChild::IsCreated()) {
88 VRManagerChild* vmc = VRManagerChild::Get();
89 vmc->RemoveListener(this);
93 void XRSystem::SessionEnded(XRSession* aSession) {
94 if (mActiveImmersiveSession == aSession) {
95 mActiveImmersiveSession = nullptr;
97 mInlineSessions.RemoveElement(aSession);
100 already_AddRefed<Promise> XRSystem::IsSessionSupported(XRSessionMode aMode,
101 ErrorResult& aRv) {
102 nsCOMPtr<nsIGlobalObject> global = GetParentObject();
103 NS_ENSURE_TRUE(global, nullptr);
105 RefPtr<Promise> promise = Promise::Create(global, aRv);
106 NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
108 if (aMode == XRSessionMode::Inline) {
109 promise->MaybeResolve(true);
110 return promise.forget();
113 if (mIsSessionSupportedRequests.IsEmpty()) {
114 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
115 vm->DetectRuntimes();
118 RefPtr<IsSessionSupportedRequest> request =
119 new IsSessionSupportedRequest(aMode, promise);
120 mIsSessionSupportedRequests.AppendElement(request);
121 return promise.forget();
124 already_AddRefed<Promise> XRSystem::RequestSession(
125 JSContext* aCx, XRSessionMode aMode, const XRSessionInit& aOptions,
126 CallerType aCallerType, ErrorResult& aRv) {
127 nsCOMPtr<nsIGlobalObject> global = GetParentObject();
128 NS_ENSURE_TRUE(global, nullptr);
130 RefPtr<Promise> promise = Promise::Create(global, aRv);
131 NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
133 bool immersive = (aMode == XRSessionMode::Immersive_vr ||
134 aMode == XRSessionMode::Immersive_ar);
136 // The document must be a responsible document, active and focused.
137 nsCOMPtr<Document> responsibleDocument = GetDocumentIfCurrent();
138 if (!responsibleDocument) {
139 // The document is not trustworthy
140 promise->MaybeRejectWithSecurityError("This document is not responsible.");
141 return promise.forget();
144 if (immersive || aOptions.mRequiredFeatures.WasPassed() ||
145 aOptions.mOptionalFeatures.WasPassed()) {
146 if (!responsibleDocument->HasValidTransientUserGestureActivation() &&
147 aCallerType != CallerType::System &&
148 StaticPrefs::dom_vr_require_gesture()) {
149 // A user gesture is required.
150 promise->MaybeRejectWithSecurityError("A user gesture is required.");
151 return promise.forget();
155 nsTArray<XRReferenceSpaceType> requiredReferenceSpaceTypes;
156 nsTArray<XRReferenceSpaceType> optionalReferenceSpaceTypes;
159 * By default, all sessions will require XRReferenceSpaceType::Viewer
160 * and immersive sessions will require XRReferenceSpaceType::Local.
162 * https://www.w3.org/TR/webxr/#default-features
164 requiredReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Viewer);
165 if (immersive) {
166 requiredReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Local);
169 BindingCallContext callCx(aCx, "XRSystem.requestSession");
171 if (aOptions.mRequiredFeatures.WasPassed()) {
172 const Sequence<JS::Value>& arr = (aOptions.mRequiredFeatures.Value());
173 for (const JS::Value& val : arr) {
174 if (!val.isNull() && !val.isUndefined()) {
175 bool bFound = false;
176 JS::Rooted<JS::Value> v(aCx, val);
177 int index = 0;
178 if (FindEnumStringIndex<false>(
179 callCx, v, XRReferenceSpaceTypeValues::strings,
180 "XRReferenceSpaceType", "Argument 2 of XR.requestSession",
181 &index)) {
182 if (index >= 0) {
183 requiredReferenceSpaceTypes.AppendElement(
184 static_cast<XRReferenceSpaceType>(index));
185 bFound = true;
188 if (!bFound) {
189 promise->MaybeRejectWithNotSupportedError(
190 "A required feature for the XRSession is not available.");
191 return promise.forget();
197 if (aOptions.mOptionalFeatures.WasPassed()) {
198 const Sequence<JS::Value>& arr = (aOptions.mOptionalFeatures.Value());
199 for (const JS::Value& val : arr) {
200 if (!val.isNull() && !val.isUndefined()) {
201 JS::Rooted<JS::Value> v(aCx, val);
202 int index = 0;
203 if (FindEnumStringIndex<false>(
204 callCx, v, XRReferenceSpaceTypeValues::strings,
205 "XRReferenceSpaceType", "Argument 2 of XR.requestSession",
206 &index)) {
207 if (index >= 0) {
208 optionalReferenceSpaceTypes.AppendElement(
209 static_cast<XRReferenceSpaceType>(index));
216 if (immersive) {
217 if (mPendingImmersiveSession || mActiveImmersiveSession) {
218 promise->MaybeRejectWithInvalidStateError(
219 "There can only be one immersive XRSession.");
220 return promise.forget();
222 mPendingImmersiveSession = true;
225 bool isChromeSession = aCallerType == CallerType::System;
226 uint32_t presentationGroup =
227 isChromeSession ? gfx::kVRGroupChrome : gfx::kVRGroupContent;
228 RefPtr<RequestSessionRequest> request = new RequestSessionRequest(
229 aMode, presentationGroup, promise, requiredReferenceSpaceTypes,
230 optionalReferenceSpaceTypes);
231 if (request->WantsHardware()) {
232 QueueSessionRequestWithEnumeration(request);
233 } else {
234 QueueSessionRequestWithoutEnumeration(request);
237 return promise.forget();
240 void XRSystem::QueueSessionRequestWithEnumeration(
241 RequestSessionRequest* aRequest) {
242 MOZ_ASSERT(aRequest->WantsHardware());
243 mRequestSessionRequestsWaitingForRuntimeDetection.AppendElement(aRequest);
244 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
245 vm->DetectRuntimes();
248 void XRSystem::QueueSessionRequestWithoutEnumeration(
249 RequestSessionRequest* aRequest) {
250 MOZ_ASSERT(!aRequest->NeedsHardware());
251 mRequestSessionRequestsWithoutHardware.AppendElement(aRequest);
253 ResolveSessionRequestsWithoutHardware();
256 bool XRSystem::CancelHardwareRequest(RequestSessionRequest* aRequest) {
257 if (!aRequest->NeedsHardware()) {
258 // If hardware access was an optional requirement and the user
259 // opted not to provide access, queue the request
260 // to be resolved without hardware.
261 QueueSessionRequestWithoutEnumeration(aRequest);
262 return false;
265 if (aRequest->IsImmersive()) {
266 mPendingImmersiveSession = false;
268 return true;
271 bool XRSystem::OnXRPermissionRequestAllow() {
272 if (!gfx::VRManagerChild::IsCreated()) {
273 // It's possible that this callback returns after
274 // we have already started shutting down.
275 return false;
277 if (!mEnumerationInFlight) {
278 mEnumerationInFlight = true;
279 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
280 Unused << vm->EnumerateVRDisplays();
282 return mEnumerationInFlight ||
283 !mRequestSessionRequestsWaitingForEnumeration.IsEmpty();
286 void XRSystem::OnXRPermissionRequestCancel() {
287 nsTArray<RefPtr<RequestSessionRequest>> requestSessionRequests(
288 std::move(mRequestSessionRequestsWaitingForEnumeration));
289 for (RefPtr<RequestSessionRequest>& request : requestSessionRequests) {
290 if (CancelHardwareRequest(request)) {
291 request->mPromise->MaybeRejectWithSecurityError(
292 "A device supporting the requested session "
293 "configuration could not be found.");
298 bool XRSystem::FeaturePolicyBlocked() const {
299 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(GetOwner());
300 if (!win) {
301 return true;
303 RefPtr<XRPermissionRequest> request =
304 new XRPermissionRequest(win, win->WindowID());
305 return !(request->CheckPermissionDelegate());
308 bool XRSystem::HasActiveImmersiveSession() const {
309 return mActiveImmersiveSession;
312 void XRSystem::ResolveSessionRequestsWithoutHardware() {
313 // Resolve promises returned by RequestSession
314 nsTArray<RefPtr<gfx::VRDisplayClient>> displays;
315 // Try resolving support without a device, for inline sessions.
316 displays.AppendElement(nullptr);
318 nsTArray<RefPtr<RequestSessionRequest>> requestSessionRequests(
319 std::move(mRequestSessionRequestsWithoutHardware));
321 ResolveSessionRequests(requestSessionRequests, displays);
324 void XRSystem::NotifyEnumerationCompleted() {
325 // Enumeration has completed.
326 mEnumerationInFlight = false;
328 if (!gfx::VRManagerChild::IsCreated()) {
329 // It's possible that this callback returns after
330 // we have already started shutting down.
331 return;
334 // Resolve promises returned by RequestSession
335 nsTArray<RefPtr<gfx::VRDisplayClient>> displays;
336 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
337 vm->GetVRDisplays(displays);
339 nsTArray<RefPtr<RequestSessionRequest>> requestSessionRequests(
340 std::move(mRequestSessionRequestsWaitingForEnumeration));
342 ResolveSessionRequests(requestSessionRequests, displays);
345 void XRSystem::ResolveSessionRequests(
346 nsTArray<RefPtr<RequestSessionRequest>>& aRequests,
347 const nsTArray<RefPtr<gfx::VRDisplayClient>>& aDisplays) {
348 for (RefPtr<RequestSessionRequest>& request : aRequests) {
349 RefPtr<XRSession> session;
350 if (request->IsImmersive()) {
351 mPendingImmersiveSession = false;
353 // Select an XR device
354 for (const RefPtr<gfx::VRDisplayClient>& display : aDisplays) {
355 nsTArray<XRReferenceSpaceType> enabledReferenceSpaceTypes;
356 if (request->ResolveSupport(display, enabledReferenceSpaceTypes)) {
357 if (request->IsImmersive()) {
358 session = XRSession::CreateImmersiveSession(
359 GetOwner(), this, display, request->GetPresentationGroup(),
360 enabledReferenceSpaceTypes);
361 mActiveImmersiveSession = session;
362 } else {
363 session = XRSession::CreateInlineSession(GetOwner(), this,
364 enabledReferenceSpaceTypes);
365 mInlineSessions.AppendElement(session);
367 request->mPromise->MaybeResolve(session);
368 break;
371 if (!session) {
372 request->mPromise->MaybeRejectWithNotSupportedError(
373 "A device supporting the required XRSession configuration "
374 "could not be found.");
379 void XRSystem::NotifyDetectRuntimesCompleted() {
380 ResolveIsSessionSupportedRequests();
381 if (!mRequestSessionRequestsWaitingForRuntimeDetection.IsEmpty()) {
382 ProcessSessionRequestsWaitingForRuntimeDetection();
386 void XRSystem::ResolveIsSessionSupportedRequests() {
387 // Resolve promises returned by IsSessionSupported
388 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
389 nsTArray<RefPtr<IsSessionSupportedRequest>> isSessionSupportedRequests(
390 std::move(mIsSessionSupportedRequests));
391 bool featurePolicyBlocked = FeaturePolicyBlocked();
393 for (RefPtr<IsSessionSupportedRequest>& request :
394 isSessionSupportedRequests) {
395 if (featurePolicyBlocked) {
396 request->mPromise->MaybeRejectWithSecurityError(
397 "The xr-spatial-tracking feature policy is required.");
398 continue;
401 bool supported = false;
402 switch (request->GetSessionMode()) {
403 case XRSessionMode::Immersive_vr:
404 supported = vm->RuntimeSupportsVR();
405 break;
406 case XRSessionMode::Immersive_ar:
407 supported = vm->RuntimeSupportsAR();
408 break;
409 default:
410 break;
412 request->mPromise->MaybeResolve(supported);
416 void XRSystem::ProcessSessionRequestsWaitingForRuntimeDetection() {
417 bool alreadyRequestedPermission =
418 !mRequestSessionRequestsWaitingForEnumeration.IsEmpty();
419 bool featurePolicyBlocked = FeaturePolicyBlocked();
420 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
422 nsTArray<RefPtr<RequestSessionRequest>> sessionRequests(
423 std::move(mRequestSessionRequestsWaitingForRuntimeDetection));
425 for (RefPtr<RequestSessionRequest>& request : sessionRequests) {
426 bool compatibleRuntime = false;
427 switch (request->GetSessionMode()) {
428 case XRSessionMode::Immersive_vr:
429 compatibleRuntime = vm->RuntimeSupportsVR();
430 break;
431 case XRSessionMode::Immersive_ar:
432 compatibleRuntime = vm->RuntimeSupportsAR();
433 break;
434 case XRSessionMode::Inline:
435 compatibleRuntime = vm->RuntimeSupportsInline();
436 break;
437 default:
438 break;
440 if (!compatibleRuntime) {
441 // If none of the requested sessions are supported by a
442 // runtime, early exit without showing a permission prompt.
443 if (CancelHardwareRequest(request)) {
444 request->mPromise->MaybeRejectWithNotSupportedError(
445 "A device supporting the required XRSession configuration "
446 "could not be found.");
448 continue;
450 if (featurePolicyBlocked) {
451 // Don't show a permission prompt if blocked by feature policy.
452 if (CancelHardwareRequest(request)) {
453 request->mPromise->MaybeRejectWithSecurityError(
454 "The xr-spatial-tracking feature policy is required.");
456 continue;
458 // To continue evaluating this request, it must wait for hardware
459 // enumeration and permission request.
460 mRequestSessionRequestsWaitingForEnumeration.AppendElement(request);
463 if (!mRequestSessionRequestsWaitingForEnumeration.IsEmpty() &&
464 !alreadyRequestedPermission) {
466 * Inline sessions will require only a user gesture
467 * and should not trigger XR permission UI.
468 * This is not a problem currently, as the only platforms
469 * allowing xr-spatial-tracking for inline sessions do not
470 * present a modal XR permission UI. (eg. Android Firefox Reality)
472 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(GetOwner());
473 win->RequestXRPermission();
477 void XRSystem::NotifyVRDisplayMounted(uint32_t aDisplayID) {}
478 void XRSystem::NotifyVRDisplayUnmounted(uint32_t aDisplayID) {}
480 void XRSystem::NotifyVRDisplayConnect(uint32_t aDisplayID) {
481 DispatchTrustedEvent(u"devicechange"_ns);
484 void XRSystem::NotifyVRDisplayDisconnect(uint32_t aDisplayID) {
485 DispatchTrustedEvent(u"devicechange"_ns);
488 void XRSystem::NotifyVRDisplayPresentChange(uint32_t aDisplayID) {}
489 void XRSystem::NotifyPresentationGenerationChanged(uint32_t aDisplayID) {
490 if (mActiveImmersiveSession) {
491 mActiveImmersiveSession->ExitPresent();
494 bool XRSystem::GetStopActivityStatus() const { return true; }
496 RequestSessionRequest::RequestSessionRequest(
497 XRSessionMode aSessionMode, uint32_t aPresentationGroup, Promise* aPromise,
498 const nsTArray<XRReferenceSpaceType>& aRequiredReferenceSpaceTypes,
499 const nsTArray<XRReferenceSpaceType>& aOptionalReferenceSpaceTypes)
500 : mPromise(aPromise),
501 mSessionMode(aSessionMode),
502 mPresentationGroup(aPresentationGroup),
503 mRequiredReferenceSpaceTypes(aRequiredReferenceSpaceTypes.Clone()),
504 mOptionalReferenceSpaceTypes(aOptionalReferenceSpaceTypes.Clone()) {}
506 bool RequestSessionRequest::ResolveSupport(
507 const gfx::VRDisplayClient* aDisplay,
508 nsTArray<XRReferenceSpaceType>& aEnabledReferenceSpaceTypes) const {
509 if (aDisplay) {
510 if (!aDisplay->GetIsConnected()) {
511 return false;
513 if ((aDisplay->GetDisplayInfo().GetPresentingGroups() &
514 mPresentationGroup) != 0) {
515 return false;
518 const gfx::VRDisplayInfo& info = aDisplay->GetDisplayInfo();
519 switch (mSessionMode) {
520 case XRSessionMode::Inline:
521 if (!bool(info.mDisplayState.capabilityFlags &
522 gfx::VRDisplayCapabilityFlags::Cap_Inline)) {
523 return false;
525 break;
526 case XRSessionMode::Immersive_vr:
527 if (!bool(info.mDisplayState.capabilityFlags &
528 gfx::VRDisplayCapabilityFlags::Cap_ImmersiveVR)) {
529 return false;
531 break;
532 case XRSessionMode::Immersive_ar:
533 if (!bool(info.mDisplayState.capabilityFlags &
534 gfx::VRDisplayCapabilityFlags::Cap_ImmersiveAR)) {
535 return false;
537 break;
538 default:
539 break;
541 } else if (mSessionMode != XRSessionMode::Inline) {
542 // If we don't have a device, we can only support inline sessions
543 return false;
546 // All sessions support XRReferenceSpaceType::Viewer by default
547 aEnabledReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Viewer);
549 // Immersive sessions support XRReferenceSpaceType::Local by default
550 if (IsImmersive()) {
551 aEnabledReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Local);
554 for (XRReferenceSpaceType type : mRequiredReferenceSpaceTypes) {
555 if (aDisplay) {
556 if (!aDisplay->IsReferenceSpaceTypeSupported(type)) {
557 return false;
559 } else if (type != XRReferenceSpaceType::Viewer) {
560 // If we don't have a device, We only support
561 // XRReferenceSpaceType::Viewer
562 return false;
564 if (!aEnabledReferenceSpaceTypes.Contains(type)) {
565 aEnabledReferenceSpaceTypes.AppendElement(type);
568 if (aDisplay) {
569 for (XRReferenceSpaceType type : mOptionalReferenceSpaceTypes) {
570 if (aDisplay->IsReferenceSpaceTypeSupported(type) &&
571 !aEnabledReferenceSpaceTypes.Contains(type)) {
572 aEnabledReferenceSpaceTypes.AppendElement(type);
576 return true;
579 bool RequestSessionRequest::IsImmersive() const {
580 return (mSessionMode == XRSessionMode::Immersive_vr ||
581 mSessionMode == XRSessionMode::Immersive_ar);
584 bool RequestSessionRequest::WantsHardware() const {
585 for (XRReferenceSpaceType type : mOptionalReferenceSpaceTypes) {
586 // Any XRReferenceSpaceType other than Viewer requires hardware
587 if (type != XRReferenceSpaceType::Viewer) {
588 return true;
591 return NeedsHardware();
594 bool RequestSessionRequest::NeedsHardware() const {
595 for (XRReferenceSpaceType type : mRequiredReferenceSpaceTypes) {
596 // Any XRReferenceSpaceType other than Viewer requires hardware
597 if (type != XRReferenceSpaceType::Viewer) {
598 return true;
601 return false;
604 XRSessionMode RequestSessionRequest::GetSessionMode() const {
605 return mSessionMode;
608 uint32_t RequestSessionRequest::GetPresentationGroup() const {
609 return mPresentationGroup;
612 ////////////////////////////////////////////////////////////////////////////////
613 // IsSessionSupportedRequest cycle collection
614 NS_IMPL_CYCLE_COLLECTION(IsSessionSupportedRequest, mPromise)
616 XRSessionMode IsSessionSupportedRequest::GetSessionMode() const {
617 return mSessionMode;
620 ////////////////////////////////////////////////////////////////////////////////
621 // XRRequestSessionPermissionRequest cycle collection
622 NS_IMPL_CYCLE_COLLECTION_INHERITED(XRRequestSessionPermissionRequest,
623 ContentPermissionRequestBase)
625 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(
626 XRRequestSessionPermissionRequest, ContentPermissionRequestBase)
628 XRRequestSessionPermissionRequest::XRRequestSessionPermissionRequest(
629 nsPIDOMWindowInner* aWindow, nsIPrincipal* aNodePrincipal,
630 AllowCallback&& aAllowCallback,
631 AllowAnySiteCallback&& aAllowAnySiteCallback,
632 CancelCallback&& aCancelCallback)
633 : ContentPermissionRequestBase(aNodePrincipal, aWindow, "dom.xr"_ns,
634 "xr"_ns),
635 mAllowCallback(std::move(aAllowCallback)),
636 mAllowAnySiteCallback(std::move(aAllowAnySiteCallback)),
637 mCancelCallback(std::move(aCancelCallback)),
638 mCallbackCalled(false) {
639 mPermissionRequests.AppendElement(
640 PermissionRequest(mType, nsTArray<nsString>()));
643 XRRequestSessionPermissionRequest::~XRRequestSessionPermissionRequest() {
644 Cancel();
647 NS_IMETHODIMP
648 XRRequestSessionPermissionRequest::Cancel() {
649 if (!mCallbackCalled) {
650 mCallbackCalled = true;
651 mCancelCallback();
653 return NS_OK;
656 NS_IMETHODIMP
657 XRRequestSessionPermissionRequest::Allow(JS::Handle<JS::Value> aChoices) {
658 nsTArray<PermissionChoice> choices;
659 nsresult rv = TranslateChoices(aChoices, mPermissionRequests, choices);
660 if (NS_FAILED(rv)) {
661 return rv;
664 // There is no support to allow grants automatically from the prompting code
665 // path.
667 if (!mCallbackCalled) {
668 mCallbackCalled = true;
669 if (choices.Length() == 1 &&
670 choices[0].choice().EqualsLiteral("allow-on-any-site")) {
671 mAllowAnySiteCallback();
672 } else if (choices.Length() == 1 &&
673 choices[0].choice().EqualsLiteral("allow")) {
674 mAllowCallback();
677 return NS_OK;
680 already_AddRefed<XRRequestSessionPermissionRequest>
681 XRRequestSessionPermissionRequest::Create(
682 nsPIDOMWindowInner* aWindow, AllowCallback&& aAllowCallback,
683 AllowAnySiteCallback&& aAllowAnySiteCallback,
684 CancelCallback&& aCancelCallback) {
685 if (!aWindow) {
686 return nullptr;
688 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(aWindow);
689 if (!win->GetPrincipal()) {
690 return nullptr;
692 RefPtr<XRRequestSessionPermissionRequest> request =
693 new XRRequestSessionPermissionRequest(
694 aWindow, win->GetPrincipal(), std::move(aAllowCallback),
695 std::move(aAllowAnySiteCallback), std::move(aCancelCallback));
696 return request.forget();
699 ////////////////////////////////////////////////////////////////////////////////
700 // RequestSessionRequest cycle collection
701 NS_IMPL_CYCLE_COLLECTION(RequestSessionRequest, mPromise)
703 } // namespace mozilla::dom