diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2019-07-23 09:44:59 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-07-23 09:44:59 -0400 |
commit | 7afe2153e89f97fed82be4da184fb1c014761948 (patch) | |
tree | 7223a32dc02bf0eddaf99f6b29610400ce53f62b | |
parent | fdbb317d7a241928d08e40dfd5b0ae3003ecba51 (diff) | |
parent | 3f95d304ec621123d675f935c77704fc60d09d60 (diff) | |
download | servo-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.lock | 4 | ||||
-rw-r--r-- | components/atoms/static_atoms.txt | 1 | ||||
-rw-r--r-- | components/script/dom/fakexrdevice.rs | 4 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 2 | ||||
-rw-r--r-- | components/script/dom/webidls/XRLayer.webidl | 8 | ||||
-rw-r--r-- | components/script/dom/webidls/XRRenderState.webidl | 4 | ||||
-rw-r--r-- | components/script/dom/webidls/XRSession.webidl | 4 | ||||
-rw-r--r-- | components/script/dom/webidls/XRSessionEvent.webidl | 15 | ||||
-rw-r--r-- | components/script/dom/webidls/XRWebGLLayer.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/xr.rs | 11 | ||||
-rw-r--r-- | components/script/dom/xrlayer.rs | 19 | ||||
-rw-r--r-- | components/script/dom/xrrenderstate.rs | 12 | ||||
-rw-r--r-- | components/script/dom/xrsession.rs | 140 | ||||
-rw-r--r-- | components/script/dom/xrsessionevent.rs | 78 | ||||
-rw-r--r-- | components/script/dom/xrtest.rs | 49 | ||||
-rw-r--r-- | components/script/dom/xrwebgllayer.rs | 18 | ||||
-rw-r--r-- | tests/wpt/metadata/webxr/idlharness.https.window.js.ini | 30 | ||||
-rw-r--r-- | tests/wpt/metadata/webxr/xrSession_end.https.html.ini | 5 | ||||
-rw-r--r-- | tests/wpt/metadata/webxr/xrSession_input_events_end.https.html.ini | 1 |
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 |