diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2019-05-30 22:04:22 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-30 22:04:22 -0400 |
commit | 7c8a4ecead45d576bec3aaba02a13d8f21434eb4 (patch) | |
tree | 30371c01567eadc86858796c438ab3304e3987bc /components/script/dom | |
parent | a5506365d6f1e8a75db7e7fa2f9e0b1ef73972ee (diff) | |
parent | c2d4900c1616cb7acfd21a7ae7a5d1d134c085f9 (diff) | |
download | servo-7c8a4ecead45d576bec3aaba02a13d8f21434eb4.tar.gz servo-7c8a4ecead45d576bec3aaba02a13d8f21434eb4.zip |
Auto merge of #23485 - Manishearth:xrtest, r=asajeffrey
Basic XR Testing support
This adds support for the XRTest and FakeXRDeviceController APIs from https://github.com/immersive-web/webxr-test-api, and plugs them into the `mock` backend of rust-webvr.
Tested with [a modified webxr test page](https://github.com/immersive-web/webxr-test-api)
r? @jdm @asajeffrey
<!-- 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/23485)
<!-- Reviewable:end -->
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/fakexrdevicecontroller.rs | 104 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 2 | ||||
-rw-r--r-- | components/script/dom/webidls/FakeXRDeviceController.webidl | 49 | ||||
-rw-r--r-- | components/script/dom/webidls/XR.webidl | 5 | ||||
-rw-r--r-- | components/script/dom/webidls/XRTest.webidl | 25 | ||||
-rw-r--r-- | components/script/dom/xr.rs | 8 | ||||
-rw-r--r-- | components/script/dom/xrspace.rs | 3 | ||||
-rw-r--r-- | components/script/dom/xrtest.rs | 66 |
8 files changed, 261 insertions, 1 deletions
diff --git a/components/script/dom/fakexrdevicecontroller.rs b/components/script/dom/fakexrdevicecontroller.rs new file mode 100644 index 00000000000..3d051283155 --- /dev/null +++ b/components/script/dom/fakexrdevicecontroller.rs @@ -0,0 +1,104 @@ +/* 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/. */ + +/* 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::FakeXRDeviceControllerBinding::{ + self, FakeXRDeviceControllerMethods, FakeXRRigidTransform, FakeXRViewInit, +}; +use crate::dom::bindings::codegen::Bindings::XRViewBinding::XREye; +use crate::dom::bindings::error::{Error, Fallible}; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::globalscope::GlobalScope; +use dom_struct::dom_struct; +use webvr_traits::{MockVRControlMsg, WebVREyeParameters, WebVRMsg}; + +#[dom_struct] +pub struct FakeXRDeviceController { + reflector: Reflector, +} + +impl FakeXRDeviceController { + pub fn new_inherited() -> FakeXRDeviceController { + FakeXRDeviceController { + reflector: Reflector::new(), + } + } + + pub fn new(global: &GlobalScope) -> DomRoot<FakeXRDeviceController> { + reflect_dom_object( + Box::new(FakeXRDeviceController::new_inherited()), + global, + FakeXRDeviceControllerBinding::Wrap, + ) + } + + pub fn send_msg(&self, msg: MockVRControlMsg) { + self.global() + .as_window() + .webvr_thread() + .unwrap() + .send(WebVRMsg::MessageMockDisplay(msg)) + .unwrap(); + } +} + +impl FakeXRDeviceControllerMethods for FakeXRDeviceController { + /// https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md + fn SetViews(&self, views: Vec<FakeXRViewInit>) -> Fallible<()> { + if views.len() != 2 { + return Err(Error::NotSupported); + } + + let (left, right) = match (views[0].eye, views[1].eye) { + (XREye::Left, XREye::Right) => (&views[0], &views[1]), + (XREye::Right, XREye::Left) => (&views[1], &views[0]), + _ => return Err(Error::NotSupported), + }; + + if left.projectionMatrix.len() != 16 || + right.projectionMatrix.len() != 16 || + left.viewOffset.position.len() != 4 || + right.viewOffset.position.len() != 4 + { + return Err(Error::Type("Incorrectly sized array".into())); + } + + let mut proj_l = [0.; 16]; + let mut proj_r = [0.; 16]; + let v: Vec<_> = left.projectionMatrix.iter().map(|x| **x).collect(); + proj_l.copy_from_slice(&v); + let v: Vec<_> = right.projectionMatrix.iter().map(|x| **x).collect(); + proj_r.copy_from_slice(&v); + + let mut params_l = WebVREyeParameters::default(); + let mut params_r = WebVREyeParameters::default(); + let v: Vec<_> = left.viewOffset.position.iter().map(|x| **x).collect(); + params_l.offset.copy_from_slice(&v); + let v: Vec<_> = right.viewOffset.position.iter().map(|x| **x).collect(); + params_r.offset.copy_from_slice(&v); + + self.send_msg(MockVRControlMsg::SetProjectionMatrices(proj_l, proj_r)); + self.send_msg(MockVRControlMsg::SetEyeParameters(params_l, params_r)); + Ok(()) + } + + /// https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md + fn SetViewerOrigin(&self, origin: &FakeXRRigidTransform) -> Fallible<()> { + if origin.position.len() != 4 || origin.orientation.len() != 4 { + return Err(Error::Type("Incorrectly sized array".into())); + } + let mut position = [0.; 3]; + let mut orientation = [0.; 4]; + let v: Vec<_> = origin.position.iter().map(|x| **x).collect(); + position.copy_from_slice(&v[0..3]); + let v: Vec<_> = origin.orientation.iter().map(|x| **x).collect(); + orientation.copy_from_slice(&v); + self.send_msg(MockVRControlMsg::SetViewerPose(position, orientation)); + Ok(()) + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 1dbc1383101..cf8d8a49389 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -301,6 +301,7 @@ pub mod eventsource; pub mod eventtarget; pub mod extendableevent; pub mod extendablemessageevent; +pub mod fakexrdevicecontroller; pub mod file; pub mod filelist; pub mod filereader; @@ -551,6 +552,7 @@ pub mod xrrigidtransform; pub mod xrsession; pub mod xrspace; pub mod xrstationaryreferencespace; +pub mod xrtest; pub mod xrview; pub mod xrviewerpose; pub mod xrviewport; diff --git a/components/script/dom/webidls/FakeXRDeviceController.webidl b/components/script/dom/webidls/FakeXRDeviceController.webidl new file mode 100644 index 00000000000..cacdb2f9819 --- /dev/null +++ b/components/script/dom/webidls/FakeXRDeviceController.webidl @@ -0,0 +1,49 @@ +/* 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://github.com/immersive-web/webxr-test-api/ + +[Exposed=Window, Pref="dom.webxr.test"] +interface FakeXRDeviceController { + // Creates and attaches a XRFrameOfReference of the type specified to the device. + // void setFrameOfReference(XRFrameOfReferenceType, FakeXRFrameOfReferenceInit); + + // // Sets the values to be used for subsequent + // // requestAnimationFrame() callbacks. + [Throws] void setViews(sequence<FakeXRViewInit> views); + + [Throws] void setViewerOrigin(FakeXRRigidTransform origin); + + // Simulates the user activating the reset pose on a device. + // void simulateResetPose(); + + // Simulates the platform ending the sessions. + // void simulateForcedEndSessions(); + + // Simulates devices focusing and blurring sessions. + // void simulateBlurSession(XRSession); + // void simulateFocusSession(XRSession); + + // void setBoundsGeometry(Array<FakeXRBoundsPoint> boundsCoodinates)l + + // Promise<FakeXRInputSourceController> + // simulateInputSourceConnection(FakeXRInputSourceInit); +}; + +dictionary FakeXRViewInit { + required XREye eye; + // https://immersive-web.github.io/webxr/#view-projection-matrix + required sequence<float> projectionMatrix; + // https://immersive-web.github.io/webxr/#view-offset + required FakeXRRigidTransform viewOffset; +}; + +dictionary FakeXRBoundsPoint { + double x; double z; +}; + +dictionary FakeXRRigidTransform { + required sequence<float> position; + required sequence<float> orientation; +}; diff --git a/components/script/dom/webidls/XR.webidl b/components/script/dom/webidls/XR.webidl index 4a6bca26a69..58732edd42b 100644 --- a/components/script/dom/webidls/XR.webidl +++ b/components/script/dom/webidls/XR.webidl @@ -28,3 +28,8 @@ dictionary XRSessionCreationOptions { XRSessionMode mode = "inline"; // XRPresentationContext outputContext; }; + +partial interface XR { + // https://github.com/immersive-web/webxr-test-api/ + [SameObject, Pref="dom.webxr.test"] readonly attribute XRTest test; +}; diff --git a/components/script/dom/webidls/XRTest.webidl b/components/script/dom/webidls/XRTest.webidl new file mode 100644 index 00000000000..30c485321d4 --- /dev/null +++ b/components/script/dom/webidls/XRTest.webidl @@ -0,0 +1,25 @@ +/* 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://github.com/immersive-web/webxr-test-api/ + +[Exposed=Window, Pref="dom.webxr.test"] +interface XRTest { + // Simulates connecting a device to the system. + // Used to instantiate a fake device for use in tests. + Promise<FakeXRDeviceController> simulateDeviceConnection(FakeXRDeviceInit init); + + // // Simulates a device being disconnected from the system. + // Promise<void> simulateDeviceDisconnection(XRDevice); + + // // Simulates a user activation (aka user gesture) for the current scope. + // // The activation is only guaranteed to be valid in the provided function and only applies to WebXR + // // Device API methods. + // void simulateUserActivation(Function); +}; + +dictionary FakeXRDeviceInit { + // TODO: Subject to change to match spec changes. + required boolean supportsImmersive; +}; diff --git a/components/script/dom/xr.rs b/components/script/dom/xr.rs index 3ff67b0042c..1626ad4e00e 100644 --- a/components/script/dom/xr.rs +++ b/components/script/dom/xr.rs @@ -21,6 +21,7 @@ use crate::dom::promise::Promise; use crate::dom::vrdisplay::VRDisplay; use crate::dom::vrdisplayevent::VRDisplayEvent; use crate::dom::xrsession::XRSession; +use crate::dom::xrtest::XRTest; use dom_struct::dom_struct; use ipc_channel::ipc::IpcSender; use profile_traits::ipc; @@ -36,6 +37,7 @@ pub struct XR { gamepads: DomRefCell<Vec<Dom<Gamepad>>>, pending_immersive_session: Cell<bool>, active_immersive_session: MutNullableDom<VRDisplay>, + test: MutNullableDom<XRTest>, } impl XR { @@ -46,6 +48,7 @@ impl XR { gamepads: DomRefCell::new(Vec::new()), pending_immersive_session: Cell::new(false), active_immersive_session: Default::default(), + test: Default::default(), } } @@ -141,6 +144,11 @@ impl XRMethods for XR { session.xr_present(promise.clone()); promise } + + // https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md + fn Test(&self) -> DomRoot<XRTest> { + self.test.or_init(|| XRTest::new(&self.global())) + } } impl XR { diff --git a/components/script/dom/xrspace.rs b/components/script/dom/xrspace.rs index 30f9246c354..171c0621dc8 100644 --- a/components/script/dom/xrspace.rs +++ b/components/script/dom/xrspace.rs @@ -99,7 +99,8 @@ impl XRSpace { orient[1] as f64, orient[2] as f64, orient[3] as f64, - ); + ) + .normalize(); RigidTransform3D::new(rotation, translation) } diff --git a/components/script/dom/xrtest.rs b/components/script/dom/xrtest.rs new file mode 100644 index 00000000000..07fac9d6a89 --- /dev/null +++ b/components/script/dom/xrtest.rs @@ -0,0 +1,66 @@ +/* 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/. */ + +/* 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::XRTestBinding::{ + self, FakeXRDeviceInit, XRTestMethods, +}; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::fakexrdevicecontroller::FakeXRDeviceController; +use crate::dom::globalscope::GlobalScope; +use crate::dom::promise::Promise; +use dom_struct::dom_struct; +use std::cell::Cell; +use std::rc::Rc; +use webvr_traits::WebVRMsg; + +#[dom_struct] +pub struct XRTest { + reflector: Reflector, + session_started: Cell<bool>, +} + +impl XRTest { + pub fn new_inherited() -> XRTest { + XRTest { + reflector: Reflector::new(), + session_started: Cell::new(false), + } + } + + pub fn new(global: &GlobalScope) -> DomRoot<XRTest> { + reflect_dom_object( + Box::new(XRTest::new_inherited()), + global, + XRTestBinding::Wrap, + ) + } +} + +impl XRTestMethods for XRTest { + /// https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md + fn SimulateDeviceConnection(&self, init: &FakeXRDeviceInit) -> Rc<Promise> { + let p = Promise::new(&self.global()); + + if !init.supportsImmersive || self.session_started.get() { + p.reject_native(&()); + return p; + } + + self.session_started.set(true); + self.global() + .as_window() + .webvr_thread() + .unwrap() + .send(WebVRMsg::CreateMockDisplay) + .unwrap(); + p.resolve_native(&FakeXRDeviceController::new(&self.global())); + + p + } +} |