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