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;
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(cx, Box::new(PointerEvent::new_inherited()), window, proto)
82 }
83
84 #[expect(clippy::too_many_arguments)]
85 pub(crate) fn new(
86 cx: &mut JSContext,
87 window: &Window,
88 event_type: Atom,
89 can_bubble: EventBubbles,
90 cancelable: EventCancelable,
91 view: Option<&Window>,
92 detail: i32,
93 screen_point: Point2D<i32, CSSPixel>,
94 client_point: Point2D<i32, CSSPixel>,
95 page_point: Point2D<i32, CSSPixel>,
96 modifiers: Modifiers,
97 button: i16,
98 buttons: u16,
99 related_target: Option<&EventTarget>,
100 point_in_target: Option<Point2D<f32, CSSPixel>>,
101 pointer_id: i32,
102 width: i32,
103 height: i32,
104 pressure: f32,
105 tangential_pressure: f32,
106 tilt_x: i32,
107 tilt_y: i32,
108 twist: i32,
109 altitude_angle: f64,
110 azimuth_angle: f64,
111 pointer_type: DOMString,
112 is_primary: bool,
113 coalesced_events: Vec<DomRoot<PointerEvent>>,
114 predicted_events: Vec<DomRoot<PointerEvent>>,
115 ) -> DomRoot<PointerEvent> {
116 Self::new_with_proto(
117 cx,
118 window,
119 None,
120 event_type,
121 can_bubble,
122 cancelable,
123 view,
124 detail,
125 screen_point,
126 client_point,
127 page_point,
128 modifiers,
129 button,
130 buttons,
131 related_target,
132 point_in_target,
133 pointer_id,
134 width,
135 height,
136 pressure,
137 tangential_pressure,
138 tilt_x,
139 tilt_y,
140 twist,
141 altitude_angle,
142 azimuth_angle,
143 pointer_type,
144 is_primary,
145 coalesced_events,
146 predicted_events,
147 )
148 }
149
150 #[expect(clippy::too_many_arguments)]
151 fn new_with_proto(
152 cx: &mut JSContext,
153 window: &Window,
154 proto: Option<HandleObject>,
155 event_type: Atom,
156 can_bubble: EventBubbles,
157 cancelable: EventCancelable,
158 view: Option<&Window>,
159 detail: i32,
160 screen_point: Point2D<i32, CSSPixel>,
161 client_point: Point2D<i32, CSSPixel>,
162 page_point: Point2D<i32, CSSPixel>,
163 modifiers: Modifiers,
164 button: i16,
165 buttons: u16,
166 related_target: Option<&EventTarget>,
167 point_in_target: Option<Point2D<f32, CSSPixel>>,
168 pointer_id: i32,
169 width: i32,
170 height: i32,
171 pressure: f32,
172 tangential_pressure: f32,
173 tilt_x: i32,
174 tilt_y: i32,
175 twist: i32,
176 altitude_angle: f64,
177 azimuth_angle: f64,
178 pointer_type: DOMString,
179 is_primary: bool,
180 coalesced_events: Vec<DomRoot<PointerEvent>>,
181 predicted_events: Vec<DomRoot<PointerEvent>>,
182 ) -> DomRoot<PointerEvent> {
183 let ev = PointerEvent::new_uninitialized_with_proto(cx, window, proto);
184 ev.mouseevent.initialize_mouse_event(
185 event_type,
186 can_bubble,
187 cancelable,
188 view,
189 detail,
190 screen_point,
191 client_point,
192 page_point,
193 modifiers,
194 button,
195 buttons,
196 related_target,
197 point_in_target,
198 None,
199 );
200 ev.pointer_id.set(pointer_id);
201 ev.width.set(width);
202 ev.height.set(height);
203 ev.pressure.set(pressure);
204 ev.tangential_pressure.set(tangential_pressure);
205 ev.tilt_x.set(tilt_x);
206 ev.tilt_y.set(tilt_y);
207 ev.twist.set(twist);
208 ev.altitude_angle.set(altitude_angle);
209 ev.azimuth_angle.set(azimuth_angle);
210 *ev.pointer_type.borrow_mut() = pointer_type;
211 ev.is_primary.set(is_primary);
212 *ev.coalesced_events.borrow_mut() = coalesced_events
213 .into_iter()
214 .map(|event| event.as_traced())
215 .collect();
216 *ev.predicted_events.borrow_mut() = predicted_events
217 .into_iter()
218 .map(|event| event.as_traced())
219 .collect();
220 ev
221 }
222}
223
224impl PointerEventMethods<crate::DomTypeHolder> for PointerEvent {
225 fn Constructor(
227 cx: &mut JSContext,
228 window: &Window,
229 proto: Option<HandleObject>,
230 event_type: DOMString,
231 init: &PointerEventInit,
232 ) -> DomRoot<PointerEvent> {
233 let bubbles = EventBubbles::from(init.parent.parent.parent.parent.bubbles);
234 let cancelable = EventCancelable::from(init.parent.parent.parent.parent.cancelable);
235 let scroll_offset = window.scroll_offset();
236 let page_point = Point2D::new(
237 scroll_offset.x as i32 + init.parent.clientX,
238 scroll_offset.y as i32 + init.parent.clientY,
239 );
240 PointerEvent::new_with_proto(
241 cx,
242 window,
243 proto,
244 event_type.into(),
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 )
272 }
273
274 fn PointerId(&self) -> i32 {
276 self.pointer_id.get()
277 }
278
279 fn Width(&self) -> i32 {
281 self.width.get()
282 }
283
284 fn Height(&self) -> i32 {
286 self.height.get()
287 }
288
289 fn Pressure(&self) -> Finite<f32> {
291 Finite::wrap(self.pressure.get())
292 }
293
294 fn TangentialPressure(&self) -> Finite<f32> {
296 Finite::wrap(self.tangential_pressure.get())
297 }
298
299 fn TiltX(&self) -> i32 {
301 self.tilt_x.get()
302 }
303
304 fn TiltY(&self) -> i32 {
306 self.tilt_y.get()
307 }
308
309 fn Twist(&self) -> i32 {
311 self.twist.get()
312 }
313
314 fn AltitudeAngle(&self) -> Finite<f64> {
316 Finite::wrap(self.altitude_angle.get())
317 }
318
319 fn AzimuthAngle(&self) -> Finite<f64> {
321 Finite::wrap(self.azimuth_angle.get())
322 }
323
324 fn PointerType(&self) -> DOMString {
326 self.pointer_type.borrow().clone()
327 }
328
329 fn IsPrimary(&self) -> bool {
331 self.is_primary.get()
332 }
333
334 fn GetCoalescedEvents(&self) -> Vec<DomRoot<PointerEvent>> {
336 self.coalesced_events
337 .borrow()
338 .iter()
339 .map(|event| event.as_rooted())
340 .collect()
341 }
342
343 fn GetPredictedEvents(&self) -> Vec<DomRoot<PointerEvent>> {
345 self.predicted_events
346 .borrow()
347 .iter()
348 .map(|event| event.as_rooted())
349 .collect()
350 }
351
352 fn IsTrusted(&self) -> bool {
354 self.mouseevent.IsTrusted()
355 }
356}