diff options
33 files changed, 1092 insertions, 71 deletions
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index e38a5e924ac..253dc2b54bb 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -479,7 +479,6 @@ pub mod validation; pub mod validitystate; pub mod values; pub mod virtualmethods; -pub mod vr; pub mod vrdisplay; pub mod vrdisplaycapabilities; pub mod vrdisplayevent; @@ -518,3 +517,15 @@ pub mod xmldocument; pub mod xmlhttprequest; pub mod xmlhttprequesteventtarget; pub mod xmlhttprequestupload; +pub mod xr; +pub mod xrframe; +pub mod xrlayer; +pub mod xrreferencespace; +pub mod xrrigidtransform; +pub mod xrsession; +pub mod xrspace; +pub mod xrstationaryreferencespace; +pub mod xrview; +pub mod xrviewerpose; +pub mod xrviewport; +pub mod xrwebgllayer; diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs index 04669ca25d9..aa49701709a 100644 --- a/components/script/dom/navigator.rs +++ b/components/script/dom/navigator.rs @@ -4,7 +4,7 @@ use crate::dom::bindings::codegen::Bindings::NavigatorBinding; use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods; -use crate::dom::bindings::codegen::Bindings::VRBinding::VRBinding::VRMethods; +use crate::dom::bindings::error::Error; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::bindings::str::DOMString; @@ -16,8 +16,8 @@ use crate::dom::permissions::Permissions; use crate::dom::pluginarray::PluginArray; use crate::dom::promise::Promise; use crate::dom::serviceworkercontainer::ServiceWorkerContainer; -use crate::dom::vr::VR; use crate::dom::window::Window; +use crate::dom::xr::XR; use dom_struct::dom_struct; use std::rc::Rc; @@ -28,7 +28,7 @@ pub struct Navigator { plugins: MutNullableDom<PluginArray>, mime_types: MutNullableDom<MimeTypeArray>, service_worker: MutNullableDom<ServiceWorkerContainer>, - vr: MutNullableDom<VR>, + xr: MutNullableDom<XR>, gamepads: MutNullableDom<GamepadList>, permissions: MutNullableDom<Permissions>, } @@ -41,7 +41,7 @@ impl Navigator { plugins: Default::default(), mime_types: Default::default(), service_worker: Default::default(), - vr: Default::default(), + xr: Default::default(), gamepads: Default::default(), permissions: Default::default(), } @@ -135,7 +135,7 @@ impl NavigatorMethods for Navigator { .gamepads .or_init(|| GamepadList::new(&self.global(), &[])); - let vr_gamepads = self.Vr().get_gamepads(); + let vr_gamepads = self.Xr().get_gamepads(); root.add_if_not_exists(&vr_gamepads); // TODO: Add not VR related gamepads root @@ -149,12 +149,17 @@ impl NavigatorMethods for Navigator { // https://w3c.github.io/webvr/spec/1.1/#navigator-getvrdisplays-attribute #[allow(unrooted_must_root)] fn GetVRDisplays(&self) -> Rc<Promise> { - self.Vr().GetDisplays() + let promise = Promise::new(&self.global()); + let displays = self.Xr().get_displays(); + match displays { + Ok(displays) => promise.resolve_native(&displays), + Err(_) => promise.reject_error(Error::Security), + } + promise } -} -impl Navigator { - pub fn Vr(&self) -> DomRoot<VR> { - self.vr.or_init(|| VR::new(&self.global())) + /// https://immersive-web.github.io/webxr/#dom-navigator-xr + fn Xr(&self) -> DomRoot<XR> { + self.xr.or_init(|| XR::new(&self.global())) } } diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs index c02d5439be8..048157a0ba7 100644 --- a/components/script/dom/vrdisplay.rs +++ b/components/script/dom/vrdisplay.rs @@ -4,14 +4,15 @@ use crate::dom::bindings::callback::ExceptionHandling; use crate::dom::bindings::cell::DomRefCell; -use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceBinding::PerformanceMethods; +use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods; use crate::dom::bindings::codegen::Bindings::VRDisplayBinding; use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods; use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VREye; use crate::dom::bindings::codegen::Bindings::VRLayerBinding::VRLayer; use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::FrameRequestCallback; -use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; +use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; +use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRFrameRequestCallback; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::num::Finite; use crate::dom::bindings::refcounted::Trusted; @@ -29,6 +30,8 @@ use crate::dom::vrframedata::VRFrameData; use crate::dom::vrpose::VRPose; use crate::dom::vrstageparameters::VRStageParameters; use crate::dom::webglrenderingcontext::WebGLRenderingContext; +use crate::dom::xrframe::XRFrame; +use crate::dom::xrsession::XRSession; use crate::script_runtime::CommonScriptMsg; use crate::script_runtime::ScriptThreadEventCategory::WebVREvent; use crate::task_source::TaskSourceName; @@ -67,6 +70,8 @@ pub struct VRDisplay { /// List of request animation frame callbacks #[ignore_malloc_size_of = "closures are hard"] raf_callback_list: DomRefCell<Vec<(u32, Option<Rc<FrameRequestCallback>>)>>, + #[ignore_malloc_size_of = "closures are hard"] + xr_raf_callback_list: DomRefCell<Vec<(u32, Option<Rc<XRFrameRequestCallback>>)>>, // Compositor VRFrameData synchonization frame_data_status: Cell<VRFrameDataStatus>, #[ignore_malloc_size_of = "closures are hard"] @@ -74,6 +79,8 @@ pub struct VRDisplay { running_display_raf: Cell<bool>, paused: Cell<bool>, stopped_on_pause: Cell<bool>, + /// Whether or not this is XR mode, and the session + xr_session: MutNullableDom<XRSession>, } unsafe_no_jsmanaged_fields!(WebVRDisplayData); @@ -120,6 +127,7 @@ impl VRDisplay { layer_ctx: MutNullableDom::default(), next_raf_id: Cell::new(1), raf_callback_list: DomRefCell::new(vec![]), + xr_raf_callback_list: DomRefCell::new(vec![]), frame_data_status: Cell::new(VRFrameDataStatus::Waiting), frame_data_receiver: DomRefCell::new(None), running_display_raf: Cell::new(false), @@ -129,6 +137,7 @@ impl VRDisplay { // This flag is set when the Display was presenting when it received a VR Pause event. // When the VR Resume event is received and the flag is set, VR presentation automatically restarts. stopped_on_pause: Cell::new(false), + xr_session: MutNullableDom::default(), } } @@ -624,25 +633,42 @@ impl VRDisplay { fn handle_raf(&self, end_sender: &Sender<Result<(f64, f64), ()>>) { self.frame_data_status.set(VRFrameDataStatus::Waiting); - self.running_display_raf.set(true); - let mut callbacks = mem::replace(&mut *self.raf_callback_list.borrow_mut(), vec![]); let now = self.global().as_window().Performance().Now(); - // Call registered VRDisplay.requestAnimationFrame callbacks. - for (_, callback) in callbacks.drain(..) { - if let Some(callback) = callback { - let _ = callback.Call__(Finite::wrap(*now), ExceptionHandling::Report); + if let Some(session) = self.xr_session.get() { + let mut callbacks = mem::replace(&mut *self.xr_raf_callback_list.borrow_mut(), vec![]); + if callbacks.is_empty() { + return; } - } - - self.running_display_raf.set(false); - if self.frame_data_status.get() == VRFrameDataStatus::Waiting { - // User didn't call getFrameData while presenting. - // We automatically reads the pending VRFrameData to avoid overflowing the IPC-Channel buffers. - // Show a warning as the WebVR Spec recommends. - warn!("WebVR: You should call GetFrameData while presenting"); self.sync_frame_data(); + let frame = XRFrame::new(&self.global(), &session, self.frame_data.borrow().clone()); + + for (_, callback) in callbacks.drain(..) { + if let Some(callback) = callback { + let _ = callback.Call__(Finite::wrap(*now), &frame, ExceptionHandling::Report); + } + } + // frame submission is automatic in XR + self.SubmitFrame(); + } else { + self.running_display_raf.set(true); + let mut callbacks = mem::replace(&mut *self.raf_callback_list.borrow_mut(), vec![]); + // Call registered VRDisplay.requestAnimationFrame callbacks. + for (_, callback) in callbacks.drain(..) { + if let Some(callback) = callback { + let _ = callback.Call__(Finite::wrap(*now), ExceptionHandling::Report); + } + } + + self.running_display_raf.set(false); + if self.frame_data_status.get() == VRFrameDataStatus::Waiting { + // User didn't call getFrameData while presenting. + // We automatically reads the pending VRFrameData to avoid overflowing the IPC-Channel buffers. + // Show a warning as the WebVR Spec recommends. + warn!("WebVR: You should call GetFrameData while presenting"); + self.sync_frame_data(); + } } match self.frame_data_status.get() { @@ -661,6 +687,52 @@ impl VRDisplay { } } +// XR stuff +// XXXManishearth eventually we should share as much logic as possible +impl VRDisplay { + pub fn xr_present(&self, session: &XRSession, ctx: &WebGLRenderingContext) { + let layer_bounds = WebVRLayer::default(); + self.xr_session.set(Some(session)); + if self.presenting.get() { + *self.layer.borrow_mut() = layer_bounds; + self.layer_ctx.set(Some(&ctx)); + return; + } + + // Request Present + let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); + self.webvr_thread() + .send(WebVRMsg::RequestPresent( + self.global().pipeline_id(), + self.display.borrow().display_id, + sender, + )) + .unwrap(); + + if let Ok(()) = receiver.recv().unwrap() { + *self.layer.borrow_mut() = layer_bounds; + self.layer_ctx.set(Some(&ctx)); + self.init_present(); + } + } + + pub fn xr_raf(&self, callback: Rc<XRFrameRequestCallback>) -> u32 { + let raf_id = self.next_raf_id.get(); + self.next_raf_id.set(raf_id + 1); + self.xr_raf_callback_list + .borrow_mut() + .push((raf_id, Some(callback))); + raf_id + } + + pub fn xr_cancel_raf(&self, handle: i32) { + let mut list = self.xr_raf_callback_list.borrow_mut(); + if let Some(pair) = list.iter_mut().find(|pair| pair.0 == handle as u32) { + pair.1 = None; + } + } +} + // WebVR Spec: If the number of values in the leftBounds/rightBounds arrays // is not 0 or 4 for any of the passed layers the promise is rejected fn parse_bounds(src: &Option<Vec<Finite<f32>>>, dst: &mut [f32; 4]) -> Result<(), &'static str> { diff --git a/components/script/dom/vrframedata.rs b/components/script/dom/vrframedata.rs index 2ae20323d02..ebd0c8cc24f 100644 --- a/components/script/dom/vrframedata.rs +++ b/components/script/dom/vrframedata.rs @@ -71,8 +71,9 @@ impl VRFrameData { } } +/// FIXME(#22526) this should be in a better place #[allow(unsafe_code)] -fn create_typed_array(cx: *mut JSContext, src: &[f32], dst: &Heap<*mut JSObject>) { +pub fn create_typed_array(cx: *mut JSContext, src: &[f32], dst: &Heap<*mut JSObject>) { rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>()); unsafe { let _ = Float32Array::create(cx, CreateWith::Slice(src), array.handle_mut()); diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 726a59db4ad..6175f2ad2b9 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -157,6 +157,7 @@ pub struct WebGLRenderingContext { current_scissor: Cell<(i32, i32, u32, u32)>, #[ignore_malloc_size_of = "Because it's small"] current_clear_color: Cell<(f32, f32, f32, f32)>, + size: Cell<Size2D<u32>>, extension_manager: WebGLExtensions, capabilities: Capabilities, default_vao: DomOnceCell<WebGLVertexArrayObjectOES>, @@ -211,6 +212,9 @@ impl WebGLRenderingContext { current_program: MutNullableDom::new(None), current_vertex_attrib_0: Cell::new((0f32, 0f32, 0f32, 1f32)), current_scissor: Cell::new((0, 0, size.width, size.height)), + // FIXME(#21718) The backend is allowed to choose a size smaller than + // what was requested + size: Cell::new(size), current_clear_color: Cell::new((0.0, 0.0, 0.0, 0.0)), extension_manager: WebGLExtensions::new(webgl_version), capabilities: Default::default(), @@ -266,6 +270,9 @@ impl WebGLRenderingContext { pub fn recreate(&self, size: Size2D<u32>) { let (sender, receiver) = webgl_channel().unwrap(); self.webgl_sender.send_resize(size, sender).unwrap(); + // FIXME(#21718) The backend is allowed to choose a size smaller than + // what was requested + self.size.set(size); if let Err(msg) = receiver.recv().unwrap() { error!("Error resizing WebGLContext: {}", msg); @@ -340,6 +347,10 @@ impl WebGLRenderingContext { } } + pub fn size(&self) -> Size2D<u32> { + self.size.get() + } + // Helper function for validating framebuffer completeness in // calls touching the framebuffer. From the GLES 2.0.25 spec, // page 119: diff --git a/components/script/dom/webidls/VR.webidl b/components/script/dom/webidls/VR.webidl deleted file mode 100644 index 536bce29338..00000000000 --- a/components/script/dom/webidls/VR.webidl +++ /dev/null @@ -1,11 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -// https://w3c.github.io/webvr/#interface-navigator -[NoInterfaceObject] -interface VR { - [Pref="dom.webvr.enabled"] - Promise<sequence<VRDisplay>> getDisplays(); - //readonly attribute FrozenArray<VRDisplay> activeVRDisplays; -}; diff --git a/components/script/dom/webidls/XR.webidl b/components/script/dom/webidls/XR.webidl new file mode 100644 index 00000000000..4a6bca26a69 --- /dev/null +++ b/components/script/dom/webidls/XR.webidl @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xr-interface +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XR: EventTarget { + // Methods + Promise<void> supportsSessionMode(XRSessionMode mode); + Promise<XRSession> requestSession(optional XRSessionCreationOptions parameters); + + // Events + // attribute EventHandler ondevicechange; +}; + +[SecureContext] +partial interface Navigator { + [SameObject, Pref="dom.webxr.enabled"] readonly attribute XR xr; +}; + +enum XRSessionMode { + "inline", + "immersive-vr", + "immersive-ar" +}; + +dictionary XRSessionCreationOptions { + XRSessionMode mode = "inline"; + // XRPresentationContext outputContext; +}; diff --git a/components/script/dom/webidls/XRFrame.webidl b/components/script/dom/webidls/XRFrame.webidl new file mode 100644 index 00000000000..6c40306755d --- /dev/null +++ b/components/script/dom/webidls/XRFrame.webidl @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrframe-interface + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRFrame { + readonly attribute XRSession session; + + XRViewerPose? getViewerPose(optional XRReferenceSpace referenceSpace); + // XRInputPose? getInputPose(XRInputSource inputSource, optional XRReferenceSpace referenceSpace); +}; diff --git a/components/script/dom/webidls/XRLayer.webidl b/components/script/dom/webidls/XRLayer.webidl new file mode 100644 index 00000000000..69c65da6143 --- /dev/null +++ b/components/script/dom/webidls/XRLayer.webidl @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrlayer-interface + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRLayer {}; diff --git a/components/script/dom/webidls/XRReferenceSpace.webidl b/components/script/dom/webidls/XRReferenceSpace.webidl new file mode 100644 index 00000000000..fdedfe0bb4f --- /dev/null +++ b/components/script/dom/webidls/XRReferenceSpace.webidl @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrreferencespace-interface + +enum XRReferenceSpaceType { + "stationary", + "bounded", + "unbounded" +}; + +dictionary XRReferenceSpaceOptions { + required XRReferenceSpaceType type; +}; + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRReferenceSpace : XRSpace { + // attribute XRRigidTransform originOffset; + // attribute EventHandler onreset; +}; diff --git a/components/script/dom/webidls/XRRigidTransform.webidl b/components/script/dom/webidls/XRRigidTransform.webidl new file mode 100644 index 00000000000..f7ccd0fb188 --- /dev/null +++ b/components/script/dom/webidls/XRRigidTransform.webidl @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrrigidtransform-interface + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +// [Constructor(optional DOMPointInit position, optional DOMPointInit orientation)] +interface XRRigidTransform { + // readonly attribute DOMPointReadOnly position; + // readonly attribute DOMPointReadOnly orientation; + // readonly attribute Float32Array matrix; +}; diff --git a/components/script/dom/webidls/XRSession.webidl b/components/script/dom/webidls/XRSession.webidl new file mode 100644 index 00000000000..7cf25bf8c36 --- /dev/null +++ b/components/script/dom/webidls/XRSession.webidl @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrsession-interface + +enum XREnvironmentBlendMode { + "opaque", + "additive", + "alpha-blend", +}; + +callback XRFrameRequestCallback = void (DOMHighResTimeStamp time, XRFrame frame); + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRSession : EventTarget { + // // Attributes + readonly attribute XRSessionMode mode; + // readonly attribute XRPresentationContext outputContext; + // readonly attribute XREnvironmentBlendMode environmentBlendMode; + + attribute double depthNear; + attribute double depthFar; + attribute XRLayer? baseLayer; + + // // Methods + // Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceType type, + // optional XRReferenceSpaceOptions options); + + // FrozenArray<XRInputSource> getInputSources(); + + long requestAnimationFrame(XRFrameRequestCallback callback); + void cancelAnimationFrame(long handle); + + // Promise<void> end(); + + // // Events + // attribute EventHandler onblur; + // attribute EventHandler onfocus; + // attribute EventHandler onend; + // attribute EventHandler onselect; + // attribute EventHandler oninputsourceschange; + // attribute EventHandler onselectstart; + // attribute EventHandler onselectend; +}; diff --git a/components/script/dom/webidls/XRSpace.webidl b/components/script/dom/webidls/XRSpace.webidl new file mode 100644 index 00000000000..54401b051c8 --- /dev/null +++ b/components/script/dom/webidls/XRSpace.webidl @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrspace-interface + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRSpace : EventTarget { + // XRRigidTransform? getTransformTo(XRSpace other); +}; diff --git a/components/script/dom/webidls/XRStationaryReferenceSpace.webidl b/components/script/dom/webidls/XRStationaryReferenceSpace.webidl new file mode 100644 index 00000000000..3580ac94602 --- /dev/null +++ b/components/script/dom/webidls/XRStationaryReferenceSpace.webidl @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrstationaryreferencespace-interface + +enum XRStationaryReferenceSpaceSubtype { + "eye-level", + "floor-level", + "position-disabled" +}; + +dictionary XRStationaryReferenceSpaceOptions : XRReferenceSpaceOptions { + required XRStationaryReferenceSpaceSubtype subtype; +}; + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRStationaryReferenceSpace: XRReferenceSpace { + // readonly attribute XRStationaryReferenceSpaceSubtype subtype; +}; diff --git a/components/script/dom/webidls/XRView.webidl b/components/script/dom/webidls/XRView.webidl new file mode 100644 index 00000000000..ab81136c28d --- /dev/null +++ b/components/script/dom/webidls/XRView.webidl @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrview-interface + +enum XREye { + "left", + "right" +}; + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRView { + readonly attribute XREye eye; + readonly attribute Float32Array projectionMatrix; + readonly attribute Float32Array viewMatrix; + // readonly attribute XRRigidTransform transform; +}; diff --git a/components/script/dom/webidls/XRViewerPose.webidl b/components/script/dom/webidls/XRViewerPose.webidl new file mode 100644 index 00000000000..8b63fd6cdb5 --- /dev/null +++ b/components/script/dom/webidls/XRViewerPose.webidl @@ -0,0 +1,14 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrviewerpose-interface + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRViewerPose { + // readonly attribute XRRigidTransform transform; + // readonly attribute FrozenArray<XRView> views; + // workaround until we have FrozenArray + // see https://github.com/servo/servo/issues/10427#issuecomment-449593626 + readonly attribute any views; +}; diff --git a/components/script/dom/webidls/XRViewport.webidl b/components/script/dom/webidls/XRViewport.webidl new file mode 100644 index 00000000000..325b52c9f8f --- /dev/null +++ b/components/script/dom/webidls/XRViewport.webidl @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrviewport-interface + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRViewport { + readonly attribute long x; + readonly attribute long y; + readonly attribute long width; + readonly attribute long height; +}; diff --git a/components/script/dom/webidls/XRWebGLLayer.webidl b/components/script/dom/webidls/XRWebGLLayer.webidl new file mode 100644 index 00000000000..163bfd24568 --- /dev/null +++ b/components/script/dom/webidls/XRWebGLLayer.webidl @@ -0,0 +1,43 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrwebgllayer-interface + +// typedef (WebGLRenderingContext or +// WebGL2RenderingContext) XRWebGLRenderingContext; + +typedef WebGLRenderingContext XRWebGLRenderingContext; + +dictionary XRWebGLLayerInit { + boolean antialias = true; + boolean depth = true; + boolean stencil = false; + boolean alpha = true; + // double framebufferScaleFactor = 1.0; +}; + +[SecureContext, Exposed=Window, Constructor(XRSession session, + XRWebGLRenderingContext context, + optional XRWebGLLayerInit layerInit), + Pref="dom.webxr.enabled"] +interface XRWebGLLayer : XRLayer { + // // Attributes + readonly attribute XRWebGLRenderingContext context; + + readonly attribute boolean antialias; + readonly attribute boolean depth; + readonly attribute boolean stencil; + readonly attribute boolean alpha; + + // readonly attribute WebGLFramebuffer framebuffer; + // readonly attribute unsigned long framebufferWidth; + // readonly attribute unsigned long framebufferHeight; + + // // Methods + XRViewport? getViewport(XRView view); + // void requestViewportScaling(double viewportScaleFactor); + + // // Static Methods + // static double getNativeFramebufferScaleFactor(XRSession session); +}; diff --git a/components/script/dom/vr.rs b/components/script/dom/xr.rs index 6686e0d917e..98d018eb0f9 100644 --- a/components/script/dom/vr.rs +++ b/components/script/dom/xr.rs @@ -3,12 +3,13 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::dom::bindings::cell::DomRefCell; -use crate::dom::bindings::codegen::Bindings::VRBinding; -use crate::dom::bindings::codegen::Bindings::VRBinding::VRMethods; use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods; +use crate::dom::bindings::codegen::Bindings::XRBinding; +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::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::event::Event; use crate::dom::eventtarget::EventTarget; @@ -18,6 +19,7 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; use crate::dom::vrdisplay::VRDisplay; use crate::dom::vrdisplayevent::VRDisplayEvent; +use crate::dom::xrsession::XRSession; use dom_struct::dom_struct; use ipc_channel::ipc::IpcSender; use profile_traits::ipc; @@ -26,44 +28,91 @@ use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVREvent, WebVRMsg}; use webvr_traits::{WebVRGamepadData, WebVRGamepadEvent, WebVRGamepadState}; #[dom_struct] -pub struct VR { - reflector_: Reflector, +pub struct XR { + eventtarget: EventTarget, displays: DomRefCell<Vec<Dom<VRDisplay>>>, gamepads: DomRefCell<Vec<Dom<Gamepad>>>, } -impl VR { - fn new_inherited() -> VR { - VR { - reflector_: Reflector::new(), +impl XR { + fn new_inherited() -> XR { + XR { + eventtarget: EventTarget::new_inherited(), displays: DomRefCell::new(Vec::new()), gamepads: DomRefCell::new(Vec::new()), } } - pub fn new(global: &GlobalScope) -> DomRoot<VR> { - let root = reflect_dom_object(Box::new(VR::new_inherited()), global, VRBinding::Wrap); + pub fn new(global: &GlobalScope) -> DomRoot<XR> { + let root = reflect_dom_object(Box::new(XR::new_inherited()), global, XRBinding::Wrap); root.register(); root } } -impl Drop for VR { +impl Drop for XR { fn drop(&mut self) { self.unregister(); } } -impl VRMethods for VR { +impl XRMethods for XR { #[allow(unrooted_must_root)] - // https://w3c.github.io/webvr/#interface-navigator - fn GetDisplays(&self) -> Rc<Promise> { + /// https://immersive-web.github.io/webxr/#dom-xr-supportssessionmode + fn SupportsSessionMode(&self, mode: XRSessionMode) -> Rc<Promise> { + // XXXManishearth this should select an XR device first let promise = Promise::new(&self.global()); + if mode == XRSessionMode::Immersive_vr { + promise.resolve_native(&()); + } else { + // XXXManishearth support other modes + promise.reject_error(Error::NotSupported); + } + + promise + } + #[allow(unrooted_must_root)] + /// https://immersive-web.github.io/webxr/#dom-xr-requestsession + fn RequestSession(&self, options: &XRSessionCreationOptions) -> Rc<Promise> { + let promise = Promise::new(&self.global()); + if options.mode != XRSessionMode::Immersive_vr { + promise.reject_error(Error::NotSupported); + return promise; + } + + 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); + } + + let session = XRSession::new(&self.global(), &displays[0]); + promise.resolve_native(&session); + // whether or not we should initiate presentation is unclear + // https://github.com/immersive-web/webxr/issues/453 + + promise + } +} + +impl XR { + pub fn get_displays(&self) -> Result<Vec<DomRoot<VRDisplay>>, ()> { if let Some(webvr_thread) = self.webvr_thread() { let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); webvr_thread.send(WebVRMsg::GetDisplays(sender)).unwrap(); + + // FIXME(#22505) we should not block here and instead produce a promise match receiver.recv().unwrap() { Ok(displays) => { // Sync displays @@ -71,31 +120,22 @@ impl VRMethods for VR { self.sync_display(&display); } }, - Err(e) => { - promise.reject_native(&e); - return promise; - }, + Err(_) => return Err(()), } } else { // WebVR spec: The Promise MUST be rejected if WebVR is not enabled/supported. - promise.reject_error(Error::Security); - return promise; + return Err(()); } // convert from Dom to DomRoot - let displays: Vec<DomRoot<VRDisplay>> = self + Ok(self .displays .borrow() .iter() .map(|d| DomRoot::from_ref(&**d)) - .collect(); - promise.resolve_native(&displays); - - promise + .collect()) } -} -impl VR { fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> { self.global().as_window().webvr_thread() } @@ -209,7 +249,7 @@ impl VR { } // Gamepad -impl VR { +impl XR { fn find_gamepad(&self, gamepad_id: u32) -> Option<DomRoot<Gamepad>> { self.gamepads .borrow() diff --git a/components/script/dom/xrframe.rs b/components/script/dom/xrframe.rs new file mode 100644 index 00000000000..8343bb76420 --- /dev/null +++ b/components/script/dom/xrframe.rs @@ -0,0 +1,67 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::XRFrameBinding; +use crate::dom::bindings::codegen::Bindings::XRFrameBinding::XRFrameMethods; +use crate::dom::bindings::codegen::Bindings::XRViewBinding::XREye; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::globalscope::GlobalScope; +use crate::dom::xrreferencespace::XRReferenceSpace; +use crate::dom::xrsession::XRSession; +use crate::dom::xrview::XRView; +use crate::dom::xrviewerpose::XRViewerPose; +use dom_struct::dom_struct; +use webvr_traits::WebVRFrameData; + +#[dom_struct] +pub struct XRFrame { + reflector_: Reflector, + session: Dom<XRSession>, + #[ignore_malloc_size_of = "defined in rust-webvr"] + data: WebVRFrameData, +} + +impl XRFrame { + fn new_inherited(session: &XRSession, data: WebVRFrameData) -> XRFrame { + XRFrame { + reflector_: Reflector::new(), + session: Dom::from_ref(session), + data, + } + } + + pub fn new( + global: &GlobalScope, + session: &XRSession, + data: WebVRFrameData, + ) -> DomRoot<XRFrame> { + reflect_dom_object( + Box::new(XRFrame::new_inherited(session, data)), + global, + XRFrameBinding::Wrap, + ) + } +} + +impl XRFrameMethods for XRFrame { + /// https://immersive-web.github.io/webxr/#dom-xrframe-session + fn Session(&self) -> DomRoot<XRSession> { + DomRoot::from_ref(&self.session) + } + + /// https://immersive-web.github.io/webxr/#dom-xrframe-getviewerpose + fn GetViewerPose(&self, reference: Option<&XRReferenceSpace>) -> Option<DomRoot<XRViewerPose>> { + // We assume the reference space is eye level for now + // since it's the only one 3DOF devices support + if reference.is_some() { + // it's not possible to obtain a reference + // space at all yet + return None; + } + let left = XRView::new(&self.global(), &self.session, XREye::Left, &self.data); + let right = XRView::new(&self.global(), &self.session, XREye::Right, &self.data); + Some(XRViewerPose::new(&self.global(), &left, &right)) + } +} diff --git a/components/script/dom/xrlayer.rs b/components/script/dom/xrlayer.rs new file mode 100644 index 00000000000..d17704be28f --- /dev/null +++ b/components/script/dom/xrlayer.rs @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::reflector::Reflector; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct XRLayer { + reflector_: Reflector, +} + +impl XRLayer { + pub fn new_inherited() -> XRLayer { + XRLayer { + reflector_: Reflector::new(), + } + } +} diff --git a/components/script/dom/xrreferencespace.rs b/components/script/dom/xrreferencespace.rs new file mode 100644 index 00000000000..308b710d928 --- /dev/null +++ b/components/script/dom/xrreferencespace.rs @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding; +use crate::dom::bindings::reflector::reflect_dom_object; +use crate::dom::bindings::root::DomRoot; +use crate::dom::globalscope::GlobalScope; +use crate::dom::xrspace::XRSpace; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct XRReferenceSpace { + xrspace: XRSpace, +} + +impl XRReferenceSpace { + pub fn new_inherited() -> XRReferenceSpace { + XRReferenceSpace { + xrspace: XRSpace::new_inherited(), + } + } + + #[allow(unused)] + pub fn new(global: &GlobalScope) -> DomRoot<XRReferenceSpace> { + reflect_dom_object( + Box::new(XRReferenceSpace::new_inherited()), + global, + XRReferenceSpaceBinding::Wrap, + ) + } +} diff --git a/components/script/dom/xrrigidtransform.rs b/components/script/dom/xrrigidtransform.rs new file mode 100644 index 00000000000..b147e274810 --- /dev/null +++ b/components/script/dom/xrrigidtransform.rs @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::XRRigidTransformBinding; +use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::globalscope::GlobalScope; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct XRRigidTransform { + reflector_: Reflector, +} + +impl XRRigidTransform { + fn new_inherited() -> XRRigidTransform { + XRRigidTransform { + reflector_: Reflector::new(), + } + } + + #[allow(unused)] + pub fn new(global: &GlobalScope) -> DomRoot<XRRigidTransform> { + reflect_dom_object( + Box::new(XRRigidTransform::new_inherited()), + global, + XRRigidTransformBinding::Wrap, + ) + } +} diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs new file mode 100644 index 00000000000..449d4acf8fc --- /dev/null +++ b/components/script/dom/xrsession.rs @@ -0,0 +1,100 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods; +use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionMode; +use crate::dom::bindings::codegen::Bindings::XRSessionBinding; +use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRFrameRequestCallback; +use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRSessionMethods; +use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::num::Finite; +use crate::dom::bindings::reflector::reflect_dom_object; +use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; +use crate::dom::eventtarget::EventTarget; +use crate::dom::globalscope::GlobalScope; +use crate::dom::vrdisplay::VRDisplay; +use crate::dom::xrlayer::XRLayer; +use crate::dom::xrwebgllayer::XRWebGLLayer; +use dom_struct::dom_struct; +use std::rc::Rc; + +#[dom_struct] +pub struct XRSession { + eventtarget: EventTarget, + display: Dom<VRDisplay>, + base_layer: MutNullableDom<XRLayer>, +} + +impl XRSession { + fn new_inherited(display: &VRDisplay) -> XRSession { + XRSession { + eventtarget: EventTarget::new_inherited(), + display: Dom::from_ref(display), + base_layer: Default::default(), + } + } + + pub fn new(global: &GlobalScope, display: &VRDisplay) -> DomRoot<XRSession> { + reflect_dom_object( + Box::new(XRSession::new_inherited(display)), + global, + XRSessionBinding::Wrap, + ) + } +} + +impl XRSessionMethods for XRSession { + /// https://immersive-web.github.io/webxr/#dom-xrsession-depthnear + fn DepthNear(&self) -> Finite<f64> { + self.display.DepthNear() + } + + /// https://immersive-web.github.io/webxr/#dom-xrsession-depthfar + fn DepthFar(&self) -> Finite<f64> { + self.display.DepthFar() + } + + /// https://immersive-web.github.io/webxr/#dom-xrsession-depthnear + fn SetDepthNear(&self, d: Finite<f64>) { + self.display.SetDepthNear(d) + } + + /// https://immersive-web.github.io/webxr/#dom-xrsession-depthfar + fn SetDepthFar(&self, d: Finite<f64>) { + self.display.SetDepthFar(d) + } + + /// https://immersive-web.github.io/webxr/#dom-xrsession-mode + fn Mode(&self) -> XRSessionMode { + XRSessionMode::Immersive_vr + } + + /// https://immersive-web.github.io/webxr/#dom-xrsession-baselayer + fn SetBaseLayer(&self, layer: Option<&XRLayer>) { + self.base_layer.set(layer); + if let Some(layer) = layer { + let layer = layer.downcast::<XRWebGLLayer>().unwrap(); + self.display.xr_present(&self, &layer.Context()); + } else { + // steps unknown + // https://github.com/immersive-web/webxr/issues/453 + } + } + + /// https://immersive-web.github.io/webxr/#dom-xrsession-baselayer + fn GetBaseLayer(&self) -> Option<DomRoot<XRLayer>> { + self.base_layer.get() + } + + /// https://immersive-web.github.io/webxr/#dom-xrsession-requestanimationframe + fn RequestAnimationFrame(&self, callback: Rc<XRFrameRequestCallback>) -> i32 { + self.display.xr_raf(callback) as i32 + } + + /// https://immersive-web.github.io/webxr/#dom-xrsession-cancelanimationframe + fn CancelAnimationFrame(&self, frame: i32) { + self.display.xr_cancel_raf(frame) + } +} diff --git a/components/script/dom/xrspace.rs b/components/script/dom/xrspace.rs new file mode 100644 index 00000000000..00e20df2c22 --- /dev/null +++ b/components/script/dom/xrspace.rs @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::XRSpaceBinding; +use crate::dom::bindings::reflector::reflect_dom_object; +use crate::dom::bindings::root::DomRoot; +use crate::dom::eventtarget::EventTarget; +use crate::dom::globalscope::GlobalScope; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct XRSpace { + eventtarget: EventTarget, +} + +impl XRSpace { + pub fn new_inherited() -> XRSpace { + XRSpace { + eventtarget: EventTarget::new_inherited(), + } + } + + #[allow(unused)] + pub fn new(global: &GlobalScope) -> DomRoot<XRSpace> { + reflect_dom_object( + Box::new(XRSpace::new_inherited()), + global, + XRSpaceBinding::Wrap, + ) + } +} diff --git a/components/script/dom/xrstationaryreferencespace.rs b/components/script/dom/xrstationaryreferencespace.rs new file mode 100644 index 00000000000..92c0dce0196 --- /dev/null +++ b/components/script/dom/xrstationaryreferencespace.rs @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::XRStationaryReferenceSpaceBinding; +use crate::dom::bindings::reflector::reflect_dom_object; +use crate::dom::bindings::root::DomRoot; +use crate::dom::globalscope::GlobalScope; +use crate::dom::xrreferencespace::XRReferenceSpace; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct XRStationaryReferenceSpace { + xrreferencespace: XRReferenceSpace, +} + +#[allow(unused)] +impl XRStationaryReferenceSpace { + pub fn new_inherited() -> XRStationaryReferenceSpace { + XRStationaryReferenceSpace { + xrreferencespace: XRReferenceSpace::new_inherited(), + } + } + + pub fn new(global: &GlobalScope) -> DomRoot<XRStationaryReferenceSpace> { + reflect_dom_object( + Box::new(XRStationaryReferenceSpace::new_inherited()), + global, + XRStationaryReferenceSpaceBinding::Wrap, + ) + } +} diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs new file mode 100644 index 00000000000..55975e5d8a0 --- /dev/null +++ b/components/script/dom/xrview.rs @@ -0,0 +1,83 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::XRViewBinding; +use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods}; +use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::globalscope::GlobalScope; +use crate::dom::vrframedata::create_typed_array; +use crate::dom::xrsession::XRSession; +use dom_struct::dom_struct; +use js::jsapi::{Heap, JSContext, JSObject}; +use std::ptr::NonNull; +use webvr_traits::WebVRFrameData; + +#[dom_struct] +pub struct XRView { + reflector_: Reflector, + session: Dom<XRSession>, + eye: XREye, + proj: Heap<*mut JSObject>, + view: Heap<*mut JSObject>, +} + +impl XRView { + fn new_inherited(session: &XRSession, eye: XREye) -> XRView { + XRView { + reflector_: Reflector::new(), + session: Dom::from_ref(session), + eye, + proj: Heap::default(), + view: Heap::default(), + } + } + + pub fn new( + global: &GlobalScope, + session: &XRSession, + eye: XREye, + data: &WebVRFrameData, + ) -> DomRoot<XRView> { + let ret = reflect_dom_object( + Box::new(XRView::new_inherited(session, eye)), + global, + XRViewBinding::Wrap, + ); + + let (proj, view) = if eye == XREye::Left { + (&data.left_projection_matrix, &data.left_view_matrix) + } else { + (&data.right_projection_matrix, &data.right_view_matrix) + }; + + let cx = global.get_cx(); + create_typed_array(cx, proj, &ret.proj); + create_typed_array(cx, view, &ret.view); + ret + } + + pub fn session(&self) -> &XRSession { + &self.session + } +} + +impl XRViewMethods for XRView { + /// https://immersive-web.github.io/webxr/#dom-xrview-eye + fn Eye(&self) -> XREye { + self.eye + } + + #[allow(unsafe_code)] + /// https://immersive-web.github.io/webxr/#dom-xrview-projectionmatrix + unsafe fn ProjectionMatrix(&self, _cx: *mut JSContext) -> NonNull<JSObject> { + NonNull::new(self.proj.get()).unwrap() + } + + #[allow(unsafe_code)] + /// https://immersive-web.github.io/webxr/#dom-xrview-projectionmatrix + unsafe fn ViewMatrix(&self, _cx: *mut JSContext) -> NonNull<JSObject> { + NonNull::new(self.view.get()).unwrap() + } +} diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs new file mode 100644 index 00000000000..af26b23aeb1 --- /dev/null +++ b/components/script/dom/xrviewerpose.rs @@ -0,0 +1,56 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::XRViewerPoseBinding; +use crate::dom::bindings::codegen::Bindings::XRViewerPoseBinding::XRViewerPoseMethods; +use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::globalscope::GlobalScope; +use crate::dom::xrview::XRView; +use dom_struct::dom_struct; +use js::conversions::ToJSValConvertible; +use js::jsapi::{Heap, JSContext}; +use js::jsval::{JSVal, UndefinedValue}; + +#[dom_struct] +pub struct XRViewerPose { + reflector_: Reflector, + views: Heap<JSVal>, +} + +impl XRViewerPose { + fn new_inherited() -> XRViewerPose { + XRViewerPose { + reflector_: Reflector::new(), + views: Heap::default(), + } + } + + #[allow(unsafe_code)] + pub fn new(global: &GlobalScope, left: &XRView, right: &XRView) -> DomRoot<XRViewerPose> { + let pose = reflect_dom_object( + Box::new(XRViewerPose::new_inherited()), + global, + XRViewerPoseBinding::Wrap, + ); + + unsafe { + let cx = global.get_cx(); + rooted!(in(cx) let mut jsval = UndefinedValue()); + let vec = vec![DomRoot::from_ref(left), DomRoot::from_ref(right)]; + vec.to_jsval(cx, jsval.handle_mut()); + pose.views.set(jsval.get()); + } + + pose + } +} + +impl XRViewerPoseMethods for XRViewerPose { + /// https://immersive-web.github.io/webxr/#dom-xrviewerpose-views + #[allow(unsafe_code)] + unsafe fn Views(&self, _cx: *mut JSContext) -> JSVal { + self.views.get() + } +} diff --git a/components/script/dom/xrviewport.rs b/components/script/dom/xrviewport.rs new file mode 100644 index 00000000000..f540558a527 --- /dev/null +++ b/components/script/dom/xrviewport.rs @@ -0,0 +1,67 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::XRViewportBinding; +use crate::dom::bindings::codegen::Bindings::XRViewportBinding::XRViewportMethods; +use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::globalscope::GlobalScope; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct XRViewport { + reflector_: Reflector, + x: u32, + y: u32, + width: u32, + height: u32, +} + +impl XRViewport { + fn new_inherited(x: u32, y: u32, width: u32, height: u32) -> XRViewport { + XRViewport { + reflector_: Reflector::new(), + x, + y, + width, + height, + } + } + + pub fn new( + global: &GlobalScope, + x: u32, + y: u32, + width: u32, + height: u32, + ) -> DomRoot<XRViewport> { + reflect_dom_object( + Box::new(XRViewport::new_inherited(x, y, width, height)), + global, + XRViewportBinding::Wrap, + ) + } +} + +impl XRViewportMethods for XRViewport { + /// https://immersive-web.github.io/webxr/#dom-xrviewport-x + fn X(&self) -> i32 { + self.x as i32 + } + + /// https://immersive-web.github.io/webxr/#dom-xrviewport-y + fn Y(&self) -> i32 { + self.y as i32 + } + + /// https://immersive-web.github.io/webxr/#dom-xrviewport-width + fn Width(&self) -> i32 { + self.height as i32 + } + + /// https://immersive-web.github.io/webxr/#dom-xrviewport-height + fn Height(&self) -> i32 { + self.height as i32 + } +} diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs new file mode 100644 index 00000000000..16653383a0b --- /dev/null +++ b/components/script/dom/xrwebgllayer.rs @@ -0,0 +1,122 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods}; +use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding; +use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerInit; +use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods; +use crate::dom::bindings::error::Fallible; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::globalscope::GlobalScope; +use crate::dom::webglrenderingcontext::WebGLRenderingContext; +use crate::dom::window::Window; +use crate::dom::xrlayer::XRLayer; +use crate::dom::xrsession::XRSession; +use crate::dom::xrview::XRView; +use crate::dom::xrviewport::XRViewport; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct XRWebGLLayer { + xrlayer: XRLayer, + antialias: bool, + depth: bool, + stencil: bool, + alpha: bool, + context: Dom<WebGLRenderingContext>, + session: Dom<XRSession>, +} + +impl XRWebGLLayer { + pub fn new_inherited( + session: &XRSession, + context: &WebGLRenderingContext, + init: &XRWebGLLayerInit, + ) -> XRWebGLLayer { + XRWebGLLayer { + xrlayer: XRLayer::new_inherited(), + antialias: init.antialias, + depth: init.depth, + stencil: init.stencil, + alpha: init.alpha, + context: Dom::from_ref(context), + session: Dom::from_ref(session), + } + } + + pub fn new( + global: &GlobalScope, + session: &XRSession, + context: &WebGLRenderingContext, + init: &XRWebGLLayerInit, + ) -> DomRoot<XRWebGLLayer> { + reflect_dom_object( + Box::new(XRWebGLLayer::new_inherited(session, context, init)), + global, + XRWebGLLayerBinding::Wrap, + ) + } + + pub fn Constructor( + global: &Window, + session: &XRSession, + context: &WebGLRenderingContext, + init: &XRWebGLLayerInit, + ) -> Fallible<DomRoot<Self>> { + Ok(XRWebGLLayer::new(&global.global(), session, context, init)) + } +} + +impl XRWebGLLayerMethods for XRWebGLLayer { + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-depth + fn Depth(&self) -> bool { + self.depth + } + + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-stencil + fn Stencil(&self) -> bool { + self.stencil + } + + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-antialias + fn Antialias(&self) -> bool { + self.antialias + } + + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-alpha + fn Alpha(&self) -> bool { + self.alpha + } + + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-context + fn Context(&self) -> DomRoot<WebGLRenderingContext> { + DomRoot::from_ref(&self.context) + } + + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport + fn GetViewport(&self, view: &XRView) -> Option<DomRoot<XRViewport>> { + if self.session != view.session() { + return None; + } + + let size = self.context.size(); + + let x = if view.Eye() == XREye::Left { + 0 + } else { + size.width / 2 + }; + // XXXManishearth this assumes the WebVR default of canvases being cut in half + // which need not be generally true for all devices, and will not work in + // inline VR mode + Some(XRViewport::new( + &self.global(), + x, + 0, + size.width / 2, + size.height, + )) + } +} diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 64cbd0af672..6114e353d97 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -24,6 +24,7 @@ use crate::dom::bindings::codegen::Bindings::DocumentBinding::{ DocumentMethods, DocumentReadyState, }; use crate::dom::bindings::codegen::Bindings::EventBinding::EventInit; +use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods; use crate::dom::bindings::codegen::Bindings::TransitionEventBinding::TransitionEventInit; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::conversions::{ @@ -3320,8 +3321,8 @@ impl ScriptThread { fn handle_webvr_events(&self, pipeline_id: PipelineId, events: Vec<WebVREvent>) { let window = self.documents.borrow().find_window(pipeline_id); if let Some(window) = window { - let vr = window.Navigator().Vr(); - vr.handle_webvr_events(events); + let xr = window.Navigator().Xr(); + xr.handle_webvr_events(events); } } diff --git a/python/tidy/servo_tidy/tidy.py b/python/tidy/servo_tidy/tidy.py index deb86e289c2..a8c4246ce09 100644 --- a/python/tidy/servo_tidy/tidy.py +++ b/python/tidy/servo_tidy/tidy.py @@ -95,6 +95,7 @@ WEBIDL_STANDARDS = [ "//svgwg.org/svg2-draft", "//wicg.github.io", "//webaudio.github.io", + "//immersive-web.github.io/", # Not a URL "// This interface is entirely internal to Servo, and should not be" + " accessible to\n// web pages." diff --git a/resources/package-prefs.json b/resources/package-prefs.json index 7a64a1f1531..d419d7e4586 100644 --- a/resources/package-prefs.json +++ b/resources/package-prefs.json @@ -7,6 +7,7 @@ "windows": {}, "vr": { "_comment": "settings specific to VR builds", - "dom.webvr.enabled": true + "dom.webvr.enabled": true, + "dom.webxr.enabled": true } } |