Skip to main content

script/dom/event/
inputevent.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 bitflags::bitflags;
6use dom_struct::dom_struct;
7use embedder_traits::Cursor;
8use euclid::Point2D;
9use js::context::JSContext;
10use js::rust::HandleObject;
11use script_bindings::domstring::TracedDOMString;
12use script_bindings::reflector::reflect_dom_object_with_proto;
13use style::Atom;
14use style_traits::CSSPixel;
15
16use crate::dom::bindings::codegen::Bindings::InputEventBinding::{self, InputEventMethods};
17use crate::dom::bindings::codegen::Bindings::UIEventBinding::UIEvent_Binding::UIEventMethods;
18use crate::dom::bindings::error::Fallible;
19use crate::dom::bindings::root::DomRoot;
20use crate::dom::bindings::str::DOMString;
21use crate::dom::datatransfer::DataTransfer;
22use crate::dom::node::Node;
23use crate::dom::selection_range::RootedSelectionBoundary;
24use crate::dom::staticrange::StaticRange;
25use crate::dom::uievent::UIEvent;
26use crate::dom::window::Window;
27
28#[dom_struct]
29pub(crate) struct InputEvent {
30    uievent: UIEvent,
31    data: Option<TracedDOMString>,
32    is_composing: bool,
33    input_type: TracedDOMString,
34}
35
36impl InputEvent {
37    #[expect(clippy::too_many_arguments)]
38    pub(crate) fn new(
39        cx: &mut JSContext,
40        window: &Window,
41        proto: Option<HandleObject>,
42        event_type: Atom,
43        flags: InputEventFlags,
44        view: Option<&Window>,
45        detail: i32,
46        data: Option<DOMString>,
47        input_type: DOMString,
48    ) -> DomRoot<InputEvent> {
49        let event = reflect_dom_object_with_proto(
50            cx,
51            Box::new(InputEvent {
52                uievent: UIEvent::new_inherited(),
53                data: data.map(|domstring| domstring.traced()),
54                is_composing: flags.intersects(InputEventFlags::COMPOSING),
55                input_type: input_type.traced(),
56            }),
57            window,
58            proto,
59        );
60        event.uievent.init_event(
61            event_type,
62            flags.intersects(InputEventFlags::BUBBLES),
63            flags.intersects(InputEventFlags::CANCELABLE),
64            view,
65            detail,
66        );
67        event
68    }
69}
70
71impl InputEventMethods<crate::DomTypeHolder> for InputEvent {
72    /// <https://w3c.github.io/uievents/#dom-inputevent-inputevent>
73    fn Constructor(
74        cx: &mut JSContext,
75        window: &Window,
76        proto: Option<HandleObject>,
77        event_type: DOMString,
78        init: &InputEventBinding::InputEventInit,
79    ) -> Fallible<DomRoot<InputEvent>> {
80        let mut flags = InputEventFlags::empty();
81        if init.parent.parent.bubbles {
82            flags |= InputEventFlags::BUBBLES;
83        }
84        if init.parent.parent.cancelable {
85            flags |= InputEventFlags::CANCELABLE;
86        }
87        if init.isComposing {
88            flags |= InputEventFlags::COMPOSING;
89        }
90        let event = InputEvent::new(
91            cx,
92            window,
93            proto,
94            event_type.into(),
95            flags,
96            init.parent.view.as_deref(),
97            init.parent.detail,
98            init.data.clone(),
99            init.inputType.clone(),
100        );
101        Ok(event)
102    }
103
104    /// <https://w3c.github.io/uievents/#dom-inputevent-data>
105    fn GetData(&self) -> Option<DOMString> {
106        self.data.clone().map(|domstring| domstring.root())
107    }
108
109    /// <https://w3c.github.io/uievents/#dom-inputevent-iscomposing>
110    fn IsComposing(&self) -> bool {
111        self.is_composing
112    }
113
114    /// <https://w3c.github.io/uievents/#dom-inputevent-inputtype>
115    fn InputType(&self) -> DOMString {
116        self.input_type.clone().root()
117    }
118
119    /// <https://w3c.github.io/input-events/#dom-inputevent-datatransfer>
120    fn GetDataTransfer(&self) -> Option<DomRoot<DataTransfer>> {
121        // TODO: Populate dataTransfer for contenteditable
122        None
123    }
124
125    /// <https://w3c.github.io/input-events/#dom-inputevent-gettargetranges>
126    fn GetTargetRanges(&self) -> Vec<DomRoot<StaticRange>> {
127        // TODO: Populate targetRanges for contenteditable
128        Vec::new()
129    }
130
131    /// <https://dom.spec.whatwg.org/#dom-event-istrusted>
132    fn IsTrusted(&self) -> bool {
133        self.uievent.IsTrusted()
134    }
135}
136
137bitflags! {
138    #[derive(Clone, Copy, Eq, PartialEq)]
139    pub struct InputEventFlags: u8 {
140        const BUBBLES = 1 << 0;
141        const CANCELABLE = 1 << 1;
142        const COMPOSING = 1 << 2;
143    }
144}
145/// A [`HitTestResult`] that is the result of doing a hit test based on a less-fine-grained
146/// `PaintHitTestResult` against our current layout.
147pub(crate) struct HitTestResult {
148    pub node: DomRoot<Node>,
149    pub dom_position_for_selection: Option<RootedSelectionBoundary>,
150    pub cursor: Cursor,
151    pub point_in_node: Point2D<f32, CSSPixel>,
152    pub point_in_frame: Point2D<f32, CSSPixel>,
153    pub point_relative_to_initial_containing_block: Point2D<f32, CSSPixel>,
154}