script/dom/webxr/
xrtest.rs1use std::rc::Rc;
10
11use base::generic_channel::GenericSender;
12use dom_struct::dom_struct;
13use js::jsval::JSVal;
14use profile_traits::generic_callback::GenericCallback as ProfileGenericCallback;
15use webxr_api::{self, Error as XRError, MockDeviceInit, MockDeviceMsg};
16
17use crate::ScriptThread;
18use crate::dom::bindings::callback::ExceptionHandling;
19use crate::dom::bindings::cell::DomRefCell;
20use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
21use crate::dom::bindings::codegen::Bindings::XRSystemBinding::XRSessionMode;
22use crate::dom::bindings::codegen::Bindings::XRTestBinding::{FakeXRDeviceInit, XRTestMethods};
23use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
24use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
25use crate::dom::bindings::root::{Dom, DomRoot};
26use crate::dom::fakexrdevice::{FakeXRDevice, get_origin, get_views, get_world};
27use crate::dom::globalscope::GlobalScope;
28use crate::dom::promise::Promise;
29use crate::script_runtime::CanGc;
30
31#[dom_struct]
32pub(crate) struct XRTest {
33 reflector: Reflector,
34 devices_connected: DomRefCell<Vec<Dom<FakeXRDevice>>>,
35}
36
37impl XRTest {
38 pub(crate) fn new_inherited() -> XRTest {
39 XRTest {
40 reflector: Reflector::new(),
41 devices_connected: DomRefCell::new(vec![]),
42 }
43 }
44
45 pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<XRTest> {
46 reflect_dom_object(Box::new(XRTest::new_inherited()), global, can_gc)
47 }
48
49 fn device_obtained(
50 &self,
51 response: Result<GenericSender<MockDeviceMsg>, XRError>,
52 trusted: TrustedPromise,
53 can_gc: CanGc,
54 ) {
55 let promise = trusted.root();
56 if let Ok(sender) = response {
57 let device = FakeXRDevice::new(&self.global(), sender, CanGc::note());
58 self.devices_connected
59 .borrow_mut()
60 .push(Dom::from_ref(&device));
61 promise.resolve_native(&device, can_gc);
62 } else {
63 promise.reject_native(&(), can_gc);
64 }
65 }
66}
67
68impl XRTestMethods<crate::DomTypeHolder> for XRTest {
69 fn SimulateDeviceConnection(&self, init: &FakeXRDeviceInit, can_gc: CanGc) -> Rc<Promise> {
71 let global = self.global();
72 let p = Promise::new(&global, can_gc);
73
74 let origin = if let Some(ref o) = init.viewerOrigin {
75 match get_origin(o) {
76 Ok(origin) => Some(origin),
77 Err(e) => {
78 p.reject_error(e, can_gc);
79 return p;
80 },
81 }
82 } else {
83 None
84 };
85
86 let floor_origin = if let Some(ref o) = init.floorOrigin {
87 match get_origin(o) {
88 Ok(origin) => Some(origin),
89 Err(e) => {
90 p.reject_error(e, can_gc);
91 return p;
92 },
93 }
94 } else {
95 None
96 };
97
98 let views = match get_views(&init.views) {
99 Ok(views) => views,
100 Err(e) => {
101 p.reject_error(e, can_gc);
102 return p;
103 },
104 };
105
106 let supported_features = if let Some(ref s) = init.supportedFeatures {
107 s.iter().cloned().map(String::from).collect()
108 } else {
109 vec![]
110 };
111
112 let world = if let Some(ref w) = init.world {
113 let w = match get_world(w) {
114 Ok(w) => w,
115 Err(e) => {
116 p.reject_error(e, can_gc);
117 return p;
118 },
119 };
120 Some(w)
121 } else {
122 None
123 };
124
125 let (mut supports_inline, mut supports_vr, mut supports_ar) = (false, false, false);
126
127 if let Some(ref modes) = init.supportedModes {
128 for mode in modes {
129 match mode {
130 XRSessionMode::Immersive_vr => supports_vr = true,
131 XRSessionMode::Immersive_ar => supports_ar = true,
132 XRSessionMode::Inline => supports_inline = true,
133 }
134 }
135 }
136
137 let init = MockDeviceInit {
138 viewer_origin: origin,
139 views,
140 supports_inline,
141 supports_vr,
142 supports_ar,
143 floor_origin,
144 supported_features,
145 world,
146 };
147
148 let global = self.global();
149 let this = Trusted::new(self);
150 let mut trusted = Some(TrustedPromise::new(p.clone()));
151
152 let task_source = global
153 .task_manager()
154 .dom_manipulation_task_source()
155 .to_sendable();
156
157 let callback =
158 ProfileGenericCallback::new(global.time_profiler_chan().clone(), move |message| {
159 let trusted = trusted
160 .take()
161 .expect("SimulateDeviceConnection callback called twice");
162 let this = this.clone();
163 let message =
164 message.expect("SimulateDeviceConnection callback given incorrect payload");
165
166 task_source.queue(task!(request_session: move || {
167 this.root().device_obtained(message, trusted, CanGc::note());
168 }));
169 })
170 .expect("Could not create callback");
171 if let Some(mut r) = global.as_window().webxr_registry() {
172 r.simulate_device_connection(init, callback);
173 }
174
175 p
176 }
177
178 fn SimulateUserActivation(&self, f: Rc<Function>, can_gc: CanGc) {
180 let _guard = ScriptThread::user_interacting_guard();
181 rooted!(in(*GlobalScope::get_cx()) let mut value: JSVal);
182 let _ = f.Call__(
183 vec![],
184 value.handle_mut(),
185 ExceptionHandling::Rethrow,
186 can_gc,
187 );
188 }
189
190 fn DisconnectAllDevices(&self, can_gc: CanGc) -> Rc<Promise> {
192 let global = self.global();
194 let p = Promise::new(&global, can_gc);
195 let mut devices = self.devices_connected.borrow_mut();
196 if devices.is_empty() {
197 p.resolve_native(&(), can_gc);
198 } else {
199 let mut len = devices.len();
200
201 let mut rooted_devices: Vec<_> =
202 devices.iter().map(|x| DomRoot::from_ref(&**x)).collect();
203 devices.clear();
204
205 let mut trusted = Some(TrustedPromise::new(p.clone()));
206 let task_source = global
207 .task_manager()
208 .dom_manipulation_task_source()
209 .to_sendable();
210
211 let callback =
212 ProfileGenericCallback::new(global.time_profiler_chan().clone(), move |_| {
213 len -= 1;
214 if len == 0 {
215 let trusted = trusted
216 .take()
217 .expect("DisconnectAllDevices disconnected more devices than expected");
218 task_source.queue(trusted.resolve_task(()));
219 }
220 })
221 .expect("Could not create callback");
222
223 for device in rooted_devices.drain(..) {
224 device.disconnect(callback.clone());
225 }
226 };
227 p
228 }
229}