Skip to main content

script/dom/event/
wheelevent.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::context::JSContext;
10use js::rust::HandleObject;
11use keyboard_types::Modifiers;
12use script_bindings::reflector::reflect_dom_object_with_proto;
13use style::Atom;
14use style_traits::CSSPixel;
15
16use crate::dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
17use crate::dom::bindings::codegen::Bindings::WheelEventBinding;
18use crate::dom::bindings::codegen::Bindings::WheelEventBinding::WheelEventMethods;
19use crate::dom::bindings::error::Fallible;
20use crate::dom::bindings::inheritance::Castable;
21use crate::dom::bindings::num::Finite;
22use crate::dom::bindings::root::DomRoot;
23use crate::dom::bindings::str::DOMString;
24use crate::dom::event::{Event, EventBubbles, EventCancelable};
25use crate::dom::eventtarget::EventTarget;
26use crate::dom::mouseevent::MouseEvent;
27use crate::dom::window::Window;
28
29#[dom_struct]
30pub(crate) struct WheelEvent {
31    mouseevent: MouseEvent,
32    delta_x: Cell<Finite<f64>>,
33    delta_y: Cell<Finite<f64>>,
34    delta_z: Cell<Finite<f64>>,
35    delta_mode: Cell<u32>,
36}
37
38impl WheelEvent {
39    fn new_inherited() -> WheelEvent {
40        WheelEvent {
41            mouseevent: MouseEvent::new_inherited(),
42            delta_x: Cell::new(Finite::wrap(0.0)),
43            delta_y: Cell::new(Finite::wrap(0.0)),
44            delta_z: Cell::new(Finite::wrap(0.0)),
45            delta_mode: Cell::new(0),
46        }
47    }
48
49    fn new_unintialized(
50        cx: &mut JSContext,
51        window: &Window,
52        proto: Option<HandleObject>,
53    ) -> DomRoot<WheelEvent> {
54        reflect_dom_object_with_proto(cx, Box::new(WheelEvent::new_inherited()), window, proto)
55    }
56
57    #[allow(clippy::too_many_arguments)]
58    pub(crate) fn new(
59        cx: &mut JSContext,
60        window: &Window,
61        event_type: Atom,
62        can_bubble: EventBubbles,
63        cancelable: EventCancelable,
64        view: Option<&Window>,
65        detail: i32,
66        screen_point: Point2D<i32, CSSPixel>,
67        client_point: Point2D<i32, CSSPixel>,
68        page_point: Point2D<i32, CSSPixel>,
69        modifiers: Modifiers,
70        button: i16,
71        buttons: u16,
72        related_target: Option<&EventTarget>,
73        point_in_target: Option<Point2D<f32, CSSPixel>>,
74        delta_x: Finite<f64>,
75        delta_y: Finite<f64>,
76        delta_z: Finite<f64>,
77        delta_mode: u32,
78    ) -> DomRoot<WheelEvent> {
79        Self::new_with_proto(
80            cx,
81            window,
82            None,
83            event_type,
84            can_bubble,
85            cancelable,
86            view,
87            detail,
88            screen_point,
89            client_point,
90            page_point,
91            modifiers,
92            button,
93            buttons,
94            related_target,
95            point_in_target,
96            delta_x,
97            delta_y,
98            delta_z,
99            delta_mode,
100        )
101    }
102
103    #[allow(clippy::too_many_arguments)]
104    fn new_with_proto(
105        cx: &mut JSContext,
106        window: &Window,
107        proto: Option<HandleObject>,
108        event_type: Atom,
109        can_bubble: EventBubbles,
110        cancelable: EventCancelable,
111        view: Option<&Window>,
112        detail: i32,
113        screen_point: Point2D<i32, CSSPixel>,
114        client_point: Point2D<i32, CSSPixel>,
115        page_point: Point2D<i32, CSSPixel>,
116        modifiers: Modifiers,
117        button: i16,
118        buttons: u16,
119        related_target: Option<&EventTarget>,
120        point_in_target: Option<Point2D<f32, CSSPixel>>,
121        delta_x: Finite<f64>,
122        delta_y: Finite<f64>,
123        delta_z: Finite<f64>,
124        delta_mode: u32,
125    ) -> DomRoot<WheelEvent> {
126        let ev = WheelEvent::new_unintialized(cx, window, proto);
127        ev.intitialize_wheel_event(
128            event_type,
129            can_bubble,
130            cancelable,
131            view,
132            detail,
133            screen_point,
134            client_point,
135            page_point,
136            modifiers,
137            button,
138            buttons,
139            related_target,
140            point_in_target,
141            delta_x,
142            delta_y,
143            delta_z,
144            delta_mode,
145        );
146
147        ev
148    }
149
150    #[allow(clippy::too_many_arguments)]
151    pub(crate) fn intitialize_wheel_event(
152        &self,
153        event_type: Atom,
154        can_bubble: EventBubbles,
155        cancelable: EventCancelable,
156        view: Option<&Window>,
157        detail: i32,
158        screen_point: Point2D<i32, CSSPixel>,
159        client_point: Point2D<i32, CSSPixel>,
160        page_point: Point2D<i32, CSSPixel>,
161        modifiers: Modifiers,
162        button: i16,
163        buttons: u16,
164        related_target: Option<&EventTarget>,
165        point_in_target: Option<Point2D<f32, CSSPixel>>,
166        delta_x: Finite<f64>,
167        delta_y: Finite<f64>,
168        delta_z: Finite<f64>,
169        delta_mode: u32,
170    ) {
171        if self.upcast::<Event>().dispatching() {
172            return;
173        }
174
175        self.upcast::<MouseEvent>().initialize_mouse_event(
176            event_type,
177            can_bubble,
178            cancelable,
179            view,
180            detail,
181            screen_point,
182            client_point,
183            page_point,
184            modifiers,
185            button,
186            buttons,
187            related_target,
188            point_in_target,
189            None,
190        );
191        self.delta_x.set(delta_x);
192        self.delta_y.set(delta_y);
193        self.delta_z.set(delta_z);
194        self.delta_mode.set(delta_mode);
195    }
196}
197
198impl WheelEventMethods<crate::DomTypeHolder> for WheelEvent {
199    /// <https://w3c.github.io/uievents/#dom-wheelevent-wheelevent>
200    fn Constructor(
201        cx: &mut JSContext,
202        window: &Window,
203        proto: Option<HandleObject>,
204        event_type: DOMString,
205        init: &WheelEventBinding::WheelEventInit,
206    ) -> Fallible<DomRoot<WheelEvent>> {
207        let bubbles = EventBubbles::from(init.parent.parent.parent.parent.bubbles);
208        let cancelable = EventCancelable::from(init.parent.parent.parent.parent.cancelable);
209        let scroll_offset = window.scroll_offset();
210
211        let page_point = Point2D::<i32, CSSPixel>::new(
212            scroll_offset.x as i32 + init.parent.clientX,
213            scroll_offset.y as i32 + init.parent.clientY,
214        );
215
216        let event = WheelEvent::new_with_proto(
217            cx,
218            window,
219            proto,
220            event_type.into(),
221            bubbles,
222            cancelable,
223            init.parent.parent.parent.view.as_deref(),
224            init.parent.parent.parent.detail,
225            Point2D::new(init.parent.screenX, init.parent.screenY),
226            Point2D::new(init.parent.clientX, init.parent.clientY),
227            Point2D::new(page_point.x, page_point.y),
228            init.parent.parent.modifiers(),
229            init.parent.button,
230            init.parent.buttons,
231            init.parent.relatedTarget.as_deref(),
232            None,
233            init.deltaX,
234            init.deltaY,
235            init.deltaZ,
236            init.deltaMode,
237        );
238
239        Ok(event)
240    }
241
242    /// <https://w3c.github.io/uievents/#widl-WheelEvent-deltaX>
243    fn DeltaX(&self) -> Finite<f64> {
244        self.delta_x.get()
245    }
246
247    /// <https://w3c.github.io/uievents/#widl-WheelEvent-deltaY>
248    fn DeltaY(&self) -> Finite<f64> {
249        self.delta_y.get()
250    }
251
252    /// <https://w3c.github.io/uievents/#widl-WheelEvent-deltaZ>
253    fn DeltaZ(&self) -> Finite<f64> {
254        self.delta_z.get()
255    }
256
257    /// <https://w3c.github.io/uievents/#widl-WheelEvent-deltaMode>
258    fn DeltaMode(&self) -> u32 {
259        self.delta_mode.get()
260    }
261
262    /// <https://w3c.github.io/uievents/#widl-WheelEvent-initWheelEvent>
263    fn InitWheelEvent(
264        &self,
265        type_arg: DOMString,
266        can_bubble_arg: bool,
267        cancelable_arg: bool,
268        view_arg: Option<&Window>,
269        detail_arg: i32,
270        delta_x_arg: Finite<f64>,
271        delta_y_arg: Finite<f64>,
272        delta_z_arg: Finite<f64>,
273        delta_mode_arg: u32,
274    ) {
275        if self.upcast::<Event>().dispatching() {
276            return;
277        }
278
279        self.upcast::<MouseEvent>().InitMouseEvent(
280            type_arg,
281            can_bubble_arg,
282            cancelable_arg,
283            view_arg,
284            detail_arg,
285            self.mouseevent.ScreenX(),
286            self.mouseevent.ScreenY(),
287            self.mouseevent.ClientX(),
288            self.mouseevent.ClientY(),
289            self.mouseevent.CtrlKey(),
290            self.mouseevent.AltKey(),
291            self.mouseevent.ShiftKey(),
292            self.mouseevent.MetaKey(),
293            self.mouseevent.Button(),
294            self.mouseevent.GetRelatedTarget().as_deref(),
295        );
296        self.delta_x.set(delta_x_arg);
297        self.delta_y.set(delta_y_arg);
298        self.delta_z.set(delta_z_arg);
299        self.delta_mode.set(delta_mode_arg);
300    }
301
302    /// <https://dom.spec.whatwg.org/#dom-event-istrusted>
303    fn IsTrusted(&self) -> bool {
304        self.mouseevent.IsTrusted()
305    }
306}