1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use euclid::Point2D;
9use js::rust::HandleObject;
10use keyboard_types::Modifiers;
11use style_traits::CSSPixel;
12
13use super::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
14use crate::dom::bindings::cell::DomRefCell;
15use crate::dom::bindings::codegen::Bindings::PointerEventBinding::{
16 PointerEventInit, PointerEventMethods,
17};
18use crate::dom::bindings::num::Finite;
19use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
20use crate::dom::bindings::root::DomRoot;
21use crate::dom::bindings::str::DOMString;
22use crate::dom::event::{EventBubbles, EventCancelable};
23use crate::dom::eventtarget::EventTarget;
24use crate::dom::mouseevent::MouseEvent;
25use crate::dom::window::Window;
26use crate::script_runtime::CanGc;
27
28#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
30pub(crate) enum PointerId {
31 NonPointerDevice = -1,
32 Mouse,
33}
34
35#[dom_struct]
36pub(crate) struct PointerEvent {
37 mouseevent: MouseEvent,
38 pointer_id: Cell<i32>,
39 width: Cell<i32>,
40 height: Cell<i32>,
41 pressure: Cell<f32>,
42 tangential_pressure: Cell<f32>,
43 tilt_x: Cell<i32>,
44 tilt_y: Cell<i32>,
45 twist: Cell<i32>,
46 altitude_angle: Cell<f64>,
47 azimuth_angle: Cell<f64>,
48 pointer_type: DomRefCell<DOMString>,
49 is_primary: Cell<bool>,
50 coalesced_events: DomRefCell<Vec<DomRoot<PointerEvent>>>,
51 predicted_events: DomRefCell<Vec<DomRoot<PointerEvent>>>,
52}
53
54impl PointerEvent {
55 pub(crate) fn new_inherited() -> PointerEvent {
56 PointerEvent {
57 mouseevent: MouseEvent::new_inherited(),
58 pointer_id: Cell::new(0),
59 width: Cell::new(0),
60 height: Cell::new(0),
61 pressure: Cell::new(0.),
62 tangential_pressure: Cell::new(0.),
63 tilt_x: Cell::new(0),
64 tilt_y: Cell::new(0),
65 twist: Cell::new(0),
66 altitude_angle: Cell::new(0.),
67 azimuth_angle: Cell::new(0.),
68 pointer_type: DomRefCell::new(DOMString::new()),
69 is_primary: Cell::new(false),
70 coalesced_events: DomRefCell::new(Vec::new()),
71 predicted_events: DomRefCell::new(Vec::new()),
72 }
73 }
74
75 pub(crate) fn new_uninitialized(window: &Window, can_gc: CanGc) -> DomRoot<PointerEvent> {
76 Self::new_uninitialized_with_proto(window, None, can_gc)
77 }
78
79 fn new_uninitialized_with_proto(
80 window: &Window,
81 proto: Option<HandleObject>,
82 can_gc: CanGc,
83 ) -> DomRoot<PointerEvent> {
84 reflect_dom_object_with_proto(
85 Box::new(PointerEvent::new_inherited()),
86 window,
87 proto,
88 can_gc,
89 )
90 }
91
92 #[allow(clippy::too_many_arguments)]
93 pub(crate) fn new(
94 window: &Window,
95 type_: DOMString,
96 can_bubble: EventBubbles,
97 cancelable: EventCancelable,
98 view: Option<&Window>,
99 detail: i32,
100 screen_point: Point2D<i32, CSSPixel>,
101 client_point: Point2D<i32, CSSPixel>,
102 page_point: Point2D<i32, CSSPixel>,
103 modifiers: Modifiers,
104 button: i16,
105 buttons: u16,
106 related_target: Option<&EventTarget>,
107 point_in_target: Option<Point2D<f32, CSSPixel>>,
108 pointer_id: i32,
109 width: i32,
110 height: i32,
111 pressure: f32,
112 tangential_pressure: f32,
113 tilt_x: i32,
114 tilt_y: i32,
115 twist: i32,
116 altitude_angle: f64,
117 azimuth_angle: f64,
118 pointer_type: DOMString,
119 is_primary: bool,
120 coalesced_events: Vec<DomRoot<PointerEvent>>,
121 predicted_events: Vec<DomRoot<PointerEvent>>,
122 can_gc: CanGc,
123 ) -> DomRoot<PointerEvent> {
124 Self::new_with_proto(
125 window,
126 None,
127 type_,
128 can_bubble,
129 cancelable,
130 view,
131 detail,
132 screen_point,
133 client_point,
134 page_point,
135 modifiers,
136 button,
137 buttons,
138 related_target,
139 point_in_target,
140 pointer_id,
141 width,
142 height,
143 pressure,
144 tangential_pressure,
145 tilt_x,
146 tilt_y,
147 twist,
148 altitude_angle,
149 azimuth_angle,
150 pointer_type,
151 is_primary,
152 coalesced_events,
153 predicted_events,
154 can_gc,
155 )
156 }
157
158 #[allow(clippy::too_many_arguments)]
159 fn new_with_proto(
160 window: &Window,
161 proto: Option<HandleObject>,
162 type_: DOMString,
163 can_bubble: EventBubbles,
164 cancelable: EventCancelable,
165 view: Option<&Window>,
166 detail: i32,
167 screen_point: Point2D<i32, CSSPixel>,
168 client_point: Point2D<i32, CSSPixel>,
169 page_point: Point2D<i32, CSSPixel>,
170 modifiers: Modifiers,
171 button: i16,
172 buttons: u16,
173 related_target: Option<&EventTarget>,
174 point_in_target: Option<Point2D<f32, CSSPixel>>,
175 pointer_id: i32,
176 width: i32,
177 height: i32,
178 pressure: f32,
179 tangential_pressure: f32,
180 tilt_x: i32,
181 tilt_y: i32,
182 twist: i32,
183 altitude_angle: f64,
184 azimuth_angle: f64,
185 pointer_type: DOMString,
186 is_primary: bool,
187 coalesced_events: Vec<DomRoot<PointerEvent>>,
188 predicted_events: Vec<DomRoot<PointerEvent>>,
189 can_gc: CanGc,
190 ) -> DomRoot<PointerEvent> {
191 let ev = PointerEvent::new_uninitialized_with_proto(window, proto, can_gc);
192 ev.mouseevent.initialize_mouse_event(
193 type_,
194 can_bubble,
195 cancelable,
196 view,
197 detail,
198 screen_point,
199 client_point,
200 page_point,
201 modifiers,
202 button,
203 buttons,
204 related_target,
205 point_in_target,
206 );
207 ev.pointer_id.set(pointer_id);
208 ev.width.set(width);
209 ev.height.set(height);
210 ev.pressure.set(pressure);
211 ev.tangential_pressure.set(tangential_pressure);
212 ev.tilt_x.set(tilt_x);
213 ev.tilt_y.set(tilt_y);
214 ev.twist.set(twist);
215 ev.altitude_angle.set(altitude_angle);
216 ev.azimuth_angle.set(azimuth_angle);
217 *ev.pointer_type.borrow_mut() = pointer_type;
218 ev.is_primary.set(is_primary);
219 *ev.coalesced_events.borrow_mut() = coalesced_events;
220 *ev.predicted_events.borrow_mut() = predicted_events;
221 ev
222 }
223}
224
225impl PointerEventMethods<crate::DomTypeHolder> for PointerEvent {
226 fn Constructor(
228 window: &Window,
229 proto: Option<HandleObject>,
230 can_gc: CanGc,
231 type_: DOMString,
232 init: &PointerEventInit,
233 ) -> DomRoot<PointerEvent> {
234 let bubbles = EventBubbles::from(init.parent.parent.parent.parent.bubbles);
235 let cancelable = EventCancelable::from(init.parent.parent.parent.parent.cancelable);
236 let scroll_offset = window.scroll_offset();
237 let page_point = Point2D::new(
238 scroll_offset.x as i32 + init.parent.clientX,
239 scroll_offset.y as i32 + init.parent.clientY,
240 );
241 PointerEvent::new_with_proto(
242 window,
243 proto,
244 type_,
245 bubbles,
246 cancelable,
247 init.parent.parent.parent.view.as_deref(),
248 init.parent.parent.parent.detail,
249 Point2D::new(init.parent.screenX, init.parent.screenY),
250 Point2D::new(init.parent.clientX, init.parent.clientY),
251 page_point,
252 init.parent.parent.modifiers(),
253 init.parent.button,
254 init.parent.buttons,
255 init.parent.relatedTarget.as_deref(),
256 None,
257 init.pointerId,
258 init.width,
259 init.height,
260 *init.pressure,
261 *init.tangentialPressure,
262 init.tiltX.unwrap_or_default(),
263 init.tiltY.unwrap_or_default(),
264 init.twist,
265 *init.altitudeAngle.unwrap_or_default(),
266 *init.azimuthAngle.unwrap_or_default(),
267 init.pointerType.clone(),
268 init.isPrimary,
269 init.coalescedEvents.clone(),
270 init.predictedEvents.clone(),
271 can_gc,
272 )
273 }
274
275 fn PointerId(&self) -> i32 {
277 self.pointer_id.get()
278 }
279
280 fn Width(&self) -> i32 {
282 self.width.get()
283 }
284
285 fn Height(&self) -> i32 {
287 self.height.get()
288 }
289
290 fn Pressure(&self) -> Finite<f32> {
292 Finite::wrap(self.pressure.get())
293 }
294
295 fn TangentialPressure(&self) -> Finite<f32> {
297 Finite::wrap(self.tangential_pressure.get())
298 }
299
300 fn TiltX(&self) -> i32 {
302 self.tilt_x.get()
303 }
304
305 fn TiltY(&self) -> i32 {
307 self.tilt_y.get()
308 }
309
310 fn Twist(&self) -> i32 {
312 self.twist.get()
313 }
314
315 fn AltitudeAngle(&self) -> Finite<f64> {
317 Finite::wrap(self.altitude_angle.get())
318 }
319
320 fn AzimuthAngle(&self) -> Finite<f64> {
322 Finite::wrap(self.azimuth_angle.get())
323 }
324
325 fn PointerType(&self) -> DOMString {
327 self.pointer_type.borrow().clone()
328 }
329
330 fn IsPrimary(&self) -> bool {
332 self.is_primary.get()
333 }
334
335 fn GetCoalescedEvents(&self) -> Vec<DomRoot<PointerEvent>> {
337 self.coalesced_events.borrow().clone()
338 }
339
340 fn GetPredictedEvents(&self) -> Vec<DomRoot<PointerEvent>> {
342 self.predicted_events.borrow().clone()
343 }
344
345 fn IsTrusted(&self) -> bool {
347 self.mouseevent.IsTrusted()
348 }
349}