1use 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 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 fn DeltaX(&self) -> Finite<f64> {
245 self.delta_x.get()
246 }
247
248 fn DeltaY(&self) -> Finite<f64> {
250 self.delta_y.get()
251 }
252
253 fn DeltaZ(&self) -> Finite<f64> {
255 self.delta_z.get()
256 }
257
258 fn DeltaMode(&self) -> u32 {
260 self.delta_mode.get()
261 }
262
263 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 fn IsTrusted(&self) -> bool {
305 self.mouseevent.IsTrusted()
306 }
307}