script: Ensure that leaving the WebView sets the cursor back to the default cursor (#38759)

This changes makes a variety of changes to ensure that the cursor is set
back to the default cursor when it leaves the `WebView`:

1. Display list updates can come after a mouse leaves the `WebView`, so
   when refreshing the cursor after the update, base the updated cursor
   on the last hovered location in the `DocumentEventHandler`, rather
   than the compositor. This allows us to catch when the last hovered
   position is `None` (ie the cursor has left the `WebView`).
2. When handling `MouseLeftViewport` events for the cursor leaving the
   entire WebView, properly set the
   MouseLeftViewport::focus_moving_to_another_iframe` on the input event
   passed to the script thread.
3. When moving out of the `WebView` entirely, explicitly ask the
   embedder to set the cursor back to the default.

Testing: This change adds a unit test verifying this behavior.
Fixes: #38710.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-08-22 00:49:56 -07:00 committed by GitHub
parent 66adf2bf9f
commit 4784ff0375
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 164 additions and 90 deletions

View file

@ -22,7 +22,6 @@ use embedder_traits::{
CompositorHitTestResult, FocusId, InputEvent, JavaScriptEvaluationId, MediaSessionActionType,
Theme, TraversalId, ViewportDetails, WebDriverCommandMsg, WebDriverCommandResponse,
};
use euclid::Point2D;
pub use from_script_message::*;
use ipc_channel::ipc::IpcSender;
use malloc_size_of_derive::MallocSizeOf;
@ -32,7 +31,6 @@ use servo_config::prefs::PrefValue;
use servo_url::{ImmutableOrigin, ServoUrl};
pub use structured_data::*;
use strum_macros::IntoStaticStr;
use style_traits::CSSPixel;
use webrender_api::units::LayoutVector2D;
use webrender_api::{ExternalScrollId, ImageKey};
@ -78,9 +76,10 @@ pub enum EmbedderToConstellationMessage {
BlurWebView,
/// Forward an input event to an appropriate ScriptTask.
ForwardInputEvent(WebViewId, InputEvent, Option<CompositorHitTestResult>),
/// Request that the given pipeline do a hit test at the location and reset the
/// cursor accordingly. This happens after a display list update is rendered.
RefreshCursor(PipelineId, Point2D<f32, CSSPixel>),
/// Request that the given pipeline refresh the cursor by doing a hit test at the most
/// recently hovered cursor position and resetting the cursor. This happens after a
/// display list update is rendered.
RefreshCursor(PipelineId),
/// Enable the sampling profiler, with a given sampling rate and max total sampling duration.
ToggleProfiler(Duration, Duration),
/// Request to exit from fullscreen mode

View file

@ -55,9 +55,10 @@ pub enum ShutdownState {
/// A cursor for the window. This is different from a CSS cursor (see
/// `CursorKind`) in that it has no `Auto` value.
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub enum Cursor {
None,
#[default]
Default,
Pointer,
ContextMenu,

View file

@ -32,7 +32,7 @@ use embedder_traits::{
CompositorHitTestResult, FocusSequenceNumber, InputEvent, JavaScriptEvaluationId,
MediaSessionActionType, Theme, ViewportDetails, WebDriverScriptCommand,
};
use euclid::{Point2D, Rect, Scale, Size2D, UnknownUnit};
use euclid::{Rect, Scale, Size2D, UnknownUnit};
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use keyboard_types::Modifiers;
use malloc_size_of_derive::MallocSizeOf;
@ -147,9 +147,10 @@ pub enum ScriptThreadMessage {
ExitScriptThread,
/// Sends a DOM event.
SendInputEvent(PipelineId, ConstellationInputEvent),
/// Ask that the given pipeline refreshes the cursor (after a display list render) based
/// on the hit test at the given point.
RefreshCursor(PipelineId, Point2D<f32, CSSPixel>),
/// Request that the given pipeline refresh the cursor by doing a hit test at the most
/// recently hovered cursor position and resetting the cursor. This happens after a
/// display list update is rendered.
RefreshCursor(PipelineId),
/// Notifies script of the viewport.
Viewport(PipelineId, Rect<f32, UnknownUnit>),
/// Requests that the script thread immediately send the constellation the title of a pipeline.