diff options
author | Euclid Ye <yezhizhenjiakang@gmail.com> | 2025-04-19 03:27:57 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-18 19:27:57 +0000 |
commit | 46247a76210daef793fec29b001cf4c05281f2e4 (patch) | |
tree | 92a824783be48e82836002a2a352c478bb3d8eae | |
parent | 2ee8427665099987f715296d4d55b6388a480c08 (diff) | |
download | servo-46247a76210daef793fec29b001cf4c05281f2e4.tar.gz servo-46247a76210daef793fec29b001cf4c05281f2e4.zip |
Move click event trigger from embedding layer to `ScriptThread` (#36413)
1. Move click event trigger from embedding layer to `ScriptThread`
2. Previously, the logic is to trigger click event at same position as
`MouseButtonAction::Up` if `MouseButtonAction::Up` is within 10px of
`MouseButtonAction::Down`, in embedding layer. This PR ~~removes the
condition~~ moves the check to `ScriptThread`.
Testing: tested for webdriver with self written test case. Perform
actions of pointermove, pointerdown, pointerup in sequence. Click event
can now be triggered.
Fixes: #35395
cc @xiaochengh @jdm
For `MAYBE? TODO:` part I added, should we do it? I read the
[spec](https://w3c.github.io/uievents/#event-type-click), it doesn't
specify we have to implement MDN's way.
If we should work in the MDN's way, it also should be fixed in another
PR, as this PR doesn't regress anything. Also I am not sure what is the
best way to do it.
Should I handle it in
https://github.com/servo/servo/blob/4d4f94936f8859f039497df370083fd7ea35fb00/components/script/dom/document.rs#L1296-L1297?
---------
Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
-rw-r--r-- | components/script/script_thread.rs | 60 | ||||
-rw-r--r-- | components/shared/embedder/input_events.rs | 2 | ||||
-rw-r--r-- | components/shared/script/lib.rs | 2 | ||||
-rw-r--r-- | ports/servoshell/desktop/headed_window.rs | 31 |
4 files changed, 60 insertions, 35 deletions
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index fad228efed0..bec4d59be0f 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -50,9 +50,10 @@ use devtools_traits::{ }; use embedder_traits::user_content_manager::UserContentManager; use embedder_traits::{ - CompositorHitTestResult, EmbedderMsg, InputEvent, MediaSessionActionType, Theme, - ViewportDetails, WebDriverScriptCommand, + CompositorHitTestResult, EmbedderMsg, InputEvent, MediaSessionActionType, MouseButton, + MouseButtonAction, MouseButtonEvent, Theme, ViewportDetails, WebDriverScriptCommand, }; +use euclid::Point2D; use euclid::default::Rect; use fonts::{FontContext, SystemFontServiceProxy}; use headers::{HeaderMapExt, LastModified, ReferrerPolicy as ReferrerPolicyHeader}; @@ -98,6 +99,7 @@ use url::Position; #[cfg(feature = "webgpu")] use webgpu_traits::{WebGPUDevice, WebGPUMsg}; use webrender_api::DocumentId; +use webrender_api::units::DevicePixel; use crate::document_collection::DocumentCollection; use crate::document_loader::DocumentLoader; @@ -333,6 +335,16 @@ pub struct ScriptThread { /// A factory for making new layouts. This allows layout to depend on script. #[no_trace] layout_factory: Arc<dyn LayoutFactory>, + + // Mouse down button: TO BE REMOVED. Not needed as click event should only + // triggered for primary button + #[no_trace] + mouse_down_button: Cell<Option<MouseButton>>, + + // Mouse down point. + // In future, this shall be mouse_down_point for primary button + #[no_trace] + relative_mouse_down_point: Cell<Point2D<f32, DevicePixel>>, } struct BHMExitSignal { @@ -947,6 +959,8 @@ impl ScriptThread { gpu_id_hub: Arc::new(IdentityHub::default()), inherited_secure_context: state.inherited_secure_context, layout_factory, + mouse_down_button: Cell::new(None), + relative_mouse_down_point: Cell::new(Point2D::zero()), } } @@ -3339,7 +3353,47 @@ impl ScriptThread { warn!("Compositor event sent to closed pipeline {pipeline_id}."); return; }; - document.note_pending_input_event(event); + + if let InputEvent::MouseButton(mouse_button_event) = event.event { + if mouse_button_event.action == MouseButtonAction::Down { + self.mouse_down_button.set(Some(mouse_button_event.button)); + self.relative_mouse_down_point.set(mouse_button_event.point) + } + } + document.note_pending_input_event(event.clone()); + + // Also send a 'click' event with same hit-test result if this is release + + // MAYBE? TODO: https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event + // If the button is pressed on one element and the pointer is moved outside the element + // before the button is released, the event is fired on the most specific ancestor element + // that contained both elements. + + // But spec doesn't specify this https://w3c.github.io/uievents/#event-type-click + + // Servo-specific: Trigger if within 10px of the down point + if let InputEvent::MouseButton(mouse_button_event) = event.event { + if let (Some(mouse_down_button), MouseButtonAction::Up) = + (self.mouse_down_button.get(), mouse_button_event.action) + { + let pixel_dist = self.relative_mouse_down_point.get() - mouse_button_event.point; + let pixel_dist = (pixel_dist.x * pixel_dist.x + pixel_dist.y * pixel_dist.y).sqrt(); + if mouse_down_button == mouse_button_event.button && + pixel_dist < 10.0 * document.window().device_pixel_ratio().get() + { + document.note_pending_input_event(ConstellationInputEvent { + hit_test_result: event.hit_test_result, + pressed_mouse_buttons: event.pressed_mouse_buttons, + active_keyboard_modifiers: event.active_keyboard_modifiers, + event: InputEvent::MouseButton(MouseButtonEvent { + action: MouseButtonAction::Click, + button: mouse_button_event.button, + point: mouse_button_event.point, + }), + }); + } + } + } } /// Handle a "navigate an iframe" message from the constellation. diff --git a/components/shared/embedder/input_events.rs b/components/shared/embedder/input_events.rs index 0268be6dd9c..16adccf8cd3 100644 --- a/components/shared/embedder/input_events.rs +++ b/components/shared/embedder/input_events.rs @@ -51,7 +51,7 @@ pub struct MouseButtonEvent { pub point: DevicePoint, } -#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub enum MouseButton { Left, Middle, diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs index 5ee143b3cdd..8b05cabd64e 100644 --- a/components/shared/script/lib.rs +++ b/components/shared/script/lib.rs @@ -256,7 +256,7 @@ pub enum DocumentState { } /// Input events from the embedder that are sent via the `Constellation`` to the `ScriptThread`. -#[derive(Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct ConstellationInputEvent { /// The hit test result of this input event, if any. pub hit_test_result: Option<CompositorHitTestResult>, diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs index a529aa83c02..8efb16954d8 100644 --- a/ports/servoshell/desktop/headed_window.rs +++ b/ports/servoshell/desktop/headed_window.rs @@ -53,8 +53,6 @@ pub struct Window { screen_size: Size2D<u32, DeviceIndependentPixel>, inner_size: Cell<PhysicalSize<u32>>, toolbar_height: Cell<Length<f32, DeviceIndependentPixel>>, - mouse_down_button: Cell<Option<MouseButton>>, - webview_relative_mouse_down_point: Cell<Point2D<f32, DevicePixel>>, monitor: winit::monitor::MonitorHandle, webview_relative_mouse_point: Cell<Point2D<f32, DevicePixel>>, last_pressed: Cell<Option<(KeyboardEvent, Option<LogicalKey>)>>, @@ -144,8 +142,6 @@ impl Window { debug!("Created window {:?}", winit_window.id()); Window { winit_window, - mouse_down_button: Cell::new(None), - webview_relative_mouse_down_point: Cell::new(Point2D::zero()), webview_relative_mouse_point: Cell::new(Point2D::zero()), last_pressed: Cell::new(None), keys_down: RefCell::new(HashMap::new()), @@ -251,7 +247,6 @@ impl Window { /// Helper function to handle a click fn handle_mouse(&self, webview: &WebView, button: MouseButton, action: ElementState) { - let max_pixel_dist = 10.0 * self.hidpi_scale_factor().get(); let mouse_button = match &button { MouseButton::Left => ServoMouseButton::Left, MouseButton::Right => ServoMouseButton::Right, @@ -263,11 +258,7 @@ impl Window { let point = self.webview_relative_mouse_point.get(); let action = match action { - ElementState::Pressed => { - self.webview_relative_mouse_down_point.set(point); - self.mouse_down_button.set(Some(button)); - MouseButtonAction::Down - }, + ElementState::Pressed => MouseButtonAction::Down, ElementState::Released => MouseButtonAction::Up, }; @@ -276,26 +267,6 @@ impl Window { button: mouse_button, point, })); - - // Also send a 'click' event if this is release and the press was recorded - // to be within a 10 pixels. - // - // TODO: This should be happening within the ScriptThread. - if action != MouseButtonAction::Up { - return; - } - - if let Some(mouse_down_button) = self.mouse_down_button.get() { - let pixel_dist = self.webview_relative_mouse_down_point.get() - point; - let pixel_dist = (pixel_dist.x * pixel_dist.x + pixel_dist.y * pixel_dist.y).sqrt(); - if mouse_down_button == button && pixel_dist < max_pixel_dist { - webview.notify_input_event(InputEvent::MouseButton(MouseButtonEvent { - action: MouseButtonAction::Click, - button: mouse_button, - point, - })); - } - } } /// Handle key events before sending them to Servo. |