diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index a0a7fa67826..44e3b8c3845 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -486,7 +486,7 @@ unsafe_no_jsmanaged_fields!(WebGLVersion); unsafe_no_jsmanaged_fields!(WebGLSLVersion); unsafe_no_jsmanaged_fields!(MediaList); unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand); -unsafe_no_jsmanaged_fields!(webxr_api::Registry); +unsafe_no_jsmanaged_fields!(webxr_api::Registry, webxr_api::Session); unsafe_no_jsmanaged_fields!(ScriptToConstellationChan); unsafe_no_jsmanaged_fields!(InteractiveMetrics); unsafe_no_jsmanaged_fields!(InteractiveWindow); diff --git a/components/script/dom/xr.rs b/components/script/dom/xr.rs index ee7033aa239..c20dd8fdafc 100644 --- a/components/script/dom/xr.rs +++ b/components/script/dom/xr.rs @@ -10,7 +10,7 @@ use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionCreationOptions use crate::dom::bindings::codegen::Bindings::XRBinding::{XRMethods, XRSessionMode}; use crate::dom::bindings::error::Error; use crate::dom::bindings::inheritance::Castable; -use crate::dom::bindings::refcounted::TrustedPromise; +use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::event::Event; @@ -32,7 +32,7 @@ use std::cell::Cell; use std::rc::Rc; use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVREvent, WebVRMsg}; use webvr_traits::{WebVRGamepadData, WebVRGamepadEvent, WebVRGamepadState}; -use webxr_api::{Error as XRError, SessionMode}; +use webxr_api::{Error as XRError, Session, SessionMode}; #[dom_struct] pub struct XR { @@ -160,6 +160,17 @@ impl XRMethods for XR { options: &XRSessionCreationOptions, comp: InCompartment, ) -> Rc { + #[derive(serde::Serialize, serde::Deserialize)] + pub struct RequestSession { + sender: IpcSender>, + } + + #[typetag::serde] + impl webxr_api::SessionRequestCallback for RequestSession { + fn callback(&mut self, result: Result) { + let _ = self.sender.send(result); + } + } let promise = Promise::new_in_current_compartment(&self.global(), comp); if options.mode != XRSessionMode::Immersive_vr { promise.reject_error(Error::NotSupported); @@ -170,28 +181,42 @@ impl XRMethods for XR { promise.reject_error(Error::InvalidState); return promise; } - // we set pending immersive session to true further down - // to handle rejections in a cleaner way - - let displays = self.get_displays(); - - let displays = match displays { - Ok(d) => d, - Err(_) => { - promise.reject_native(&()); - return promise; - }, - }; - - // XXXManishearth filter for displays which can_present - if displays.is_empty() { - promise.reject_error(Error::Security); - } self.set_pending(); - let session = XRSession::new(&self.global(), &displays[0]); - session.xr_present(promise.clone()); + let promise = Promise::new_in_current_compartment(&self.global(), comp); + let mut trusted = Some(TrustedPromise::new(promise.clone())); + let this = Trusted::new(self); + let global = self.global(); + let window = global.as_window(); + let (task_source, canceller) = window + .task_manager() + .dom_manipulation_task_source_with_canceller(); + let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); + ROUTER.add_route( + receiver.to_opaque(), + Box::new(move |message| { + // router doesn't know this is only called once + let trusted = trusted.take().unwrap(); + let this = this.clone(); + let message = if let Ok(message) = message.to() { + message + } else { + error!("requestSession callback given incorrect payload"); + return; + }; + let _ = task_source.queue_with_canceller( + task!(request_session: move || { + this.root().session_obtained(message, trusted.root()); + }), + &canceller, + ); + }), + ); + window + .webxr_registry() + .request_session(options.mode.into(), RequestSession { sender }); + promise } @@ -202,6 +227,19 @@ impl XRMethods for XR { } impl XR { + fn session_obtained(&self, response: Result, promise: Rc) { + let session = match response { + Ok(session) => session, + Err(_) => { + promise.reject_native(&()); + return; + }, + }; + + let session = XRSession::new(&self.global(), session); + promise.resolve_native(&session); + } + pub fn get_displays(&self) -> Result>, ()> { if let Some(webvr_thread) = self.webvr_thread() { let (sender, receiver) = diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 98e21516981..ea32bdfc1f6 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -3,7 +3,6 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::compartments::InCompartment; -use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods; use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionMode; use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType; use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateInit; @@ -13,59 +12,61 @@ use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRFrameRequestCal use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRSessionMethods; use crate::dom::bindings::error::Error; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; -use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; +use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; -use crate::dom::vrdisplay::VRDisplay; use crate::dom::xrinputsource::XRInputSource; use crate::dom::xrlayer::XRLayer; use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrrenderstate::XRRenderState; use crate::dom::xrspace::XRSpace; use dom_struct::dom_struct; +use euclid::Vector3D; use std::rc::Rc; +use webxr_api::Session; #[dom_struct] pub struct XRSession { eventtarget: EventTarget, - display: Dom, base_layer: MutNullableDom, blend_mode: XREnvironmentBlendMode, viewer_space: MutNullableDom, + #[ignore_malloc_size_of = "defined in webxr"] + session: Session, } impl XRSession { - fn new_inherited(display: &VRDisplay) -> XRSession { + fn new_inherited(session: Session) -> XRSession { XRSession { eventtarget: EventTarget::new_inherited(), - display: Dom::from_ref(display), base_layer: Default::default(), // we don't yet support any AR devices blend_mode: XREnvironmentBlendMode::Opaque, viewer_space: Default::default(), + session, } } - pub fn new(global: &GlobalScope, display: &VRDisplay) -> DomRoot { + pub fn new(global: &GlobalScope, session: Session) -> DomRoot { reflect_dom_object( - Box::new(XRSession::new_inherited(display)), + Box::new(XRSession::new_inherited(session)), global, XRSessionBinding::Wrap, ) } - pub fn xr_present(&self, p: Rc) { - self.display.xr_present(self, None, Some(p)); - } - - pub fn display(&self) -> &VRDisplay { - &self.display - } - pub fn set_layer(&self, layer: &XRLayer) { self.base_layer.set(Some(layer)) } + + pub fn left_eye_params_offset(&self) -> Vector3D { + unimplemented!() + } + + pub fn right_eye_params_offset(&self) -> Vector3D { + unimplemented!() + } } impl XRSessionMethods for XRSession { @@ -76,30 +77,22 @@ impl XRSessionMethods for XRSession { // https://immersive-web.github.io/webxr/#dom-xrsession-renderstate fn RenderState(&self) -> DomRoot { - // XXXManishearth maybe cache this - XRRenderState::new( - &self.global(), - *self.display.DepthNear(), - *self.display.DepthFar(), - self.base_layer.get().as_ref().map(|l| &**l), - ) + unimplemented!() } /// https://immersive-web.github.io/webxr/#dom-xrsession-requestanimationframe fn UpdateRenderState(&self, init: &XRRenderStateInit, comp: InCompartment) -> Rc { - let p = Promise::new_in_current_compartment(&self.global(), comp); - self.display.queue_renderstate(init, p.clone()); - p + unimplemented!() } /// https://immersive-web.github.io/webxr/#dom-xrsession-requestanimationframe fn RequestAnimationFrame(&self, callback: Rc) -> i32 { - self.display.xr_raf(callback) as i32 + unimplemented!() } /// https://immersive-web.github.io/webxr/#dom-xrsession-cancelanimationframe fn CancelAnimationFrame(&self, frame: i32) { - self.display.xr_cancel_raf(frame) + unimplemented!() } /// https://immersive-web.github.io/webxr/#dom-xrsession-environmentblendmode @@ -131,6 +124,6 @@ impl XRSessionMethods for XRSession { /// https://immersive-web.github.io/webxr/#dom-xrsession-getinputsources fn GetInputSources(&self) -> Vec> { - self.display.get_input_sources() + unimplemented!() } } diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs index c53eb8cb947..bac9e3612a1 100644 --- a/components/script/dom/xrview.rs +++ b/components/script/dom/xrview.rs @@ -11,7 +11,7 @@ use crate::dom::vrframedata::create_typed_array; use crate::dom::xrrigidtransform::XRRigidTransform; use crate::dom::xrsession::XRSession; use dom_struct::dom_struct; -use euclid::{RigidTransform3D, Vector3D}; +use euclid::RigidTransform3D; use js::jsapi::{Heap, JSContext, JSObject}; use std::ptr::NonNull; use webvr_traits::WebVRFrameData; @@ -48,22 +48,19 @@ impl XRView { pose: &RigidTransform3D, data: &WebVRFrameData, ) -> DomRoot { - let vr_display = session.display(); - // XXXManishearth compute and cache projection matrices on the Display let (proj, offset) = if eye == XREye::Left { ( &data.left_projection_matrix, - vr_display.left_eye_params_offset(), + session.left_eye_params_offset(), ) } else { ( &data.right_projection_matrix, - vr_display.right_eye_params_offset(), + session.right_eye_params_offset(), ) }; - let offset = Vector3D::new(offset[0] as f64, offset[1] as f64, offset[2] as f64); let transform = pose.post_mul(&offset.into()); let transform = XRRigidTransform::new(global, transform);