diff options
author | Andrei Volykhin <andrei.volykhin@gmail.com> | 2025-04-02 14:20:25 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-02 11:20:25 +0000 |
commit | 3bc0eeab8f70bab8b4a1998b5d4c636a9cbfd552 (patch) | |
tree | 2c1ae41d10c0b058d2f3349c43545fd0de44e8ca /components/script | |
parent | b925c3142407f977cd77b695b750177a9eaf940d (diff) | |
download | servo-3bc0eeab8f70bab8b4a1998b5d4c636a9cbfd552.tar.gz servo-3bc0eeab8f70bab8b4a1998b5d4c636a9cbfd552.zip |
dom: Firing "click" event as synthetic pointer event (#36274)
According to specification
https://html.spec.whatwg.org/multipage/webappapis.html#fire-a-click-event
"Firing a click event at target means firing a synthetic pointer event
named click at target"
So need to replace synthetic mouse event with "click" type to pointer
event.
https://w3c.github.io/pointerevents/#the-click-auxclick-and-contextmenu-events
https://www.w3.org/TR/uievents/#event-type-click
Firing "click" event could be triggered from script or by UA:
- element.click()
(https://html.spec.whatwg.org/multipage/interaction.html#dom-click)
- form implicit submission
(https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#implicit-submission)
- keyboard activation (space)
---
- [x] ./mach build -d does not report any errors
- [x] ./mach test-tidy does not report any errors
- [x] There are tests for these changes
tests/wpt/tests/shadow-dom/event-composed.html
tests/wpt/tests/uievents/interface/click-event.htm
Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/document.rs | 35 | ||||
-rw-r--r-- | components/script/dom/htmlelement.rs | 4 | ||||
-rw-r--r-- | components/script/dom/htmlinputelement.rs | 2 | ||||
-rw-r--r-- | components/script/dom/node.rs | 75 | ||||
-rw-r--r-- | components/script/dom/pointerevent.rs | 10 |
5 files changed, 73 insertions, 53 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index dd521776702..78580bb20f6 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -171,7 +171,7 @@ use crate::dom::nodeiterator::NodeIterator; use crate::dom::nodelist::NodeList; use crate::dom::pagetransitionevent::PageTransitionEvent; use crate::dom::performanceentry::PerformanceEntry; -use crate::dom::pointerevent::PointerEvent; +use crate::dom::pointerevent::{PointerEvent, PointerId}; use crate::dom::processinginstruction::ProcessingInstruction; use crate::dom::promise::Promise; use crate::dom::range::Range; @@ -1402,7 +1402,6 @@ impl Document { // <https://w3c.github.io/uievents/#contextmenu> let menu_event = PointerEvent::new( &self.window, // window - None, // proto DOMString::from("contextmenu"), // type EventBubbles::Bubbles, // can_bubble EventCancelable::Cancelable, // cancelable @@ -1420,22 +1419,20 @@ impl Document { pressed_mouse_buttons, // buttons None, // related_target None, // point_in_target - // TODO: decide generic pointer id - // <https://www.w3.org/TR/pointerevents3/#dom-pointerevent-pointerid> - 0, // 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 + 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, ); let event = menu_event.upcast::<Event>(); @@ -2186,7 +2183,7 @@ impl Document { { if let Some(elem) = target.downcast::<Element>() { elem.upcast::<Node>() - .fire_synthetic_mouse_event_not_trusted(DOMString::from("click"), can_gc); + .fire_synthetic_pointer_event_not_trusted(DOMString::from("click"), can_gc); } } } diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index 5b11b3bae98..bf95f8528e9 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -395,7 +395,7 @@ impl HTMLElementMethods<crate::DomTypeHolder> for HTMLElement { Some(item_attr_values.into_iter().collect()) } - // https://html.spec.whatwg.org/multipage/#dom-click + /// <https://html.spec.whatwg.org/multipage/#dom-click> fn Click(&self, can_gc: CanGc) { let element = self.as_element(); if element.disabled_state() { @@ -407,7 +407,7 @@ impl HTMLElementMethods<crate::DomTypeHolder> for HTMLElement { element.set_click_in_progress(true); self.upcast::<Node>() - .fire_synthetic_mouse_event_not_trusted(DOMString::from("click"), can_gc); + .fire_synthetic_pointer_event_not_trusted(DOMString::from("click"), can_gc); element.set_click_in_progress(false); } diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 901d154af17..85ebac012bb 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -2149,7 +2149,7 @@ impl HTMLInputElement { // but we can get here from synthetic keydown events button .upcast::<Node>() - .fire_synthetic_mouse_event_not_trusted(DOMString::from("click"), can_gc); + .fire_synthetic_pointer_event_not_trusted(DOMString::from("click"), can_gc); } }, None => { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index d89263d2bf2..94e3d94b540 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -7,6 +7,7 @@ use std::borrow::Cow; use std::cell::{Cell, LazyCell, UnsafeCell}; use std::default::Default; +use std::f64::consts::PI; use std::ops::Range; use std::slice::from_ref; use std::sync::Arc as StdArc; @@ -105,9 +106,9 @@ use crate::dom::htmlslotelement::{HTMLSlotElement, Slottable}; use crate::dom::htmlstyleelement::HTMLStyleElement; use crate::dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers}; use crate::dom::htmlvideoelement::{HTMLVideoElement, LayoutHTMLVideoElementHelpers}; -use crate::dom::mouseevent::MouseEvent; use crate::dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver}; use crate::dom::nodelist::NodeList; +use crate::dom::pointerevent::{PointerEvent, PointerId}; use crate::dom::processinginstruction::ProcessingInstruction; use crate::dom::range::WeakRangeVec; use crate::dom::raredata::NodeRareData; @@ -438,43 +439,59 @@ impl Node { }) } - /// <https://html.spec.whatg.org/#fire_a_synthetic_mouse_event> - pub(crate) fn fire_synthetic_mouse_event_not_trusted(&self, name: DOMString, can_gc: CanGc) { - // Spec says the choice of which global to create - // the mouse event on is not well-defined, + /// <https://html.spec.whatwg.org/multipage/#fire-a-synthetic-pointer-event> + pub(crate) fn fire_synthetic_pointer_event_not_trusted(&self, name: DOMString, can_gc: CanGc) { + // Spec says the choice of which global to create the pointer event + // on is not well-defined, // and refers to heycam/webidl#135 - let win = self.owner_window(); + let window = self.owner_window(); - let mouse_event = MouseEvent::new( - &win, // ambiguous in spec + // <https://w3c.github.io/pointerevents/#the-click-auxclick-and-contextmenu-events> + let pointer_event = PointerEvent::new( + &window, // ambiguous in spec name, - EventBubbles::Bubbles, // Step 3: bubbles - EventCancelable::Cancelable, // Step 3: cancelable, - Some(&win), // Step 7: view (this is unambiguous in spec) - 0, // detail uninitialized - 0, // coordinates uninitialized - 0, // coordinates uninitialized - 0, // coordinates uninitialized - 0, // coordinates uninitialized - false, - false, - false, - false, // Step 6 modifier keys TODO compositor hook needed - 0, // button uninitialized (and therefore left) - 0, // buttons uninitialized (and therefore none) - None, // related_target uninitialized, - None, // point_in_target uninitialized, + EventBubbles::Bubbles, // Step 3: bubbles + EventCancelable::Cancelable, // Step 3: cancelable + Some(&window), // Step 7: view + 0, // detail uninitialized + 0, // coordinates uninitialized + 0, // coordinates uninitialized + 0, // coordinates uninitialized + 0, // coordinates uninitialized + false, // ctrl_key + false, // alt_key + false, // shift_key + false, // meta_key + 0, // button, left mouse button + 0, // buttons + None, // related_target + None, // point_in_target + PointerId::NonPointerDevice 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(""), // pointer_type + false, // is_primary + vec![], // coalesced_events + vec![], // predicted_events can_gc, ); - // Step 4: TODO composed flag for shadow root + // Step 4. Set event's composed flag. + pointer_event.upcast::<Event>().set_composed(true); - // Step 5 - mouse_event.upcast::<Event>().set_trusted(false); + // Step 5. If the not trusted flag is set, initialize event's isTrusted attribute to false. + pointer_event.upcast::<Event>().set_trusted(false); - // Step 8: TODO keyboard modifiers + // Step 6,8. TODO keyboard modifiers - mouse_event + pointer_event .upcast::<Event>() .dispatch(self.upcast::<EventTarget>(), false, can_gc); } diff --git a/components/script/dom/pointerevent.rs b/components/script/dom/pointerevent.rs index 719518c64b2..d3cd9434e7d 100644 --- a/components/script/dom/pointerevent.rs +++ b/components/script/dom/pointerevent.rs @@ -23,6 +23,13 @@ use crate::dom::mouseevent::MouseEvent; use crate::dom::window::Window; use crate::script_runtime::CanGc; +/// <https://w3c.github.io/pointerevents/#dom-pointerevent-pointerid> +#[derive(Clone, Copy, MallocSizeOf, PartialEq)] +pub(crate) enum PointerId { + NonPointerDevice = -1, + Mouse, +} + #[dom_struct] pub(crate) struct PointerEvent { mouseevent: MouseEvent, @@ -83,7 +90,6 @@ impl PointerEvent { #[allow(clippy::too_many_arguments)] pub(crate) fn new( window: &Window, - proto: Option<HandleObject>, type_: DOMString, can_bubble: EventBubbles, cancelable: EventCancelable, @@ -119,7 +125,7 @@ impl PointerEvent { ) -> DomRoot<PointerEvent> { Self::new_with_proto( window, - proto, + None, type_, can_bubble, cancelable, |