diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2020-01-09 02:45:49 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-09 02:45:49 -0500 |
commit | dbee7f7d2764af0eb2c380f15b0bd3f4fc52920e (patch) | |
tree | 6b06769a296c068bf8ad2a76fc59988ab91b64fb /components | |
parent | 95e6c7157285368281c492888f1c0b92eddeec71 (diff) | |
parent | 94e8ce5739677db8bd4c0ffbe50d035b37fafe51 (diff) | |
download | servo-dbee7f7d2764af0eb2c380f15b0bd3f4fc52920e.tar.gz servo-dbee7f7d2764af0eb2c380f15b0bd3f4fc52920e.zip |
Auto merge of #25463 - Manishearth:input-mocking, r=asajeffrey
Add input mocking, input sources change event
Depends on https://github.com/servo/webxr/pull/118
Also fixes some bugs I found.
Wanted to finish and merge this before I started on hit testing since the transient hit test stuff might have overlap.
There are a bunch of missing mock pieces that I'll probably do in a separate PR.
Still need to run tests.
Some things I skipped:
- Doing handedness/target ray setting: See https://github.com/immersive-web/webxr-test-api/issues/46 , this would require making our impl support these changing
- Handling button initial state: Would require some mock changes, but I ran out of time
- Handling profiles/etc: We don't yet have impl support for these
r? @jdm
Diffstat (limited to 'components')
-rw-r--r-- | components/atoms/static_atoms.txt | 1 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 3 | ||||
-rw-r--r-- | components/script/dom/fakexrdevice.rs | 89 | ||||
-rw-r--r-- | components/script/dom/fakexrinputcontroller.rs | 106 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 2 | ||||
-rw-r--r-- | components/script/dom/webidls/FakeXRDevice.webidl | 11 | ||||
-rw-r--r-- | components/script/dom/webidls/FakeXRInputController.webidl | 53 | ||||
-rw-r--r-- | components/script/dom/webidls/XRInputSource.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/webidls/XRInputSourcesChangeEvent.webidl | 19 | ||||
-rw-r--r-- | components/script/dom/webidls/XRSession.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/xrinputsource.rs | 15 | ||||
-rw-r--r-- | components/script/dom/xrinputsourcearray.rs | 55 | ||||
-rw-r--r-- | components/script/dom/xrinputsourceschangeevent.rs | 117 | ||||
-rw-r--r-- | components/script/dom/xrsession.rs | 14 | ||||
-rw-r--r-- | components/script/dom/xrviewerpose.rs | 2 |
15 files changed, 472 insertions, 19 deletions
diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt index bf50e2e9acd..65ca743ed90 100644 --- a/components/atoms/static_atoms.txt +++ b/components/atoms/static_atoms.txt @@ -44,6 +44,7 @@ iceconnectionstatechange icegatheringstatechange image input +inputsourceschange invalid keydown keypress diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index d2e1876b9d8..3bad24b1b1d 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -534,7 +534,8 @@ unsafe_no_jsmanaged_fields!( webxr_api::Registry, webxr_api::Session, webxr_api::Frame, - webxr_api::InputSource + webxr_api::InputSource, + webxr_api::InputId ); unsafe_no_jsmanaged_fields!(ScriptToConstellationChan); unsafe_no_jsmanaged_fields!(InteractiveMetrics); diff --git a/components/script/dom/fakexrdevice.rs b/components/script/dom/fakexrdevice.rs index bb73580e98a..f43b0b1155b 100644 --- a/components/script/dom/fakexrdevice.rs +++ b/components/script/dom/fakexrdevice.rs @@ -5,11 +5,17 @@ use crate::dom::bindings::codegen::Bindings::FakeXRDeviceBinding::{ self, FakeXRDeviceMethods, FakeXRRigidTransformInit, FakeXRViewInit, }; +use crate::dom::bindings::codegen::Bindings::FakeXRInputControllerBinding::FakeXRInputSourceInit; +use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{ + XRHandedness, XRTargetRayMode, +}; +use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRVisibilityState; use crate::dom::bindings::codegen::Bindings::XRViewBinding::XREye; use crate::dom::bindings::error::{Error, Fallible}; use crate::dom::bindings::refcounted::TrustedPromise; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::DomRoot; +use crate::dom::fakexrinputcontroller::FakeXRInputController; use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; use crate::task_source::TaskSource; @@ -19,14 +25,20 @@ use euclid::{RigidTransform3D, Rotation3D, Transform3D, Vector3D}; use ipc_channel::ipc::IpcSender; use ipc_channel::router::ROUTER; use profile_traits::ipc; +use std::cell::Cell; use std::rc::Rc; -use webxr_api::{MockDeviceMsg, MockViewInit, MockViewsInit}; +use webxr_api::{ + Handedness, InputId, InputSource, MockDeviceMsg, MockInputInit, MockViewInit, MockViewsInit, + TargetRayMode, Visibility, +}; #[dom_struct] pub struct FakeXRDevice { reflector: Reflector, #[ignore_malloc_size_of = "defined in ipc-channel"] sender: IpcSender<MockDeviceMsg>, + #[ignore_malloc_size_of = "defined in webxr-api"] + next_input_id: Cell<InputId>, } impl FakeXRDevice { @@ -34,6 +46,7 @@ impl FakeXRDevice { FakeXRDevice { reflector: Reflector::new(), sender, + next_input_id: Cell::new(InputId(0)), } } @@ -163,7 +176,59 @@ impl FakeXRDeviceMethods for FakeXRDevice { Ok(()) } - /// https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrdevice-simulatevisibilitychange + fn SimulateVisibilityChange(&self, v: XRVisibilityState) { + let v = match v { + XRVisibilityState::Visible => Visibility::Visible, + XRVisibilityState::Visible_blurred => Visibility::VisibleBlurred, + XRVisibilityState::Hidden => Visibility::Hidden, + }; + let _ = self.sender.send(MockDeviceMsg::VisibilityChange(v)); + } + + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrdevice-simulateinputsourceconnection + fn SimulateInputSourceConnection( + &self, + init: &FakeXRInputSourceInit, + ) -> Fallible<DomRoot<FakeXRInputController>> { + let id = self.next_input_id.get(); + self.next_input_id.set(InputId(id.0 + 1)); + + let handedness = init.handedness.into(); + let target_ray_mode = init.targetRayMode.into(); + + let pointer_origin = Some(get_origin(&init.pointerOrigin)?); + + let grip_origin = if let Some(ref g) = init.gripOrigin { + Some(get_origin(g)?) + } else { + None + }; + + // XXXManishearth deal with profiles, supportedButtons, selection* + + let source = InputSource { + handedness, + target_ray_mode, + id, + supports_grip: true, + }; + + let init = MockInputInit { + source, + pointer_origin, + grip_origin, + }; + + let global = self.global(); + let _ = self.sender.send(MockDeviceMsg::AddInputSource(init)); + + let controller = FakeXRInputController::new(&global, self.sender.clone(), id); + + Ok(controller) + } + + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrdevice-disconnect fn Disconnect(&self) -> Rc<Promise> { let global = self.global(); let p = Promise::new(&global); @@ -186,3 +251,23 @@ impl FakeXRDeviceMethods for FakeXRDevice { p } } + +impl From<XRHandedness> for Handedness { + fn from(h: XRHandedness) -> Self { + match h { + XRHandedness::None => Handedness::None, + XRHandedness::Left => Handedness::Left, + XRHandedness::Right => Handedness::Right, + } + } +} + +impl From<XRTargetRayMode> for TargetRayMode { + fn from(t: XRTargetRayMode) -> Self { + match t { + XRTargetRayMode::Gaze => TargetRayMode::Gaze, + XRTargetRayMode::Tracked_pointer => TargetRayMode::TrackedPointer, + XRTargetRayMode::Screen => TargetRayMode::Screen, + } + } +} diff --git a/components/script/dom/fakexrinputcontroller.rs b/components/script/dom/fakexrinputcontroller.rs new file mode 100644 index 00000000000..67e6f72cf70 --- /dev/null +++ b/components/script/dom/fakexrinputcontroller.rs @@ -0,0 +1,106 @@ +/* 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::FakeXRDeviceBinding::FakeXRRigidTransformInit; +use crate::dom::bindings::codegen::Bindings::FakeXRInputControllerBinding::{ + self, FakeXRInputControllerMethods, +}; +use crate::dom::bindings::error::Fallible; +use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; +use crate::dom::bindings::root::DomRoot; +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}; + +#[dom_struct] +pub struct FakeXRInputController { + reflector: Reflector, + #[ignore_malloc_size_of = "defined in ipc-channel"] + sender: IpcSender<MockDeviceMsg>, + #[ignore_malloc_size_of = "defined in webxr-api"] + id: InputId, +} + +impl FakeXRInputController { + pub fn new_inherited(sender: IpcSender<MockDeviceMsg>, id: InputId) -> FakeXRInputController { + FakeXRInputController { + reflector: Reflector::new(), + sender, + id, + } + } + + pub fn new( + global: &GlobalScope, + sender: IpcSender<MockDeviceMsg>, + id: InputId, + ) -> DomRoot<FakeXRInputController> { + reflect_dom_object( + Box::new(FakeXRInputController::new_inherited(sender, id)), + global, + FakeXRInputControllerBinding::Wrap, + ) + } + + fn send_message(&self, msg: MockInputMsg) { + let _ = self + .sender + .send(MockDeviceMsg::MessageInputSource(self.id, msg)); + } +} + +impl FakeXRInputControllerMethods for FakeXRInputController { + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-setpointerorigin + fn SetPointerOrigin(&self, origin: &FakeXRRigidTransformInit, _emulated: bool) -> Fallible<()> { + self.send_message(MockInputMsg::SetPointerOrigin(Some(get_origin(origin)?))); + Ok(()) + } + + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-setgriporigin + fn SetGripOrigin(&self, origin: &FakeXRRigidTransformInit, _emulated: bool) -> Fallible<()> { + self.send_message(MockInputMsg::SetGripOrigin(Some(get_origin(origin)?))); + Ok(()) + } + + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-cleargriporigin + fn ClearGripOrigin(&self) { + self.send_message(MockInputMsg::SetGripOrigin(None)) + } + + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-disconnect + fn Disconnect(&self) { + self.send_message(MockInputMsg::Disconnect) + } + + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-reconnect + fn Reconnect(&self) { + self.send_message(MockInputMsg::Reconnect) + } + + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-startselection + fn StartSelection(&self) { + self.send_message(MockInputMsg::TriggerSelect( + SelectKind::Select, + SelectEvent::Start, + )) + } + + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-endselection + fn EndSelection(&self) { + self.send_message(MockInputMsg::TriggerSelect( + SelectKind::Select, + SelectEvent::End, + )) + } + + /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-simulateselect + fn SimulateSelect(&self) { + self.send_message(MockInputMsg::TriggerSelect( + SelectKind::Select, + SelectEvent::Select, + )) + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index b8bdc638c17..0fdf4a80b69 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -301,6 +301,7 @@ pub mod eventtarget; pub mod extendableevent; pub mod extendablemessageevent; pub mod fakexrdevice; +pub mod fakexrinputcontroller; pub mod file; pub mod filelist; pub mod filereader; @@ -564,6 +565,7 @@ pub mod xrframe; pub mod xrinputsource; pub mod xrinputsourcearray; pub mod xrinputsourceevent; +pub mod xrinputsourceschangeevent; pub mod xrpose; pub mod xrreferencespace; pub mod xrrenderstate; diff --git a/components/script/dom/webidls/FakeXRDevice.webidl b/components/script/dom/webidls/FakeXRDevice.webidl index 4dde2678435..856df51cc7a 100644 --- a/components/script/dom/webidls/FakeXRDevice.webidl +++ b/components/script/dom/webidls/FakeXRDevice.webidl @@ -10,9 +10,6 @@ interface FakeXRDevice { // requestAnimationFrame() callbacks. [Throws] void setViews(sequence<FakeXRViewInit> views); - // // behaves as if device was disconnected - // Promise<void> disconnect(); - [Throws] void setViewerOrigin(FakeXRRigidTransformInit origin, optional boolean emulatedPosition = false); void clearViewerOrigin(); @@ -20,15 +17,11 @@ interface FakeXRDevice { void clearFloorOrigin(); // // Simulates devices focusing and blurring sessions. - // void simulateVisibilityChange(XRVisibilityState); + void simulateVisibilityChange(XRVisibilityState state); // void setBoundsGeometry(sequence<FakeXRBoundsPoint> boundsCoodinates); - // // Sets eye level used for calculating floor-level spaces - // void setEyeLevel(float eyeLevel); - - // Promise<FakeXRInputController> - // simulateInputSourceConnection(FakeXRInputSourceInit); + [Throws] FakeXRInputController simulateInputSourceConnection(FakeXRInputSourceInit init); // behaves as if device was disconnected Promise<void> disconnect(); diff --git a/components/script/dom/webidls/FakeXRInputController.webidl b/components/script/dom/webidls/FakeXRInputController.webidl new file mode 100644 index 00000000000..a50950cdee3 --- /dev/null +++ b/components/script/dom/webidls/FakeXRInputController.webidl @@ -0,0 +1,53 @@ +/* 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-test-api/#fakexrinputcontroller + +[Exposed=Window, Pref="dom.webxr.test"] +interface FakeXRInputController { + // void setHandedness(XRHandedness handedness); + // void setTargetRayMode(XRTargetRayMode targetRayMode); + // void setProfiles(sequence<DOMString> profiles); + [Throws] void setGripOrigin(FakeXRRigidTransformInit gripOrigin, optional boolean emulatedPosition = false); + void clearGripOrigin(); + [Throws] void setPointerOrigin(FakeXRRigidTransformInit pointerOrigin, optional boolean emulatedPosition = false); + + void disconnect(); + void reconnect(); + + void startSelection(); + void endSelection(); + void simulateSelect(); + + // void setSupportedButtons(sequence<FakeXRButtonStateInit> supportedButtons); + // void updateButtonState(FakeXRButtonStateInit buttonState); +}; + +dictionary FakeXRInputSourceInit { + required XRHandedness handedness; + required XRTargetRayMode targetRayMode; + required FakeXRRigidTransformInit pointerOrigin; + required sequence<DOMString> profiles; + boolean selectionStarted = false; + boolean selectionClicked = false; + sequence<FakeXRButtonStateInit> supportedButtons; + FakeXRRigidTransformInit gripOrigin; +}; + +enum FakeXRButtonType { + "grip", + "touchpad", + "thumbstick", + "optional-button", + "optional-thumbstick" +}; + +dictionary FakeXRButtonStateInit { + required FakeXRButtonType buttonType; + required boolean pressed; + required boolean touched; + required float pressedValue; + float xValue = 0.0; + float yValue = 0.0; +}; diff --git a/components/script/dom/webidls/XRInputSource.webidl b/components/script/dom/webidls/XRInputSource.webidl index 51efc645282..f07de183927 100644 --- a/components/script/dom/webidls/XRInputSource.webidl +++ b/components/script/dom/webidls/XRInputSource.webidl @@ -19,7 +19,7 @@ enum XRTargetRayMode { [SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] interface XRInputSource { readonly attribute XRHandedness handedness; - // [SameObject] readonly attribute XRTargetRayMode targetRayMode; + readonly attribute XRTargetRayMode targetRayMode; [SameObject] readonly attribute XRSpace targetRaySpace; [SameObject] readonly attribute XRSpace? gripSpace; // [SameObject] readonly attribute Gamepad? gamepad; diff --git a/components/script/dom/webidls/XRInputSourcesChangeEvent.webidl b/components/script/dom/webidls/XRInputSourcesChangeEvent.webidl new file mode 100644 index 00000000000..aba56f8b0a6 --- /dev/null +++ b/components/script/dom/webidls/XRInputSourcesChangeEvent.webidl @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrinputsourceschangedevent-interface + +[SecureContext, Exposed=Window, Pref="dom.webxr.test"] +interface XRInputSourcesChangeEvent : Event { + constructor(DOMString type, XRInputSourcesChangeEventInit eventInitDict); + [SameObject] readonly attribute XRSession session; + /* [SameObject] */ readonly attribute /* FrozenArray<XRInputSource> */ any added; + /* [SameObject] */ readonly attribute /* FrozenArray<XRInputSource> */ any removed; +}; + +dictionary XRInputSourcesChangeEventInit : EventInit { + required XRSession session; + required sequence<XRInputSource> added; + required sequence<XRInputSource> removed; +}; diff --git a/components/script/dom/webidls/XRSession.webidl b/components/script/dom/webidls/XRSession.webidl index e726a500cb7..a00e0c4cd3d 100644 --- a/components/script/dom/webidls/XRSession.webidl +++ b/components/script/dom/webidls/XRSession.webidl @@ -40,7 +40,7 @@ interface XRSession : EventTarget { attribute EventHandler onend; attribute EventHandler onselect; attribute EventHandler onsqueeze; - // attribute EventHandler oninputsourceschange; + attribute EventHandler oninputsourceschange; attribute EventHandler onselectstart; attribute EventHandler onselectend; attribute EventHandler onsqueezestart; diff --git a/components/script/dom/xrinputsource.rs b/components/script/dom/xrinputsource.rs index 7516fe49f2f..fed76937d9c 100644 --- a/components/script/dom/xrinputsource.rs +++ b/components/script/dom/xrinputsource.rs @@ -4,7 +4,7 @@ use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding; use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{ - XRHandedness, XRInputSourceMethods, + XRHandedness, XRInputSourceMethods, XRTargetRayMode, }; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; @@ -12,7 +12,7 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::xrsession::XRSession; use crate::dom::xrspace::XRSpace; use dom_struct::dom_struct; -use webxr_api::{Handedness, InputId, InputSource}; +use webxr_api::{Handedness, InputId, InputSource, TargetRayMode}; #[dom_struct] pub struct XRInputSource { @@ -64,6 +64,15 @@ impl XRInputSourceMethods for XRInputSource { } } + /// https://immersive-web.github.io/webxr/#dom-xrinputsource-targetraymode + fn TargetRayMode(&self) -> XRTargetRayMode { + match self.info.target_ray_mode { + TargetRayMode::Gaze => XRTargetRayMode::Gaze, + TargetRayMode::TrackedPointer => XRTargetRayMode::Tracked_pointer, + TargetRayMode::Screen => XRTargetRayMode::Screen, + } + } + /// https://immersive-web.github.io/webxr/#dom-xrinputsource-targetrayspace fn TargetRaySpace(&self) -> DomRoot<XRSpace> { self.target_ray_space.or_init(|| { @@ -75,7 +84,7 @@ impl XRInputSourceMethods for XRInputSource { /// https://immersive-web.github.io/webxr/#dom-xrinputsource-gripspace fn GetGripSpace(&self) -> Option<DomRoot<XRSpace>> { if self.info.supports_grip { - Some(self.target_ray_space.or_init(|| { + Some(self.grip_space.or_init(|| { let global = self.global(); XRSpace::new_inputspace(&global, &self.session, &self, true) })) diff --git a/components/script/dom/xrinputsourcearray.rs b/components/script/dom/xrinputsourcearray.rs index 48f84991db0..45e0f2851e4 100644 --- a/components/script/dom/xrinputsourcearray.rs +++ b/components/script/dom/xrinputsourcearray.rs @@ -5,13 +5,16 @@ use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::XRInputSourceArrayBinding; use crate::dom::bindings::codegen::Bindings::XRInputSourceArrayBinding::XRInputSourceArrayMethods; +use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::event::Event; use crate::dom::globalscope::GlobalScope; use crate::dom::xrinputsource::XRInputSource; +use crate::dom::xrinputsourceschangeevent::XRInputSourcesChangeEvent; use crate::dom::xrsession::XRSession; use dom_struct::dom_struct; -use webxr_api::InputId; +use webxr_api::{InputId, InputSource}; #[dom_struct] pub struct XRInputSourceArray { @@ -48,6 +51,56 @@ 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!" + ); + input_sources.push(Dom::from_ref(&input)); + + let added = [input]; + + let event = XRInputSourcesChangeEvent::new( + &global, + atom!("inputsourceschange"), + false, + true, + session, + &added, + &[], + ); + // Release the refcell guard + drop(input_sources); + event.upcast::<Event>().fire(session.upcast()); + } + + pub fn remove_input_source(&self, session: &XRSession, id: InputId) { + let mut input_sources = self.input_sources.borrow_mut(); + let global = self.global(); + let removed = if let Some(i) = input_sources.iter().find(|i| i.id() == id) { + [DomRoot::from_ref(&**i)] + } else { + return; + }; + + let event = XRInputSourcesChangeEvent::new( + &global, + atom!("inputsourceschange"), + false, + true, + session, + &[], + &removed, + ); + input_sources.retain(|i| i.id() != id); + // release the refcell guard + drop(input_sources); + event.upcast::<Event>().fire(session.upcast()); + } + pub fn find(&self, id: InputId) -> Option<DomRoot<XRInputSource>> { self.input_sources .borrow() diff --git a/components/script/dom/xrinputsourceschangeevent.rs b/components/script/dom/xrinputsourceschangeevent.rs new file mode 100644 index 00000000000..f5a2e6f33ad --- /dev/null +++ b/components/script/dom/xrinputsourceschangeevent.rs @@ -0,0 +1,117 @@ +/* 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::compartments::enter_realm; +use crate::dom::bindings::codegen::Bindings::EventBinding::EventBinding::EventMethods; +use crate::dom::bindings::codegen::Bindings::XRInputSourcesChangeEventBinding::{ + self, XRInputSourcesChangeEventMethods, +}; +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::xrinputsource::XRInputSource; +use crate::dom::xrsession::XRSession; +use crate::script_runtime::JSContext; +use dom_struct::dom_struct; +use js::conversions::ToJSValConvertible; +use js::jsapi::Heap; +use js::jsval::{JSVal, UndefinedValue}; +use servo_atoms::Atom; + +#[dom_struct] +pub struct XRInputSourcesChangeEvent { + event: Event, + session: Dom<XRSession>, + #[ignore_malloc_size_of = "mozjs"] + added: Heap<JSVal>, + #[ignore_malloc_size_of = "mozjs"] + removed: Heap<JSVal>, +} + +impl XRInputSourcesChangeEvent { + #[allow(unrooted_must_root)] + fn new_inherited(session: &XRSession) -> XRInputSourcesChangeEvent { + XRInputSourcesChangeEvent { + event: Event::new_inherited(), + session: Dom::from_ref(session), + added: Heap::default(), + removed: Heap::default(), + } + } + + #[allow(unsafe_code)] + pub fn new( + global: &GlobalScope, + type_: Atom, + bubbles: bool, + cancelable: bool, + session: &XRSession, + added: &[DomRoot<XRInputSource>], + removed: &[DomRoot<XRInputSource>], + ) -> DomRoot<XRInputSourcesChangeEvent> { + let changeevent = reflect_dom_object( + Box::new(XRInputSourcesChangeEvent::new_inherited(session)), + global, + XRInputSourcesChangeEventBinding::Wrap, + ); + { + let event = changeevent.upcast::<Event>(); + event.init_event(type_, bubbles, cancelable); + } + let _ac = enter_realm(&*global); + let cx = global.get_cx(); + unsafe { + rooted!(in(*cx) let mut added_val = UndefinedValue()); + added.to_jsval(*cx, added_val.handle_mut()); + 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 + } + + pub fn Constructor( + window: &Window, + type_: DOMString, + init: &XRInputSourcesChangeEventBinding::XRInputSourcesChangeEventInit, + ) -> DomRoot<XRInputSourcesChangeEvent> { + XRInputSourcesChangeEvent::new( + &window.global(), + Atom::from(type_), + init.parent.bubbles, + init.parent.cancelable, + &init.session, + &*init.added, + &*init.removed, + ) + } +} + +impl XRInputSourcesChangeEventMethods for XRInputSourcesChangeEvent { + // https://immersive-web.github.io/webxr/#dom-xrinputsourceschangeevent-session + fn Session(&self) -> DomRoot<XRSession> { + DomRoot::from_ref(&*self.session) + } + + // https://immersive-web.github.io/webxr/#dom-xrinputsourceschangeevent-added + fn Added(&self, _cx: JSContext) -> JSVal { + self.added.get() + } + + // https://immersive-web.github.io/webxr/#dom-xrinputsourceschangeevent-removed + fn Removed(&self, _cx: JSContext) -> JSVal { + self.removed.get() + } + + // https://dom.spec.whatwg.org/#dom-event-istrusted + fn IsTrusted(&self) -> bool { + self.event.IsTrusted() + } +} diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index a4ced8689a5..4979835fc42 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -289,7 +289,12 @@ impl XRSession { ); event.upcast::<Event>().fire(self.upcast()); }, - _ => (), // XXXManishearth TBD + XREvent::AddInput(info) => { + self.input_sources.add_input_source(self, info); + }, + XREvent::RemoveInput(id) => { + self.input_sources.remove_input_source(self, id); + }, } } @@ -432,6 +437,13 @@ impl XRSessionMethods for XRSession { SetOnvisibilitychange ); + /// https://immersive-web.github.io/webxr/#eventdef-xrsession-inputsourceschange + event_handler!( + inputsourceschange, + GetOninputsourceschange, + SetOninputsourceschange + ); + // https://immersive-web.github.io/webxr/#dom-xrsession-renderstate fn RenderState(&self) -> DomRoot<XRRenderState> { self.active_render_state.get() diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs index 0e64613294b..6e11944b788 100644 --- a/components/script/dom/xrviewerpose.rs +++ b/components/script/dom/xrviewerpose.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::XRViewBinding::XREye; use crate::dom::bindings::codegen::Bindings::XRViewerPoseBinding; use crate::dom::bindings::codegen::Bindings::XRViewerPoseBinding::XRViewerPoseMethods; @@ -40,6 +41,7 @@ impl XRViewerPose { session: &XRSession, pose: ApiViewerPose, ) -> DomRoot<XRViewerPose> { + let _ac = enter_realm(&*global); rooted_vec!(let mut views); session.with_session(|s| match s.views() { Views::Inline => views.push(XRView::new( |