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