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