Bug 1688354 [wpt PR 27298] - Treat 'rem' as an absolute unit for font size, a=testonly
[gecko.git] / dom / vr / XRSystem.cpp
bloba8765ea8baa7065072205c900d64eabcd9f6e0a7
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 "nsGlobalWindow.h"
18 #include "nsThreadUtils.h"
19 #include "gfxVR.h"
20 #include "VRDisplayClient.h"
21 #include "VRManagerChild.h"
23 namespace mozilla {
24 namespace dom {
26 using namespace gfx;
28 ////////////////////////////////////////////////////////////////////////////////
29 // XRSystem cycle collection
30 NS_IMPL_CYCLE_COLLECTION_CLASS(XRSystem)
32 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XRSystem,
33 DOMEventTargetHelper)
34 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mActiveImmersiveSession)
35 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInlineSessions)
36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIsSessionSupportedRequests)
37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
38 mRequestSessionRequestsWaitingForRuntimeDetection)
39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequestSessionRequestsWithoutHardware)
40 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
41 mRequestSessionRequestsWaitingForEnumeration)
42 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
44 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XRSystem, DOMEventTargetHelper)
45 NS_IMPL_CYCLE_COLLECTION_UNLINK(mActiveImmersiveSession)
46 NS_IMPL_CYCLE_COLLECTION_UNLINK(mInlineSessions)
47 NS_IMPL_CYCLE_COLLECTION_UNLINK(mIsSessionSupportedRequests)
48 NS_IMPL_CYCLE_COLLECTION_UNLINK(
49 mRequestSessionRequestsWaitingForRuntimeDetection)
50 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequestSessionRequestsWithoutHardware)
51 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequestSessionRequestsWaitingForEnumeration)
52 // Don't need NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER because
53 // DOMEventTargetHelper does it for us.
54 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
56 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(XRSystem, DOMEventTargetHelper)
58 JSObject* XRSystem::WrapObject(JSContext* aCx,
59 JS::Handle<JSObject*> aGivenProto) {
60 return XRSystem_Binding::Wrap(aCx, this, aGivenProto);
63 // static
64 already_AddRefed<XRSystem> XRSystem::Create(nsPIDOMWindowInner* aWindow) {
65 MOZ_ASSERT(aWindow);
67 RefPtr<XRSystem> service = new XRSystem(aWindow);
68 return service.forget();
71 XRSystem::XRSystem(nsPIDOMWindowInner* aWindow)
72 : DOMEventTargetHelper(aWindow),
73 mShuttingDown(false),
74 mPendingImmersiveSession(false),
75 mEnumerationInFlight(false) {
76 // Unregister with VRManagerChild
77 VRManagerChild* vmc = VRManagerChild::Get();
78 if (vmc) {
79 vmc->AddListener(this);
83 void XRSystem::Shutdown() {
84 MOZ_ASSERT(!mShuttingDown);
85 mShuttingDown = true;
87 // Unregister from VRManagerChild
88 if (VRManagerChild::IsCreated()) {
89 VRManagerChild* vmc = VRManagerChild::Get();
90 vmc->RemoveListener(this);
94 void XRSystem::SessionEnded(XRSession* aSession) {
95 if (mActiveImmersiveSession == aSession) {
96 mActiveImmersiveSession = nullptr;
98 mInlineSessions.RemoveElement(aSession);
101 already_AddRefed<Promise> XRSystem::IsSessionSupported(XRSessionMode aMode,
102 ErrorResult& aRv) {
103 nsCOMPtr<nsIGlobalObject> global = GetParentObject();
104 NS_ENSURE_TRUE(global, nullptr);
106 RefPtr<Promise> promise = Promise::Create(global, aRv);
107 NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
109 if (aMode == XRSessionMode::Inline) {
110 promise->MaybeResolve(true);
111 return promise.forget();
114 if (mIsSessionSupportedRequests.IsEmpty()) {
115 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
116 vm->DetectRuntimes();
119 RefPtr<IsSessionSupportedRequest> request =
120 new IsSessionSupportedRequest(aMode, promise);
121 mIsSessionSupportedRequests.AppendElement(request);
122 return promise.forget();
125 already_AddRefed<Promise> XRSystem::RequestSession(
126 JSContext* aCx, XRSessionMode aMode, const XRSessionInit& aOptions,
127 CallerType aCallerType, ErrorResult& aRv) {
128 nsCOMPtr<nsIGlobalObject> global = GetParentObject();
129 NS_ENSURE_TRUE(global, nullptr);
131 RefPtr<Promise> promise = Promise::Create(global, aRv);
132 NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
134 bool immersive = (aMode == XRSessionMode::Immersive_vr ||
135 aMode == XRSessionMode::Immersive_ar);
137 // The document must be a responsible document, active and focused.
138 nsCOMPtr<Document> responsibleDocument = GetDocumentIfCurrent();
139 if (!responsibleDocument) {
140 // The document is not trustworthy
141 promise->MaybeRejectWithSecurityError("This document is not responsible.");
142 return promise.forget();
145 if (immersive || aOptions.mRequiredFeatures.WasPassed() ||
146 aOptions.mOptionalFeatures.WasPassed()) {
147 if (!responsibleDocument->HasValidTransientUserGestureActivation() &&
148 aCallerType != CallerType::System &&
149 StaticPrefs::dom_vr_require_gesture()) {
150 // A user gesture is required.
151 promise->MaybeRejectWithSecurityError("A user gesture is required.");
152 return promise.forget();
156 nsTArray<XRReferenceSpaceType> requiredReferenceSpaceTypes;
157 nsTArray<XRReferenceSpaceType> optionalReferenceSpaceTypes;
160 * By default, all sessions will require XRReferenceSpaceType::Viewer
161 * and immersive sessions will require XRReferenceSpaceType::Local.
163 * https://www.w3.org/TR/webxr/#default-features
165 requiredReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Viewer);
166 if (immersive) {
167 requiredReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Local);
170 BindingCallContext callCx(aCx, "XRSystem.requestSession");
172 if (aOptions.mRequiredFeatures.WasPassed()) {
173 const Sequence<JS::Value>& arr = (aOptions.mRequiredFeatures.Value());
174 for (const JS::Value& val : arr) {
175 if (!val.isNull() && !val.isUndefined()) {
176 bool bFound = false;
177 JS::RootedValue v(aCx, val);
178 int index = 0;
179 if (FindEnumStringIndex<false>(
180 callCx, v, XRReferenceSpaceTypeValues::strings,
181 "XRReferenceSpaceType", "Argument 2 of XR.requestSession",
182 &index)) {
183 if (index >= 0) {
184 requiredReferenceSpaceTypes.AppendElement(
185 static_cast<XRReferenceSpaceType>(index));
186 bFound = true;
189 if (!bFound) {
190 promise->MaybeRejectWithNotSupportedError(
191 "A required feature for the XRSession is not available.");
192 return promise.forget();
198 if (aOptions.mOptionalFeatures.WasPassed()) {
199 const Sequence<JS::Value>& arr = (aOptions.mOptionalFeatures.Value());
200 for (const JS::Value& val : arr) {
201 if (!val.isNull() && !val.isUndefined()) {
202 JS::RootedValue v(aCx, val);
203 int index = 0;
204 if (FindEnumStringIndex<false>(
205 callCx, v, XRReferenceSpaceTypeValues::strings,
206 "XRReferenceSpaceType", "Argument 2 of XR.requestSession",
207 &index)) {
208 if (index >= 0) {
209 optionalReferenceSpaceTypes.AppendElement(
210 static_cast<XRReferenceSpaceType>(index));
217 if (immersive) {
218 if (mPendingImmersiveSession || mActiveImmersiveSession) {
219 promise->MaybeRejectWithInvalidStateError(
220 "There can only be one immersive XRSession.");
221 return promise.forget();
223 mPendingImmersiveSession = true;
226 bool isChromeSession = aCallerType == CallerType::System;
227 uint32_t presentationGroup =
228 isChromeSession ? gfx::kVRGroupChrome : gfx::kVRGroupContent;
229 RefPtr<RequestSessionRequest> request = new RequestSessionRequest(
230 aMode, presentationGroup, promise, requiredReferenceSpaceTypes,
231 optionalReferenceSpaceTypes);
232 if (request->WantsHardware()) {
233 QueueSessionRequestWithEnumeration(request);
234 } else {
235 QueueSessionRequestWithoutEnumeration(request);
238 return promise.forget();
241 void XRSystem::QueueSessionRequestWithEnumeration(
242 RequestSessionRequest* aRequest) {
243 MOZ_ASSERT(aRequest->WantsHardware());
244 mRequestSessionRequestsWaitingForRuntimeDetection.AppendElement(aRequest);
245 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
246 vm->DetectRuntimes();
249 void XRSystem::QueueSessionRequestWithoutEnumeration(
250 RequestSessionRequest* aRequest) {
251 MOZ_ASSERT(!aRequest->NeedsHardware());
252 mRequestSessionRequestsWithoutHardware.AppendElement(aRequest);
254 ResolveSessionRequestsWithoutHardware();
257 bool XRSystem::CancelHardwareRequest(RequestSessionRequest* aRequest) {
258 if (!aRequest->NeedsHardware()) {
259 // If hardware access was an optional requirement and the user
260 // opted not to provide access, queue the request
261 // to be resolved without hardware.
262 QueueSessionRequestWithoutEnumeration(aRequest);
263 return false;
266 if (aRequest->IsImmersive()) {
267 mPendingImmersiveSession = false;
269 return true;
272 bool XRSystem::OnXRPermissionRequestAllow() {
273 if (!gfx::VRManagerChild::IsCreated()) {
274 // It's possible that this callback returns after
275 // we have already started shutting down.
276 return false;
278 if (!mEnumerationInFlight) {
279 mEnumerationInFlight = true;
280 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
281 Unused << vm->EnumerateVRDisplays();
283 return mEnumerationInFlight ||
284 !mRequestSessionRequestsWaitingForEnumeration.IsEmpty();
287 void XRSystem::OnXRPermissionRequestCancel() {
288 nsTArray<RefPtr<RequestSessionRequest>> requestSessionRequests(
289 std::move(mRequestSessionRequestsWaitingForEnumeration));
290 for (RefPtr<RequestSessionRequest>& request : requestSessionRequests) {
291 if (CancelHardwareRequest(request)) {
292 request->mPromise->MaybeRejectWithSecurityError(
293 "A device supporting the requested session "
294 "configuration could not be found.");
299 bool XRSystem::FeaturePolicyBlocked() const {
300 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(GetOwner());
301 if (!win) {
302 return true;
304 RefPtr<XRPermissionRequest> request =
305 new XRPermissionRequest(win, win->WindowID());
306 return !(request->CheckPermissionDelegate());
309 bool XRSystem::HasActiveImmersiveSession() const {
310 return mActiveImmersiveSession;
313 void XRSystem::ResolveSessionRequestsWithoutHardware() {
314 // Resolve promises returned by RequestSession
315 nsTArray<RefPtr<gfx::VRDisplayClient>> displays;
316 // Try resolving support without a device, for inline sessions.
317 displays.AppendElement(nullptr);
319 nsTArray<RefPtr<RequestSessionRequest>> requestSessionRequests(
320 std::move(mRequestSessionRequestsWithoutHardware));
322 ResolveSessionRequests(requestSessionRequests, displays);
325 void XRSystem::NotifyEnumerationCompleted() {
326 // Enumeration has completed.
327 mEnumerationInFlight = false;
329 if (!gfx::VRManagerChild::IsCreated()) {
330 // It's possible that this callback returns after
331 // we have already started shutting down.
332 return;
335 // Resolve promises returned by RequestSession
336 nsTArray<RefPtr<gfx::VRDisplayClient>> displays;
337 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
338 vm->GetVRDisplays(displays);
340 nsTArray<RefPtr<RequestSessionRequest>> requestSessionRequests(
341 std::move(mRequestSessionRequestsWaitingForEnumeration));
343 ResolveSessionRequests(requestSessionRequests, displays);
346 void XRSystem::ResolveSessionRequests(
347 nsTArray<RefPtr<RequestSessionRequest>>& aRequests,
348 const nsTArray<RefPtr<gfx::VRDisplayClient>>& aDisplays) {
349 for (RefPtr<RequestSessionRequest>& request : aRequests) {
350 RefPtr<XRSession> session;
351 if (request->IsImmersive()) {
352 mPendingImmersiveSession = false;
354 // Select an XR device
355 for (const RefPtr<gfx::VRDisplayClient>& display : aDisplays) {
356 nsTArray<XRReferenceSpaceType> enabledReferenceSpaceTypes;
357 if (request->ResolveSupport(display, enabledReferenceSpaceTypes)) {
358 if (request->IsImmersive()) {
359 session = XRSession::CreateImmersiveSession(
360 GetOwner(), this, display, request->GetPresentationGroup(),
361 enabledReferenceSpaceTypes);
362 mActiveImmersiveSession = session;
363 } else {
364 session = XRSession::CreateInlineSession(GetOwner(), this,
365 enabledReferenceSpaceTypes);
366 mInlineSessions.AppendElement(session);
368 request->mPromise->MaybeResolve(session);
369 break;
372 if (!session) {
373 request->mPromise->MaybeRejectWithNotSupportedError(
374 "A device supporting the required XRSession configuration "
375 "could not be found.");
380 void XRSystem::NotifyDetectRuntimesCompleted() {
381 ResolveIsSessionSupportedRequests();
382 if (!mRequestSessionRequestsWaitingForRuntimeDetection.IsEmpty()) {
383 ProcessSessionRequestsWaitingForRuntimeDetection();
387 void XRSystem::ResolveIsSessionSupportedRequests() {
388 // Resolve promises returned by IsSessionSupported
389 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
390 nsTArray<RefPtr<IsSessionSupportedRequest>> isSessionSupportedRequests(
391 std::move(mIsSessionSupportedRequests));
392 bool featurePolicyBlocked = FeaturePolicyBlocked();
394 for (RefPtr<IsSessionSupportedRequest>& request :
395 isSessionSupportedRequests) {
396 if (featurePolicyBlocked) {
397 request->mPromise->MaybeRejectWithSecurityError(
398 "The xr-spatial-tracking feature policy is required.");
399 continue;
402 bool supported = false;
403 switch (request->GetSessionMode()) {
404 case XRSessionMode::Immersive_vr:
405 supported = vm->RuntimeSupportsVR();
406 break;
407 case XRSessionMode::Immersive_ar:
408 supported = vm->RuntimeSupportsAR();
409 break;
410 default:
411 break;
413 request->mPromise->MaybeResolve(supported);
417 void XRSystem::ProcessSessionRequestsWaitingForRuntimeDetection() {
418 bool alreadyRequestedPermission =
419 !mRequestSessionRequestsWaitingForEnumeration.IsEmpty();
420 bool featurePolicyBlocked = FeaturePolicyBlocked();
421 gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
423 nsTArray<RefPtr<RequestSessionRequest>> sessionRequests(
424 std::move(mRequestSessionRequestsWaitingForRuntimeDetection));
426 for (RefPtr<RequestSessionRequest>& request : sessionRequests) {
427 bool compatibleRuntime = false;
428 switch (request->GetSessionMode()) {
429 case XRSessionMode::Immersive_vr:
430 compatibleRuntime = vm->RuntimeSupportsVR();
431 break;
432 case XRSessionMode::Immersive_ar:
433 compatibleRuntime = vm->RuntimeSupportsAR();
434 break;
435 case XRSessionMode::Inline:
436 compatibleRuntime = vm->RuntimeSupportsInline();
437 break;
438 default:
439 break;
441 if (!compatibleRuntime) {
442 // If none of the requested sessions are supported by a
443 // runtime, early exit without showing a permission prompt.
444 if (CancelHardwareRequest(request)) {
445 request->mPromise->MaybeRejectWithNotSupportedError(
446 "A device supporting the required XRSession configuration "
447 "could not be found.");
449 continue;
451 if (featurePolicyBlocked) {
452 // Don't show a permission prompt if blocked by feature policy.
453 if (CancelHardwareRequest(request)) {
454 request->mPromise->MaybeRejectWithSecurityError(
455 "The xr-spatial-tracking feature policy is required.");
457 continue;
459 // To continue evaluating this request, it must wait for hardware
460 // enumeration and permission request.
461 mRequestSessionRequestsWaitingForEnumeration.AppendElement(request);
464 if (!mRequestSessionRequestsWaitingForEnumeration.IsEmpty() &&
465 !alreadyRequestedPermission) {
467 * Inline sessions will require only a user gesture
468 * and should not trigger XR permission UI.
469 * This is not a problem currently, as the only platforms
470 * allowing xr-spatial-tracking for inline sessions do not
471 * present a modal XR permission UI. (eg. Android Firefox Reality)
473 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(GetOwner());
474 win->RequestXRPermission();
478 void XRSystem::NotifyVRDisplayMounted(uint32_t aDisplayID) {}
479 void XRSystem::NotifyVRDisplayUnmounted(uint32_t aDisplayID) {}
481 void XRSystem::NotifyVRDisplayConnect(uint32_t aDisplayID) {
482 DispatchTrustedEvent(u"devicechange"_ns);
485 void XRSystem::NotifyVRDisplayDisconnect(uint32_t aDisplayID) {
486 DispatchTrustedEvent(u"devicechange"_ns);
489 void XRSystem::NotifyVRDisplayPresentChange(uint32_t aDisplayID) {}
490 void XRSystem::NotifyPresentationGenerationChanged(uint32_t aDisplayID) {
491 if (mActiveImmersiveSession) {
492 mActiveImmersiveSession->ExitPresent();
495 bool XRSystem::GetStopActivityStatus() const { return true; }
497 RequestSessionRequest::RequestSessionRequest(
498 XRSessionMode aSessionMode, uint32_t aPresentationGroup, Promise* aPromise,
499 const nsTArray<XRReferenceSpaceType>& aRequiredReferenceSpaceTypes,
500 const nsTArray<XRReferenceSpaceType>& aOptionalReferenceSpaceTypes)
501 : mPromise(aPromise),
502 mSessionMode(aSessionMode),
503 mPresentationGroup(aPresentationGroup),
504 mRequiredReferenceSpaceTypes(aRequiredReferenceSpaceTypes.Clone()),
505 mOptionalReferenceSpaceTypes(aOptionalReferenceSpaceTypes.Clone()) {}
507 bool RequestSessionRequest::ResolveSupport(
508 const gfx::VRDisplayClient* aDisplay,
509 nsTArray<XRReferenceSpaceType>& aEnabledReferenceSpaceTypes) const {
510 if (aDisplay) {
511 if (!aDisplay->GetIsConnected()) {
512 return false;
514 if ((aDisplay->GetDisplayInfo().GetPresentingGroups() &
515 mPresentationGroup) != 0) {
516 return false;
519 const gfx::VRDisplayInfo& info = aDisplay->GetDisplayInfo();
520 switch (mSessionMode) {
521 case XRSessionMode::Inline:
522 if (!bool(info.mDisplayState.capabilityFlags &
523 gfx::VRDisplayCapabilityFlags::Cap_Inline)) {
524 return false;
526 break;
527 case XRSessionMode::Immersive_vr:
528 if (!bool(info.mDisplayState.capabilityFlags &
529 gfx::VRDisplayCapabilityFlags::Cap_ImmersiveVR)) {
530 return false;
532 break;
533 case XRSessionMode::Immersive_ar:
534 if (!bool(info.mDisplayState.capabilityFlags &
535 gfx::VRDisplayCapabilityFlags::Cap_ImmersiveAR)) {
536 return false;
538 break;
539 default:
540 break;
542 } else if (mSessionMode != XRSessionMode::Inline) {
543 // If we don't have a device, we can only support inline sessions
544 return false;
547 // All sessions support XRReferenceSpaceType::Viewer by default
548 aEnabledReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Viewer);
550 // Immersive sessions support XRReferenceSpaceType::Local by default
551 if (IsImmersive()) {
552 aEnabledReferenceSpaceTypes.AppendElement(XRReferenceSpaceType::Local);
555 for (XRReferenceSpaceType type : mRequiredReferenceSpaceTypes) {
556 if (aDisplay) {
557 if (!aDisplay->IsReferenceSpaceTypeSupported(type)) {
558 return false;
560 } else if (type != XRReferenceSpaceType::Viewer) {
561 // If we don't have a device, We only support
562 // XRReferenceSpaceType::Viewer
563 return false;
565 if (!aEnabledReferenceSpaceTypes.Contains(type)) {
566 aEnabledReferenceSpaceTypes.AppendElement(type);
569 if (aDisplay) {
570 for (XRReferenceSpaceType type : mOptionalReferenceSpaceTypes) {
571 if (aDisplay->IsReferenceSpaceTypeSupported(type) &&
572 !aEnabledReferenceSpaceTypes.Contains(type)) {
573 aEnabledReferenceSpaceTypes.AppendElement(type);
577 return true;
580 bool RequestSessionRequest::IsImmersive() const {
581 return (mSessionMode == XRSessionMode::Immersive_vr ||
582 mSessionMode == XRSessionMode::Immersive_ar);
585 bool RequestSessionRequest::WantsHardware() const {
586 for (XRReferenceSpaceType type : mOptionalReferenceSpaceTypes) {
587 // Any XRReferenceSpaceType other than Viewer requires hardware
588 if (type != XRReferenceSpaceType::Viewer) {
589 return true;
592 return NeedsHardware();
595 bool RequestSessionRequest::NeedsHardware() const {
596 for (XRReferenceSpaceType type : mRequiredReferenceSpaceTypes) {
597 // Any XRReferenceSpaceType other than Viewer requires hardware
598 if (type != XRReferenceSpaceType::Viewer) {
599 return true;
602 return false;
605 XRSessionMode RequestSessionRequest::GetSessionMode() const {
606 return mSessionMode;
609 uint32_t RequestSessionRequest::GetPresentationGroup() const {
610 return mPresentationGroup;
613 ////////////////////////////////////////////////////////////////////////////////
614 // IsSessionSupportedRequest cycle collection
615 NS_IMPL_CYCLE_COLLECTION(IsSessionSupportedRequest, mPromise)
617 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(IsSessionSupportedRequest, AddRef)
618 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(IsSessionSupportedRequest, Release)
620 XRSessionMode IsSessionSupportedRequest::GetSessionMode() const {
621 return mSessionMode;
624 ////////////////////////////////////////////////////////////////////////////////
625 // XRRequestSessionPermissionRequest cycle collection
626 NS_IMPL_CYCLE_COLLECTION_INHERITED(XRRequestSessionPermissionRequest,
627 ContentPermissionRequestBase)
629 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(
630 XRRequestSessionPermissionRequest, ContentPermissionRequestBase)
632 XRRequestSessionPermissionRequest::XRRequestSessionPermissionRequest(
633 nsPIDOMWindowInner* aWindow, nsIPrincipal* aNodePrincipal,
634 AllowCallback&& aAllowCallback,
635 AllowAnySiteCallback&& aAllowAnySiteCallback,
636 CancelCallback&& aCancelCallback)
637 : ContentPermissionRequestBase(aNodePrincipal, aWindow, "dom.xr"_ns,
638 "xr"_ns),
639 mAllowCallback(std::move(aAllowCallback)),
640 mAllowAnySiteCallback(std::move(aAllowAnySiteCallback)),
641 mCancelCallback(std::move(aCancelCallback)),
642 mCallbackCalled(false) {
643 mPermissionRequests.AppendElement(
644 PermissionRequest(mType, nsTArray<nsString>()));
647 XRRequestSessionPermissionRequest::~XRRequestSessionPermissionRequest() {
648 Cancel();
651 NS_IMETHODIMP
652 XRRequestSessionPermissionRequest::Cancel() {
653 if (!mCallbackCalled) {
654 mCallbackCalled = true;
655 mCancelCallback();
657 return NS_OK;
660 NS_IMETHODIMP
661 XRRequestSessionPermissionRequest::Allow(JS::HandleValue aChoices) {
662 nsTArray<PermissionChoice> choices;
663 nsresult rv = TranslateChoices(aChoices, mPermissionRequests, choices);
664 if (NS_FAILED(rv)) {
665 return rv;
668 // There is no support to allow grants automatically from the prompting code
669 // path.
671 if (!mCallbackCalled) {
672 mCallbackCalled = true;
673 if (choices.Length() == 1 &&
674 choices[0].choice().EqualsLiteral("allow-on-any-site")) {
675 mAllowAnySiteCallback();
676 } else if (choices.Length() == 1 &&
677 choices[0].choice().EqualsLiteral("allow")) {
678 mAllowCallback();
681 return NS_OK;
684 already_AddRefed<XRRequestSessionPermissionRequest>
685 XRRequestSessionPermissionRequest::Create(
686 nsPIDOMWindowInner* aWindow, AllowCallback&& aAllowCallback,
687 AllowAnySiteCallback&& aAllowAnySiteCallback,
688 CancelCallback&& aCancelCallback) {
689 if (!aWindow) {
690 return nullptr;
692 nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(aWindow);
693 if (!win->GetPrincipal()) {
694 return nullptr;
696 RefPtr<XRRequestSessionPermissionRequest> request =
697 new XRRequestSessionPermissionRequest(
698 aWindow, win->GetPrincipal(), std::move(aAllowCallback),
699 std::move(aAllowAnySiteCallback), std::move(aCancelCallback));
700 return request.forget();
703 ////////////////////////////////////////////////////////////////////////////////
704 // RequestSessionRequest cycle collection
705 NS_IMPL_CYCLE_COLLECTION(RequestSessionRequest, mPromise)
707 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(RequestSessionRequest, AddRef)
708 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(RequestSessionRequest, Release)
710 } // namespace dom
711 } // namespace mozilla