Skip to main content

script/dom/event/
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::context::JSContext;
10use js::rust::HandleObject;
11use script_bindings::reflector::reflect_dom_object_with_proto_and_cx;
12use servo_config::pref;
13use stylo_atoms::Atom;
14
15use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
16use crate::dom::bindings::codegen::Bindings::UIEventBinding;
17use crate::dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
18use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
19use crate::dom::bindings::error::Fallible;
20use crate::dom::bindings::inheritance::Castable;
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::node::NodeTraits;
27use crate::dom::window::Window;
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(cx: &mut JSContext, window: &Window) -> DomRoot<UIEvent> {
53        Self::new_uninitialized_with_proto(cx, window, None)
54    }
55
56    fn new_uninitialized_with_proto(
57        cx: &mut JSContext,
58        window: &Window,
59        proto: Option<HandleObject>,
60    ) -> DomRoot<UIEvent> {
61        reflect_dom_object_with_proto_and_cx(Box::new(UIEvent::new_inherited()), window, proto, cx)
62    }
63
64    #[allow(clippy::too_many_arguments)]
65    pub(crate) fn new(
66        cx: &mut JSContext,
67        window: &Window,
68        event_type: Atom,
69        can_bubble: EventBubbles,
70        cancelable: EventCancelable,
71        view: Option<&Window>,
72        detail: i32,
73        which: u32,
74    ) -> DomRoot<UIEvent> {
75        Self::new_with_proto(
76            cx, window, None, event_type, can_bubble, cancelable, view, detail, which,
77        )
78    }
79
80    #[allow(clippy::too_many_arguments)]
81    fn new_with_proto(
82        cx: &mut JSContext,
83        window: &Window,
84        proto: Option<HandleObject>,
85        event_type: Atom,
86        can_bubble: EventBubbles,
87        cancelable: EventCancelable,
88        view: Option<&Window>,
89        detail: i32,
90        which: u32,
91    ) -> DomRoot<UIEvent> {
92        let ev = UIEvent::new_uninitialized_with_proto(cx, window, proto);
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        cx: &mut JSContext,
156        window: &Window,
157        proto: Option<HandleObject>,
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            cx,
165            window,
166            proto,
167            event_type.into(),
168            bubbles,
169            cancelable,
170            init.view.as_deref(),
171            init.detail,
172            init.which,
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}