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