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