mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
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:
commit
c4a6dcfe4b
33 changed files with 1092 additions and 71 deletions
|
@ -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;
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,11 +633,27 @@ 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();
|
||||
|
||||
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.
|
||||
for (_, callback) in callbacks.drain(..) {
|
||||
if let Some(callback) = callback {
|
||||
|
@ -644,6 +669,7 @@ impl VRDisplay {
|
|||
warn!("WebVR: You should call GetFrameData while presenting");
|
||||
self.sync_frame_data();
|
||||
}
|
||||
}
|
||||
|
||||
match self.frame_data_status.get() {
|
||||
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
|
||||
// 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> {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
};
|
30
components/script/dom/webidls/XR.webidl
Normal file
30
components/script/dom/webidls/XR.webidl
Normal 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;
|
||||
};
|
13
components/script/dom/webidls/XRFrame.webidl
Normal file
13
components/script/dom/webidls/XRFrame.webidl
Normal 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);
|
||||
};
|
8
components/script/dom/webidls/XRLayer.webidl
Normal file
8
components/script/dom/webidls/XRLayer.webidl
Normal 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 {};
|
21
components/script/dom/webidls/XRReferenceSpace.webidl
Normal file
21
components/script/dom/webidls/XRReferenceSpace.webidl
Normal 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;
|
||||
};
|
13
components/script/dom/webidls/XRRigidTransform.webidl
Normal file
13
components/script/dom/webidls/XRRigidTransform.webidl
Normal 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;
|
||||
};
|
45
components/script/dom/webidls/XRSession.webidl
Normal file
45
components/script/dom/webidls/XRSession.webidl
Normal 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;
|
||||
};
|
10
components/script/dom/webidls/XRSpace.webidl
Normal file
10
components/script/dom/webidls/XRSpace.webidl
Normal 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);
|
||||
};
|
|
@ -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;
|
||||
};
|
18
components/script/dom/webidls/XRView.webidl
Normal file
18
components/script/dom/webidls/XRView.webidl
Normal 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;
|
||||
};
|
14
components/script/dom/webidls/XRViewerPose.webidl
Normal file
14
components/script/dom/webidls/XRViewerPose.webidl
Normal 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;
|
||||
};
|
13
components/script/dom/webidls/XRViewport.webidl
Normal file
13
components/script/dom/webidls/XRViewport.webidl
Normal 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;
|
||||
};
|
43
components/script/dom/webidls/XRWebGLLayer.webidl
Normal file
43
components/script/dom/webidls/XRWebGLLayer.webidl
Normal 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);
|
||||
};
|
|
@ -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()
|
67
components/script/dom/xrframe.rs
Normal file
67
components/script/dom/xrframe.rs
Normal 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))
|
||||
}
|
||||
}
|
19
components/script/dom/xrlayer.rs
Normal file
19
components/script/dom/xrlayer.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
32
components/script/dom/xrreferencespace.rs
Normal file
32
components/script/dom/xrreferencespace.rs
Normal 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,
|
||||
)
|
||||
}
|
||||
}
|
31
components/script/dom/xrrigidtransform.rs
Normal file
31
components/script/dom/xrrigidtransform.rs
Normal 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,
|
||||
)
|
||||
}
|
||||
}
|
100
components/script/dom/xrsession.rs
Normal file
100
components/script/dom/xrsession.rs
Normal 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)
|
||||
}
|
||||
}
|
32
components/script/dom/xrspace.rs
Normal file
32
components/script/dom/xrspace.rs
Normal 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,
|
||||
)
|
||||
}
|
||||
}
|
32
components/script/dom/xrstationaryreferencespace.rs
Normal file
32
components/script/dom/xrstationaryreferencespace.rs
Normal 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,
|
||||
)
|
||||
}
|
||||
}
|
83
components/script/dom/xrview.rs
Normal file
83
components/script/dom/xrview.rs
Normal 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()
|
||||
}
|
||||
}
|
56
components/script/dom/xrviewerpose.rs
Normal file
56
components/script/dom/xrviewerpose.rs
Normal 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()
|
||||
}
|
||||
}
|
67
components/script/dom/xrviewport.rs
Normal file
67
components/script/dom/xrviewport.rs
Normal 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
|
||||
}
|
||||
}
|
122
components/script/dom/xrwebgllayer.rs
Normal file
122
components/script/dom/xrwebgllayer.rs
Normal 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,
|
||||
))
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"windows": {},
|
||||
"vr": {
|
||||
"_comment": "settings specific to VR builds",
|
||||
"dom.webvr.enabled": true
|
||||
"dom.webvr.enabled": true,
|
||||
"dom.webxr.enabled": true
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue