script/compositor: Handle cursor updates from script (#38518)

Instead of using WebRender hit testing to update the cursor, base it on
layout hit tests. This allows removing the majority of WebRender hit
test items and finally opens up the possibility of adding support for
custom cursors. In addition, this change fixes an issue where cursors
were not set properly on areas of the viewport that extended past the
page content.

Testing: This is difficult to test as verifying that the cursor changed
properly is beyond the capabilities of Servo's test harnesses.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Martin Robinson 2025-08-07 20:49:38 +02:00 committed by GitHub
parent 87538282db
commit 6651f37c05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 279 additions and 259 deletions

View file

@ -34,6 +34,7 @@ serde = { workspace = true }
servo_url = { path = "../../url" }
strum = { workspace = true }
strum_macros = { workspace = true }
stylo_traits = { workspace = true }
uuid = { workspace = true }
webgpu_traits = { workspace = true }
webrender_api = { workspace = true }

View file

@ -19,10 +19,10 @@ use base::Epoch;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{MessagePortId, PipelineId, WebViewId};
use embedder_traits::{
CompositorHitTestResult, Cursor, FocusId, InputEvent, JavaScriptEvaluationId,
MediaSessionActionType, Theme, TraversalId, ViewportDetails, WebDriverCommandMsg,
WebDriverCommandResponse,
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;
@ -31,6 +31,7 @@ use serde::{Deserialize, Serialize};
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};
@ -76,8 +77,9 @@ pub enum EmbedderToConstellationMessage {
BlurWebView,
/// Forward an input event to an appropriate ScriptTask.
ForwardInputEvent(WebViewId, InputEvent, Option<CompositorHitTestResult>),
/// Requesting a change to the onscreen cursor.
SetCursor(WebViewId, Cursor),
/// 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>),
/// 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

@ -29,7 +29,6 @@ log = { workspace = true }
malloc_size_of = { workspace = true }
malloc_size_of_derive = { workspace = true }
num-derive = "0.4"
num-traits = { workspace = true }
pixels = { path = "../../pixels" }
serde = { workspace = true }
servo_url = { path = "../../url" }

View file

@ -28,7 +28,6 @@ use ipc_channel::ipc::IpcSender;
use log::warn;
use malloc_size_of::malloc_size_of_is_0;
use malloc_size_of_derive::MallocSizeOf;
use num_derive::FromPrimitive;
use pixels::RasterImage;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
@ -56,7 +55,7 @@ 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, FromPrimitive, PartialEq, Serialize)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub enum Cursor {
None,
Default,
@ -889,9 +888,6 @@ pub struct CompositorHitTestResult {
/// containing block.
pub point_relative_to_initial_containing_block: Point2D<f32, CSSPixel>,
/// The cursor that should be used when hovering the item hit by the hit test.
pub cursor: Option<Cursor>,
/// The [`ExternalScrollId`] of the scroll tree node associated with this hit test item.
pub external_scroll_id: ExternalScrollId,
}

View file

@ -24,7 +24,7 @@ use base::id::{BrowsingContextId, PipelineId, WebViewId};
use bitflags::bitflags;
use compositing_traits::CrossProcessCompositorApi;
use constellation_traits::LoadData;
use embedder_traits::{Theme, UntrustedNodeAddress, ViewportDetails};
use embedder_traits::{Cursor, Theme, UntrustedNodeAddress, ViewportDetails};
use euclid::Point2D;
use euclid::default::{Point2D as UntypedPoint2D, Rect};
use fnv::FnvHashMap;
@ -613,6 +613,9 @@ pub struct ElementsFromPointResult {
/// The [`Point2D`] of the original query point relative to the
/// node fragment rectangle.
pub point_in_target: Point2D<f32, CSSPixel>,
/// The [`Cursor`] that's defined on the item that is hit by this
/// hit test result.
pub cursor: Cursor,
}
bitflags! {

View file

@ -31,7 +31,7 @@ use embedder_traits::{
CompositorHitTestResult, FocusSequenceNumber, InputEvent, JavaScriptEvaluationId,
MediaSessionActionType, Theme, ViewportDetails, WebDriverScriptCommand,
};
use euclid::{Rect, Scale, Size2D, UnknownUnit};
use euclid::{Point2D, Rect, Scale, Size2D, UnknownUnit};
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use keyboard_types::Modifiers;
use malloc_size_of_derive::MallocSizeOf;
@ -145,6 +145,9 @@ 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>),
/// Notifies script of the viewport.
Viewport(PipelineId, Rect<f32, UnknownUnit>),
/// Requests that the script thread immediately send the constellation the title of a pipeline.