From e9221e6ce02b4fc16676bda2895105bea8e95e7f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 13 Jan 2020 15:08:53 +0530 Subject: [PATCH 1/7] Update webxr --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 883afe5ff4f..8e6dc6e6473 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6729,7 +6729,7 @@ dependencies = [ [[package]] name = "webxr" version = "0.0.1" -source = "git+https://github.com/servo/webxr#ed1ec1afadce730247401e60994b7f6ff226639d" +source = "git+https://github.com/servo/webxr#33072cbbb67ff14b5938e886ee11a13f4cf2bafc" dependencies = [ "bindgen", "euclid", @@ -6750,7 +6750,7 @@ dependencies = [ [[package]] name = "webxr-api" version = "0.0.1" -source = "git+https://github.com/servo/webxr#ed1ec1afadce730247401e60994b7f6ff226639d" +source = "git+https://github.com/servo/webxr#33072cbbb67ff14b5938e886ee11a13f4cf2bafc" dependencies = [ "euclid", "ipc-channel", From 9c34a6585b50b7c20468060dafca717d1d363e6c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 13 Jan 2020 15:13:08 +0530 Subject: [PATCH 2/7] Handle SetTargetRayMode and SetHandedness --- .../script/dom/fakexrinputcontroller.rs | 27 +++++++++++++++- .../dom/webidls/FakeXRInputController.webidl | 4 +-- components/script/dom/xrinputsourcearray.rs | 31 +++++++++++++++++++ .../script/dom/xrinputsourceschangeevent.rs | 2 +- components/script/dom/xrsession.rs | 3 ++ ...nts_input_source_recreation.https.html.ini | 1 - .../getInputPose_handedness.https.html.ini | 5 --- .../xrSession_input_events_end.https.html.ini | 3 +- .../webxr/xrSession_sameObject.https.html.ini | 5 --- 9 files changed, 64 insertions(+), 17 deletions(-) delete mode 100644 tests/wpt/metadata/webxr/getInputPose_handedness.https.html.ini delete mode 100644 tests/wpt/metadata/webxr/xrSession_sameObject.https.html.ini diff --git a/components/script/dom/fakexrinputcontroller.rs b/components/script/dom/fakexrinputcontroller.rs index 67e6f72cf70..7c145a3ed20 100644 --- a/components/script/dom/fakexrinputcontroller.rs +++ b/components/script/dom/fakexrinputcontroller.rs @@ -6,6 +6,9 @@ use crate::dom::bindings::codegen::Bindings::FakeXRDeviceBinding::FakeXRRigidTra use crate::dom::bindings::codegen::Bindings::FakeXRInputControllerBinding::{ self, FakeXRInputControllerMethods, }; +use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{ + XRHandedness, XRTargetRayMode, +}; use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; @@ -13,7 +16,9 @@ use crate::dom::fakexrdevice::get_origin; use crate::dom::globalscope::GlobalScope; use dom_struct::dom_struct; use ipc_channel::ipc::IpcSender; -use webxr_api::{InputId, MockDeviceMsg, MockInputMsg, SelectEvent, SelectKind}; +use webxr_api::{ + Handedness, InputId, MockDeviceMsg, MockInputMsg, SelectEvent, SelectKind, TargetRayMode, +}; #[dom_struct] pub struct FakeXRInputController { @@ -103,4 +108,24 @@ impl FakeXRInputControllerMethods for FakeXRInputController { SelectEvent::Select, )) } + + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-sethandedness + fn SetHandedness(&self, handedness: XRHandedness) { + let h = match handedness { + XRHandedness::None => Handedness::None, + XRHandedness::Left => Handedness::Left, + XRHandedness::Right => Handedness::Right, + }; + let _ = self.send_message(MockInputMsg::SetHandedness(h)); + } + + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-settargetraymode + fn SetTargetRayMode(&self, target_ray_mode: XRTargetRayMode) { + let t = match target_ray_mode { + XRTargetRayMode::Gaze => TargetRayMode::Gaze, + XRTargetRayMode::Tracked_pointer => TargetRayMode::TrackedPointer, + XRTargetRayMode::Screen => TargetRayMode::Screen, + }; + let _ = self.send_message(MockInputMsg::SetTargetRayMode(t)); + } } diff --git a/components/script/dom/webidls/FakeXRInputController.webidl b/components/script/dom/webidls/FakeXRInputController.webidl index a50950cdee3..164012f3d83 100644 --- a/components/script/dom/webidls/FakeXRInputController.webidl +++ b/components/script/dom/webidls/FakeXRInputController.webidl @@ -6,8 +6,8 @@ [Exposed=Window, Pref="dom.webxr.test"] interface FakeXRInputController { - // void setHandedness(XRHandedness handedness); - // void setTargetRayMode(XRTargetRayMode targetRayMode); + void setHandedness(XRHandedness handedness); + void setTargetRayMode(XRTargetRayMode targetRayMode); // void setProfiles(sequence profiles); [Throws] void setGripOrigin(FakeXRRigidTransformInit gripOrigin, optional boolean emulatedPosition = false); void clearGripOrigin(); diff --git a/components/script/dom/xrinputsourcearray.rs b/components/script/dom/xrinputsourcearray.rs index 45e0f2851e4..66e4045e44a 100644 --- a/components/script/dom/xrinputsourcearray.rs +++ b/components/script/dom/xrinputsourcearray.rs @@ -101,6 +101,37 @@ impl XRInputSourceArray { event.upcast::().fire(session.upcast()); } + pub fn add_remove_input_source(&self, session: &XRSession, id: InputId, info: InputSource) { + let mut input_sources = self.input_sources.borrow_mut(); + let global = self.global(); + let root; + let removed = if let Some(i) = input_sources.iter().find(|i| i.id() == id) { + root = [DomRoot::from_ref(&**i)]; + &root as &[_] + } else { + warn!("Could not find removed input source with id {:?}", id); + &[] + }; + input_sources.retain(|i| i.id() != id); + let input = XRInputSource::new(&global, &session, info); + input_sources.push(Dom::from_ref(&input)); + + let added = [input]; + + let event = XRInputSourcesChangeEvent::new( + &global, + atom!("inputsourceschange"), + false, + true, + session, + &added, + removed, + ); + // release the refcell guard + drop(input_sources); + event.upcast::().fire(session.upcast()); + } + pub fn find(&self, id: InputId) -> Option> { self.input_sources .borrow() diff --git a/components/script/dom/xrinputsourceschangeevent.rs b/components/script/dom/xrinputsourceschangeevent.rs index 3b68a3b8d2a..b3275cd800c 100644 --- a/components/script/dom/xrinputsourceschangeevent.rs +++ b/components/script/dom/xrinputsourceschangeevent.rs @@ -71,7 +71,7 @@ impl XRInputSourcesChangeEvent { changeevent.added.set(added_val.get()); rooted!(in(*cx) let mut removed_val = UndefinedValue()); removed.to_jsval(*cx, removed_val.handle_mut()); - changeevent.added.set(removed_val.get()); + changeevent.removed.set(removed_val.get()); } changeevent diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 4979835fc42..e822a69eb8e 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -295,6 +295,9 @@ impl XRSession { XREvent::RemoveInput(id) => { self.input_sources.remove_input_source(self, id); }, + XREvent::UpdateInput(id, source) => { + self.input_sources.add_remove_input_source(self, id, source); + }, } } diff --git a/tests/wpt/metadata/webxr/events_input_source_recreation.https.html.ini b/tests/wpt/metadata/webxr/events_input_source_recreation.https.html.ini index 82ce39a5108..976a3ad323d 100644 --- a/tests/wpt/metadata/webxr/events_input_source_recreation.https.html.ini +++ b/tests/wpt/metadata/webxr/events_input_source_recreation.https.html.ini @@ -1,5 +1,4 @@ [events_input_source_recreation.https.html] - expected: ERROR [Input sources are re-created when handedness or target ray mode changes] expected: FAIL diff --git a/tests/wpt/metadata/webxr/getInputPose_handedness.https.html.ini b/tests/wpt/metadata/webxr/getInputPose_handedness.https.html.ini deleted file mode 100644 index f10131010ef..00000000000 --- a/tests/wpt/metadata/webxr/getInputPose_handedness.https.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[getInputPose_handedness.https.html] - expected: ERROR - [XRInputSources properly communicate their handedness] - 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 1d6cd17924d..739e7b4c112 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,5 +1,4 @@ [xrSession_input_events_end.https.html] - expected: TIMEOUT [Calling end during an input callback stops processing at the right time] - expected: TIMEOUT + expected: FAIL diff --git a/tests/wpt/metadata/webxr/xrSession_sameObject.https.html.ini b/tests/wpt/metadata/webxr/xrSession_sameObject.https.html.ini deleted file mode 100644 index 0013dc7b4cc..00000000000 --- a/tests/wpt/metadata/webxr/xrSession_sameObject.https.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[xrSession_sameObject.https.html] - expected: ERROR - [XRSession attributes meet [SameObject\] requirement] - expected: TIMEOUT - From e0135fe7832382b01d3269f6d231477196d09b4f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 13 Jan 2020 15:31:31 +0530 Subject: [PATCH 3/7] Support profiles --- components/script/dom/fakexrdevice.rs | 5 +++- .../script/dom/fakexrinputcontroller.rs | 7 +++++ .../dom/webidls/FakeXRInputController.webidl | 2 +- .../script/dom/webidls/XRInputSource.webidl | 1 + components/script/dom/xrinputsource.rs | 26 +++++++++++++++++-- components/script/dom/xrinputsourcearray.rs | 4 +-- ...nts_input_source_recreation.https.html.ini | 4 --- .../webxr/idlharness.https.window.js.ini | 3 --- .../xrInputSource_profiles.https.html.ini | 4 --- .../xrSession_input_events_end.https.html.ini | 1 + 10 files changed, 40 insertions(+), 17 deletions(-) delete mode 100644 tests/wpt/metadata/webxr/events_input_source_recreation.https.html.ini delete mode 100644 tests/wpt/metadata/webxr/xrInputSource_profiles.https.html.ini diff --git a/components/script/dom/fakexrdevice.rs b/components/script/dom/fakexrdevice.rs index f43b0b1155b..dd599d4a3a4 100644 --- a/components/script/dom/fakexrdevice.rs +++ b/components/script/dom/fakexrdevice.rs @@ -205,13 +205,16 @@ impl FakeXRDeviceMethods for FakeXRDevice { None }; - // XXXManishearth deal with profiles, supportedButtons, selection* + let profiles = init.profiles.iter().cloned().map(String::from).collect(); + + // XXXManishearth deal with supportedButtons and selection* let source = InputSource { handedness, target_ray_mode, id, supports_grip: true, + profiles, }; let init = MockInputInit { diff --git a/components/script/dom/fakexrinputcontroller.rs b/components/script/dom/fakexrinputcontroller.rs index 7c145a3ed20..e93d328ff29 100644 --- a/components/script/dom/fakexrinputcontroller.rs +++ b/components/script/dom/fakexrinputcontroller.rs @@ -12,6 +12,7 @@ use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{ use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::str::DOMString; use crate::dom::fakexrdevice::get_origin; use crate::dom::globalscope::GlobalScope; use dom_struct::dom_struct; @@ -128,4 +129,10 @@ impl FakeXRInputControllerMethods for FakeXRInputController { }; let _ = self.send_message(MockInputMsg::SetTargetRayMode(t)); } + + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-setprofiles + fn SetProfiles(&self, profiles: Vec) { + let t = profiles.into_iter().map(String::from).collect(); + let _ = self.send_message(MockInputMsg::SetProfiles(t)); + } } diff --git a/components/script/dom/webidls/FakeXRInputController.webidl b/components/script/dom/webidls/FakeXRInputController.webidl index 164012f3d83..b8faad1038a 100644 --- a/components/script/dom/webidls/FakeXRInputController.webidl +++ b/components/script/dom/webidls/FakeXRInputController.webidl @@ -8,7 +8,7 @@ interface FakeXRInputController { void setHandedness(XRHandedness handedness); void setTargetRayMode(XRTargetRayMode targetRayMode); - // void setProfiles(sequence profiles); + void setProfiles(sequence profiles); [Throws] void setGripOrigin(FakeXRRigidTransformInit gripOrigin, optional boolean emulatedPosition = false); void clearGripOrigin(); [Throws] void setPointerOrigin(FakeXRRigidTransformInit pointerOrigin, optional boolean emulatedPosition = false); diff --git a/components/script/dom/webidls/XRInputSource.webidl b/components/script/dom/webidls/XRInputSource.webidl index f07de183927..487c959859d 100644 --- a/components/script/dom/webidls/XRInputSource.webidl +++ b/components/script/dom/webidls/XRInputSource.webidl @@ -23,4 +23,5 @@ interface XRInputSource { [SameObject] readonly attribute XRSpace targetRaySpace; [SameObject] readonly attribute XRSpace? gripSpace; // [SameObject] readonly attribute Gamepad? gamepad; + /* [SameObject] */ readonly attribute /* FrozenArray */ any profiles; }; diff --git a/components/script/dom/xrinputsource.rs b/components/script/dom/xrinputsource.rs index fed76937d9c..e0da8bea550 100644 --- a/components/script/dom/xrinputsource.rs +++ b/components/script/dom/xrinputsource.rs @@ -2,6 +2,7 @@ * 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::compartments::enter_realm; use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding; use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{ XRHandedness, XRInputSourceMethods, XRTargetRayMode, @@ -11,7 +12,11 @@ use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::globalscope::GlobalScope; use crate::dom::xrsession::XRSession; use crate::dom::xrspace::XRSpace; +use crate::script_runtime::JSContext; use dom_struct::dom_struct; +use js::conversions::ToJSValConvertible; +use js::jsapi::Heap; +use js::jsval::{JSVal, UndefinedValue}; use webxr_api::{Handedness, InputId, InputSource, TargetRayMode}; #[dom_struct] @@ -24,6 +29,8 @@ pub struct XRInputSource { target_ray_space: MutNullableDom, #[ignore_malloc_size_of = "Defined in rust-webxr"] grip_space: MutNullableDom, + #[ignore_malloc_size_of = "mozjs"] + profiles: Heap, } impl XRInputSource { @@ -34,19 +41,30 @@ impl XRInputSource { info, target_ray_space: Default::default(), grip_space: Default::default(), + profiles: Heap::default(), } } + #[allow(unsafe_code)] pub fn new( global: &GlobalScope, session: &XRSession, info: InputSource, ) -> DomRoot { - reflect_dom_object( + let source = reflect_dom_object( Box::new(XRInputSource::new_inherited(session, info)), global, XRInputSourceBinding::Wrap, - ) + ); + + let _ac = enter_realm(&*global); + let cx = global.get_cx(); + unsafe { + rooted!(in(*cx) let mut profiles = UndefinedValue()); + source.info.profiles.to_jsval(*cx, profiles.handle_mut()); + source.profiles.set(profiles.get()); + } + source } pub fn id(&self) -> InputId { @@ -92,4 +110,8 @@ impl XRInputSourceMethods for XRInputSource { None } } + // https://immersive-web.github.io/webxr/#dom-xrinputsource-profiles + fn Profiles(&self, _cx: JSContext) -> JSVal { + self.profiles.get() + } } diff --git a/components/script/dom/xrinputsourcearray.rs b/components/script/dom/xrinputsourcearray.rs index 66e4045e44a..86a107bcd27 100644 --- a/components/script/dom/xrinputsourcearray.rs +++ b/components/script/dom/xrinputsourcearray.rs @@ -45,7 +45,7 @@ impl XRInputSourceArray { for info in sess.initial_inputs() { // XXXManishearth we should be able to listen for updates // to the input sources - let input = XRInputSource::new(&global, &session, *info); + let input = XRInputSource::new(&global, &session, info.clone()); input_sources.push(Dom::from_ref(&input)); } }); @@ -54,11 +54,11 @@ impl XRInputSourceArray { pub fn add_input_source(&self, session: &XRSession, info: InputSource) { let mut input_sources = self.input_sources.borrow_mut(); let global = self.global(); - let input = XRInputSource::new(&global, &session, info); debug_assert!( input_sources.iter().find(|i| i.id() == info.id).is_none(), "Should never add a duplicate input id!" ); + let input = XRInputSource::new(&global, &session, info); input_sources.push(Dom::from_ref(&input)); let added = [input]; diff --git a/tests/wpt/metadata/webxr/events_input_source_recreation.https.html.ini b/tests/wpt/metadata/webxr/events_input_source_recreation.https.html.ini deleted file mode 100644 index 976a3ad323d..00000000000 --- a/tests/wpt/metadata/webxr/events_input_source_recreation.https.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[events_input_source_recreation.https.html] - [Input sources are re-created when handedness or target ray mode changes] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/idlharness.https.window.js.ini b/tests/wpt/metadata/webxr/idlharness.https.window.js.ini index 1b47a7ad858..df4d0eabbcd 100644 --- a/tests/wpt/metadata/webxr/idlharness.https.window.js.ini +++ b/tests/wpt/metadata/webxr/idlharness.https.window.js.ini @@ -95,9 +95,6 @@ [XRReferenceSpaceEvent interface: existence and properties of interface prototype object's "constructor" property] expected: FAIL - [XRInputSource interface: attribute profiles] - expected: FAIL - [XR interface: operation requestSession(XRSessionMode, XRSessionInit)] expected: FAIL diff --git a/tests/wpt/metadata/webxr/xrInputSource_profiles.https.html.ini b/tests/wpt/metadata/webxr/xrInputSource_profiles.https.html.ini deleted file mode 100644 index 3e2806dfae7..00000000000 --- a/tests/wpt/metadata/webxr/xrInputSource_profiles.https.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[xrInputSource_profiles.https.html] - [WebXR InputSource's profiles list can be set] - expected: FAIL - 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..1c2f8518d1a 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: TIMEOUT [Calling end during an input callback stops processing at the right time] expected: FAIL From d33d21ce72e6396018712608251b3392c1786a68 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 13 Jan 2020 17:50:13 +0530 Subject: [PATCH 4/7] Add support for requesting features --- components/script/dom/webidls/XR.webidl | 4 +- components/script/dom/webidls/XRTest.webidl | 3 + components/script/dom/xr.rs | 56 ++++++++++++++++--- components/script/dom/xrtest.rs | 11 +++- ...ssion_immersive_unsupported.https.html.ini | 4 -- ...sion_features_deviceSupport.https.html.ini | 3 +- 6 files changed, 66 insertions(+), 15 deletions(-) delete mode 100644 tests/wpt/metadata/webxr/xrDevice_requestSession_immersive_unsupported.https.html.ini diff --git a/components/script/dom/webidls/XR.webidl b/components/script/dom/webidls/XR.webidl index 2bee5c07cd8..8b0311f0c3f 100644 --- a/components/script/dom/webidls/XR.webidl +++ b/components/script/dom/webidls/XR.webidl @@ -25,8 +25,8 @@ enum XRSessionMode { }; dictionary XRSessionInit { - sequence requiredFeatures; - sequence optionalFeatures; + sequence requiredFeatures; + sequence optionalFeatures; }; partial interface XR { diff --git a/components/script/dom/webidls/XRTest.webidl b/components/script/dom/webidls/XRTest.webidl index a190fd75472..914bcb2d54d 100644 --- a/components/script/dom/webidls/XRTest.webidl +++ b/components/script/dom/webidls/XRTest.webidl @@ -23,6 +23,9 @@ dictionary FakeXRDeviceInit { required boolean supportsImmersive; required sequence views; + // this is actually sequence, but we don't support + // non-string features anyway + sequence supportedFeatures; boolean supportsUnbounded = false; // Whether the space supports tracking in inline sessions boolean supportsTrackingInInline = true; diff --git a/components/script/dom/xr.rs b/components/script/dom/xr.rs index 5804918a532..a2c4fd059f0 100644 --- a/components/script/dom/xr.rs +++ b/components/script/dom/xr.rs @@ -8,11 +8,13 @@ use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods; use crate::dom::bindings::codegen::Bindings::XRBinding; use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionInit; use crate::dom::bindings::codegen::Bindings::XRBinding::{XRMethods, XRSessionMode}; +use crate::dom::bindings::conversions::{ConversionResult, FromJSValConvertible}; use crate::dom::bindings::error::Error; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; +use crate::dom::bindings::trace::RootedTraceableBox; use crate::dom::event::Event; use crate::dom::eventtarget::EventTarget; use crate::dom::gamepad::Gamepad; @@ -33,7 +35,7 @@ use std::cell::Cell; use std::rc::Rc; use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVREvent, WebVRMsg}; use webvr_traits::{WebVRGamepadData, WebVRGamepadEvent, WebVRGamepadState}; -use webxr_api::{Error as XRError, Frame, Session, SessionMode}; +use webxr_api::{Error as XRError, Frame, Session, SessionInit, SessionMode}; #[dom_struct] pub struct XR { @@ -154,13 +156,16 @@ impl XRMethods for XR { } /// https://immersive-web.github.io/webxr/#dom-xr-requestsession + #[allow(unsafe_code)] fn RequestSession( &self, mode: XRSessionMode, - _: &XRSessionInit, + init: RootedTraceableBox, comp: InCompartment, ) -> Rc { - let promise = Promise::new_in_current_compartment(&self.global(), comp); + let global = self.global(); + let window = global.as_window(); + let promise = Promise::new_in_current_compartment(&global, comp); if mode != XRSessionMode::Inline { if !ScriptThread::is_user_interacting() { @@ -176,11 +181,48 @@ impl XRMethods for XR { self.set_pending(); } + let mut required_features = vec![]; + let mut optional_features = vec![]; + let cx = global.get_cx(); + + if let Some(ref r) = init.requiredFeatures { + for feature in r { + unsafe { + if let Ok(ConversionResult::Success(s)) = + String::from_jsval(*cx, feature.handle(), ()) + { + required_features.push(s) + } else { + warn!("Unable to convert required feature to string"); + promise.reject_error(Error::NotSupported); + return promise; + } + } + } + } + + if let Some(ref o) = init.optionalFeatures { + for feature in o { + unsafe { + if let Ok(ConversionResult::Success(s)) = + String::from_jsval(*cx, feature.handle(), ()) + { + optional_features.push(s) + } else { + warn!("Unable to convert optional feature to string"); + } + } + } + } + + let init = SessionInit { + required_features, + optional_features, + }; + let promise = Promise::new_in_current_compartment(&self.global(), comp); let mut trusted = Some(TrustedPromise::new(promise.clone())); 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(); @@ -210,7 +252,7 @@ impl XRMethods for XR { ); window .webxr_registry() - .request_session(mode.into(), sender, frame_sender); + .request_session(mode.into(), init, sender, frame_sender); promise } @@ -232,7 +274,7 @@ impl XR { let session = match response { Ok(session) => session, Err(_) => { - promise.reject_native(&()); + promise.reject_error(Error::NotSupported); return; }, }; diff --git a/components/script/dom/xrtest.rs b/components/script/dom/xrtest.rs index b00a69b8fca..4c6852fc121 100644 --- a/components/script/dom/xrtest.rs +++ b/components/script/dom/xrtest.rs @@ -69,8 +69,10 @@ impl XRTest { impl XRTestMethods for XRTest { /// https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md + #[allow(unsafe_code)] fn SimulateDeviceConnection(&self, init: &FakeXRDeviceInit) -> Rc { - let p = Promise::new(&self.global()); + let global = self.global(); + let p = Promise::new(&global); let origin = if let Some(ref o) = init.viewerOrigin { match get_origin(&o) { @@ -104,12 +106,19 @@ impl XRTestMethods for XRTest { }, }; + let supported_features = if let Some(ref s) = init.supportedFeatures { + s.iter().cloned().map(String::from).collect() + } else { + vec![] + }; + let init = MockDeviceInit { viewer_origin: origin, views, supports_immersive: init.supportsImmersive, supports_unbounded: init.supportsUnbounded, floor_origin, + supported_features, }; let global = self.global(); diff --git a/tests/wpt/metadata/webxr/xrDevice_requestSession_immersive_unsupported.https.html.ini b/tests/wpt/metadata/webxr/xrDevice_requestSession_immersive_unsupported.https.html.ini deleted file mode 100644 index 58db0b825f9..00000000000 --- a/tests/wpt/metadata/webxr/xrDevice_requestSession_immersive_unsupported.https.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[xrDevice_requestSession_immersive_unsupported.https.html] - [Requesting an immersive session when unsupported rejects] - expected: FAIL - diff --git a/tests/wpt/metadata/webxr/xrSession_features_deviceSupport.https.html.ini b/tests/wpt/metadata/webxr/xrSession_features_deviceSupport.https.html.ini index c2051682335..7bd0c101858 100644 --- a/tests/wpt/metadata/webxr/xrSession_features_deviceSupport.https.html.ini +++ b/tests/wpt/metadata/webxr/xrSession_features_deviceSupport.https.html.ini @@ -1,4 +1,5 @@ [xrSession_features_deviceSupport.https.html] + expected: ERROR [Immersive XRSession requests with no supported device should reject] - expected: FAIL + expected: TIMEOUT From 535e05f7b2f8828f54b0a2f2196556b9227ed891 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 15 Jan 2020 13:16:33 +0530 Subject: [PATCH 5/7] Correctly unset pending flag --- components/script/dom/xr.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/script/dom/xr.rs b/components/script/dom/xr.rs index a2c4fd059f0..ab9c2c8264d 100644 --- a/components/script/dom/xr.rs +++ b/components/script/dom/xr.rs @@ -194,6 +194,9 @@ impl XRMethods for XR { required_features.push(s) } else { warn!("Unable to convert required feature to string"); + if mode != XRSessionMode::Inline { + self.pending_immersive_session.set(false); + } promise.reject_error(Error::NotSupported); return promise; } @@ -220,7 +223,6 @@ impl XRMethods for XR { optional_features, }; - let promise = Promise::new_in_current_compartment(&self.global(), comp); let mut trusted = Some(TrustedPromise::new(promise.clone())); let this = Trusted::new(self); let (task_source, canceller) = window @@ -253,7 +255,6 @@ impl XRMethods for XR { window .webxr_registry() .request_session(mode.into(), init, sender, frame_sender); - promise } @@ -274,6 +275,9 @@ impl XR { let session = match response { Ok(session) => session, Err(_) => { + if mode != XRSessionMode::Inline { + self.pending_immersive_session.set(false); + } promise.reject_error(Error::NotSupported); return; }, From 8cc7c5180398ad46f51036aa9876293968553074 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 14 Jan 2020 16:41:18 +0530 Subject: [PATCH 6/7] Update xrSession_features_deviceSupport to use new user activations for each session request --- tests/wpt/metadata/MANIFEST.json | 6 ++-- ...sion_features_deviceSupport.https.html.ini | 5 ---- .../webxr/resources/webxr_util.js | 12 ++++++++ ...rSession_features_deviceSupport.https.html | 29 ++++++++----------- .../xrSession_viewer_availability.https.html | 12 ++------ 5 files changed, 29 insertions(+), 35 deletions(-) delete mode 100644 tests/wpt/metadata/webxr/xrSession_features_deviceSupport.https.html.ini diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 9fbf4e053ad..d3622831fda 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -735150,7 +735150,7 @@ "support" ], "webxr/resources/webxr_util.js": [ - "5f66dc9573d37630d588265f20e5b57a8175766f", + "dbe1585929f50089bb3e26a981b9c12b30e9fa1f", "support" ], "webxr/webGLCanvasContext_create_xrcompatible.https.html": [ @@ -735302,7 +735302,7 @@ "testharness" ], "webxr/xrSession_features_deviceSupport.https.html": [ - "d8858bd4be689bf8e4f3a3795e13fad2a2057019", + "1ee63bae047bd196233f5e4253baec94b6a576a9", "testharness" ], "webxr/xrSession_input_events_end.https.html": [ @@ -735342,7 +735342,7 @@ "testharness" ], "webxr/xrSession_viewer_availability.https.html": [ - "c509e5f1a2a992b9329fd55e591e37fcea2b6e91", + "f28a07ad8bd0f8529b791048840bf60495186a7e", "testharness" ], "webxr/xrSession_viewer_referenceSpace.https.html": [ diff --git a/tests/wpt/metadata/webxr/xrSession_features_deviceSupport.https.html.ini b/tests/wpt/metadata/webxr/xrSession_features_deviceSupport.https.html.ini deleted file mode 100644 index 7bd0c101858..00000000000 --- a/tests/wpt/metadata/webxr/xrSession_features_deviceSupport.https.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[xrSession_features_deviceSupport.https.html] - expected: ERROR - [Immersive XRSession requests with no supported device should reject] - expected: TIMEOUT - diff --git a/tests/wpt/web-platform-tests/webxr/resources/webxr_util.js b/tests/wpt/web-platform-tests/webxr/resources/webxr_util.js index 5f66dc9573d..dbe1585929f 100644 --- a/tests/wpt/web-platform-tests/webxr/resources/webxr_util.js +++ b/tests/wpt/web-platform-tests/webxr/resources/webxr_util.js @@ -101,6 +101,18 @@ function xr_session_promise_test( properties); } + +// This function wraps the provided function in a +// simulateUserActivation() call, and resolves the promise with the +// result of func(), or an error if one is thrown +function promise_simulate_user_activation(func) { + return new Promise((resolve, reject) => { + navigator.xr.test.simulateUserActivation(() => { + try { let a = func(); resolve(a); } catch(e) { reject(e); } + }); + }); +} + // This functions calls a callback with each API object as specified // by https://immersive-web.github.io/webxr/spec/latest/, allowing // checks to be made on all ojects. diff --git a/tests/wpt/web-platform-tests/webxr/xrSession_features_deviceSupport.https.html b/tests/wpt/web-platform-tests/webxr/xrSession_features_deviceSupport.https.html index d8858bd4be6..1ee63bae047 100644 --- a/tests/wpt/web-platform-tests/webxr/xrSession_features_deviceSupport.https.html +++ b/tests/wpt/web-platform-tests/webxr/xrSession_features_deviceSupport.https.html @@ -21,6 +21,7 @@ "local-floor"] }; + xr_promise_test(testName, (t) => { function session_resolves(sessionMode, sessionInit) { @@ -31,34 +32,28 @@ } return navigator.xr.test.simulateDeviceConnection(fakeDeviceInitParams) - .then((controller) => new Promise((resolve, reject) => { - navigator.xr.test.simulateUserActivation(() => { + .then((controller) => + promise_simulate_user_activation(() => { // Attempting to request required features that aren't supported by // the device should reject. - promise_rejects(t, "NotSupportedError", + + return promise_rejects(t, "NotSupportedError", navigator.xr.requestSession("immersive-vr", { requiredFeatures: ['bounded-floor'] })) - .then(() => { + }).then(() => promise_simulate_user_activation(() => { // Attempting to request with an unsupported feature as optional // should succeed return session_resolves("immersive-vr", { optionalFeatures: ['bounded-floor'] }); + })).then(() => promise_simulate_user_activation(() => { + // Attempting to request with supported features only should succeed. + return session_resolves("immersive-vr", { + requiredFeatures: ['local', 'local-floor'] }) - .then(() => { - // Attempting to request with supported features only should succeed. - return session_resolves("immersive-vr", { - requiredFeatures: ['local', 'local-floor'] - }) - .then(() => { - resolve(); - }).catch((err) => { - reject(err); - });; - }); - }); - })); + })) + ); }); diff --git a/tests/wpt/web-platform-tests/webxr/xrSession_viewer_availability.https.html b/tests/wpt/web-platform-tests/webxr/xrSession_viewer_availability.https.html index c509e5f1a2a..f28a07ad8bd 100644 --- a/tests/wpt/web-platform-tests/webxr/xrSession_viewer_availability.https.html +++ b/tests/wpt/web-platform-tests/webxr/xrSession_viewer_availability.https.html @@ -24,14 +24,6 @@ .then(session => session.end())); } - function simulate_user_activation(func) { - return new Promise((resolve, reject) => { - navigator.xr.test.simulateUserActivation(() => { - try { resolve(func()); } catch(e) { reject(e); } - }); - }); - } - return session_resolves('inline', { // RequestSession with 'viewer' as a required featre should succeed, even // without user activation. @@ -62,14 +54,14 @@ optionalFeatures: ['local'] }); }) - .then(() => simulate_user_activation(() => { + .then(() => promise_simulate_user_activation(() => { // RequestSession with unsupported optional features should succeed. return session_resolves('inline', { requiredFeatures: ['viewer'], optionalFeatures: ['local'] }) })) - .then(() => simulate_user_activation(() => { + .then(() => promise_simulate_user_activation(() => { // Request with unsupported required features should reject. return session_rejects("NotSupportedError", 'inline', { requiredFeatures: ['local'] From 9a04a37c1cdd0f6f5fe5feca45f9468701fa3799 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 14 Jan 2020 18:09:28 +0530 Subject: [PATCH 7/7] Gate reference space creation on requested features --- components/script/dom/xr.rs | 2 ++ components/script/dom/xrsession.rs | 17 ++++++++++++++++- ...equestReferenceSpace_features.https.html.ini | 7 ------- 3 files changed, 18 insertions(+), 8 deletions(-) delete mode 100644 tests/wpt/metadata/webxr/xrSession_requestReferenceSpace_features.https.html.ini diff --git a/components/script/dom/xr.rs b/components/script/dom/xr.rs index ab9c2c8264d..46bcc46b090 100644 --- a/components/script/dom/xr.rs +++ b/components/script/dom/xr.rs @@ -185,6 +185,8 @@ impl XRMethods for XR { let mut optional_features = vec![]; let cx = global.get_cx(); + // We are supposed to include "viewer" and on immersive devices "local" + // by default here, but this is handled directly in requestReferenceSpace() if let Some(ref r) = init.requiredFeatures { for feature in r { unsafe { diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index e822a69eb8e..3f7f09baa9c 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -559,10 +559,25 @@ impl XRSessionMethods for XRSession { p.reject_error(Error::NotSupported) }, ty => { + if ty != XRReferenceSpaceType::Viewer && + (!self.is_immersive() || ty != XRReferenceSpaceType::Local) + { + let s = ty.as_str(); + if self + .session + .borrow() + .granted_features() + .iter() + .find(|f| &**f == s) + .is_none() + { + p.reject_error(Error::NotSupported); + return p; + } + } p.resolve_native(&XRReferenceSpace::new(&self.global(), self, ty)); }, } - p } diff --git a/tests/wpt/metadata/webxr/xrSession_requestReferenceSpace_features.https.html.ini b/tests/wpt/metadata/webxr/xrSession_requestReferenceSpace_features.https.html.ini deleted file mode 100644 index 42ddb3aa092..00000000000 --- a/tests/wpt/metadata/webxr/xrSession_requestReferenceSpace_features.https.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[xrSession_requestReferenceSpace_features.https.html] - [Immersive session rejects local-floor space if not requested] - expected: FAIL - - [Non-immersive session rejects local space if not requested] - expected: FAIL -