script/dom/
uievent.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;
6use std::default::Default;
7
8use dom_struct::dom_struct;
9use js::rust::HandleObject;
10use servo_config::pref;
11use stylo_atoms::Atom;
12
13use super::node::NodeTraits;
14use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
15use crate::dom::bindings::codegen::Bindings::UIEventBinding;
16use crate::dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
17use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
18use crate::dom::bindings::error::Fallible;
19use crate::dom::bindings::inheritance::Castable;
20use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
21use crate::dom::bindings::root::{DomRoot, MutNullableDom};
22use crate::dom::bindings::str::DOMString;
23use crate::dom::element::Element;
24use crate::dom::event::{Event, EventBubbles, EventCancelable};
25use crate::dom::eventtarget::EventTarget;
26use crate::dom::window::Window;
27use crate::script_runtime::CanGc;
28
29// https://w3c.github.io/uievents/#interface-uievent
30#[dom_struct]
31pub(crate) struct UIEvent {
32    event: Event,
33    view: MutNullableDom<Window>,
34    detail: Cell<i32>,
35    which: Cell<u32>,
36}
37
38impl UIEvent {
39    pub(crate) fn new_inherited() -> UIEvent {
40        UIEvent {
41            event: Event::new_inherited(),
42            view: Default::default(),
43            detail: Cell::new(0),
44            which: Cell::new(0),
45        }
46    }
47
48    pub(crate) fn set_which(&self, v: u32) {
49        self.which.set(v);
50    }
51
52    pub(crate) fn new_uninitialized(window: &Window, can_gc: CanGc) -> DomRoot<UIEvent> {
53        Self::new_uninitialized_with_proto(window, None, can_gc)
54    }
55
56    fn new_uninitialized_with_proto(
57        window: &Window,
58        proto: Option<HandleObject>,
59        can_gc: CanGc,
60    ) -> DomRoot<UIEvent> {
61        reflect_dom_object_with_proto(Box::new(UIEvent::new_inherited()), window, proto, can_gc)
62    }
63
64    #[allow(clippy::too_many_arguments)]
65    pub(crate) fn new(
66        window: &Window,
67        event_type: Atom,
68        can_bubble: EventBubbles,
69        cancelable: EventCancelable,
70        view: Option<&Window>,
71        detail: i32,
72        which: u32,
73        can_gc: CanGc,
74    ) -> DomRoot<UIEvent> {
75        Self::new_with_proto(
76            window, None, event_type, can_bubble, cancelable, view, detail, which, can_gc,
77        )
78    }
79
80    #[allow(clippy::too_many_arguments)]
81    fn new_with_proto(
82        window: &Window,
83        proto: Option<HandleObject>,
84        event_type: Atom,
85        can_bubble: EventBubbles,
86        cancelable: EventCancelable,
87        view: Option<&Window>,
88        detail: i32,
89        which: u32,
90        can_gc: CanGc,
91    ) -> DomRoot<UIEvent> {
92        let ev = UIEvent::new_uninitialized_with_proto(window, proto, can_gc);
93        ev.initialize_ui_event(
94            event_type,
95            view.map(|window| window.upcast::<EventTarget>()),
96            can_bubble,
97            cancelable,
98        );
99        ev.detail.set(detail);
100        ev.which.set(which);
101        ev
102    }
103
104    /// <https://w3c.github.io/uievents/#initialize-a-uievent>
105    pub(crate) fn initialize_ui_event(
106        &self,
107        event_type: Atom,
108        target_: Option<&EventTarget>,
109        bubbles: EventBubbles,
110        cancelable: EventCancelable,
111    ) {
112        // 1. Initialize the base Event attributes:
113        self.event
114            .init_event(event_type, bool::from(bubbles), bool::from(cancelable));
115        self.event.set_target(target_);
116        // 2. Initialize view/detail:
117        if let Some(target_) = target_ {
118            let element = target_.downcast::<Element>();
119            let document = match element {
120                Some(element) => element.owner_document(),
121                None => target_.downcast::<Window>().unwrap().Document(),
122            };
123            self.view.set(Some(document.window()));
124        }
125        self.detail.set(0_i32);
126    }
127
128    pub(crate) fn set_detail(&self, detail_: i32) {
129        self.detail.set(detail_);
130    }
131
132    /// <https://w3c.github.io/uievents/#widl-UIEvent-initUIEvent>
133    pub(crate) fn init_event(
134        &self,
135        event_type: Atom,
136        can_bubble: bool,
137        cancelable: bool,
138        view: Option<&Window>,
139        detail: i32,
140    ) {
141        let event = self.upcast::<Event>();
142        if event.dispatching() {
143            return;
144        }
145
146        event.init_event(event_type, can_bubble, cancelable);
147        self.view.set(view);
148        self.detail.set(detail);
149    }
150}
151
152impl UIEventMethods<crate::DomTypeHolder> for UIEvent {
153    /// <https://w3c.github.io/uievents/#dom-uievent-uievent>
154    fn Constructor(
155        window: &Window,
156        proto: Option<HandleObject>,
157        can_gc: CanGc,
158        event_type: DOMString,
159        init: &UIEventBinding::UIEventInit,
160    ) -> Fallible<DomRoot<UIEvent>> {
161        let bubbles = EventBubbles::from(init.parent.bubbles);
162        let cancelable = EventCancelable::from(init.parent.cancelable);
163        let event = UIEvent::new_with_proto(
164            window,
165            proto,
166            event_type.into(),
167            bubbles,
168            cancelable,
169            init.view.as_deref(),
170            init.detail,
171            init.which,
172            can_gc,
173        );
174        Ok(event)
175    }
176
177    /// <https://w3c.github.io/uievents/#widl-UIEvent-view>
178    fn GetView(&self) -> Option<DomRoot<Window>> {
179        self.view.get()
180    }
181
182    /// <https://w3c.github.io/uievents/#widl-UIEvent-detail>
183    fn Detail(&self) -> i32 {
184        self.detail.get()
185    }
186
187    /// <https://w3c.github.io/uievents/#widl-UIEvent-initUIEvent>
188    fn InitUIEvent(
189        &self,
190        event_type: DOMString,
191        can_bubble: bool,
192        cancelable: bool,
193        view: Option<&Window>,
194        detail: i32,
195    ) {
196        self.init_event(event_type.into(), can_bubble, cancelable, view, detail);
197    }
198
199    /// <https://dom.spec.whatwg.org/#dom-event-istrusted>
200    fn IsTrusted(&self) -> bool {
201        self.event.IsTrusted()
202    }
203
204    /// <https://w3c.github.io/uievents/#dom-uievent-which>
205    fn Which(&self) -> u32 {
206        if pref!(dom_uievent_which_enabled) {
207            self.which.get()
208        } else {
209            0
210        }
211    }
212}