script/dom/
pointerevent.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use euclid::Point2D;
9use js::rust::HandleObject;
10use keyboard_types::Modifiers;
11use style_traits::CSSPixel;
12
13use super::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
14use crate::dom::bindings::cell::DomRefCell;
15use crate::dom::bindings::codegen::Bindings::PointerEventBinding::{
16    PointerEventInit, PointerEventMethods,
17};
18use crate::dom::bindings::num::Finite;
19use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
20use crate::dom::bindings::root::DomRoot;
21use crate::dom::bindings::str::DOMString;
22use crate::dom::event::{EventBubbles, EventCancelable};
23use crate::dom::eventtarget::EventTarget;
24use crate::dom::mouseevent::MouseEvent;
25use crate::dom::window::Window;
26use crate::script_runtime::CanGc;
27
28/// <https://w3c.github.io/pointerevents/#dom-pointerevent-pointerid>
29#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
30pub(crate) enum PointerId {
31    NonPointerDevice = -1,
32    Mouse,
33}
34
35#[dom_struct]
36pub(crate) struct PointerEvent {
37    mouseevent: MouseEvent,
38    pointer_id: Cell<i32>,
39    width: Cell<i32>,
40    height: Cell<i32>,
41    pressure: Cell<f32>,
42    tangential_pressure: Cell<f32>,
43    tilt_x: Cell<i32>,
44    tilt_y: Cell<i32>,
45    twist: Cell<i32>,
46    altitude_angle: Cell<f64>,
47    azimuth_angle: Cell<f64>,
48    pointer_type: DomRefCell<DOMString>,
49    is_primary: Cell<bool>,
50    coalesced_events: DomRefCell<Vec<DomRoot<PointerEvent>>>,
51    predicted_events: DomRefCell<Vec<DomRoot<PointerEvent>>>,
52}
53
54impl PointerEvent {
55    pub(crate) fn new_inherited() -> PointerEvent {
56        PointerEvent {
57            mouseevent: MouseEvent::new_inherited(),
58            pointer_id: Cell::new(0),
59            width: Cell::new(0),
60            height: Cell::new(0),
61            pressure: Cell::new(0.),
62            tangential_pressure: Cell::new(0.),
63            tilt_x: Cell::new(0),
64            tilt_y: Cell::new(0),
65            twist: Cell::new(0),
66            altitude_angle: Cell::new(0.),
67            azimuth_angle: Cell::new(0.),
68            pointer_type: DomRefCell::new(DOMString::new()),
69            is_primary: Cell::new(false),
70            coalesced_events: DomRefCell::new(Vec::new()),
71            predicted_events: DomRefCell::new(Vec::new()),
72        }
73    }
74
75    pub(crate) fn new_uninitialized(window: &Window, can_gc: CanGc) -> DomRoot<PointerEvent> {
76        Self::new_uninitialized_with_proto(window, None, can_gc)
77    }
78
79    fn new_uninitialized_with_proto(
80        window: &Window,
81        proto: Option<HandleObject>,
82        can_gc: CanGc,
83    ) -> DomRoot<PointerEvent> {
84        reflect_dom_object_with_proto(
85            Box::new(PointerEvent::new_inherited()),
86            window,
87            proto,
88            can_gc,
89        )
90    }
91
92    #[allow(clippy::too_many_arguments)]
93    pub(crate) fn new(
94        window: &Window,
95        type_: DOMString,
96        can_bubble: EventBubbles,
97        cancelable: EventCancelable,
98        view: Option<&Window>,
99        detail: i32,
100        screen_point: Point2D<i32, CSSPixel>,
101        client_point: Point2D<i32, CSSPixel>,
102        page_point: Point2D<i32, CSSPixel>,
103        modifiers: Modifiers,
104        button: i16,
105        buttons: u16,
106        related_target: Option<&EventTarget>,
107        point_in_target: Option<Point2D<f32, CSSPixel>>,
108        pointer_id: i32,
109        width: i32,
110        height: i32,
111        pressure: f32,
112        tangential_pressure: f32,
113        tilt_x: i32,
114        tilt_y: i32,
115        twist: i32,
116        altitude_angle: f64,
117        azimuth_angle: f64,
118        pointer_type: DOMString,
119        is_primary: bool,
120        coalesced_events: Vec<DomRoot<PointerEvent>>,
121        predicted_events: Vec<DomRoot<PointerEvent>>,
122        can_gc: CanGc,
123    ) -> DomRoot<PointerEvent> {
124        Self::new_with_proto(
125            window,
126            None,
127            type_,
128            can_bubble,
129            cancelable,
130            view,
131            detail,
132            screen_point,
133            client_point,
134            page_point,
135            modifiers,
136            button,
137            buttons,
138            related_target,
139            point_in_target,
140            pointer_id,
141            width,
142            height,
143            pressure,
144            tangential_pressure,
145            tilt_x,
146            tilt_y,
147            twist,
148            altitude_angle,
149            azimuth_angle,
150            pointer_type,
151            is_primary,
152            coalesced_events,
153            predicted_events,
154            can_gc,
155        )
156    }
157
158    #[allow(clippy::too_many_arguments)]
159    fn new_with_proto(
160        window: &Window,
161        proto: Option<HandleObject>,
162        type_: DOMString,
163        can_bubble: EventBubbles,
164        cancelable: EventCancelable,
165        view: Option<&Window>,
166        detail: i32,
167        screen_point: Point2D<i32, CSSPixel>,
168        client_point: Point2D<i32, CSSPixel>,
169        page_point: Point2D<i32, CSSPixel>,
170        modifiers: Modifiers,
171        button: i16,
172        buttons: u16,
173        related_target: Option<&EventTarget>,
174        point_in_target: Option<Point2D<f32, CSSPixel>>,
175        pointer_id: i32,
176        width: i32,
177        height: i32,
178        pressure: f32,
179        tangential_pressure: f32,
180        tilt_x: i32,
181        tilt_y: i32,
182        twist: i32,
183        altitude_angle: f64,
184        azimuth_angle: f64,
185        pointer_type: DOMString,
186        is_primary: bool,
187        coalesced_events: Vec<DomRoot<PointerEvent>>,
188        predicted_events: Vec<DomRoot<PointerEvent>>,
189        can_gc: CanGc,
190    ) -> DomRoot<PointerEvent> {
191        let ev = PointerEvent::new_uninitialized_with_proto(window, proto, can_gc);
192        ev.mouseevent.initialize_mouse_event(
193            type_,
194            can_bubble,
195            cancelable,
196            view,
197            detail,
198            screen_point,
199            client_point,
200            page_point,
201            modifiers,
202            button,
203            buttons,
204            related_target,
205            point_in_target,
206        );
207        ev.pointer_id.set(pointer_id);
208        ev.width.set(width);
209        ev.height.set(height);
210        ev.pressure.set(pressure);
211        ev.tangential_pressure.set(tangential_pressure);
212        ev.tilt_x.set(tilt_x);
213        ev.tilt_y.set(tilt_y);
214        ev.twist.set(twist);
215        ev.altitude_angle.set(altitude_angle);
216        ev.azimuth_angle.set(azimuth_angle);
217        *ev.pointer_type.borrow_mut() = pointer_type;
218        ev.is_primary.set(is_primary);
219        *ev.coalesced_events.borrow_mut() = coalesced_events;
220        *ev.predicted_events.borrow_mut() = predicted_events;
221        ev
222    }
223}
224
225impl PointerEventMethods<crate::DomTypeHolder> for PointerEvent {
226    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-constructor>
227    fn Constructor(
228        window: &Window,
229        proto: Option<HandleObject>,
230        can_gc: CanGc,
231        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            window,
243            proto,
244            type_,
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            can_gc,
272        )
273    }
274
275    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-pointerid>
276    fn PointerId(&self) -> i32 {
277        self.pointer_id.get()
278    }
279
280    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-width>
281    fn Width(&self) -> i32 {
282        self.width.get()
283    }
284
285    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-height>
286    fn Height(&self) -> i32 {
287        self.height.get()
288    }
289
290    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-pressure>
291    fn Pressure(&self) -> Finite<f32> {
292        Finite::wrap(self.pressure.get())
293    }
294
295    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-tangentialpressure>
296    fn TangentialPressure(&self) -> Finite<f32> {
297        Finite::wrap(self.tangential_pressure.get())
298    }
299
300    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-tiltx>
301    fn TiltX(&self) -> i32 {
302        self.tilt_x.get()
303    }
304
305    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-tilty>
306    fn TiltY(&self) -> i32 {
307        self.tilt_y.get()
308    }
309
310    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-twist>
311    fn Twist(&self) -> i32 {
312        self.twist.get()
313    }
314
315    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-altitudeangle>
316    fn AltitudeAngle(&self) -> Finite<f64> {
317        Finite::wrap(self.altitude_angle.get())
318    }
319
320    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-azimuthangle>
321    fn AzimuthAngle(&self) -> Finite<f64> {
322        Finite::wrap(self.azimuth_angle.get())
323    }
324
325    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-pointertype>
326    fn PointerType(&self) -> DOMString {
327        self.pointer_type.borrow().clone()
328    }
329
330    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-isprimary>
331    fn IsPrimary(&self) -> bool {
332        self.is_primary.get()
333    }
334
335    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-getcoalescedevents>
336    fn GetCoalescedEvents(&self) -> Vec<DomRoot<PointerEvent>> {
337        self.coalesced_events.borrow().clone()
338    }
339
340    /// <https://w3c.github.io/pointerevents/#dom-pointerevent-getpredictedevents>
341    fn GetPredictedEvents(&self) -> Vec<DomRoot<PointerEvent>> {
342        self.predicted_events.borrow().clone()
343    }
344
345    /// <https://dom.spec.whatwg.org/#dom-event-istrusted>
346    fn IsTrusted(&self) -> bool {
347        self.mouseevent.IsTrusted()
348    }
349}