Auto merge of #22528 - Manishearth:webxr, r=jdm,MortimerGoro

Preliminary WebXR support

This implements just enough WebXR to display to 3DOF devices in
immersive mode only.

Couple missing things:

 - [ ] Handling reference spaces (even if just supporting eye-level spaces)
 - [x] Spec links
 - [ ] We enter immersive mode when baseLayer is set, but it seems like
we're supposed to do this when requestSession is called (https://github.com/immersive-web/webxr/issues/453)
 - [ ] VR/XR should block less (https://github.com/servo/servo/issues/22505)
 - [x] More pref-gating
 - [x] `views` is a method instead of an attribute because we don't support FrozenArray

<s>Once I add spec links and pref gating</s> this can be landed as-is for further experimentation.

r? @jdm @MortimerGoro

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/22528)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-01-04 02:54:16 -05:00 committed by GitHub
commit c4a6dcfe4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 1092 additions and 71 deletions

View file

@ -479,7 +479,6 @@ pub mod validation;
pub mod validitystate; pub mod validitystate;
pub mod values; pub mod values;
pub mod virtualmethods; pub mod virtualmethods;
pub mod vr;
pub mod vrdisplay; pub mod vrdisplay;
pub mod vrdisplaycapabilities; pub mod vrdisplaycapabilities;
pub mod vrdisplayevent; pub mod vrdisplayevent;
@ -518,3 +517,15 @@ pub mod xmldocument;
pub mod xmlhttprequest; pub mod xmlhttprequest;
pub mod xmlhttprequesteventtarget; pub mod xmlhttprequesteventtarget;
pub mod xmlhttprequestupload; 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;

View file

@ -4,7 +4,7 @@
use crate::dom::bindings::codegen::Bindings::NavigatorBinding; use crate::dom::bindings::codegen::Bindings::NavigatorBinding;
use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods; 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::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{DomRoot, MutNullableDom}; use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
@ -16,8 +16,8 @@ use crate::dom::permissions::Permissions;
use crate::dom::pluginarray::PluginArray; use crate::dom::pluginarray::PluginArray;
use crate::dom::promise::Promise; use crate::dom::promise::Promise;
use crate::dom::serviceworkercontainer::ServiceWorkerContainer; use crate::dom::serviceworkercontainer::ServiceWorkerContainer;
use crate::dom::vr::VR;
use crate::dom::window::Window; use crate::dom::window::Window;
use crate::dom::xr::XR;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use std::rc::Rc; use std::rc::Rc;
@ -28,7 +28,7 @@ pub struct Navigator {
plugins: MutNullableDom<PluginArray>, plugins: MutNullableDom<PluginArray>,
mime_types: MutNullableDom<MimeTypeArray>, mime_types: MutNullableDom<MimeTypeArray>,
service_worker: MutNullableDom<ServiceWorkerContainer>, service_worker: MutNullableDom<ServiceWorkerContainer>,
vr: MutNullableDom<VR>, xr: MutNullableDom<XR>,
gamepads: MutNullableDom<GamepadList>, gamepads: MutNullableDom<GamepadList>,
permissions: MutNullableDom<Permissions>, permissions: MutNullableDom<Permissions>,
} }
@ -41,7 +41,7 @@ impl Navigator {
plugins: Default::default(), plugins: Default::default(),
mime_types: Default::default(), mime_types: Default::default(),
service_worker: Default::default(), service_worker: Default::default(),
vr: Default::default(), xr: Default::default(),
gamepads: Default::default(), gamepads: Default::default(),
permissions: Default::default(), permissions: Default::default(),
} }
@ -135,7 +135,7 @@ impl NavigatorMethods for Navigator {
.gamepads .gamepads
.or_init(|| GamepadList::new(&self.global(), &[])); .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); root.add_if_not_exists(&vr_gamepads);
// TODO: Add not VR related gamepads // TODO: Add not VR related gamepads
root root
@ -149,12 +149,17 @@ impl NavigatorMethods for Navigator {
// https://w3c.github.io/webvr/spec/1.1/#navigator-getvrdisplays-attribute // https://w3c.github.io/webvr/spec/1.1/#navigator-getvrdisplays-attribute
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
fn GetVRDisplays(&self) -> Rc<Promise> { 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 { /// https://immersive-web.github.io/webxr/#dom-navigator-xr
pub fn Vr(&self) -> DomRoot<VR> { fn Xr(&self) -> DomRoot<XR> {
self.vr.or_init(|| VR::new(&self.global())) self.xr.or_init(|| XR::new(&self.global()))
} }
} }

View file

@ -4,14 +4,15 @@
use crate::dom::bindings::callback::ExceptionHandling; use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::cell::DomRefCell; 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;
use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods; use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods;
use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VREye; use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VREye;
use crate::dom::bindings::codegen::Bindings::VRLayerBinding::VRLayer; use crate::dom::bindings::codegen::Bindings::VRLayerBinding::VRLayer;
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods;
use crate::dom::bindings::codegen::Bindings::WindowBinding::FrameRequestCallback; 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::inheritance::Castable;
use crate::dom::bindings::num::Finite; use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::Trusted; use crate::dom::bindings::refcounted::Trusted;
@ -29,6 +30,8 @@ use crate::dom::vrframedata::VRFrameData;
use crate::dom::vrpose::VRPose; use crate::dom::vrpose::VRPose;
use crate::dom::vrstageparameters::VRStageParameters; use crate::dom::vrstageparameters::VRStageParameters;
use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::webglrenderingcontext::WebGLRenderingContext;
use crate::dom::xrframe::XRFrame;
use crate::dom::xrsession::XRSession;
use crate::script_runtime::CommonScriptMsg; use crate::script_runtime::CommonScriptMsg;
use crate::script_runtime::ScriptThreadEventCategory::WebVREvent; use crate::script_runtime::ScriptThreadEventCategory::WebVREvent;
use crate::task_source::TaskSourceName; use crate::task_source::TaskSourceName;
@ -67,6 +70,8 @@ pub struct VRDisplay {
/// List of request animation frame callbacks /// List of request animation frame callbacks
#[ignore_malloc_size_of = "closures are hard"] #[ignore_malloc_size_of = "closures are hard"]
raf_callback_list: DomRefCell<Vec<(u32, Option<Rc<FrameRequestCallback>>)>>, 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 // Compositor VRFrameData synchonization
frame_data_status: Cell<VRFrameDataStatus>, frame_data_status: Cell<VRFrameDataStatus>,
#[ignore_malloc_size_of = "closures are hard"] #[ignore_malloc_size_of = "closures are hard"]
@ -74,6 +79,8 @@ pub struct VRDisplay {
running_display_raf: Cell<bool>, running_display_raf: Cell<bool>,
paused: Cell<bool>, paused: Cell<bool>,
stopped_on_pause: 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); unsafe_no_jsmanaged_fields!(WebVRDisplayData);
@ -120,6 +127,7 @@ impl VRDisplay {
layer_ctx: MutNullableDom::default(), layer_ctx: MutNullableDom::default(),
next_raf_id: Cell::new(1), next_raf_id: Cell::new(1),
raf_callback_list: DomRefCell::new(vec![]), raf_callback_list: DomRefCell::new(vec![]),
xr_raf_callback_list: DomRefCell::new(vec![]),
frame_data_status: Cell::new(VRFrameDataStatus::Waiting), frame_data_status: Cell::new(VRFrameDataStatus::Waiting),
frame_data_receiver: DomRefCell::new(None), frame_data_receiver: DomRefCell::new(None),
running_display_raf: Cell::new(false), 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. // 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. // When the VR Resume event is received and the flag is set, VR presentation automatically restarts.
stopped_on_pause: Cell::new(false), stopped_on_pause: Cell::new(false),
xr_session: MutNullableDom::default(),
} }
} }
@ -624,11 +633,27 @@ impl VRDisplay {
fn handle_raf(&self, end_sender: &Sender<Result<(f64, f64), ()>>) { fn handle_raf(&self, end_sender: &Sender<Result<(f64, f64), ()>>) {
self.frame_data_status.set(VRFrameDataStatus::Waiting); 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(); let now = self.global().as_window().Performance().Now();
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.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. // Call registered VRDisplay.requestAnimationFrame callbacks.
for (_, callback) in callbacks.drain(..) { for (_, callback) in callbacks.drain(..) {
if let Some(callback) = callback { if let Some(callback) = callback {
@ -644,6 +669,7 @@ impl VRDisplay {
warn!("WebVR: You should call GetFrameData while presenting"); warn!("WebVR: You should call GetFrameData while presenting");
self.sync_frame_data(); self.sync_frame_data();
} }
}
match self.frame_data_status.get() { match self.frame_data_status.get() {
VRFrameDataStatus::Synced => { VRFrameDataStatus::Synced => {
@ -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 // 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 // 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> { fn parse_bounds(src: &Option<Vec<Finite<f32>>>, dst: &mut [f32; 4]) -> Result<(), &'static str> {

View file

@ -71,8 +71,9 @@ impl VRFrameData {
} }
} }
/// FIXME(#22526) this should be in a better place
#[allow(unsafe_code)] #[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>()); rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
unsafe { unsafe {
let _ = Float32Array::create(cx, CreateWith::Slice(src), array.handle_mut()); let _ = Float32Array::create(cx, CreateWith::Slice(src), array.handle_mut());

View file

@ -157,6 +157,7 @@ pub struct WebGLRenderingContext {
current_scissor: Cell<(i32, i32, u32, u32)>, current_scissor: Cell<(i32, i32, u32, u32)>,
#[ignore_malloc_size_of = "Because it's small"] #[ignore_malloc_size_of = "Because it's small"]
current_clear_color: Cell<(f32, f32, f32, f32)>, current_clear_color: Cell<(f32, f32, f32, f32)>,
size: Cell<Size2D<u32>>,
extension_manager: WebGLExtensions, extension_manager: WebGLExtensions,
capabilities: Capabilities, capabilities: Capabilities,
default_vao: DomOnceCell<WebGLVertexArrayObjectOES>, default_vao: DomOnceCell<WebGLVertexArrayObjectOES>,
@ -211,6 +212,9 @@ impl WebGLRenderingContext {
current_program: MutNullableDom::new(None), current_program: MutNullableDom::new(None),
current_vertex_attrib_0: Cell::new((0f32, 0f32, 0f32, 1f32)), current_vertex_attrib_0: Cell::new((0f32, 0f32, 0f32, 1f32)),
current_scissor: Cell::new((0, 0, size.width, size.height)), 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)), current_clear_color: Cell::new((0.0, 0.0, 0.0, 0.0)),
extension_manager: WebGLExtensions::new(webgl_version), extension_manager: WebGLExtensions::new(webgl_version),
capabilities: Default::default(), capabilities: Default::default(),
@ -266,6 +270,9 @@ impl WebGLRenderingContext {
pub fn recreate(&self, size: Size2D<u32>) { pub fn recreate(&self, size: Size2D<u32>) {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
self.webgl_sender.send_resize(size, sender).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() { if let Err(msg) = receiver.recv().unwrap() {
error!("Error resizing WebGLContext: {}", msg); 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 // Helper function for validating framebuffer completeness in
// calls touching the framebuffer. From the GLES 2.0.25 spec, // calls touching the framebuffer. From the GLES 2.0.25 spec,
// page 119: // page 119:

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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);
};

View file

@ -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 {};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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);
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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);
};

View file

@ -3,12 +3,13 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::cell::DomRefCell; 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::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::error::Error;
use crate::dom::bindings::inheritance::Castable; 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::bindings::root::{Dom, DomRoot};
use crate::dom::event::Event; use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
@ -18,6 +19,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise; use crate::dom::promise::Promise;
use crate::dom::vrdisplay::VRDisplay; use crate::dom::vrdisplay::VRDisplay;
use crate::dom::vrdisplayevent::VRDisplayEvent; use crate::dom::vrdisplayevent::VRDisplayEvent;
use crate::dom::xrsession::XRSession;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use profile_traits::ipc; use profile_traits::ipc;
@ -26,44 +28,91 @@ use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVREvent, WebVRMsg};
use webvr_traits::{WebVRGamepadData, WebVRGamepadEvent, WebVRGamepadState}; use webvr_traits::{WebVRGamepadData, WebVRGamepadEvent, WebVRGamepadState};
#[dom_struct] #[dom_struct]
pub struct VR { pub struct XR {
reflector_: Reflector, eventtarget: EventTarget,
displays: DomRefCell<Vec<Dom<VRDisplay>>>, displays: DomRefCell<Vec<Dom<VRDisplay>>>,
gamepads: DomRefCell<Vec<Dom<Gamepad>>>, gamepads: DomRefCell<Vec<Dom<Gamepad>>>,
} }
impl VR { impl XR {
fn new_inherited() -> VR { fn new_inherited() -> XR {
VR { XR {
reflector_: Reflector::new(), eventtarget: EventTarget::new_inherited(),
displays: DomRefCell::new(Vec::new()), displays: DomRefCell::new(Vec::new()),
gamepads: DomRefCell::new(Vec::new()), gamepads: DomRefCell::new(Vec::new()),
} }
} }
pub fn new(global: &GlobalScope) -> DomRoot<VR> { pub fn new(global: &GlobalScope) -> DomRoot<XR> {
let root = reflect_dom_object(Box::new(VR::new_inherited()), global, VRBinding::Wrap); let root = reflect_dom_object(Box::new(XR::new_inherited()), global, XRBinding::Wrap);
root.register(); root.register();
root root
} }
} }
impl Drop for VR { impl Drop for XR {
fn drop(&mut self) { fn drop(&mut self) {
self.unregister(); self.unregister();
} }
} }
impl VRMethods for VR { impl XRMethods for XR {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
// https://w3c.github.io/webvr/#interface-navigator /// https://immersive-web.github.io/webxr/#dom-xr-supportssessionmode
fn GetDisplays(&self) -> Rc<Promise> { fn SupportsSessionMode(&self, mode: XRSessionMode) -> Rc<Promise> {
// XXXManishearth this should select an XR device first
let promise = Promise::new(&self.global()); 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() { if let Some(webvr_thread) = self.webvr_thread() {
let (sender, receiver) = let (sender, receiver) =
ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
webvr_thread.send(WebVRMsg::GetDisplays(sender)).unwrap(); webvr_thread.send(WebVRMsg::GetDisplays(sender)).unwrap();
// FIXME(#22505) we should not block here and instead produce a promise
match receiver.recv().unwrap() { match receiver.recv().unwrap() {
Ok(displays) => { Ok(displays) => {
// Sync displays // Sync displays
@ -71,31 +120,22 @@ impl VRMethods for VR {
self.sync_display(&display); self.sync_display(&display);
} }
}, },
Err(e) => { Err(_) => return Err(()),
promise.reject_native(&e);
return promise;
},
} }
} else { } else {
// WebVR spec: The Promise MUST be rejected if WebVR is not enabled/supported. // WebVR spec: The Promise MUST be rejected if WebVR is not enabled/supported.
promise.reject_error(Error::Security); return Err(());
return promise;
} }
// convert from Dom to DomRoot // convert from Dom to DomRoot
let displays: Vec<DomRoot<VRDisplay>> = self Ok(self
.displays .displays
.borrow() .borrow()
.iter() .iter()
.map(|d| DomRoot::from_ref(&**d)) .map(|d| DomRoot::from_ref(&**d))
.collect(); .collect())
promise.resolve_native(&displays);
promise
}
} }
impl VR {
fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> { fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> {
self.global().as_window().webvr_thread() self.global().as_window().webvr_thread()
} }
@ -209,7 +249,7 @@ impl VR {
} }
// Gamepad // Gamepad
impl VR { impl XR {
fn find_gamepad(&self, gamepad_id: u32) -> Option<DomRoot<Gamepad>> { fn find_gamepad(&self, gamepad_id: u32) -> Option<DomRoot<Gamepad>> {
self.gamepads self.gamepads
.borrow() .borrow()

View file

@ -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))
}
}

View file

@ -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(),
}
}
}

View file

@ -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,
)
}
}

View file

@ -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,
)
}
}

View file

@ -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)
}
}

View file

@ -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,
)
}
}

View file

@ -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,
)
}
}

View file

@ -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()
}
}

View file

@ -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()
}
}

View file

@ -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
}
}

View file

@ -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,
))
}
}

View file

@ -24,6 +24,7 @@ use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
DocumentMethods, DocumentReadyState, DocumentMethods, DocumentReadyState,
}; };
use crate::dom::bindings::codegen::Bindings::EventBinding::EventInit; 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::TransitionEventBinding::TransitionEventInit;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use crate::dom::bindings::conversions::{ use crate::dom::bindings::conversions::{
@ -3320,8 +3321,8 @@ impl ScriptThread {
fn handle_webvr_events(&self, pipeline_id: PipelineId, events: Vec<WebVREvent>) { fn handle_webvr_events(&self, pipeline_id: PipelineId, events: Vec<WebVREvent>) {
let window = self.documents.borrow().find_window(pipeline_id); let window = self.documents.borrow().find_window(pipeline_id);
if let Some(window) = window { if let Some(window) = window {
let vr = window.Navigator().Vr(); let xr = window.Navigator().Xr();
vr.handle_webvr_events(events); xr.handle_webvr_events(events);
} }
} }

View file

@ -95,6 +95,7 @@ WEBIDL_STANDARDS = [
"//svgwg.org/svg2-draft", "//svgwg.org/svg2-draft",
"//wicg.github.io", "//wicg.github.io",
"//webaudio.github.io", "//webaudio.github.io",
"//immersive-web.github.io/",
# Not a URL # Not a URL
"// This interface is entirely internal to Servo, and should not be" + "// This interface is entirely internal to Servo, and should not be" +
" accessible to\n// web pages." " accessible to\n// web pages."

View file

@ -7,6 +7,7 @@
"windows": {}, "windows": {},
"vr": { "vr": {
"_comment": "settings specific to VR builds", "_comment": "settings specific to VR builds",
"dom.webvr.enabled": true "dom.webvr.enabled": true,
"dom.webxr.enabled": true
} }
} }