aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2020-01-09 02:45:49 -0500
committerGitHub <noreply@github.com>2020-01-09 02:45:49 -0500
commitdbee7f7d2764af0eb2c380f15b0bd3f4fc52920e (patch)
tree6b06769a296c068bf8ad2a76fc59988ab91b64fb /components
parent95e6c7157285368281c492888f1c0b92eddeec71 (diff)
parent94e8ce5739677db8bd4c0ffbe50d035b37fafe51 (diff)
downloadservo-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.txt1
-rw-r--r--components/script/dom/bindings/trace.rs3
-rw-r--r--components/script/dom/fakexrdevice.rs89
-rw-r--r--components/script/dom/fakexrinputcontroller.rs106
-rw-r--r--components/script/dom/mod.rs2
-rw-r--r--components/script/dom/webidls/FakeXRDevice.webidl11
-rw-r--r--components/script/dom/webidls/FakeXRInputController.webidl53
-rw-r--r--components/script/dom/webidls/XRInputSource.webidl2
-rw-r--r--components/script/dom/webidls/XRInputSourcesChangeEvent.webidl19
-rw-r--r--components/script/dom/webidls/XRSession.webidl2
-rw-r--r--components/script/dom/xrinputsource.rs15
-rw-r--r--components/script/dom/xrinputsourcearray.rs55
-rw-r--r--components/script/dom/xrinputsourceschangeevent.rs117
-rw-r--r--components/script/dom/xrsession.rs14
-rw-r--r--components/script/dom/xrviewerpose.rs2
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(