aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2019-07-23 09:44:59 -0400
committerGitHub <noreply@github.com>2019-07-23 09:44:59 -0400
commit7afe2153e89f97fed82be4da184fb1c014761948 (patch)
tree7223a32dc02bf0eddaf99f6b29610400ce53f62b
parentfdbb317d7a241928d08e40dfd5b0ae3003ecba51 (diff)
parent3f95d304ec621123d675f935c77704fc60d09d60 (diff)
downloadservo-7afe2153e89f97fed82be4da184fb1c014761948.tar.gz
servo-7afe2153e89f97fed82be4da184fb1c014761948.zip
Auto merge of #23814 - Manishearth:events, r=asajeffrey
Partial support for events in WebXR Needs https://github.com/servo/webxr/pull/20 r? @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/23814) <!-- Reviewable:end -->
-rw-r--r--Cargo.lock4
-rw-r--r--components/atoms/static_atoms.txt1
-rw-r--r--components/script/dom/fakexrdevice.rs4
-rw-r--r--components/script/dom/mod.rs2
-rw-r--r--components/script/dom/webidls/XRLayer.webidl8
-rw-r--r--components/script/dom/webidls/XRRenderState.webidl4
-rw-r--r--components/script/dom/webidls/XRSession.webidl4
-rw-r--r--components/script/dom/webidls/XRSessionEvent.webidl15
-rw-r--r--components/script/dom/webidls/XRWebGLLayer.webidl2
-rw-r--r--components/script/dom/xr.rs11
-rw-r--r--components/script/dom/xrlayer.rs19
-rw-r--r--components/script/dom/xrrenderstate.rs12
-rw-r--r--components/script/dom/xrsession.rs140
-rw-r--r--components/script/dom/xrsessionevent.rs78
-rw-r--r--components/script/dom/xrtest.rs49
-rw-r--r--components/script/dom/xrwebgllayer.rs18
-rw-r--r--tests/wpt/metadata/webxr/idlharness.https.window.js.ini30
-rw-r--r--tests/wpt/metadata/webxr/xrSession_end.https.html.ini5
-rw-r--r--tests/wpt/metadata/webxr/xrSession_input_events_end.https.html.ini1
19 files changed, 299 insertions, 108 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5213a915aa8..97f3f869cb8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5462,7 +5462,7 @@ dependencies = [
[[package]]
name = "webxr"
version = "0.0.1"
-source = "git+https://github.com/servo/webxr#5c0eb61f8f38429fde45673d0884f947d14e9c79"
+source = "git+https://github.com/servo/webxr#b5a4b93fcfb2b03ee264a8f95bbaa1500ff0a087"
dependencies = [
"euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -5474,7 +5474,7 @@ dependencies = [
[[package]]
name = "webxr-api"
version = "0.0.1"
-source = "git+https://github.com/servo/webxr#5c0eb61f8f38429fde45673d0884f947d14e9c79"
+source = "git+https://github.com/servo/webxr#b5a4b93fcfb2b03ee264a8f95bbaa1500ff0a087"
dependencies = [
"euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt
index c85d3563e75..7b3d2fc7f88 100644
--- a/components/atoms/static_atoms.txt
+++ b/components/atoms/static_atoms.txt
@@ -25,6 +25,7 @@ dir
durationchange
email
emptied
+end
ended
error
fantasy
diff --git a/components/script/dom/fakexrdevice.rs b/components/script/dom/fakexrdevice.rs
index c1268d743d9..c5e1d16eaff 100644
--- a/components/script/dom/fakexrdevice.rs
+++ b/components/script/dom/fakexrdevice.rs
@@ -38,6 +38,10 @@ impl FakeXRDevice {
FakeXRDeviceBinding::Wrap,
)
}
+
+ pub fn disconnect(&self, sender: IpcSender<()>) {
+ let _ = self.sender.send(MockDeviceMsg::Disconnect(sender));
+ }
}
pub fn get_views(views: &[FakeXRViewInit]) -> Fallible<Views> {
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 7ddc96472ad..ff36a485529 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -547,12 +547,12 @@ pub mod xmlserializer;
pub mod xr;
pub mod xrframe;
pub mod xrinputsource;
-pub mod xrlayer;
pub mod xrpose;
pub mod xrreferencespace;
pub mod xrrenderstate;
pub mod xrrigidtransform;
pub mod xrsession;
+pub mod xrsessionevent;
pub mod xrspace;
pub mod xrtest;
pub mod xrview;
diff --git a/components/script/dom/webidls/XRLayer.webidl b/components/script/dom/webidls/XRLayer.webidl
deleted file mode 100644
index 69c65da6143..00000000000
--- a/components/script/dom/webidls/XRLayer.webidl
+++ /dev/null
@@ -1,8 +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://immersive-web.github.io/webxr/#xrlayer-interface
-
-[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"]
-interface XRLayer {};
diff --git a/components/script/dom/webidls/XRRenderState.webidl b/components/script/dom/webidls/XRRenderState.webidl
index 195d5acf3ac..01d7fd39191 100644
--- a/components/script/dom/webidls/XRRenderState.webidl
+++ b/components/script/dom/webidls/XRRenderState.webidl
@@ -7,11 +7,11 @@
dictionary XRRenderStateInit {
double depthNear;
double depthFar;
- XRLayer baseLayer;
+ XRWebGLLayer baseLayer;
};
[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] interface XRRenderState {
readonly attribute double depthNear;
readonly attribute double depthFar;
- readonly attribute XRLayer? baseLayer;
+ readonly attribute XRWebGLLayer? baseLayer;
};
diff --git a/components/script/dom/webidls/XRSession.webidl b/components/script/dom/webidls/XRSession.webidl
index 1429579353b..6d946ccef55 100644
--- a/components/script/dom/webidls/XRSession.webidl
+++ b/components/script/dom/webidls/XRSession.webidl
@@ -29,7 +29,7 @@ interface XRSession : EventTarget {
// FrozenArray<XRInputSource> getInputSources();
sequence<XRInputSource> getInputSources();
- void updateRenderState(optional XRRenderStateInit state = {});
+ [Throws] void updateRenderState(optional XRRenderStateInit state = {});
long requestAnimationFrame(XRFrameRequestCallback callback);
void cancelAnimationFrame(long handle);
@@ -38,7 +38,7 @@ interface XRSession : EventTarget {
// // Events
// attribute EventHandler onblur;
// attribute EventHandler onfocus;
- // attribute EventHandler onend;
+ attribute EventHandler onend;
// attribute EventHandler onselect;
// attribute EventHandler oninputsourceschange;
// attribute EventHandler onselectstart;
diff --git a/components/script/dom/webidls/XRSessionEvent.webidl b/components/script/dom/webidls/XRSessionEvent.webidl
new file mode 100644
index 00000000000..f48fa5eb342
--- /dev/null
+++ b/components/script/dom/webidls/XRSessionEvent.webidl
@@ -0,0 +1,15 @@
+/* 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/#xrsessionevent-interface
+
+[SecureContext, Exposed=Window, Pref="dom.webxr.enabled", Constructor
+(DOMString type, XRSessionEventInit eventInitDict)]
+interface XRSessionEvent : Event {
+ [SameObject] readonly attribute XRSession session;
+};
+
+dictionary XRSessionEventInit : EventInit {
+ required XRSession session;
+};
diff --git a/components/script/dom/webidls/XRWebGLLayer.webidl b/components/script/dom/webidls/XRWebGLLayer.webidl
index f83e1e4c35a..769b3e9b567 100644
--- a/components/script/dom/webidls/XRWebGLLayer.webidl
+++ b/components/script/dom/webidls/XRWebGLLayer.webidl
@@ -21,7 +21,7 @@ dictionary XRWebGLLayerInit {
XRWebGLRenderingContext context,
optional XRWebGLLayerInit layerInit = {}),
Pref="dom.webxr.enabled"]
-interface XRWebGLLayer : XRLayer {
+interface XRWebGLLayer {
// // Attributes
readonly attribute XRWebGLRenderingContext context;
diff --git a/components/script/dom/xr.rs b/components/script/dom/xr.rs
index 1ddf93c7a23..d24e8f144cd 100644
--- a/components/script/dom/xr.rs
+++ b/components/script/dom/xr.rs
@@ -76,6 +76,17 @@ impl XR {
self.pending_immersive_session.set(false);
self.active_immersive_session.set(Some(session))
}
+
+ /// https://immersive-web.github.io/webxr/#ref-for-eventdef-xrsession-end
+ pub fn end_session(&self, session: &XRSession) {
+ // Step 3
+ if let Some(active) = self.active_immersive_session.get() {
+ if Dom::from_ref(&*active) == Dom::from_ref(session) {
+ self.active_immersive_session.set(None);
+ }
+ }
+ // XXXManishearth when we support inline sessions we should remove them too
+ }
}
impl Drop for XR {
diff --git a/components/script/dom/xrlayer.rs b/components/script/dom/xrlayer.rs
deleted file mode 100644
index d17704be28f..00000000000
--- a/components/script/dom/xrlayer.rs
+++ /dev/null
@@ -1,19 +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/. */
-
-use crate::dom::bindings::reflector::Reflector;
-use dom_struct::dom_struct;
-
-#[dom_struct]
-pub struct XRLayer {
- reflector_: Reflector,
-}
-
-impl XRLayer {
- pub fn new_inherited() -> XRLayer {
- XRLayer {
- reflector_: Reflector::new(),
- }
- }
-}
diff --git a/components/script/dom/xrrenderstate.rs b/components/script/dom/xrrenderstate.rs
index 824b7a6d37a..2aba4e46493 100644
--- a/components/script/dom/xrrenderstate.rs
+++ b/components/script/dom/xrrenderstate.rs
@@ -7,7 +7,7 @@ use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::globalscope::GlobalScope;
-use crate::dom::xrlayer::XRLayer;
+use crate::dom::xrwebgllayer::XRWebGLLayer;
use dom_struct::dom_struct;
use std::cell::Cell;
@@ -17,14 +17,14 @@ pub struct XRRenderState {
reflector_: Reflector,
depth_near: Cell<f64>,
depth_far: Cell<f64>,
- layer: MutNullableDom<XRLayer>,
+ layer: MutNullableDom<XRWebGLLayer>,
}
impl XRRenderState {
pub fn new_inherited(
depth_near: f64,
depth_far: f64,
- layer: Option<&XRLayer>,
+ layer: Option<&XRWebGLLayer>,
) -> XRRenderState {
XRRenderState {
reflector_: Reflector::new(),
@@ -38,7 +38,7 @@ impl XRRenderState {
global: &GlobalScope,
depth_near: f64,
depth_far: f64,
- layer: Option<&XRLayer>,
+ layer: Option<&XRWebGLLayer>,
) -> DomRoot<XRRenderState> {
reflect_dom_object(
Box::new(XRRenderState::new_inherited(depth_near, depth_far, layer)),
@@ -62,7 +62,7 @@ impl XRRenderState {
pub fn set_depth_far(&self, depth: f64) {
self.depth_far.set(depth)
}
- pub fn set_layer(&self, layer: Option<&XRLayer>) {
+ pub fn set_layer(&self, layer: Option<&XRWebGLLayer>) {
self.layer.set(layer)
}
}
@@ -79,7 +79,7 @@ impl XRRenderStateMethods for XRRenderState {
}
/// https://immersive-web.github.io/webxr/#dom-xrrenderstate-baselayer
- fn GetBaseLayer(&self) -> Option<DomRoot<XRLayer>> {
+ fn GetBaseLayer(&self) -> Option<DomRoot<XRWebGLLayer>> {
self.layer.get()
}
}
diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs
index 50e89a773dc..0ea8a0e0e46 100644
--- a/components/script/dom/xrsession.rs
+++ b/components/script/dom/xrsession.rs
@@ -5,7 +5,9 @@
use crate::compartments::InCompartment;
use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorBinding::NavigatorMethods;
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods;
+use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionMode;
use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType;
use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateInit;
@@ -15,12 +17,13 @@ use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XREnvironmentBlen
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::error::Error;
+use crate::dom::bindings::error::{Error, ErrorResult};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot, MutDom, MutNullableDom};
+use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::node::Node;
@@ -28,9 +31,9 @@ use crate::dom::node::NodeDamage;
use crate::dom::promise::Promise;
use crate::dom::xrframe::XRFrame;
use crate::dom::xrinputsource::XRInputSource;
-use crate::dom::xrlayer::XRLayer;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrrenderstate::XRRenderState;
+use crate::dom::xrsessionevent::XRSessionEvent;
use crate::dom::xrspace::XRSpace;
use crate::dom::xrwebgllayer::XRWebGLLayer;
use crate::task_source::TaskSource;
@@ -42,12 +45,12 @@ use profile_traits::ipc;
use std::cell::Cell;
use std::mem;
use std::rc::Rc;
-use webxr_api::{self, Frame, Session};
+use webxr_api::{self, Event as XREvent, Frame, Session};
#[dom_struct]
pub struct XRSession {
eventtarget: EventTarget,
- base_layer: MutNullableDom<XRLayer>,
+ base_layer: MutNullableDom<XRWebGLLayer>,
blend_mode: XREnvironmentBlendMode,
viewer_space: MutNullableDom<XRSpace>,
#[ignore_malloc_size_of = "defined in webxr"]
@@ -62,6 +65,11 @@ pub struct XRSession {
#[ignore_malloc_size_of = "defined in ipc-channel"]
raf_sender: DomRefCell<Option<IpcSender<(f64, Frame)>>>,
input_sources: DomRefCell<Vec<Dom<XRInputSource>>>,
+ // Any promises from calling end()
+ #[ignore_malloc_size_of = "promises are hard"]
+ end_promises: DomRefCell<Vec<Rc<Promise>>>,
+ /// https://immersive-web.github.io/webxr/#ended
+ ended: Cell<bool>,
}
impl XRSession {
@@ -81,6 +89,8 @@ impl XRSession {
raf_callback_list: DomRefCell::new(vec![]),
raf_sender: DomRefCell::new(None),
input_sources: DomRefCell::new(vec![]),
+ end_promises: DomRefCell::new(vec![]),
+ ended: Cell::new(false),
}
}
@@ -100,6 +110,7 @@ impl XRSession {
input_sources.push(Dom::from_ref(&input));
}
}
+ ret.attach_event_handler();
ret
}
@@ -108,6 +119,71 @@ impl XRSession {
with(&session)
}
+ pub fn is_ended(&self) -> bool {
+ self.ended.get()
+ }
+
+ fn attach_event_handler(&self) {
+ #[derive(serde::Serialize, serde::Deserialize)]
+ pub struct EventCallback {
+ sender: IpcSender<XREvent>,
+ }
+
+ #[typetag::serde]
+ impl webxr_api::EventCallback for EventCallback {
+ fn callback(&mut self, event: XREvent) {
+ let _ = self.sender.send(event);
+ }
+ }
+
+ let this = Trusted::new(self);
+ let global = self.global();
+ let window = global.as_window();
+ let (task_source, canceller) = window
+ .task_manager()
+ .dom_manipulation_task_source_with_canceller();
+ let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
+ ROUTER.add_route(
+ receiver.to_opaque(),
+ Box::new(move |message| {
+ let this = this.clone();
+ let _ = task_source.queue_with_canceller(
+ task!(xr_event_callback: move || {
+ this.root().event_callback(message.to().unwrap());
+ }),
+ &canceller,
+ );
+ }),
+ );
+
+ // request animation frame
+ self.session
+ .borrow_mut()
+ .set_event_callback(EventCallback { sender });
+ }
+
+ fn event_callback(&self, event: XREvent) {
+ match event {
+ XREvent::SessionEnd => {
+ // https://immersive-web.github.io/webxr/#shut-down-the-session
+ // Step 2
+ self.ended.set(true);
+ // Step 3-4
+ self.global().as_window().Navigator().Xr().end_session(self);
+ // Step 5: We currently do not have any such promises
+ // Step 6 is happening n the XR session
+ // https://immersive-web.github.io/webxr/#dom-xrsession-end step 3
+ for promise in self.end_promises.borrow_mut().drain(..) {
+ promise.resolve_native(&());
+ }
+ // Step 7
+ let event = XRSessionEvent::new(&self.global(), atom!("end"), false, false, self);
+ event.upcast::<Event>().fire(self.upcast());
+ },
+ _ => (), // XXXManishearth TBD
+ }
+ }
+
/// https://immersive-web.github.io/webxr/#xr-animation-frame
fn raf_callback(&self, (time, frame): (f64, Frame)) {
// Step 1
@@ -122,13 +198,9 @@ impl XRSession {
let layer = pending.GetBaseLayer();
if let Some(layer) = layer {
let mut session = self.session.borrow_mut();
- if let Some(layer) = layer.downcast::<XRWebGLLayer>() {
- session.update_webgl_external_image_api(
- layer.Context().webgl_sender().webxr_external_image_api(),
- );
- } else {
- error!("updateRenderState() called with unknown layer type")
- }
+ session.update_webgl_external_image_api(
+ layer.Context().webgl_sender().webxr_external_image_api(),
+ );
}
}
@@ -160,17 +232,18 @@ impl XRSession {
// If the canvas element is attached to the DOM, it is now dirty,
// and we need to trigger a reflow.
- if let Some(webgl_layer) = base_layer.downcast::<XRWebGLLayer>() {
- webgl_layer
- .Context()
- .Canvas()
- .upcast::<Node>()
- .dirty(NodeDamage::OtherNodeDamage);
- }
+ base_layer
+ .Context()
+ .Canvas()
+ .upcast::<Node>()
+ .dirty(NodeDamage::OtherNodeDamage);
}
}
impl XRSessionMethods for XRSession {
+ /// https://immersive-web.github.io/webxr/#eventdef-xrsession-end
+ event_handler!(end, GetOnend, SetOnend);
+
/// https://immersive-web.github.io/webxr/#dom-xrsession-mode
fn Mode(&self) -> XRSessionMode {
XRSessionMode::Immersive_vr
@@ -182,11 +255,19 @@ impl XRSessionMethods for XRSession {
}
/// https://immersive-web.github.io/webxr/#dom-xrsession-updaterenderstate
- fn UpdateRenderState(&self, init: &XRRenderStateInit, _: InCompartment) {
- // XXXManishearth various checks:
- // If session’s ended value is true, throw an InvalidStateError and abort these steps
- // If newState’s baseLayer's was created with an XRSession other than session,
- // throw an InvalidStateError and abort these steps
+ fn UpdateRenderState(&self, init: &XRRenderStateInit, _: InCompartment) -> ErrorResult {
+ // Step 2
+ if self.ended.get() {
+ return Err(Error::InvalidState);
+ }
+ // Step 3:
+ if let Some(ref layer) = init.baseLayer {
+ if Dom::from_ref(layer.session()) != Dom::from_ref(self) {
+ return Err(Error::InvalidState);
+ }
+ }
+
+ // XXXManishearth step 4:
// If newState’s inlineVerticalFieldOfView is set and session is an
// immersive session, throw an InvalidStateError and abort these steps.
@@ -203,6 +284,7 @@ impl XRSessionMethods for XRSession {
pending.set_layer(Some(&layer))
}
// XXXManishearth handle inlineVerticalFieldOfView
+ Ok(())
}
/// https://immersive-web.github.io/webxr/#dom-xrsession-requestanimationframe
@@ -305,9 +387,15 @@ impl XRSessionMethods for XRSession {
/// https://immersive-web.github.io/webxr/#dom-xrsession-end
fn End(&self) -> Rc<Promise> {
- // XXXManishearth implement device disconnection and session ending
- let p = Promise::new(&self.global());
- p.resolve_native(&());
+ let global = self.global();
+ let p = Promise::new(&global);
+ self.end_promises.borrow_mut().push(p.clone());
+ // This is duplicated in event_callback since this should
+ // happen ASAP for end() but can happen later if the device
+ // shuts itself down
+ self.ended.set(true);
+ global.as_window().Navigator().Xr().end_session(self);
+ self.session.borrow_mut().end_session();
p
}
}
diff --git a/components/script/dom/xrsessionevent.rs b/components/script/dom/xrsessionevent.rs
new file mode 100644
index 00000000000..6c2e8c0fb00
--- /dev/null
+++ b/components/script/dom/xrsessionevent.rs
@@ -0,0 +1,78 @@
+/* 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::EventBinding::EventBinding::EventMethods;
+use crate::dom::bindings::codegen::Bindings::XRSessionEventBinding::{self, XRSessionEventMethods};
+use crate::dom::bindings::error::Fallible;
+use crate::dom::bindings::inheritance::Castable;
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::root::{Dom, DomRoot};
+use crate::dom::bindings::str::DOMString;
+use crate::dom::event::Event;
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
+use crate::dom::xrsession::XRSession;
+use dom_struct::dom_struct;
+use servo_atoms::Atom;
+
+#[dom_struct]
+pub struct XRSessionEvent {
+ event: Event,
+ session: Dom<XRSession>,
+}
+
+impl XRSessionEvent {
+ #[allow(unrooted_must_root)]
+ fn new_inherited(session: &XRSession) -> XRSessionEvent {
+ XRSessionEvent {
+ event: Event::new_inherited(),
+ session: Dom::from_ref(session),
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ type_: Atom,
+ bubbles: bool,
+ cancelable: bool,
+ session: &XRSession,
+ ) -> DomRoot<XRSessionEvent> {
+ let trackevent = reflect_dom_object(
+ Box::new(XRSessionEvent::new_inherited(&session)),
+ global,
+ XRSessionEventBinding::Wrap,
+ );
+ {
+ let event = trackevent.upcast::<Event>();
+ event.init_event(type_, bubbles, cancelable);
+ }
+ trackevent
+ }
+
+ pub fn Constructor(
+ window: &Window,
+ type_: DOMString,
+ init: &XRSessionEventBinding::XRSessionEventInit,
+ ) -> Fallible<DomRoot<XRSessionEvent>> {
+ Ok(XRSessionEvent::new(
+ &window.global(),
+ Atom::from(type_),
+ init.parent.bubbles,
+ init.parent.cancelable,
+ &init.session,
+ ))
+ }
+}
+
+impl XRSessionEventMethods for XRSessionEvent {
+ // https://immersive-web.github.io/webxr/#dom-xrsessioneventinit-session
+ fn Session(&self) -> DomRoot<XRSession> {
+ DomRoot::from_ref(&*self.session)
+ }
+
+ // https://dom.spec.whatwg.org/#dom-event-istrusted
+ fn IsTrusted(&self) -> bool {
+ self.event.IsTrusted()
+ }
+}
diff --git a/components/script/dom/xrtest.rs b/components/script/dom/xrtest.rs
index 3e695bc1f5e..81949addf02 100644
--- a/components/script/dom/xrtest.rs
+++ b/components/script/dom/xrtest.rs
@@ -7,13 +7,14 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::callback::ExceptionHandling;
+use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
use crate::dom::bindings::codegen::Bindings::XRTestBinding::{
self, FakeXRDeviceInit, XRTestMethods,
};
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
-use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::fakexrdevice::{get_origin, get_views, FakeXRDevice};
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
@@ -31,6 +32,7 @@ use webxr_api::{self, Error as XRError, MockDeviceInit, MockDeviceMsg};
pub struct XRTest {
reflector: Reflector,
session_started: Cell<bool>,
+ devices_connected: DomRefCell<Vec<Dom<FakeXRDevice>>>,
}
impl XRTest {
@@ -38,6 +40,7 @@ impl XRTest {
XRTest {
reflector: Reflector::new(),
session_started: Cell::new(false),
+ devices_connected: DomRefCell::new(vec![]),
}
}
@@ -57,6 +60,9 @@ impl XRTest {
let promise = trusted.root();
if let Ok(sender) = response {
let device = FakeXRDevice::new(&self.global(), sender);
+ self.devices_connected
+ .borrow_mut()
+ .push(Dom::from_ref(&device));
promise.resolve_native(&device);
} else {
promise.reject_native(&());
@@ -174,8 +180,45 @@ impl XRTestMethods for XRTest {
/// https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md
fn DisconnectAllDevices(&self) -> Rc<Promise> {
// XXXManishearth implement device disconnection and session ending
- let p = Promise::new(&self.global());
- p.resolve_native(&());
+ let global = self.global();
+ let p = Promise::new(&global);
+ let mut devices = self.devices_connected.borrow_mut();
+ if devices.is_empty() {
+ p.resolve_native(&());
+ } else {
+ let mut len = devices.len();
+
+ let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
+ let mut rooted_devices: Vec<_> =
+ devices.iter().map(|x| DomRoot::from_ref(&**x)).collect();
+ devices.clear();
+ for device in rooted_devices.drain(..) {
+ device.disconnect(sender.clone());
+ }
+ let mut trusted = Some(TrustedPromise::new(p.clone()));
+ let (task_source, canceller) = global
+ .as_window()
+ .task_manager()
+ .dom_manipulation_task_source_with_canceller();
+
+ ROUTER.add_route(
+ receiver.to_opaque(),
+ Box::new(move |_| {
+ len -= 1;
+ if len == 0 {
+ let trusted = trusted
+ .take()
+ .expect("DisconnectAllDevices disconnected more devices than expected");
+ let _ =
+ task_source.queue_with_canceller(trusted.resolve_task(()), &canceller);
+ }
+ }),
+ );
+
+ // XXXManishearth this is a hack, it will need to be replaced when
+ // we improve how mock messaging works
+ p.resolve_native(&())
+ };
p
}
}
diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs
index a2a7c93f37c..a5f06df0e52 100644
--- a/components/script/dom/xrwebgllayer.rs
+++ b/components/script/dom/xrwebgllayer.rs
@@ -10,14 +10,13 @@ use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGL
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::error::Fallible;
-use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::reflector::{reflect_dom_object, Reflector, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
use crate::dom::webgl_validations::types::TexImageTarget;
use crate::dom::webglframebuffer::WebGLFramebuffer;
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;
@@ -28,7 +27,7 @@ use webxr_api::Views;
#[dom_struct]
pub struct XRWebGLLayer {
- xrlayer: XRLayer,
+ reflector_: Reflector,
antialias: bool,
depth: bool,
stencil: bool,
@@ -46,7 +45,7 @@ impl XRWebGLLayer {
framebuffer: &WebGLFramebuffer,
) -> XRWebGLLayer {
XRWebGLLayer {
- xrlayer: XRLayer::new_inherited(),
+ reflector_: Reflector::new(),
antialias: init.antialias,
depth: init.depth,
stencil: init.stencil,
@@ -83,6 +82,13 @@ impl XRWebGLLayer {
context: &WebGLRenderingContext,
init: &XRWebGLLayerInit,
) -> Fallible<DomRoot<Self>> {
+ // Step 2
+ if session.is_ended() {
+ return Err(Error::InvalidState);
+ }
+ // XXXManishearth step 3: throw error if context is lost
+ // XXXManishearth step 4: check XR compat flag for immersive sessions
+
let cx = global.get_cx();
let old_fbo = context.bound_framebuffer();
let old_texture = context
@@ -139,6 +145,10 @@ impl XRWebGLLayer {
&framebuffer,
))
}
+
+ pub fn session(&self) -> &XRSession {
+ &self.session
+ }
}
impl XRWebGLLayerMethods for XRWebGLLayer {
diff --git a/tests/wpt/metadata/webxr/idlharness.https.window.js.ini b/tests/wpt/metadata/webxr/idlharness.https.window.js.ini
index b3906bc63f5..c85b29a6c1d 100644
--- a/tests/wpt/metadata/webxr/idlharness.https.window.js.ini
+++ b/tests/wpt/metadata/webxr/idlharness.https.window.js.ini
@@ -44,18 +44,12 @@
[XRInputSourceArray interface: attribute length]
expected: FAIL
- [XRSessionEvent interface: existence and properties of interface object]
- expected: FAIL
-
[XRInputSource interface: attribute targetRayMode]
expected: FAIL
[XRBoundedReferenceSpace interface object length]
expected: FAIL
- [XRSessionEvent interface object length]
- expected: FAIL
-
[XRWebGLLayer interface: operation getNativeFramebufferScaleFactor(XRSession)]
expected: FAIL
@@ -74,18 +68,12 @@
[XRReferenceSpaceEvent interface object length]
expected: FAIL
- [XRSessionEvent interface: existence and properties of interface prototype object's @@unscopables property]
- expected: FAIL
-
[WebGLRenderingContext interface: operation makeXRCompatible()]
expected: FAIL
[XRInputSourcesChangeEvent interface: attribute added]
expected: FAIL
- [XRSessionEvent interface object name]
- expected: FAIL
-
[XRInputSourceEvent interface: attribute inputSource]
expected: FAIL
@@ -98,18 +86,12 @@
[XRInputSourcesChangeEvent interface: attribute removed]
expected: FAIL
- [XRSessionEvent interface: existence and properties of interface prototype object's "constructor" property]
- expected: FAIL
-
[XRSession interface: attribute onselectstart]
expected: FAIL
[XRInputSourceEvent interface: existence and properties of interface prototype object]
expected: FAIL
- [XRSessionEvent interface: attribute session]
- expected: FAIL
-
[XRReferenceSpaceEvent interface: existence and properties of interface object]
expected: FAIL
@@ -149,12 +131,6 @@
[XRBoundedReferenceSpace interface: attribute boundsGeometry]
expected: FAIL
- [XRWebGLLayer interface: existence and properties of interface object]
- expected: FAIL
-
- [XRWebGLLayer interface: existence and properties of interface prototype object]
- expected: FAIL
-
[XRReferenceSpaceEvent interface object name]
expected: FAIL
@@ -236,18 +212,12 @@
[XRSession interface: attribute oninputsourceschange]
expected: FAIL
- [XRSessionEvent interface: existence and properties of interface prototype object]
- expected: FAIL
-
[XRBoundedReferenceSpace interface: existence and properties of interface prototype object]
expected: FAIL
[XR interface: calling requestSession(XRSessionMode, XRSessionInit) on navigator.xr with too few arguments must throw TypeError]
expected: FAIL
- [XRSession interface: attribute onend]
- expected: FAIL
-
[XRSession interface: operation end()]
expected: FAIL
diff --git a/tests/wpt/metadata/webxr/xrSession_end.https.html.ini b/tests/wpt/metadata/webxr/xrSession_end.https.html.ini
index 99ff6da253a..d03914bcd66 100644
--- a/tests/wpt/metadata/webxr/xrSession_end.https.html.ini
+++ b/tests/wpt/metadata/webxr/xrSession_end.https.html.ini
@@ -1,8 +1,5 @@
[xrSession_end.https.html]
- expected: TIMEOUT
+ expected: ERROR
[end event fires when non-immersive session ends]
expected: NOTRUN
- [end event fires when immersive session ends]
- expected: TIMEOUT
-
diff --git a/tests/wpt/metadata/webxr/xrSession_input_events_end.https.html.ini b/tests/wpt/metadata/webxr/xrSession_input_events_end.https.html.ini
index 739e7b4c112..fba510c47e9 100644
--- a/tests/wpt/metadata/webxr/xrSession_input_events_end.https.html.ini
+++ b/tests/wpt/metadata/webxr/xrSession_input_events_end.https.html.ini
@@ -1,4 +1,5 @@
[xrSession_input_events_end.https.html]
+ expected: ERROR
[Calling end during an input callback stops processing at the right time]
expected: FAIL