1use dom_struct::dom_struct;
6use js::jsapi::JSContext;
7use js::rust::MutableHandleValue;
8use webxr_api::{FingerJoint, Hand, Joint};
9
10use crate::dom::bindings::codegen::Bindings::XRHandBinding::{XRHandJoint, XRHandMethods};
11use crate::dom::bindings::conversions::ToJSValConvertible;
12use crate::dom::bindings::iterable::Iterable;
13use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
14use crate::dom::bindings::root::{Dom, DomRoot};
15use crate::dom::globalscope::GlobalScope;
16use crate::dom::xrinputsource::XRInputSource;
17use crate::dom::xrjointspace::XRJointSpace;
18use crate::script_runtime::CanGc;
19
20const JOINT_SPACE_MAP: [(XRHandJoint, Joint); 25] = [
21 (XRHandJoint::Wrist, Joint::Wrist),
22 (XRHandJoint::Thumb_metacarpal, Joint::ThumbMetacarpal),
23 (
24 XRHandJoint::Thumb_phalanx_proximal,
25 Joint::ThumbPhalanxProximal,
26 ),
27 (XRHandJoint::Thumb_phalanx_distal, Joint::ThumbPhalanxDistal),
28 (XRHandJoint::Thumb_tip, Joint::ThumbPhalanxTip),
29 (
30 XRHandJoint::Index_finger_metacarpal,
31 Joint::Index(FingerJoint::Metacarpal),
32 ),
33 (
34 XRHandJoint::Index_finger_phalanx_proximal,
35 Joint::Index(FingerJoint::PhalanxProximal),
36 ),
37 (XRHandJoint::Index_finger_phalanx_intermediate, {
38 Joint::Index(FingerJoint::PhalanxIntermediate)
39 }),
40 (
41 XRHandJoint::Index_finger_phalanx_distal,
42 Joint::Index(FingerJoint::PhalanxDistal),
43 ),
44 (
45 XRHandJoint::Index_finger_tip,
46 Joint::Index(FingerJoint::PhalanxTip),
47 ),
48 (
49 XRHandJoint::Middle_finger_metacarpal,
50 Joint::Middle(FingerJoint::Metacarpal),
51 ),
52 (
53 XRHandJoint::Middle_finger_phalanx_proximal,
54 Joint::Middle(FingerJoint::PhalanxProximal),
55 ),
56 (XRHandJoint::Middle_finger_phalanx_intermediate, {
57 Joint::Middle(FingerJoint::PhalanxIntermediate)
58 }),
59 (
60 XRHandJoint::Middle_finger_phalanx_distal,
61 Joint::Middle(FingerJoint::PhalanxDistal),
62 ),
63 (
64 XRHandJoint::Middle_finger_tip,
65 Joint::Middle(FingerJoint::PhalanxTip),
66 ),
67 (
68 XRHandJoint::Ring_finger_metacarpal,
69 Joint::Ring(FingerJoint::Metacarpal),
70 ),
71 (
72 XRHandJoint::Ring_finger_phalanx_proximal,
73 Joint::Ring(FingerJoint::PhalanxProximal),
74 ),
75 (XRHandJoint::Ring_finger_phalanx_intermediate, {
76 Joint::Ring(FingerJoint::PhalanxIntermediate)
77 }),
78 (
79 XRHandJoint::Ring_finger_phalanx_distal,
80 Joint::Ring(FingerJoint::PhalanxDistal),
81 ),
82 (
83 XRHandJoint::Ring_finger_tip,
84 Joint::Ring(FingerJoint::PhalanxTip),
85 ),
86 (
87 XRHandJoint::Pinky_finger_metacarpal,
88 Joint::Little(FingerJoint::Metacarpal),
89 ),
90 (
91 XRHandJoint::Pinky_finger_phalanx_proximal,
92 Joint::Little(FingerJoint::PhalanxProximal),
93 ),
94 (XRHandJoint::Pinky_finger_phalanx_intermediate, {
95 Joint::Little(FingerJoint::PhalanxIntermediate)
96 }),
97 (
98 XRHandJoint::Pinky_finger_phalanx_distal,
99 Joint::Little(FingerJoint::PhalanxDistal),
100 ),
101 (
102 XRHandJoint::Pinky_finger_tip,
103 Joint::Little(FingerJoint::PhalanxTip),
104 ),
105];
106
107#[dom_struct]
108pub(crate) struct XRHand {
109 reflector_: Reflector,
110 #[ignore_malloc_size_of = "defined in webxr"]
111 source: Dom<XRInputSource>,
112 #[ignore_malloc_size_of = "partially defind in webxr"]
113 #[custom_trace]
114 spaces: Hand<Dom<XRJointSpace>>,
115}
116
117impl XRHand {
118 fn new_inherited(source: &XRInputSource, spaces: &Hand<DomRoot<XRJointSpace>>) -> XRHand {
119 XRHand {
120 reflector_: Reflector::new(),
121 source: Dom::from_ref(source),
122 spaces: spaces.map(|j, _| j.as_ref().map(|j| Dom::from_ref(&**j))),
123 }
124 }
125
126 pub(crate) fn new(
127 global: &GlobalScope,
128 source: &XRInputSource,
129 support: Hand<()>,
130 can_gc: CanGc,
131 ) -> DomRoot<XRHand> {
132 let id = source.id();
133 let session = source.session();
134 let spaces = support.map(|field, joint| {
135 let hand_joint = JOINT_SPACE_MAP
136 .iter()
137 .find(|&&(_, value)| value == joint)
138 .map(|&(hand_joint, _)| hand_joint)
139 .expect("Invalid joint name");
140 field.map(|_| XRJointSpace::new(global, session, id, joint, hand_joint, CanGc::note()))
141 });
142 reflect_dom_object(
143 Box::new(XRHand::new_inherited(source, &spaces)),
144 global,
145 can_gc,
146 )
147 }
148}
149
150impl XRHandMethods<crate::DomTypeHolder> for XRHand {
151 fn Size(&self) -> u32 {
153 XRHandJoint::Pinky_finger_tip as u32 + 1
154 }
155
156 fn Get(&self, joint_name: XRHandJoint) -> DomRoot<XRJointSpace> {
158 let joint = JOINT_SPACE_MAP
159 .iter()
160 .find(|&&(key, _)| key == joint_name)
161 .map(|&(_, joint)| joint)
162 .expect("Invalid joint name");
163 self.spaces
164 .get(joint)
165 .map(|j| DomRoot::from_ref(&**j))
166 .expect("Failed to get joint pose")
167 }
168}
169
170pub(crate) struct ValueWrapper(pub DomRoot<XRJointSpace>);
173
174impl ToJSValConvertible for ValueWrapper {
175 #[allow(unsafe_code)]
176 unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
177 self.0.to_jsval(cx, rval)
178 }
179}
180
181impl Iterable for XRHand {
182 type Key = XRHandJoint;
183 type Value = ValueWrapper;
184
185 fn get_iterable_length(&self) -> u32 {
186 JOINT_SPACE_MAP.len() as u32
187 }
188
189 fn get_value_at_index(&self, n: u32) -> ValueWrapper {
190 let joint = JOINT_SPACE_MAP[n as usize].1;
191 self.spaces
192 .get(joint)
193 .map(|j| ValueWrapper(DomRoot::from_ref(&**j)))
194 .expect("Failed to get joint pose")
195 }
196
197 fn get_key_at_index(&self, n: u32) -> XRHandJoint {
198 JOINT_SPACE_MAP[n as usize].0
199 }
200}