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::domstring::TracedDOMString;
15use script_bindings::reflector::reflect_dom_object_with_proto;
16use script_traits::MouseButtons;
17use style::Atom;
18use style_traits::CSSPixel;
19
20use crate::dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
21use crate::dom::bindings::codegen::Bindings::PointerEventBinding::{
22 PointerEventInit, PointerEventMethods,
23};
24use crate::dom::bindings::num::Finite;
25use crate::dom::bindings::root::{Dom, DomRoot};
26use crate::dom::bindings::str::DOMString;
27use crate::dom::event::{EventBubbles, EventCancelable};
28use crate::dom::eventtarget::EventTarget;
29use crate::dom::mouseevent::MouseEvent;
30use crate::dom::window::Window;
31
32#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
34pub(crate) enum PointerId {
35 NonPointerDevice = -1,
36 Mouse,
37}
38
39#[dom_struct]
40pub(crate) struct PointerEvent {
41 mouseevent: MouseEvent,
42 pointer_id: Cell<i32>,
43 width: Cell<i32>,
44 height: Cell<i32>,
45 pressure: Cell<f32>,
46 tangential_pressure: Cell<f32>,
47 tilt_x: Cell<i32>,
48 tilt_y: Cell<i32>,
49 twist: Cell<i32>,
50 altitude_angle: Cell<f64>,
51 azimuth_angle: Cell<f64>,
52 pointer_type: DomRefCell<TracedDOMString>,
53 is_primary: Cell<bool>,
54 coalesced_events: DomRefCell<Vec<Dom<PointerEvent>>>,
55 predicted_events: DomRefCell<Vec<Dom<PointerEvent>>>,
56}
57
58impl PointerEvent {
59 fn new_inherited() -> PointerEvent {
60 PointerEvent {
61 mouseevent: MouseEvent::new_inherited(),
62 pointer_id: Cell::new(0),
63 width: Cell::new(0),
64 height: Cell::new(0),
65 pressure: Cell::new(0.),
66 tangential_pressure: Cell::new(0.),
67 tilt_x: Cell::new(0),
68 tilt_y: Cell::new(0),
69 twist: Cell::new(0),
70 altitude_angle: Cell::new(0.),
71 azimuth_angle: Cell::new(0.),
72 pointer_type: DomRefCell::new(DOMString::new().traced()),
73 is_primary: Cell::new(false),
74 coalesced_events: DomRefCell::new(Vec::new()),
75 predicted_events: DomRefCell::new(Vec::new()),
76 }
77 }
78
79 fn new_uninitialized_with_proto(
80 cx: &mut JSContext,
81 window: &Window,
82 proto: Option<HandleObject>,
83 ) -> DomRoot<PointerEvent> {
84 reflect_dom_object_with_proto(cx, Box::new(PointerEvent::new_inherited()), window, proto)
85 }
86
87 #[expect(clippy::too_many_arguments)]
88 pub(crate) fn new(
89 cx: &mut JSContext,
90 window: &Window,
91 event_type: Atom,
92 can_bubble: EventBubbles,
93 cancelable: EventCancelable,
94 view: Option<&Window>,
95 detail: i32,
96 screen_point: Point2D<i32, CSSPixel>,
97 client_point: Point2D<i32, CSSPixel>,
98 page_point: Point2D<i32, CSSPixel>,
99 modifiers: Modifiers,
100 button: MouseButton,
101 buttons: MouseButtons,
102 related_target: Option<&EventTarget>,
103 point_in_target: Option<Point2D<f32, CSSPixel>>,
104 pointer_id: i32,
105 width: i32,
106 height: i32,
107 pressure: f32,
108 tangential_pressure: f32,
109 tilt_x: i32,
110 tilt_y: i32,
111 twist: i32,
112 altitude_angle: f64,
113 azimuth_angle: f64,
114 pointer_type: DOMString,
115 is_primary: bool,
116 coalesced_events: Vec<DomRoot<PointerEvent>>,
117 predicted_events: Vec<DomRoot<PointerEvent>>,
118 ) -> DomRoot<PointerEvent> {
119 Self::new_with_proto(
120 cx,
121 window,
122 None,
123 event_type,
124 can_bubble,
125 cancelable,
126 view,
127 detail,
128 screen_point,
129 client_point,
130 page_point,
131 modifiers,
132 button,
133 buttons,
134 related_target,
135 point_in_target,
136 pointer_id,
137 width,
138 height,
139 pressure,
140 tangential_pressure,
141 tilt_x,
142 tilt_y,
143 twist,
144 altitude_angle,
145 azimuth_angle,
146 pointer_type,
147 is_primary,
148 coalesced_events,
149 predicted_events,
150 )
151 }
152
153 #[expect(clippy::too_many_arguments)]
154 fn new_with_proto(
155 cx: &mut JSContext,
156 window: &Window,
157 proto: Option<HandleObject>,
158 event_type: Atom,
159 can_bubble: EventBubbles,
160 cancelable: EventCancelable,
161 view: Option<&Window>,
162 detail: i32,
163 screen_point: Point2D<i32, CSSPixel>,
164 client_point: Point2D<i32, CSSPixel>,
165 page_point: Point2D<i32, CSSPixel>,
166 modifiers: Modifiers,
167 button: MouseButton,
168 buttons: MouseButtons,
169 related_target: Option<&EventTarget>,
170 point_in_target: Option<Point2D<f32, CSSPixel>>,
171 pointer_id: i32,
172 width: i32,
173 height: i32,
174 pressure: f32,
175 tangential_pressure: f32,
176 tilt_x: i32,
177 tilt_y: i32,
178 twist: i32,
179 altitude_angle: f64,
180 azimuth_angle: f64,
181 pointer_type: DOMString,
182 is_primary: bool,
183 coalesced_events: Vec<DomRoot<PointerEvent>>,
184 predicted_events: Vec<DomRoot<PointerEvent>>,
185 ) -> DomRoot<PointerEvent> {
186 let ev = PointerEvent::new_uninitialized_with_proto(cx, window, proto);
187 ev.mouseevent.initialize_mouse_event(
188 event_type,
189 can_bubble,
190 cancelable,
191 view,
192 detail,
193 screen_point,
194 client_point,
195 page_point,
196 modifiers,
197 button,
198 buttons,
199 related_target,
200 point_in_target,
201 );
202 ev.pointer_id.set(pointer_id);
203 ev.width.set(width);
204 ev.height.set(height);
205 ev.pressure.set(pressure);
206 ev.tangential_pressure.set(tangential_pressure);
207 ev.tilt_x.set(tilt_x);
208 ev.tilt_y.set(tilt_y);
209 ev.twist.set(twist);
210 ev.altitude_angle.set(altitude_angle);
211 ev.azimuth_angle.set(azimuth_angle);
212 *ev.pointer_type.safe_borrow_mut(cx.no_gc()) = pointer_type.traced();
213 ev.is_primary.set(is_primary);
214 *ev.coalesced_events.safe_borrow_mut(cx.no_gc()) = coalesced_events
215 .into_iter()
216 .map(|event| event.as_traced())
217 .collect();
218 *ev.predicted_events.safe_borrow_mut(cx.no_gc()) = predicted_events
219 .into_iter()
220 .map(|event| event.as_traced())
221 .collect();
222 ev
223 }
224}
225
226impl PointerEventMethods<crate::DomTypeHolder> for PointerEvent {
227 fn Constructor(
229 cx: &mut JSContext,
230 window: &Window,
231 proto: Option<HandleObject>,
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 cx,
244 window,
245 proto,
246 event_type.into(),
247 bubbles,
248 cancelable,
249 init.parent.parent.parent.view.as_deref(),
250 init.parent.parent.parent.detail,
251 Point2D::new(init.parent.screenX, init.parent.screenY),
252 Point2D::new(init.parent.clientX, init.parent.clientY),
253 page_point,
254 init.parent.parent.modifiers(),
255 init.parent.button.into(),
256 MouseButtons::from_bits_retain(init.parent.buttons),
257 init.parent.relatedTarget.as_deref(),
258 None,
259 init.pointerId,
260 init.width,
261 init.height,
262 *init.pressure,
263 *init.tangentialPressure,
264 init.tiltX.unwrap_or_default(),
265 init.tiltY.unwrap_or_default(),
266 init.twist,
267 *init.altitudeAngle.unwrap_or_default(),
268 *init.azimuthAngle.unwrap_or_default(),
269 init.pointerType.clone(),
270 init.isPrimary,
271 init.coalescedEvents.clone(),
272 init.predictedEvents.clone(),
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().root()
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
339 .borrow()
340 .iter()
341 .map(|event| event.as_rooted())
342 .collect()
343 }
344
345 fn GetPredictedEvents(&self) -> Vec<DomRoot<PointerEvent>> {
347 self.predicted_events
348 .borrow()
349 .iter()
350 .map(|event| event.as_rooted())
351 .collect()
352 }
353
354 fn IsTrusted(&self) -> bool {
356 self.mouseevent.IsTrusted()
357 }
358}