1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use euclid::Point2D;
9use js::rust::HandleObject;
10use keyboard_types::Modifiers;
11use style::Atom;
12use style_traits::CSSPixel;
13
14use crate::dom::bindings::cell::DomRefCell;
15use crate::dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
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::{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 event_type: Atom,
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 event_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 event_type: Atom,
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 ev.mouseevent.initialize_mouse_event(
194 event_type,
195 can_bubble,
196 cancelable,
197 view,
198 detail,
199 screen_point,
200 client_point,
201 page_point,
202 modifiers,
203 button,
204 buttons,
205 related_target,
206 point_in_target,
207 );
208 ev.pointer_id.set(pointer_id);
209 ev.width.set(width);
210 ev.height.set(height);
211 ev.pressure.set(pressure);
212 ev.tangential_pressure.set(tangential_pressure);
213 ev.tilt_x.set(tilt_x);
214 ev.tilt_y.set(tilt_y);
215 ev.twist.set(twist);
216 ev.altitude_angle.set(altitude_angle);
217 ev.azimuth_angle.set(azimuth_angle);
218 *ev.pointer_type.borrow_mut() = pointer_type;
219 ev.is_primary.set(is_primary);
220 *ev.coalesced_events.borrow_mut() = coalesced_events;
221 *ev.predicted_events.borrow_mut() = predicted_events;
222 ev
223 }
224}
225
226impl PointerEventMethods<crate::DomTypeHolder> for PointerEvent {
227 fn Constructor(
229 window: &Window,
230 proto: Option<HandleObject>,
231 can_gc: CanGc,
232 event_type: DOMString,
233 init: &PointerEventInit,
234 ) -> DomRoot<PointerEvent> {
235 let bubbles = EventBubbles::from(init.parent.parent.parent.parent.bubbles);
236 let cancelable = EventCancelable::from(init.parent.parent.parent.parent.cancelable);
237 let scroll_offset = window.scroll_offset();
238 let page_point = Point2D::new(
239 scroll_offset.x as i32 + init.parent.clientX,
240 scroll_offset.y as i32 + init.parent.clientY,
241 );
242 PointerEvent::new_with_proto(
243 window,
244 proto,
245 event_type.into(),
246 bubbles,
247 cancelable,
248 init.parent.parent.parent.view.as_deref(),
249 init.parent.parent.parent.detail,
250 Point2D::new(init.parent.screenX, init.parent.screenY),
251 Point2D::new(init.parent.clientX, init.parent.clientY),
252 page_point,
253 init.parent.parent.modifiers(),
254 init.parent.button,
255 init.parent.buttons,
256 init.parent.relatedTarget.as_deref(),
257 None,
258 init.pointerId,
259 init.width,
260 init.height,
261 *init.pressure,
262 *init.tangentialPressure,
263 init.tiltX.unwrap_or_default(),
264 init.tiltY.unwrap_or_default(),
265 init.twist,
266 *init.altitudeAngle.unwrap_or_default(),
267 *init.azimuthAngle.unwrap_or_default(),
268 init.pointerType.clone(),
269 init.isPrimary,
270 init.coalescedEvents.clone(),
271 init.predictedEvents.clone(),
272 can_gc,
273 )
274 }
275
276 fn PointerId(&self) -> i32 {
278 self.pointer_id.get()
279 }
280
281 fn Width(&self) -> i32 {
283 self.width.get()
284 }
285
286 fn Height(&self) -> i32 {
288 self.height.get()
289 }
290
291 fn Pressure(&self) -> Finite<f32> {
293 Finite::wrap(self.pressure.get())
294 }
295
296 fn TangentialPressure(&self) -> Finite<f32> {
298 Finite::wrap(self.tangential_pressure.get())
299 }
300
301 fn TiltX(&self) -> i32 {
303 self.tilt_x.get()
304 }
305
306 fn TiltY(&self) -> i32 {
308 self.tilt_y.get()
309 }
310
311 fn Twist(&self) -> i32 {
313 self.twist.get()
314 }
315
316 fn AltitudeAngle(&self) -> Finite<f64> {
318 Finite::wrap(self.altitude_angle.get())
319 }
320
321 fn AzimuthAngle(&self) -> Finite<f64> {
323 Finite::wrap(self.azimuth_angle.get())
324 }
325
326 fn PointerType(&self) -> DOMString {
328 self.pointer_type.borrow().clone()
329 }
330
331 fn IsPrimary(&self) -> bool {
333 self.is_primary.get()
334 }
335
336 fn GetCoalescedEvents(&self) -> Vec<DomRoot<PointerEvent>> {
338 self.coalesced_events.borrow().clone()
339 }
340
341 fn GetPredictedEvents(&self) -> Vec<DomRoot<PointerEvent>> {
343 self.predicted_events.borrow().clone()
344 }
345
346 fn IsTrusted(&self) -> bool {
348 self.mouseevent.IsTrusted()
349 }
350}