Bug 1911966 - Skip resolution refresh rate check on windows 10. r=kshampur
[gecko.git] / dom / vr / XRSystem.cpp
blob4afa95d63107ec0b433a2c5926aac13772cde917
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 XRSessionMode aMode, const XRSessionInit& aOptions, CallerType aCallerType,
126 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 if (aOptions.mRequiredFeatures.WasPassed()) {
170 for (const nsString& val : aOptions.mRequiredFeatures.Value()) {
171 Maybe<XRReferenceSpaceType> type =
172 StringToEnum<XRReferenceSpaceType>(val);
173 if (type.isNothing()) {
174 promise->MaybeRejectWithNotSupportedError(
175 "A required feature for the XRSession is not available.");
176 return promise.forget();
178 requiredReferenceSpaceTypes.AppendElement(type.value());
182 if (aOptions.mOptionalFeatures.WasPassed()) {
183 for (const nsString& val : aOptions.mOptionalFeatures.Value()) {
184 Maybe<XRReferenceSpaceType> type =
185 StringToEnum<XRReferenceSpaceType>(val);
186 if (type.isSome()) {
187 optionalReferenceSpaceTypes.AppendElement(type.value());
192 if (immersive) {
193 if (mPendingImmersiveSession || mActiveImmersiveSession) {
194 promise->MaybeRejectWithInvalidStateError(
195 "There can only be one immersive XRSession.");
196 return promise.forget();
198 mPendingImmersiveSession = true;
201 bool isChromeSession = aCallerType == CallerType::System;
202 uint32_t presentationGroup =
203 isChromeSession ? gfx::kVRGroupChrome : gfx::kVRGroupContent;
204 RefPtr<RequestSessionRequest> request = new RequestSessionRequest(
205 aMode, presentationGroup, promise, requiredReferenceSpaceTypes,
206 optionalReferenceSpaceTypes);
207 if (request->WantsHardware()) {
208 QueueSessionRequestWithEnumeration(request);
209 } else {
210 QueueSessionRequestWithoutEnumeration(request);
213 return promise.forget();
216 void XRSystem::QueueSessionRequestWithEnumeration(
217 RequestSessionRequest* aRequest) {
218 MOZ_ASSERT(aRequest->WantsHardware());
219 mRequestSessionRequestsWaitingForRuntimeDetection.AppendElement(aRequest);
220 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
221 vm->DetectRuntimes();
224 void XRSystem::QueueSessionRequestWithoutEnumeration(
225 RequestSessionRequest* aRequest) {
226 MOZ_ASSERT(!aRequest->NeedsHardware());
227 mRequestSessionRequestsWithoutHardware.AppendElement(aRequest);
229 ResolveSessionRequestsWithoutHardware();
232 bool XRSystem::CancelHardwareRequest(RequestSessionRequest* aRequest) {
233 if (!aRequest->NeedsHardware()) {
234 // If hardware access was an optional requirement and the user
235 // opted not to provide access, queue the request
236 // to be resolved without hardware.
237 QueueSessionRequestWithoutEnumeration(aRequest);
238 return false;
241 if (aRequest->IsImmersive()) {
242 mPendingImmersiveSession = false;
244 return true;
247 bool XRSystem::OnXRPermissionRequestAllow() {
248 if (!gfx::VRManagerChild::IsCreated()) {
249 // It's possible that this callback returns after
250 // we have already started shutting down.
251 return false;
253 if (!mEnumerationInFlight) {
254 mEnumerationInFlight = true;
255 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
256 Unused << vm->EnumerateVRDisplays();
258 return mEnumerationInFlight ||
259 !mRequestSessionRequestsWaitingForEnumeration.IsEmpty();
262 void XRSystem::OnXRPermissionRequestCancel() {
263 nsTArray<RefPtr<RequestSessionRequest>> requestSessionRequests(
264 std::move(mRequestSessionRequestsWaitingForEnumeration));
265 for (RefPtr<RequestSessionRequest>& request : requestSessionRequests) {
266 if (CancelHardwareRequest(request)) {
267 request->mPromise->MaybeRejectWithSecurityError(
268 "A device supporting the requested session "
269 "configuration could not be found.");
274 bool XRSystem::FeaturePolicyBlocked() const {
275 nsGlobalWindowInner* win = GetOwnerWindow();
276 if (!win) {
277 return true;
279 RefPtr<XRPermissionRequest> request =
280 new XRPermissionRequest(win, win->WindowID());
281 return !(request->CheckPermissionDelegate());
284 bool XRSystem::HasActiveImmersiveSession() const {
285 return mActiveImmersiveSession;
288 void XRSystem::ResolveSessionRequestsWithoutHardware() {
289 // Resolve promises returned by RequestSession
290 nsTArray<RefPtr<gfx::VRDisplayClient>> displays;
291 // Try resolving support without a device, for inline sessions.
292 displays.AppendElement(nullptr);
294 nsTArray<RefPtr<RequestSessionRequest>> requestSessionRequests(
295 std::move(mRequestSessionRequestsWithoutHardware));
297 ResolveSessionRequests(requestSessionRequests, displays);
300 void XRSystem::NotifyEnumerationCompleted() {
301 // Enumeration has completed.
302 mEnumerationInFlight = false;
304 if (!gfx::VRManagerChild::IsCreated()) {
305 // It's possible that this callback returns after
306 // we have already started shutting down.
307 return;
310 // Resolve promises returned by RequestSession
311 nsTArray<RefPtr<gfx::VRDisplayClient>> displays;
312 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
313 vm->GetVRDisplays(displays);
315 nsTArray<RefPtr<RequestSessionRequest>> requestSessionRequests(
316 std::move(mRequestSessionRequestsWaitingForEnumeration));
318 ResolveSessionRequests(requestSessionRequests, displays);
321 void XRSystem::ResolveSessionRequests(
322 nsTArray<RefPtr<RequestSessionRequest>>& aRequests,
323 const nsTArray<RefPtr<gfx::VRDisplayClient>>& aDisplays) {
324 for (RefPtr<RequestSessionRequest>& request : aRequests) {
325 RefPtr<XRSession> session;
326 if (request->IsImmersive()) {
327 mPendingImmersiveSession = false;
329 // Select an XR device
330 for (const RefPtr<gfx::VRDisplayClient>& display : aDisplays) {
331 nsTArray<XRReferenceSpaceType> enabledReferenceSpaceTypes;
332 if (request->ResolveSupport(display, enabledReferenceSpaceTypes)) {
333 if (request->IsImmersive()) {
334 session = XRSession::CreateImmersiveSession(
335 GetOwnerWindow(), this, display, request->GetPresentationGroup(),
336 enabledReferenceSpaceTypes);
337 mActiveImmersiveSession = session;
338 } else {
339 session = XRSession::CreateInlineSession(GetOwnerWindow(), this,
340 enabledReferenceSpaceTypes);
341 mInlineSessions.AppendElement(session);
343 request->mPromise->MaybeResolve(session);
344 break;
347 if (!session) {
348 request->mPromise->MaybeRejectWithNotSupportedError(
349 "A device supporting the required XRSession configuration "
350 "could not be found.");
355 void XRSystem::NotifyDetectRuntimesCompleted() {
356 ResolveIsSessionSupportedRequests();
357 if (!mRequestSessionRequestsWaitingForRuntimeDetection.IsEmpty()) {
358 ProcessSessionRequestsWaitingForRuntimeDetection();
362 void XRSystem::ResolveIsSessionSupportedRequests() {
363 // Resolve promises returned by IsSessionSupported
364 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
365 nsTArray<RefPtr<IsSessionSupportedRequest>> isSessionSupportedRequests(
366 std::move(mIsSessionSupportedRequests));
367 bool featurePolicyBlocked = FeaturePolicyBlocked();
369 for (RefPtr<IsSessionSupportedRequest>& request :
370 isSessionSupportedRequests) {
371 if (featurePolicyBlocked) {
372 request->mPromise->MaybeRejectWithSecurityError(
373 "The xr-spatial-tracking feature policy is required.");
374 continue;
377 bool supported = false;
378 switch (request->GetSessionMode()) {
379 case XRSessionMode::Immersive_vr:
380 supported = vm->RuntimeSupportsVR();
381 break;
382 case XRSessionMode::Immersive_ar:
383 supported = vm->RuntimeSupportsAR();
384 break;
385 default:
386 break;
388 request->mPromise->MaybeResolve(supported);
392 void XRSystem::ProcessSessionRequestsWaitingForRuntimeDetection() {
393 bool alreadyRequestedPermission =
394 !mRequestSessionRequestsWaitingForEnumeration.IsEmpty();
395 bool featurePolicyBlocked = FeaturePolicyBlocked();
396 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
398 nsTArray<RefPtr<RequestSessionRequest>> sessionRequests(
399 std::move(mRequestSessionRequestsWaitingForRuntimeDetection));
401 for (RefPtr<RequestSessionRequest>& request : sessionRequests) {
402 bool compatibleRuntime = false;
403 switch (request->GetSessionMode()) {
404 case XRSessionMode::Immersive_vr:
405 compatibleRuntime = vm->RuntimeSupportsVR();
406 break;
407 case XRSessionMode::Immersive_ar:
408 compatibleRuntime = vm->RuntimeSupportsAR();
409 break;
410 case XRSessionMode::Inline:
411 compatibleRuntime = vm->RuntimeSupportsInline();
412 break;
413 default:
414 break;
416 if (!compatibleRuntime) {
417 // If none of the requested sessions are supported by a
418 // runtime, early exit without showing a permission prompt.
419 if (CancelHardwareRequest(request)) {
420 request->mPromise->MaybeRejectWithNotSupportedError(
421 "A device supporting the required XRSession configuration "
422 "could not be found.");
424 continue;
426 if (featurePolicyBlocked) {
427 // Don't show a permission prompt if blocked by feature policy.
428 if (CancelHardwareRequest(request)) {
429 request->mPromise->MaybeRejectWithSecurityError(
430 "The xr-spatial-tracking feature policy is required.");
432 continue;
434 // To continue evaluating this request, it must wait for hardware
435 // enumeration and permission request.
436 mRequestSessionRequestsWaitingForEnumeration.AppendElement(request);
439 if (!mRequestSessionRequestsWaitingForEnumeration.IsEmpty() &&
440 !alreadyRequestedPermission) {
442 * Inline sessions will require only a user gesture
443 * and should not trigger XR permission UI.
444 * This is not a problem currently, as the only platforms
445 * allowing xr-spatial-tracking for inline sessions do not
446 * present a modal XR permission UI. (eg. Android Firefox Reality)
448 GetOwnerWindow()->RequestXRPermission();
452 void XRSystem::NotifyVRDisplayMounted(uint32_t aDisplayID) {}
453 void XRSystem::NotifyVRDisplayUnmounted(uint32_t aDisplayID) {}
455 void XRSystem::NotifyVRDisplayConnect(uint32_t aDisplayID) {
456 DispatchTrustedEvent(u"devicechange"_ns);
459 void XRSystem::NotifyVRDisplayDisconnect(uint32_t aDisplayID) {
460 DispatchTrustedEvent(u"devicechange"_ns);
463 void XRSystem::NotifyVRDisplayPresentChange(uint32_t aDisplayID) {}
464 void XRSystem::NotifyPresentationGenerationChanged(uint32_t aDisplayID) {
465 if (mActiveImmersiveSession) {
466 mActiveImmersiveSession->ExitPresent();
469 bool XRSystem::GetStopActivityStatus() const { return true; }
471 RequestSessionRequest::RequestSessionRequest(
472 XRSessionMode aSessionMode, uint32_t aPresentationGroup, Promise* aPromise,
473 const nsTArray<XRReferenceSpaceType>& aRequiredReferenceSpaceTypes,
474 const nsTArray<XRReferenceSpaceType>& aOptionalReferenceSpaceTypes)
475 : mPromise(aPromise),
476 mSessionMode(aSessionMode),
477 mPresentationGroup(aPresentationGroup),
478 mRequiredReferenceSpaceTypes(aRequiredReferenceSpaceTypes.Clone()),
479 mOptionalReferenceSpaceTypes(aOptionalReferenceSpaceTypes.Clone()) {}
481 bool RequestSessionRequest::ResolveSupport(
482 const gfx::VRDisplayClient* aDisplay,
483 nsTArray<XRReferenceSpaceType>& aEnabledReferenceSpaceTypes) const {
484 if (aDisplay) {
485 if (!aDisplay->GetIsConnected()) {
486 return false;
488 if ((aDisplay->GetDisplayInfo().GetPresentingGroups() &
489 mPresentationGroup) != 0) {
490 return false;
493 const gfx::VRDisplayInfo& info = aDisplay->GetDisplayInfo();
494 switch (mSessionMode) {
495 case XRSessionMode::Inline:
496 if (!bool(info.mDisplayState.capabilityFlags &
497 gfx::VRDisplayCapabilityFlags::Cap_Inline)) {
498 return false;
500 break;
501 case XRSessionMode::Immersive_vr:
502 if (!bool(info.mDisplayState.capabilityFlags &
503 gfx::VRDisplayCapabilityFlags::Cap_ImmersiveVR)) {
504 return false;
506 break;
507 case XRSessionMode::Immersive_ar:
508 if (!bool(info.mDisplayState.capabilityFlags &
509 gfx::VRDisplayCapabilityFlags::Cap_ImmersiveAR)) {
510 return false;
512 break;
513 default:
514 break;
516 } else if (mSessionMode != XRSessionMode::Inline) {
517 // If we don't have a device, we can only support inline sessions
518 return false;
521 // All sessions support XRReferenceSpaceType::Viewer by default
522 aEnabledReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Viewer);
524 // Immersive sessions support XRReferenceSpaceType::Local by default
525 if (IsImmersive()) {
526 aEnabledReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Local);
529 for (XRReferenceSpaceType type : mRequiredReferenceSpaceTypes) {
530 if (aDisplay) {
531 if (!aDisplay->IsReferenceSpaceTypeSupported(type)) {
532 return false;
534 } else if (type != XRReferenceSpaceType::Viewer) {
535 // If we don't have a device, We only support
536 // XRReferenceSpaceType::Viewer
537 return false;
539 if (!aEnabledReferenceSpaceTypes.Contains(type)) {
540 aEnabledReferenceSpaceTypes.AppendElement(type);
543 if (aDisplay) {
544 for (XRReferenceSpaceType type : mOptionalReferenceSpaceTypes) {
545 if (aDisplay->IsReferenceSpaceTypeSupported(type) &&
546 !aEnabledReferenceSpaceTypes.Contains(type)) {
547 aEnabledReferenceSpaceTypes.AppendElement(type);
551 return true;
554 bool RequestSessionRequest::IsImmersive() const {
555 return (mSessionMode == XRSessionMode::Immersive_vr ||
556 mSessionMode == XRSessionMode::Immersive_ar);
559 bool RequestSessionRequest::WantsHardware() const {
560 for (XRReferenceSpaceType type : mOptionalReferenceSpaceTypes) {
561 // Any XRReferenceSpaceType other than Viewer requires hardware
562 if (type != XRReferenceSpaceType::Viewer) {
563 return true;
566 return NeedsHardware();
569 bool RequestSessionRequest::NeedsHardware() const {
570 for (XRReferenceSpaceType type : mRequiredReferenceSpaceTypes) {
571 // Any XRReferenceSpaceType other than Viewer requires hardware
572 if (type != XRReferenceSpaceType::Viewer) {
573 return true;
576 return false;
579 XRSessionMode RequestSessionRequest::GetSessionMode() const {
580 return mSessionMode;
583 uint32_t RequestSessionRequest::GetPresentationGroup() const {
584 return mPresentationGroup;
587 ////////////////////////////////////////////////////////////////////////////////
588 // IsSessionSupportedRequest cycle collection
589 NS_IMPL_CYCLE_COLLECTION(IsSessionSupportedRequest, mPromise)
591 XRSessionMode IsSessionSupportedRequest::GetSessionMode() const {
592 return mSessionMode;
595 ////////////////////////////////////////////////////////////////////////////////
596 // XRRequestSessionPermissionRequest cycle collection
597 NS_IMPL_CYCLE_COLLECTION_INHERITED(XRRequestSessionPermissionRequest,
598 ContentPermissionRequestBase)
600 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(
601 XRRequestSessionPermissionRequest, ContentPermissionRequestBase)
603 XRRequestSessionPermissionRequest::XRRequestSessionPermissionRequest(
604 nsPIDOMWindowInner* aWindow, nsIPrincipal* aNodePrincipal,
605 AllowCallback&& aAllowCallback,
606 AllowAnySiteCallback&& aAllowAnySiteCallback,
607 CancelCallback&& aCancelCallback)
608 : ContentPermissionRequestBase(aNodePrincipal, aWindow, "dom.xr"_ns,
609 "xr"_ns),
610 mAllowCallback(std::move(aAllowCallback)),
611 mAllowAnySiteCallback(std::move(aAllowAnySiteCallback)),
612 mCancelCallback(std::move(aCancelCallback)),
613 mCallbackCalled(false) {
614 mPermissionRequests.AppendElement(
615 PermissionRequest(mType, nsTArray<nsString>()));
618 XRRequestSessionPermissionRequest::~XRRequestSessionPermissionRequest() {
619 Cancel();
622 NS_IMETHODIMP
623 XRRequestSessionPermissionRequest::Cancel() {
624 if (!mCallbackCalled) {
625 mCallbackCalled = true;
626 mCancelCallback();
628 return NS_OK;
631 NS_IMETHODIMP
632 XRRequestSessionPermissionRequest::Allow(JS::Handle<JS::Value> aChoices) {
633 nsTArray<PermissionChoice> choices;
634 nsresult rv = TranslateChoices(aChoices, mPermissionRequests, choices);
635 if (NS_FAILED(rv)) {
636 return rv;
639 // There is no support to allow grants automatically from the prompting code
640 // path.
642 if (!mCallbackCalled) {
643 mCallbackCalled = true;
644 if (choices.Length() == 1 &&
645 choices[0].choice().EqualsLiteral("allow-on-any-site")) {
646 mAllowAnySiteCallback();
647 } else if (choices.Length() == 1 &&
648 choices[0].choice().EqualsLiteral("allow")) {
649 mAllowCallback();
652 return NS_OK;
655 already_AddRefed<XRRequestSessionPermissionRequest>
656 XRRequestSessionPermissionRequest::Create(
657 nsPIDOMWindowInner* aWindow, AllowCallback&& aAllowCallback,
658 AllowAnySiteCallback&& aAllowAnySiteCallback,
659 CancelCallback&& aCancelCallback) {
660 if (!aWindow) {
661 return nullptr;
663 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(aWindow);
664 if (!win->GetPrincipal()) {
665 return nullptr;
667 RefPtr<XRRequestSessionPermissionRequest> request =
668 new XRRequestSessionPermissionRequest(
669 aWindow, win->GetPrincipal(), std::move(aAllowCallback),
670 std::move(aAllowAnySiteCallback), std::move(aCancelCallback));
671 return request.forget();
674 ////////////////////////////////////////////////////////////////////////////////
675 // RequestSessionRequest cycle collection
676 NS_IMPL_CYCLE_COLLECTION(RequestSessionRequest, mPromise)
678 } // namespace mozilla::dom