/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use std::array::from_ref;
use std::cell::{Cell, RefCell};
use std::f64::consts::PI;
use std::mem;
use std::rc::Rc;
use std::time::{Duration, Instant};

use base::generic_channel;
use constellation_traits::ScriptToConstellationMessage;
use embedder_traits::{
    Cursor, EditingActionEvent, EmbedderMsg, GamepadEvent as EmbedderGamepadEvent,
    GamepadSupportedHapticEffects, GamepadUpdateType, ImeEvent, InputEvent,
    KeyboardEvent as EmbedderKeyboardEvent, MouseButton, MouseButtonAction, MouseButtonEvent,
    MouseLeftViewportEvent, ScrollEvent, TouchEvent as EmbedderTouchEvent, TouchEventType, TouchId,
    UntrustedNodeAddress, WheelEvent as EmbedderWheelEvent,
};
use euclid::Point2D;
use ipc_channel::ipc;
use keyboard_types::{Code, Key, KeyState, Modifiers, NamedKey};
use layout_api::node_id_from_scroll_id;
use script_bindings::codegen::GenericBindings::DocumentBinding::DocumentMethods;
use script_bindings::codegen::GenericBindings::EventBinding::EventMethods;
use script_bindings::codegen::GenericBindings::NavigatorBinding::NavigatorMethods;
use script_bindings::codegen::GenericBindings::NodeBinding::NodeMethods;
use script_bindings::codegen::GenericBindings::PerformanceBinding::PerformanceMethods;
use script_bindings::codegen::GenericBindings::TouchBinding::TouchMethods;
use script_bindings::codegen::GenericBindings::WindowBinding::WindowMethods;
use script_bindings::inheritance::Castable;
use script_bindings::num::Finite;
use script_bindings::root::{Dom, DomRoot, DomSlice};
use script_bindings::script_runtime::CanGc;
use script_bindings::str::DOMString;
use script_traits::ConstellationInputEvent;
use servo_config::pref;
use style_traits::CSSPixel;
use xml5ever::{local_name, ns};

use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::root::MutNullableDom;
use crate::dom::clipboardevent::ClipboardEventType;
use crate::dom::document::{FireMouseEventType, FocusInitiator, TouchEventResult};
use crate::dom::event::{EventBubbles, EventCancelable, EventDefault};
use crate::dom::gamepad::gamepad::{Gamepad, contains_user_gesture};
use crate::dom::gamepad::gamepadevent::GamepadEventType;
use crate::dom::inputevent::HitTestResult;
use crate::dom::node::{self, Node, ShadowIncluding};
use crate::dom::pointerevent::PointerId;
use crate::dom::types::{
    ClipboardEvent, CompositionEvent, DataTransfer, Element, Event, EventTarget, GlobalScope,
    HTMLAnchorElement, KeyboardEvent, MouseEvent, PointerEvent, Touch, TouchEvent, TouchList,
    WheelEvent, Window,
};
use crate::drag_data_store::{DragDataStore, Kind, Mode};
use crate::realms::enter_realm;

/// The [`DocumentEventHandler`] is a structure responsible for handling input events for
/// the [`crate::Document`] and storing data related to event handling. It exists to
/// decrease the size of the [`crate::Document`] structure.
#[derive(JSTraceable, MallocSizeOf)]
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
pub(crate) struct DocumentEventHandler {
    /// The [`Window`] element for this [`DocumentEventHandler`].
    window: Dom<Window>,
    /// Pending input events, to be handled at the next rendering opportunity.
    #[no_trace]
    #[ignore_malloc_size_of = "CompositorEvent contains data from outside crates"]
    pending_input_events: DomRefCell<Vec<ConstellationInputEvent>>,
    /// The index of the last mouse move event in the pending compositor events queue.
    mouse_move_event_index: DomRefCell<Option<usize>>,
    /// <https://w3c.github.io/uievents/#event-type-dblclick>
    #[ignore_malloc_size_of = "Defined in std"]
    #[no_trace]
    last_click_info: DomRefCell<Option<(Instant, Point2D<f32, CSSPixel>)>>,
    /// The element that is currently hovered by the cursor.
    current_hover_target: MutNullableDom<Element>,
    /// The most recent mouse movement point, used for processing `mouseleave` events.
    #[no_trace]
    most_recent_mousemove_point: Cell<Option<Point2D<f32, CSSPixel>>>,
    /// The currently set [`Cursor`] or `None` if the `Document` isn't being hovered
    /// by the cursor.
    #[no_trace]
    current_cursor: Cell<Option<Cursor>>,
    /// <http://w3c.github.io/touch-events/#dfn-active-touch-point>
    active_touch_points: DomRefCell<Vec<Dom<Touch>>>,
    /// The active keyboard modifiers for the WebView. This is updated when receiving any input event.
    #[no_trace]
    active_keyboard_modifiers: Cell<Modifiers>,
}

impl DocumentEventHandler {
    pub(crate) fn new(window: &Window) -> Self {
        Self {
            window: Dom::from_ref(window),
            pending_input_events: Default::default(),
            mouse_move_event_index: Default::default(),
            last_click_info: Default::default(),
            current_hover_target: Default::default(),
            most_recent_mousemove_point: Default::default(),
            current_cursor: Default::default(),
            active_touch_points: Default::default(),
            active_keyboard_modifiers: Default::default(),
        }
    }

    /// Note a pending compositor event, to be processed at the next `update_the_rendering` task.
    pub(crate) fn note_pending_input_event(&self, event: ConstellationInputEvent) {
        let mut pending_compositor_events = self.pending_input_events.borrow_mut();
        if matches!(event.event, InputEvent::MouseMove(..)) {
            // First try to replace any existing mouse move event.
            if let Some(mouse_move_event) = self
                .mouse_move_event_index
                .borrow()
                .and_then(|index| pending_compositor_events.get_mut(index))
            {
                *mouse_move_event = event;
                return;
            }

            *self.mouse_move_event_index.borrow_mut() = Some(pending_compositor_events.len());
        }

        pending_compositor_events.push(event);
    }

    /// Whether or not this [`Document`] has any pending input events to be processed during
    /// "update the rendering."
    pub(crate) fn has_pending_input_events(&self) -> bool {
        !self.pending_input_events.borrow().is_empty()
    }

    pub(crate) fn alternate_action_keyboard_modifier_active(&self) -> bool {
        #[cfg(target_os = "macos")]
        {
            self.active_keyboard_modifiers
                .get()
                .contains(Modifiers::META)
        }
        #[cfg(not(target_os = "macos"))]
        {
            self.active_keyboard_modifiers
                .get()
                .contains(Modifiers::CONTROL)
        }
    }

    pub(crate) fn handle_pending_input_events(&self, can_gc: CanGc) {
        let _realm = enter_realm(&*self.window);

        // Reset the mouse event index.
        *self.mouse_move_event_index.borrow_mut() = None;
        let pending_input_events = mem::take(&mut *self.pending_input_events.borrow_mut());

        for event in pending_input_events {
            self.active_keyboard_modifiers
                .set(event.active_keyboard_modifiers);

            match event.event.clone() {
                InputEvent::MouseButton(mouse_button_event) => {
                    self.handle_native_mouse_button_event(mouse_button_event, &event, can_gc);
                },
                InputEvent::MouseMove(_) => {
                    self.handle_native_mouse_move_event(&event, can_gc);
                },
                InputEvent::MouseLeftViewport(mouse_leave_event) => {
                    self.handle_mouse_left_viewport_event(&event, &mouse_leave_event, can_gc);
                },
                InputEvent::Touch(touch_event) => {
                    self.handle_touch_event(touch_event, &event, can_gc);
                },
                InputEvent::Wheel(wheel_event) => {
                    self.handle_wheel_event(wheel_event, &event, can_gc);
                },
                InputEvent::Keyboard(keyboard_event) => {
                    self.handle_keyboard_event(keyboard_event, can_gc);
                },
                InputEvent::Ime(ime_event) => {
                    self.handle_ime_event(ime_event, can_gc);
                },
                InputEvent::Gamepad(gamepad_event) => {
                    self.handle_gamepad_event(gamepad_event);
                },
                InputEvent::EditingAction(editing_action_event) => {
                    self.handle_editing_action(editing_action_event, can_gc);
                },
                InputEvent::Scroll(scroll_event) => {
                    self.handle_embedder_scroll_event(scroll_event);
                },
            }

            self.notify_webdriver_input_event_completed(event.event);
        }
    }

    fn notify_webdriver_input_event_completed(&self, event: InputEvent) {
        let Some(id) = event.webdriver_message_id() else {
            return;
        };

        // Webdriver should be notified once all current dom events have been processed.
        let trusted_window = Trusted::new(&*self.window);
        self.window
            .as_global_scope()
            .task_manager()
            .dom_manipulation_task_source()
            .queue(task!(notify_webdriver_input_event_completed: move || {
                let window = trusted_window.root();
                window.send_to_constellation(ScriptToConstellationMessage::WebDriverInputComplete(id));
            }));
    }

    pub(crate) fn set_cursor(&self, cursor: Option<Cursor>) {
        if cursor == self.current_cursor.get() {
            return;
        }
        self.current_cursor.set(cursor);
        self.window.send_to_embedder(EmbedderMsg::SetCursor(
            self.window.webview_id(),
            cursor.unwrap_or_default(),
        ));
    }

    fn handle_mouse_left_viewport_event(
        &self,
        input_event: &ConstellationInputEvent,
        mouse_leave_event: &MouseLeftViewportEvent,
        can_gc: CanGc,
    ) {
        if let Some(current_hover_target) = self.current_hover_target.get() {
            let current_hover_target = current_hover_target.upcast::<Node>();
            for element in current_hover_target
                .inclusive_ancestors(ShadowIncluding::No)
                .filter_map(DomRoot::downcast::<Element>)
            {
                element.set_hover_state(false);
                element.set_active_state(false);
            }

            if let Some(hit_test_result) = self
                .most_recent_mousemove_point
                .get()
                .and_then(|point| self.window.hit_test_from_point_in_viewport(point))
            {
                MouseEvent::new_simple(
                    &self.window,
                    FireMouseEventType::Out,
                    EventBubbles::Bubbles,
                    EventCancelable::Cancelable,
                    &hit_test_result,
                    input_event,
                    can_gc,
                )
                .upcast::<Event>()
                .fire(current_hover_target.upcast(), can_gc);
                self.handle_mouse_enter_leave_event(
                    DomRoot::from_ref(current_hover_target),
                    None,
                    FireMouseEventType::Leave,
                    &hit_test_result,
                    input_event,
                    can_gc,
                );
            }
        }

        // We do not want to always inform the embedder that cursor has been set to the
        // default cursor, in order to avoid a timing issue when moving between `<iframe>`
        // elements. There is currently no way to control which `SetCursor` message will
        // reach the embedder first. This is safer when leaving the `WebView` entirely.
        if !mouse_leave_event.focus_moving_to_another_iframe {
            // If focus is moving to another frame, it will decide what the new status
            // text is, but if this mouse leave event is leaving the WebView entirely,
            // then clear it.
            self.window
                .send_to_embedder(EmbedderMsg::Status(self.window.webview_id(), None));
            self.set_cursor(None);
        } else {
            self.current_cursor.set(None);
        }

        self.current_hover_target.set(None);
        self.most_recent_mousemove_point.set(None);
    }

    fn handle_mouse_enter_leave_event(
        &self,
        event_target: DomRoot<Node>,
        related_target: Option<DomRoot<Node>>,
        event_type: FireMouseEventType,
        hit_test_result: &HitTestResult,
        input_event: &ConstellationInputEvent,
        can_gc: CanGc,
    ) {
        assert!(matches!(
            event_type,
            FireMouseEventType::Enter | FireMouseEventType::Leave
        ));

        let common_ancestor = match related_target.as_ref() {
            Some(related_target) => event_target
                .common_ancestor(related_target, ShadowIncluding::No)
                .unwrap_or_else(|| DomRoot::from_ref(&*event_target)),
            None => DomRoot::from_ref(&*event_target),
        };

        // We need to create a target chain in case the event target shares
        // its boundaries with its ancestors.
        let mut targets = vec![];
        let mut current = Some(event_target);
        while let Some(node) = current {
            if node == common_ancestor {
                break;
            }
            current = node.GetParentNode();
            targets.push(node);
        }

        // The order for dispatching mouseenter events starts from the topmost
        // common ancestor of the event target and the related target.
        if event_type == FireMouseEventType::Enter {
            targets = targets.into_iter().rev().collect();
        }

        for target in targets {
            MouseEvent::new_simple(
                &self.window,
                event_type,
                EventBubbles::DoesNotBubble,
                EventCancelable::NotCancelable,
                hit_test_result,
                input_event,
                can_gc,
            )
            .upcast::<Event>()
            .fire(target.upcast(), can_gc);
        }
    }

    /// <https://w3c.github.io/uievents/#handle-native-mouse-move>
    fn handle_native_mouse_move_event(&self, input_event: &ConstellationInputEvent, can_gc: CanGc) {
        // Ignore all incoming events without a hit test.
        let Some(hit_test_result) = self.window.hit_test_from_input_event(input_event) else {
            return;
        };

        // Update the cursor when the mouse moves, if it has changed.
        self.set_cursor(Some(hit_test_result.cursor));

        let Some(new_target) = hit_test_result
            .node
            .inclusive_ancestors(ShadowIncluding::No)
            .filter_map(DomRoot::downcast::<Element>)
            .next()
        else {
            return;
        };

        let target_has_changed = self
            .current_hover_target
            .get()
            .is_none_or(|old_target| old_target != new_target);

        // Here we know the target has changed, so we must update the state,
        // dispatch mouseout to the previous one, mouseover to the new one.
        if target_has_changed {
            // Dispatch mouseout and mouseleave to previous target.
            if let Some(old_target) = self.current_hover_target.get() {
                let old_target_is_ancestor_of_new_target = old_target
                    .upcast::<Node>()
                    .is_ancestor_of(new_target.upcast::<Node>());

                // If the old target is an ancestor of the new target, this can be skipped
                // completely, since the node's hover state will be reset below.
                if !old_target_is_ancestor_of_new_target {
                    for element in old_target
                        .upcast::<Node>()
                        .inclusive_ancestors(ShadowIncluding::No)
                        .filter_map(DomRoot::downcast::<Element>)
                    {
                        element.set_hover_state(false);
                        element.set_active_state(false);
                    }
                }

                MouseEvent::new_simple(
                    &self.window,
                    FireMouseEventType::Out,
                    EventBubbles::Bubbles,
                    EventCancelable::Cancelable,
                    &hit_test_result,
                    input_event,
                    can_gc,
                )
                .upcast::<Event>()
                .fire(old_target.upcast(), can_gc);

                if !old_target_is_ancestor_of_new_target {
                    let event_target = DomRoot::from_ref(old_target.upcast::<Node>());
                    let moving_into = Some(DomRoot::from_ref(new_target.upcast::<Node>()));
                    self.handle_mouse_enter_leave_event(
                        event_target,
                        moving_into,
                        FireMouseEventType::Leave,
                        &hit_test_result,
                        input_event,
                        can_gc,
                    );
                }
            }

            // Dispatch mouseover and mouseenter to new target.
            for element in new_target
                .upcast::<Node>()
                .inclusive_ancestors(ShadowIncluding::No)
                .filter_map(DomRoot::downcast::<Element>)
            {
                element.set_hover_state(true);
            }

            MouseEvent::new_simple(
                &self.window,
                FireMouseEventType::Over,
                EventBubbles::Bubbles,
                EventCancelable::Cancelable,
                &hit_test_result,
                input_event,
                can_gc,
            )
            .upcast::<Event>()
            .fire(new_target.upcast(), can_gc);

            let moving_from = self
                .current_hover_target
                .get()
                .map(|old_target| DomRoot::from_ref(old_target.upcast::<Node>()));
            let event_target = DomRoot::from_ref(new_target.upcast::<Node>());
            self.handle_mouse_enter_leave_event(
                event_target,
                moving_from,
                FireMouseEventType::Enter,
                &hit_test_result,
                input_event,
                can_gc,
            );
        }

        // Send mousemove event to topmost target, unless it's an iframe, in which case the
        // compositor should have also sent an event to the inner document.
        MouseEvent::new_simple(
            &self.window,
            FireMouseEventType::Move,
            EventBubbles::Bubbles,
            EventCancelable::Cancelable,
            &hit_test_result,
            input_event,
            can_gc,
        )
        .upcast::<Event>()
        .fire(new_target.upcast(), can_gc);

        self.update_current_hover_target_and_status(Some(new_target));
        self.most_recent_mousemove_point
            .set(Some(hit_test_result.point_in_frame));
    }

    fn update_current_hover_target_and_status(&self, new_hover_target: Option<DomRoot<Element>>) {
        let current_hover_target = self.current_hover_target.get();
        if current_hover_target == new_hover_target {
            return;
        }

        let previous_hover_target = self.current_hover_target.get();
        self.current_hover_target.set(new_hover_target.as_deref());

        // If the new hover target is an anchor with a status value, inform the embedder
        // of the new value.
        if let Some(target) = self.current_hover_target.get() {
            if let Some(anchor) = target
                .upcast::<Node>()
                .inclusive_ancestors(ShadowIncluding::No)
                .filter_map(DomRoot::downcast::<HTMLAnchorElement>)
                .next()
            {
                let status = anchor
                    .upcast::<Element>()
                    .get_attribute(&ns!(), &local_name!("href"))
                    .and_then(|href| {
                        let value = href.value();
                        let url = self.window.get_url();
                        url.join(&value).map(|url| url.to_string()).ok()
                    });
                self.window
                    .send_to_embedder(EmbedderMsg::Status(self.window.webview_id(), status));
                return;
            }
        }

        // No state was set above, which means that the new value of the status in the embedder
        // should be `None`. Set that now. If `previous_hover_target` is `None` that means this
        // is the first mouse move event we are seeing after getting the cursor. In that case,
        // we also clear the status.
        if previous_hover_target.is_none_or(|previous_hover_target| {
            previous_hover_target
                .upcast::<Node>()
                .inclusive_ancestors(ShadowIncluding::No)
                .filter_map(DomRoot::downcast::<HTMLAnchorElement>)
                .next()
                .is_some()
        }) {
            self.window
                .send_to_embedder(EmbedderMsg::Status(self.window.webview_id(), None));
        }
    }

    pub(crate) fn handle_refresh_cursor(&self) {
        let Some(most_recent_mousemove_point) = self.most_recent_mousemove_point.get() else {
            return;
        };

        let Some(hit_test_result) = self
            .window
            .hit_test_from_point_in_viewport(most_recent_mousemove_point)
        else {
            return;
        };

        self.set_cursor(Some(hit_test_result.cursor));
    }

    /// <https://w3c.github.io/uievents/#mouseevent-algorithms>
    /// Handles native mouse down, mouse up, mouse click.
    fn handle_native_mouse_button_event(
        &self,
        event: MouseButtonEvent,
        input_event: &ConstellationInputEvent,
        can_gc: CanGc,
    ) {
        // Ignore all incoming events without a hit test.
        let Some(hit_test_result) = self.window.hit_test_from_input_event(input_event) else {
            return;
        };

        debug!(
            "{:?}: at {:?}",
            event.action, hit_test_result.point_in_frame
        );

        let Some(el) = hit_test_result
            .node
            .inclusive_ancestors(ShadowIncluding::Yes)
            .filter_map(DomRoot::downcast::<Element>)
            .next()
        else {
            return;
        };

        let node = el.upcast::<Node>();
        debug!("{:?} on {:?}", event.action, node.debug_str());

        // https://w3c.github.io/uievents/#hit-test
        // Prevent mouse event if element is disabled.
        // TODO: also inert.
        if el.is_actually_disabled() {
            return;
        }

        let dom_event = DomRoot::upcast::<Event>(MouseEvent::for_platform_mouse_event(
            event,
            input_event.pressed_mouse_buttons,
            &self.window,
            &hit_test_result,
            input_event.active_keyboard_modifiers,
            can_gc,
        ));

        let activatable = el.as_maybe_activatable();
        match event.action {
            // https://w3c.github.io/uievents/#handle-native-mouse-click
            MouseButtonAction::Click => {
                el.set_click_in_progress(true);
                dom_event.dispatch(node.upcast(), false, can_gc);
                el.set_click_in_progress(false);

                self.maybe_fire_dblclick(node, &hit_test_result, input_event, can_gc);
            },
            // https://w3c.github.io/uievents/#handle-native-mouse-down
            MouseButtonAction::Down => {
                if let Some(a) = activatable {
                    a.enter_formal_activation_state();
                }

                // (TODO) Step 6. Maybe send pointerdown event with `dom_event`.

                // For a node within a text input UA shadow DOM,
                // delegate the focus target into its shadow host.
                // TODO: This focus delegation should be done
                // with shadow DOM delegateFocus attribute.
                let target_el = el.find_focusable_shadow_host_if_necessary();

                let document = self.window.Document();
                document.begin_focus_transaction();

                // Try to focus `el`. If it's not focusable, focus the document instead.
                document.request_focus(None, FocusInitiator::Local, can_gc);
                document.request_focus(target_el.as_deref(), FocusInitiator::Local, can_gc);

                // Step 7. Let result = dispatch event at target
                let result = dom_event.dispatch(node.upcast(), false, can_gc);

                // Step 8. If result is true and target is a focusable area
                // that is click focusable, then Run the focusing steps at target.
                if result && document.has_focus_transaction() {
                    document.commit_focus_transaction(FocusInitiator::Local, can_gc);
                }

                // Step 9. If mbutton is the secondary mouse button, then
                // Maybe show context menu with native, target.
                if let MouseButton::Right = event.button {
                    self.maybe_show_context_menu(
                        node.upcast(),
                        &hit_test_result,
                        input_event,
                        can_gc,
                    );
                }
            },
            // https://w3c.github.io/uievents/#handle-native-mouse-up
            MouseButtonAction::Up => {
                if let Some(a) = activatable {
                    a.exit_formal_activation_state();
                }

                // (TODO) Step 6. Maybe send pointerup event with `dom_event``.

                // Step 7. dispatch event at target.
                dom_event.dispatch(node.upcast(), false, can_gc);
            },
        }
    }

    /// <https://www.w3.org/TR/uievents/#maybe-show-context-menu>
    fn maybe_show_context_menu(
        &self,
        target: &EventTarget,
        hit_test_result: &HitTestResult,
        input_event: &ConstellationInputEvent,
        can_gc: CanGc,
    ) {
        // <https://w3c.github.io/uievents/#contextmenu>
        let menu_event = PointerEvent::new(
            &self.window,                   // window
            DOMString::from("contextmenu"), // type
            EventBubbles::Bubbles,          // can_bubble
            EventCancelable::Cancelable,    // cancelable
            Some(&self.window),             // view
            0,                              // detail
            hit_test_result.point_in_frame.to_i32(),
            hit_test_result.point_in_frame.to_i32(),
            hit_test_result
                .point_relative_to_initial_containing_block
                .to_i32(),
            input_event.active_keyboard_modifiers,
            2i16, // button, right mouse button
            input_event.pressed_mouse_buttons,
            None,                     // related_target
            None,                     // point_in_target
            PointerId::Mouse as i32,  // pointer_id
            1,                        // width
            1,                        // height
            0.5,                      // pressure
            0.0,                      // tangential_pressure
            0,                        // tilt_x
            0,                        // tilt_y
            0,                        // twist
            PI / 2.0,                 // altitude_angle
            0.0,                      // azimuth_angle
            DOMString::from("mouse"), // pointer_type
            true,                     // is_primary
            vec![],                   // coalesced_events
            vec![],                   // predicted_events
            can_gc,
        );

        // Step 3. Let result = dispatch menuevent at target.
        let result = menu_event.upcast::<Event>().fire(target, can_gc);

        // Step 4. If result is true, then show the UA context menu
        if result {
            let (sender, receiver) =
                generic_channel::channel().expect("Failed to create IPC channel.");
            self.window.send_to_embedder(EmbedderMsg::ShowContextMenu(
                self.window.webview_id(),
                sender,
                None,
                vec![],
            ));
            let _ = receiver.recv().unwrap();
        };
    }

    fn maybe_fire_dblclick(
        &self,
        target: &Node,
        hit_test_result: &HitTestResult,
        input_event: &ConstellationInputEvent,
        can_gc: CanGc,
    ) {
        // https://w3c.github.io/uievents/#event-type-dblclick
        let now = Instant::now();
        let point_in_frame = hit_test_result.point_in_frame;
        let opt = self.last_click_info.borrow_mut().take();

        if let Some((last_time, last_pos)) = opt {
            let double_click_timeout =
                Duration::from_millis(pref!(dom_document_dblclick_timeout) as u64);
            let double_click_distance_threshold = pref!(dom_document_dblclick_dist) as u64;

            // Calculate distance between this click and the previous click.
            let line = point_in_frame - last_pos;
            let dist = (line.dot(line) as f64).sqrt();

            if now.duration_since(last_time) < double_click_timeout &&
                dist < double_click_distance_threshold as f64
            {
                // A double click has occurred if this click is within a certain time and dist. of previous click.
                let click_count = 2;

                let event = MouseEvent::new(
                    &self.window,
                    DOMString::from("dblclick"),
                    EventBubbles::Bubbles,
                    EventCancelable::Cancelable,
                    Some(&self.window),
                    click_count,
                    point_in_frame.to_i32(),
                    point_in_frame.to_i32(),
                    hit_test_result
                        .point_relative_to_initial_containing_block
                        .to_i32(),
                    input_event.active_keyboard_modifiers,
                    0i16,
                    input_event.pressed_mouse_buttons,
                    None,
                    None,
                    can_gc,
                );
                event.upcast::<Event>().fire(target.upcast(), can_gc);

                // When a double click occurs, self.last_click_info is left as None so that a
                // third sequential click will not cause another double click.
                return;
            }
        }

        // Update last_click_info with the time and position of the click.
        *self.last_click_info.borrow_mut() = Some((now, point_in_frame));
    }

    fn handle_touch_event(
        &self,
        event: EmbedderTouchEvent,
        input_event: &ConstellationInputEvent,
        can_gc: CanGc,
    ) {
        let result = self.handle_touch_event_inner(event, input_event, can_gc);
        if let (TouchEventResult::Processed(handled), true) = (result, event.is_cancelable()) {
            let sequence_id = event.expect_sequence_id();
            let result = if handled {
                embedder_traits::TouchEventResult::DefaultAllowed(sequence_id, event.event_type)
            } else {
                embedder_traits::TouchEventResult::DefaultPrevented(sequence_id, event.event_type)
            };
            self.window
                .send_to_constellation(ScriptToConstellationMessage::TouchEventProcessed(result));
        }
    }

    fn handle_touch_event_inner(
        &self,
        event: EmbedderTouchEvent,
        input_event: &ConstellationInputEvent,
        can_gc: CanGc,
    ) -> TouchEventResult {
        // Ignore all incoming events without a hit test.
        let Some(hit_test_result) = self.window.hit_test_from_input_event(input_event) else {
            self.update_active_touch_points_when_early_return(event);
            return TouchEventResult::Forwarded;
        };

        let TouchId(identifier) = event.id;
        let event_name = match event.event_type {
            TouchEventType::Down => "touchstart",
            TouchEventType::Move => "touchmove",
            TouchEventType::Up => "touchend",
            TouchEventType::Cancel => "touchcancel",
        };

        let Some(el) = hit_test_result
            .node
            .inclusive_ancestors(ShadowIncluding::No)
            .filter_map(DomRoot::downcast::<Element>)
            .next()
        else {
            self.update_active_touch_points_when_early_return(event);
            return TouchEventResult::Forwarded;
        };

        let target = DomRoot::upcast::<EventTarget>(el);
        let window = &*self.window;

        let client_x = Finite::wrap(hit_test_result.point_in_frame.x as f64);
        let client_y = Finite::wrap(hit_test_result.point_in_frame.y as f64);
        let page_x =
            Finite::wrap(hit_test_result.point_in_frame.x as f64 + window.PageXOffset() as f64);
        let page_y =
            Finite::wrap(hit_test_result.point_in_frame.y as f64 + window.PageYOffset() as f64);

        let touch = Touch::new(
            window, identifier, &target, client_x,
            client_y, // TODO: Get real screen coordinates?
            client_x, client_y, page_x, page_y, can_gc,
        );

        match event.event_type {
            TouchEventType::Down => {
                // Add a new touch point
                self.active_touch_points
                    .borrow_mut()
                    .push(Dom::from_ref(&*touch));
            },
            TouchEventType::Move => {
                // Replace an existing touch point
                let mut active_touch_points = self.active_touch_points.borrow_mut();
                match active_touch_points
                    .iter_mut()
                    .find(|t| t.Identifier() == identifier)
                {
                    Some(t) => *t = Dom::from_ref(&*touch),
                    None => warn!("Got a touchmove event for a non-active touch point"),
                }
            },
            TouchEventType::Up | TouchEventType::Cancel => {
                // Remove an existing touch point
                let mut active_touch_points = self.active_touch_points.borrow_mut();
                match active_touch_points
                    .iter()
                    .position(|t| t.Identifier() == identifier)
                {
                    Some(i) => {
                        active_touch_points.swap_remove(i);
                    },
                    None => warn!("Got a touchend event for a non-active touch point"),
                }
            },
        }

        rooted_vec!(let mut target_touches);
        let touches = {
            let touches = self.active_touch_points.borrow();
            target_touches.extend(touches.iter().filter(|t| t.Target() == target).cloned());
            TouchList::new(window, touches.r(), can_gc)
        };

        let event = TouchEvent::new(
            window,
            DOMString::from(event_name),
            EventBubbles::Bubbles,
            EventCancelable::from(event.is_cancelable()),
            Some(window),
            0i32,
            &touches,
            &TouchList::new(window, from_ref(&&*touch), can_gc),
            &TouchList::new(window, target_touches.r(), can_gc),
            // FIXME: modifier keys
            false,
            false,
            false,
            false,
            can_gc,
        );

        TouchEventResult::Processed(event.upcast::<Event>().fire(&target, can_gc))
    }

    // If hittest fails, we still need to update the active point information.
    fn update_active_touch_points_when_early_return(&self, event: EmbedderTouchEvent) {
        match event.event_type {
            TouchEventType::Down => {
                // If the touchdown fails, we don't need to do anything.
                // When a touchmove or touchdown occurs at that touch point,
                // a warning is triggered: Got a touchmove/touchend event for a non-active touch point
            },
            TouchEventType::Move => {
                // The failure of touchmove does not affect the number of active points.
                // Since there is no position information when it fails, we do not need to update.
            },
            TouchEventType::Up | TouchEventType::Cancel => {
                // Remove an existing touch point
                let mut active_touch_points = self.active_touch_points.borrow_mut();
                match active_touch_points
                    .iter()
                    .position(|t| t.Identifier() == event.id.0)
                {
                    Some(i) => {
                        active_touch_points.swap_remove(i);
                    },
                    None => warn!("Got a touchend event for a non-active touch point"),
                }
            },
        }
    }

    /// The entry point for all key processing for web content
    fn handle_keyboard_event(&self, keyboard_event: EmbedderKeyboardEvent, can_gc: CanGc) {
        let document = self.window.Document();
        let focused = document.get_focused_element();
        let body = document.GetBody();

        let target = match (&focused, &body) {
            (Some(focused), _) => focused.upcast(),
            (&None, Some(body)) => body.upcast(),
            (&None, &None) => self.window.upcast(),
        };

        let keyevent = KeyboardEvent::new(
            &self.window,
            DOMString::from(keyboard_event.event.state.event_type()),
            true,
            true,
            Some(&self.window),
            0,
            keyboard_event.event.key.clone(),
            DOMString::from(keyboard_event.event.code.to_string()),
            keyboard_event.event.location as u32,
            keyboard_event.event.repeat,
            keyboard_event.event.is_composing,
            keyboard_event.event.modifiers,
            0,
            keyboard_event.event.key.legacy_keycode(),
            can_gc,
        );
        let event = keyevent.upcast::<Event>();
        event.fire(target, can_gc);
        let mut cancel_state = event.get_cancel_state();

        // https://w3c.github.io/uievents/#keys-cancelable-keys
        // it MUST prevent the respective beforeinput and input
        // (and keypress if supported) events from being generated
        // TODO: keypress should be deprecated and superceded by beforeinput

        let is_character_value_key = matches!(
            keyboard_event.event.key,
            Key::Character(_) | Key::Named(NamedKey::Enter)
        );
        if keyboard_event.event.state == KeyState::Down &&
            is_character_value_key &&
            !keyboard_event.event.is_composing &&
            cancel_state != EventDefault::Prevented
        {
            // https://w3c.github.io/uievents/#keypress-event-order
            let event = KeyboardEvent::new(
                &self.window,
                DOMString::from("keypress"),
                true,
                true,
                Some(&self.window),
                0,
                keyboard_event.event.key.clone(),
                DOMString::from(keyboard_event.event.code.to_string()),
                keyboard_event.event.location as u32,
                keyboard_event.event.repeat,
                keyboard_event.event.is_composing,
                keyboard_event.event.modifiers,
                keyboard_event.event.key.legacy_charcode(),
                0,
                can_gc,
            );
            let ev = event.upcast::<Event>();
            ev.fire(target, can_gc);
            cancel_state = ev.get_cancel_state();
        }

        if cancel_state == EventDefault::Allowed {
            self.window.send_to_embedder(EmbedderMsg::Keyboard(
                self.window.webview_id(),
                keyboard_event.clone(),
            ));

            // This behavior is unspecced
            // We are supposed to dispatch synthetic click activation for Space and/or Return,
            // however *when* we do it is up to us.
            // Here, we're dispatching it after the key event so the script has a chance to cancel it
            // https://www.w3.org/Bugs/Public/show_bug.cgi?id=27337
            if (keyboard_event.event.key == Key::Named(NamedKey::Enter) ||
                keyboard_event.event.code == Code::Space) &&
                keyboard_event.event.state == KeyState::Up
            {
                if let Some(elem) = target.downcast::<Element>() {
                    elem.upcast::<Node>()
                        .fire_synthetic_pointer_event_not_trusted(DOMString::from("click"), can_gc);
                }
            }
        }
    }

    fn handle_ime_event(&self, event: ImeEvent, can_gc: CanGc) {
        let document = self.window.Document();
        let composition_event = match event {
            ImeEvent::Dismissed => {
                document.request_focus(
                    document.GetBody().as_ref().map(|e| e.upcast()),
                    FocusInitiator::Local,
                    can_gc,
                );
                return;
            },
            ImeEvent::Composition(composition_event) => composition_event,
        };

        // spec: https://w3c.github.io/uievents/#compositionstart
        // spec: https://w3c.github.io/uievents/#compositionupdate
        // spec: https://w3c.github.io/uievents/#compositionend
        // > Event.target : focused element processing the composition
        let focused = document.get_focused_element();
        let target = if let Some(elem) = &focused {
            elem.upcast()
        } else {
            // Event is only dispatched if there is a focused element.
            return;
        };

        let cancelable = composition_event.state == keyboard_types::CompositionState::Start;
        CompositionEvent::new(
            &self.window,
            DOMString::from(composition_event.state.event_type()),
            true,
            cancelable,
            Some(&self.window),
            0,
            DOMString::from(composition_event.data),
            can_gc,
        )
        .upcast::<Event>()
        .fire(target, can_gc);
    }

    fn handle_wheel_event(
        &self,
        event: EmbedderWheelEvent,
        input_event: &ConstellationInputEvent,
        can_gc: CanGc,
    ) {
        // Ignore all incoming events without a hit test.
        let Some(hit_test_result) = self.window.hit_test_from_input_event(input_event) else {
            return;
        };

        let Some(el) = hit_test_result
            .node
            .inclusive_ancestors(ShadowIncluding::No)
            .filter_map(DomRoot::downcast::<Element>)
            .next()
        else {
            return;
        };

        let node = el.upcast::<Node>();
        let wheel_event_type_string = "wheel".to_owned();
        debug!(
            "{}: on {:?} at {:?}",
            wheel_event_type_string,
            node.debug_str(),
            hit_test_result.point_in_frame
        );

        // https://w3c.github.io/uievents/#event-wheelevents
        let dom_event = WheelEvent::new(
            &self.window,
            DOMString::from(wheel_event_type_string),
            EventBubbles::Bubbles,
            EventCancelable::Cancelable,
            Some(&self.window),
            0i32,
            hit_test_result.point_in_frame.to_i32(),
            hit_test_result.point_in_frame.to_i32(),
            hit_test_result
                .point_relative_to_initial_containing_block
                .to_i32(),
            input_event.active_keyboard_modifiers,
            0i16,
            input_event.pressed_mouse_buttons,
            None,
            None,
            // winit defines positive wheel delta values as revealing more content left/up.
            // https://docs.rs/winit-gtk/latest/winit/event/enum.MouseScrollDelta.html
            // This is the opposite of wheel delta in uievents
            // https://w3c.github.io/uievents/#dom-wheeleventinit-deltaz
            Finite::wrap(-event.delta.x),
            Finite::wrap(-event.delta.y),
            Finite::wrap(-event.delta.z),
            event.delta.mode as u32,
            can_gc,
        );

        let dom_event = dom_event.upcast::<Event>();
        dom_event.set_trusted(true);

        let target = node.upcast();
        dom_event.fire(target, can_gc);
    }

    fn handle_gamepad_event(&self, gamepad_event: EmbedderGamepadEvent) {
        match gamepad_event {
            EmbedderGamepadEvent::Connected(index, name, bounds, supported_haptic_effects) => {
                self.handle_gamepad_connect(
                    index.0,
                    name,
                    bounds.axis_bounds,
                    bounds.button_bounds,
                    supported_haptic_effects,
                );
            },
            EmbedderGamepadEvent::Disconnected(index) => {
                self.handle_gamepad_disconnect(index.0);
            },
            EmbedderGamepadEvent::Updated(index, update_type) => {
                self.receive_new_gamepad_button_or_axis(index.0, update_type);
            },
        };
    }

    /// <https://www.w3.org/TR/gamepad/#dfn-gamepadconnected>
    fn handle_gamepad_connect(
        &self,
        // As the spec actually defines how to set the gamepad index, the GilRs index
        // is currently unused, though in practice it will almost always be the same.
        // More infra is currently needed to track gamepads across windows.
        _index: usize,
        name: String,
        axis_bounds: (f64, f64),
        button_bounds: (f64, f64),
        supported_haptic_effects: GamepadSupportedHapticEffects,
    ) {
        // TODO: 2. If document is not null and is not allowed to use the "gamepad" permission,
        //          then abort these steps.
        let trusted_window = Trusted::new(&*self.window);
        self.window
            .upcast::<GlobalScope>()
            .task_manager()
            .gamepad_task_source()
            .queue(task!(gamepad_connected: move || {
                let window = trusted_window.root();

                let navigator = window.Navigator();
                let selected_index = navigator.select_gamepad_index();
                let gamepad = Gamepad::new(
                    &window,
                    selected_index,
                    name,
                    "standard".into(),
                    axis_bounds,
                    button_bounds,
                    supported_haptic_effects,
                    false,
                    CanGc::note(),
                );
                navigator.set_gamepad(selected_index as usize, &gamepad, CanGc::note());
            }));
    }

    /// <https://www.w3.org/TR/gamepad/#dfn-gamepaddisconnected>
    fn handle_gamepad_disconnect(&self, index: usize) {
        let trusted_window = Trusted::new(&*self.window);
        self.window
            .upcast::<GlobalScope>()
            .task_manager()
            .gamepad_task_source()
            .queue(task!(gamepad_disconnected: move || {
                let window = trusted_window.root();
                let navigator = window.Navigator();
                if let Some(gamepad) = navigator.get_gamepad(index) {
                    if window.Document().is_fully_active() {
                        gamepad.update_connected(false, gamepad.exposed(), CanGc::note());
                        navigator.remove_gamepad(index);
                    }
                }
            }));
    }

    /// <https://www.w3.org/TR/gamepad/#receiving-inputs>
    fn receive_new_gamepad_button_or_axis(&self, index: usize, update_type: GamepadUpdateType) {
        let trusted_window = Trusted::new(&*self.window);

        // <https://w3c.github.io/gamepad/#dfn-update-gamepad-state>
        self.window.upcast::<GlobalScope>().task_manager().gamepad_task_source().queue(
                task!(update_gamepad_state: move || {
                    let window = trusted_window.root();
                    let navigator = window.Navigator();
                    if let Some(gamepad) = navigator.get_gamepad(index) {
                        let current_time = window.Performance().Now();
                        gamepad.update_timestamp(*current_time);
                        match update_type {
                            GamepadUpdateType::Axis(index, value) => {
                                gamepad.map_and_normalize_axes(index, value);
                            },
                            GamepadUpdateType::Button(index, value) => {
                                gamepad.map_and_normalize_buttons(index, value);
                            }
                        };
                        if !navigator.has_gamepad_gesture() && contains_user_gesture(update_type) {
                            navigator.set_has_gamepad_gesture(true);
                            navigator.GetGamepads()
                                .iter()
                                .filter_map(|g| g.as_ref())
                                .for_each(|gamepad| {
                                    gamepad.set_exposed(true);
                                    gamepad.update_timestamp(*current_time);
                                    let new_gamepad = Trusted::new(&**gamepad);
                                    if window.Document().is_fully_active() {
                                        window.upcast::<GlobalScope>().task_manager().gamepad_task_source().queue(
                                            task!(update_gamepad_connect: move || {
                                                let gamepad = new_gamepad.root();
                                                gamepad.notify_event(GamepadEventType::Connected, CanGc::note());
                                            })
                                        );
                                    }
                                });
                        }
                    }
                })
            );
    }

    /// <https://www.w3.org/TR/clipboard-apis/#clipboard-actions>
    fn handle_editing_action(&self, action: EditingActionEvent, can_gc: CanGc) -> bool {
        let clipboard_event_type = match action {
            EditingActionEvent::Copy => ClipboardEventType::Copy,
            EditingActionEvent::Cut => ClipboardEventType::Cut,
            EditingActionEvent::Paste => ClipboardEventType::Paste,
        };

        // The script_triggered flag is set if the action runs because of a script, e.g. document.execCommand()
        let script_triggered = false;

        // The script_may_access_clipboard flag is set
        // if action is paste and the script thread is allowed to read from clipboard or
        // if action is copy or cut and the script thread is allowed to modify the clipboard
        let script_may_access_clipboard = false;

        // Step 1 If the script-triggered flag is set and the script-may-access-clipboard flag is unset
        if script_triggered && !script_may_access_clipboard {
            return false;
        }

        // Step 2 Fire a clipboard event
        let event = ClipboardEvent::new(
            &self.window,
            None,
            DOMString::from(clipboard_event_type.as_str()),
            EventBubbles::Bubbles,
            EventCancelable::Cancelable,
            None,
            can_gc,
        );
        self.fire_clipboard_event(&event, clipboard_event_type, can_gc);

        // Step 3 If a script doesn't call preventDefault()
        // the event will be handled inside target's VirtualMethods::handle_event

        let e = event.upcast::<Event>();

        if !e.IsTrusted() {
            return false;
        }

        // Step 4 If the event was canceled, then
        if e.DefaultPrevented() {
            match e.Type().str() {
                "copy" => {
                    // Step 4.1 Call the write content to the clipboard algorithm,
                    // passing on the DataTransferItemList items, a clear-was-called flag and a types-to-clear list.
                    if let Some(clipboard_data) = event.get_clipboard_data() {
                        let drag_data_store =
                            clipboard_data.data_store().expect("This shouldn't fail");
                        self.write_content_to_the_clipboard(&drag_data_store);
                    }
                },
                "cut" => {
                    // Step 4.1 Call the write content to the clipboard algorithm,
                    // passing on the DataTransferItemList items, a clear-was-called flag and a types-to-clear list.
                    if let Some(clipboard_data) = event.get_clipboard_data() {
                        let drag_data_store =
                            clipboard_data.data_store().expect("This shouldn't fail");
                        self.write_content_to_the_clipboard(&drag_data_store);
                    }

                    // Step 4.2 Fire a clipboard event named clipboardchange
                    self.fire_clipboardchange_event(can_gc);
                },
                "paste" => return false,
                _ => (),
            }
        }
        // Step 5
        true
    }

    /// <https://www.w3.org/TR/clipboard-apis/#fire-a-clipboard-event>
    fn fire_clipboard_event(
        &self,
        event: &ClipboardEvent,
        action: ClipboardEventType,
        can_gc: CanGc,
    ) {
        // Step 1 Let clear_was_called be false
        // Step 2 Let types_to_clear an empty list
        let mut drag_data_store = DragDataStore::new();

        // Step 4 let clipboard-entry be the sequence number of clipboard content, null if the OS doesn't support it.

        // Step 5 let trusted be true if the event is generated by the user agent, false otherwise
        let trusted = true;

        // Step 6 if the context is editable:
        let document = self.window.Document();
        let focused = document.get_focused_element();
        let body = document.GetBody();

        let target = match (&focused, &body) {
            (Some(focused), _) => focused.upcast(),
            (&None, Some(body)) => body.upcast(),
            (&None, &None) => self.window.upcast(),
        };
        // Step 6.2 else TODO require Selection see https://github.com/w3c/clipboard-apis/issues/70

        // Step 7
        match action {
            ClipboardEventType::Copy | ClipboardEventType::Cut => {
                // Step 7.2.1
                drag_data_store.set_mode(Mode::ReadWrite);
            },
            ClipboardEventType::Paste => {
                let (sender, receiver) = ipc::channel().unwrap();
                self.window.send_to_embedder(EmbedderMsg::GetClipboardText(
                    self.window.webview_id(),
                    sender,
                ));
                let text_contents = receiver
                    .recv()
                    .map(Result::unwrap_or_default)
                    .unwrap_or_default();

                // Step 7.1.1
                drag_data_store.set_mode(Mode::ReadOnly);
                // Step 7.1.2 If trusted or the implementation gives script-generated events access to the clipboard
                if trusted {
                    // Step 7.1.2.1 For each clipboard-part on the OS clipboard:

                    // Step 7.1.2.1.1 If clipboard-part contains plain text, then
                    let data = DOMString::from(text_contents.to_string());
                    let type_ = DOMString::from("text/plain");
                    let _ = drag_data_store.add(Kind::Text { data, type_ });

                    // Step 7.1.2.1.2 TODO If clipboard-part represents file references, then for each file reference
                    // Step 7.1.2.1.3 TODO If clipboard-part contains HTML- or XHTML-formatted text then

                    // Step 7.1.3 Update clipboard-event-data’s files to match clipboard-event-data’s items
                    // Step 7.1.4 Update clipboard-event-data’s types to match clipboard-event-data’s items
                }
            },
            ClipboardEventType::Change => (),
        }

        // Step 3
        let clipboard_event_data = DataTransfer::new(
            &self.window,
            Rc::new(RefCell::new(Some(drag_data_store))),
            can_gc,
        );

        // Step 8
        event.set_clipboard_data(Some(&clipboard_event_data));
        let event = event.upcast::<Event>();
        // Step 9
        event.set_trusted(trusted);
        // Step 10 Set event’s composed to true.
        event.set_composed(true);
        // Step 11
        event.dispatch(target, false, can_gc);
    }

    pub(crate) fn fire_clipboardchange_event(&self, can_gc: CanGc) {
        let clipboardchange_event = ClipboardEvent::new(
            &self.window,
            None,
            DOMString::from("clipboardchange"),
            EventBubbles::Bubbles,
            EventCancelable::Cancelable,
            None,
            can_gc,
        );
        self.fire_clipboard_event(&clipboardchange_event, ClipboardEventType::Change, can_gc);
    }

    /// <https://www.w3.org/TR/clipboard-apis/#write-content-to-the-clipboard>
    fn write_content_to_the_clipboard(&self, drag_data_store: &DragDataStore) {
        // Step 1
        if drag_data_store.list_len() > 0 {
            // Step 1.1 Clear the clipboard.
            self.window
                .send_to_embedder(EmbedderMsg::ClearClipboard(self.window.webview_id()));
            // Step 1.2
            for item in drag_data_store.iter_item_list() {
                match item {
                    Kind::Text { data, .. } => {
                        // Step 1.2.1.1 Ensure encoding is correct per OS and locale conventions
                        // Step 1.2.1.2 Normalize line endings according to platform conventions
                        // Step 1.2.1.3
                        self.window.send_to_embedder(EmbedderMsg::SetClipboardText(
                            self.window.webview_id(),
                            data.to_string(),
                        ));
                    },
                    Kind::File { .. } => {
                        // Step 1.2.2 If data is of a type listed in the mandatory data types list, then
                        // Step 1.2.2.1 Place part on clipboard with the appropriate OS clipboard format description
                        // Step 1.2.3 Else this is left to the implementation
                    },
                }
            }
        } else {
            // Step 2.1
            if drag_data_store.clear_was_called {
                // Step 2.1.1 If types-to-clear list is empty, clear the clipboard
                self.window
                    .send_to_embedder(EmbedderMsg::ClearClipboard(self.window.webview_id()));
                // Step 2.1.2 Else remove the types in the list from the clipboard
                // As of now this can't be done with Arboard, and it's possible that will be removed from the spec
            }
        }
    }

    /// Handle scroll event triggered by user interactions from embedder side.
    /// <https://drafts.csswg.org/cssom-view/#scrolling-events>
    #[allow(unsafe_code)]
    fn handle_embedder_scroll_event(&self, event: ScrollEvent) {
        // If it is a viewport scroll.
        let document = self.window.Document();
        if event.external_id.is_root() {
            document.handle_viewport_scroll_event();
        } else {
            // Otherwise, check whether it is for a relevant element within the document.
            let Some(node_id) = node_id_from_scroll_id(event.external_id.0 as usize) else {
                return;
            };
            let node = unsafe {
                node::from_untrusted_node_address(UntrustedNodeAddress::from_id(node_id))
            };
            let Some(element) = node
                .inclusive_ancestors(ShadowIncluding::No)
                .filter_map(DomRoot::downcast::<Element>)
                .next()
            else {
                return;
            };

            document.handle_element_scroll_event(&element);
        }
    }
}
