aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEuclid Ye <yezhizhenjiakang@gmail.com>2025-04-19 03:27:57 +0800
committerGitHub <noreply@github.com>2025-04-18 19:27:57 +0000
commit46247a76210daef793fec29b001cf4c05281f2e4 (patch)
tree92a824783be48e82836002a2a352c478bb3d8eae
parent2ee8427665099987f715296d4d55b6388a480c08 (diff)
downloadservo-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.rs60
-rw-r--r--components/shared/embedder/input_events.rs2
-rw-r--r--components/shared/script/lib.rs2
-rw-r--r--ports/servoshell/desktop/headed_window.rs31
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.