1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use euclid::Point2D;
9use js::rust::HandleObject;
10use keyboard_types::Modifiers;
11use script_bindings::inheritance::Castable;
12use style_traits::CSSPixel;
13
14use super::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
15use crate::dom::bindings::cell::DomRefCell;
16use crate::dom::bindings::codegen::Bindings::PointerEventBinding::{
17 PointerEventInit, PointerEventMethods,
18};
19use crate::dom::bindings::num::Finite;
20use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
21use crate::dom::bindings::root::DomRoot;
22use crate::dom::bindings::str::DOMString;
23use crate::dom::event::{Event, EventBubbles, EventCancelable};
24use crate::dom::eventtarget::EventTarget;
25use crate::dom::mouseevent::MouseEvent;
26use crate::dom::window::Window;
27use crate::script_runtime::CanGc;
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<DomRoot<PointerEvent>>>,
52 predicted_events: DomRefCell<Vec<DomRoot<PointerEvent>>>,
53}
54
55impl PointerEvent {
56 pub(crate) 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 pub(crate) fn new_uninitialized(window: &Window, can_gc: CanGc) -> DomRoot<PointerEvent> {
77 Self::new_uninitialized_with_proto(window, None, can_gc)
78 }
79
80 fn new_uninitialized_with_proto(
81 window: &Window,
82 proto: Option<HandleObject>,
83 can_gc: CanGc,
84 ) -> DomRoot<PointerEvent> {
85 reflect_dom_object_with_proto(
86 Box::new(PointerEvent::new_inherited()),
87 window,
88 proto,
89 can_gc,
90 )
91 }
92
93 #[expect(clippy::too_many_arguments)]
94 pub(crate) fn new(
95 window: &Window,
96 type_: DOMString,
97 can_bubble: EventBubbles,
98 cancelable: EventCancelable,
99 view: Option<&Window>,
100 detail: i32,
101 screen_point: Point2D<i32, CSSPixel>,
102 client_point: Point2D<i32, CSSPixel>,
103 page_point: Point2D<i32, CSSPixel>,
104 modifiers: Modifiers,
105 button: i16,
106 buttons: u16,
107 related_target: Option<&EventTarget>,
108 point_in_target: Option<Point2D<f32, CSSPixel>>,
109 pointer_id: i32,
110 width: i32,
111 height: i32,
112 pressure: f32,
113 tangential_pressure: f32,
114 tilt_x: i32,
115 tilt_y: i32,
116 twist: i32,
117 altitude_angle: f64,
118 azimuth_angle: f64,
119 pointer_type: DOMString,
120 is_primary: bool,
121 coalesced_events: Vec<DomRoot<PointerEvent>>,
122 predicted_events: Vec<DomRoot<PointerEvent>>,
123 can_gc: CanGc,
124 ) -> DomRoot<PointerEvent> {
125 Self::new_with_proto(
126 window,
127 None,
128 type_,
129 can_bubble,
130 cancelable,
131 view,
132 detail,
133 screen_point,
134 client_point,
135 page_point,
136 modifiers,
137 button,
138 buttons,
139 related_target,
140 point_in_target,
141 pointer_id,
142 width,
143 height,
144 pressure,
145 tangential_pressure,
146 tilt_x,
147 tilt_y,
148 twist,
149 altitude_angle,
150 azimuth_angle,
151 pointer_type,
152 is_primary,
153 coalesced_events,
154 predicted_events,
155 can_gc,
156 )
157 }
158
159 #[expect(clippy::too_many_arguments)]
160 fn new_with_proto(
161 window: &Window,
162 proto: Option<HandleObject>,
163 type_: DOMString,
164 can_bubble: EventBubbles,
165 cancelable: EventCancelable,
166 view: Option<&Window>,
167 detail: i32,
168 screen_point: Point2D<i32, CSSPixel>,
169 client_point: Point2D<i32, CSSPixel>,
170 page_point: Point2D<i32, CSSPixel>,
171 modifiers: Modifiers,
172 button: i16,
173 buttons: u16,
174 related_target: Option<&EventTarget>,
175 point_in_target: Option<Point2D<f32, CSSPixel>>,
176 pointer_id: i32,
177 width: i32,
178 height: i32,
179 pressure: f32,
180 tangential_pressure: f32,
181 tilt_x: i32,
182 tilt_y: i32,
183 twist: i32,
184 altitude_angle: f64,
185 azimuth_angle: f64,
186 pointer_type: DOMString,
187 is_primary: bool,
188 coalesced_events: Vec<DomRoot<PointerEvent>>,
189 predicted_events: Vec<DomRoot<PointerEvent>>,
190 can_gc: CanGc,
191 ) -> DomRoot<PointerEvent> {
192 let ev = PointerEvent::new_uninitialized_with_proto(window, proto, can_gc);
193 let composed = type_ != "pointerenter" && type_ != "pointerleave";
195 ev.mouseevent.initialize_mouse_event(
196 type_,
197 can_bubble,
198 cancelable,
199 view,
200 detail,
201 screen_point,
202 client_point,
203 page_point,
204 modifiers,
205 button,
206 buttons,
207 related_target,
208 point_in_target,
209 );
210 ev.mouseevent.upcast::<Event>().set_composed(composed);
211 ev.pointer_id.set(pointer_id);
212 ev.width.set(width);
213 ev.height.set(height);
214 ev.pressure.set(pressure);
215 ev.tangential_pressure.set(tangential_pressure);
216 ev.tilt_x.set(tilt_x);
217 ev.tilt_y.set(tilt_y);
218 ev.twist.set(twist);
219 ev.altitude_angle.set(altitude_angle);
220 ev.azimuth_angle.set(azimuth_angle);
221 *ev.pointer_type.borrow_mut() = pointer_type;
222 ev.is_primary.set(is_primary);
223 *ev.coalesced_events.borrow_mut() = coalesced_events;
224 *ev.predicted_events.borrow_mut() = predicted_events;
225 ev
226 }
227}
228
229impl PointerEventMethods<crate::DomTypeHolder> for PointerEvent {
230 fn Constructor(
232 window: &Window,
233 proto: Option<HandleObject>,
234 can_gc: CanGc,
235 type_: DOMString,
236 init: &PointerEventInit,
237 ) -> DomRoot<PointerEvent> {
238 let bubbles = EventBubbles::from(init.parent.parent.parent.parent.bubbles);
239 let cancelable = EventCancelable::from(init.parent.parent.parent.parent.cancelable);
240 let scroll_offset = window.scroll_offset();
241 let page_point = Point2D::new(
242 scroll_offset.x as i32 + init.parent.clientX,
243 scroll_offset.y as i32 + init.parent.clientY,
244 );
245 PointerEvent::new_with_proto(
246 window,
247 proto,
248 type_,
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 can_gc,
276 )
277 }
278
279 fn PointerId(&self) -> i32 {
281 self.pointer_id.get()
282 }
283
284 fn Width(&self) -> i32 {
286 self.width.get()
287 }
288
289 fn Height(&self) -> i32 {
291 self.height.get()
292 }
293
294 fn Pressure(&self) -> Finite<f32> {
296 Finite::wrap(self.pressure.get())
297 }
298
299 fn TangentialPressure(&self) -> Finite<f32> {
301 Finite::wrap(self.tangential_pressure.get())
302 }
303
304 fn TiltX(&self) -> i32 {
306 self.tilt_x.get()
307 }
308
309 fn TiltY(&self) -> i32 {
311 self.tilt_y.get()
312 }
313
314 fn Twist(&self) -> i32 {
316 self.twist.get()
317 }
318
319 fn AltitudeAngle(&self) -> Finite<f64> {
321 Finite::wrap(self.altitude_angle.get())
322 }
323
324 fn AzimuthAngle(&self) -> Finite<f64> {
326 Finite::wrap(self.azimuth_angle.get())
327 }
328
329 fn PointerType(&self) -> DOMString {
331 self.pointer_type.borrow().clone()
332 }
333
334 fn IsPrimary(&self) -> bool {
336 self.is_primary.get()
337 }
338
339 fn GetCoalescedEvents(&self) -> Vec<DomRoot<PointerEvent>> {
341 self.coalesced_events.borrow().clone()
342 }
343
344 fn GetPredictedEvents(&self) -> Vec<DomRoot<PointerEvent>> {
346 self.predicted_events.borrow().clone()
347 }
348
349 fn IsTrusted(&self) -> bool {
351 self.mouseevent.IsTrusted()
352 }
353}