aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/mod.rs13
-rw-r--r--components/script/dom/navigator.rs25
-rw-r--r--components/script/dom/vrdisplay.rs104
-rw-r--r--components/script/dom/vrframedata.rs3
-rw-r--r--components/script/dom/webglrenderingcontext.rs11
-rw-r--r--components/script/dom/webidls/VR.webidl11
-rw-r--r--components/script/dom/webidls/XR.webidl30
-rw-r--r--components/script/dom/webidls/XRFrame.webidl13
-rw-r--r--components/script/dom/webidls/XRLayer.webidl8
-rw-r--r--components/script/dom/webidls/XRReferenceSpace.webidl21
-rw-r--r--components/script/dom/webidls/XRRigidTransform.webidl13
-rw-r--r--components/script/dom/webidls/XRSession.webidl45
-rw-r--r--components/script/dom/webidls/XRSpace.webidl10
-rw-r--r--components/script/dom/webidls/XRStationaryReferenceSpace.webidl20
-rw-r--r--components/script/dom/webidls/XRView.webidl18
-rw-r--r--components/script/dom/webidls/XRViewerPose.webidl14
-rw-r--r--components/script/dom/webidls/XRViewport.webidl13
-rw-r--r--components/script/dom/webidls/XRWebGLLayer.webidl43
-rw-r--r--components/script/dom/xr.rs (renamed from components/script/dom/vr.rs)98
-rw-r--r--components/script/dom/xrframe.rs67
-rw-r--r--components/script/dom/xrlayer.rs19
-rw-r--r--components/script/dom/xrreferencespace.rs32
-rw-r--r--components/script/dom/xrrigidtransform.rs31
-rw-r--r--components/script/dom/xrsession.rs100
-rw-r--r--components/script/dom/xrspace.rs32
-rw-r--r--components/script/dom/xrstationaryreferencespace.rs32
-rw-r--r--components/script/dom/xrview.rs83
-rw-r--r--components/script/dom/xrviewerpose.rs56
-rw-r--r--components/script/dom/xrviewport.rs67
-rw-r--r--components/script/dom/xrwebgllayer.rs122
-rw-r--r--components/script/script_thread.rs5
-rw-r--r--python/tidy/servo_tidy/tidy.py1
-rw-r--r--resources/package-prefs.json3
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
}
}