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_and_cx;
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::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<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(cx: &mut JSContext, window: &Window) -> DomRoot<PointerEvent> {
77 Self::new_uninitialized_with_proto(cx, window, None)
78 }
79
80 fn new_uninitialized_with_proto(
81 cx: &mut JSContext,
82 window: &Window,
83 proto: Option<HandleObject>,
84 ) -> DomRoot<PointerEvent> {
85 reflect_dom_object_with_proto_and_cx(
86 Box::new(PointerEvent::new_inherited()),
87 window,
88 proto,
89 cx,
90 )
91 }
92
93 #[expect(clippy::too_many_arguments)]
94 pub(crate) fn new(
95 cx: &mut JSContext,
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 ) -> DomRoot<PointerEvent> {
125 Self::new_with_proto(
126 cx,
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 )
157 }
158
159 #[expect(clippy::too_many_arguments)]
160 fn new_with_proto(
161 cx: &mut JSContext,
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 ) -> DomRoot<PointerEvent> {
192 let ev = PointerEvent::new_uninitialized_with_proto(cx, window, proto);
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 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,
256 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()
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}