Skip to content

Commit 36dc928

Browse files
mrobinsonatbrakhi
andauthored
libservo: Have wheel events trigger scroll in Servo (servo#40269)
Instead of forcing embedders to implement scrolling when wheel events happen, have Servo take care of this. This means that scrolling happens consistently with wheel events across all embedders. Testing: This is tested by the WebDriver conformance suite. Signed-off-by: Martin Robinson <[email protected]> Co-authored-by: atbrakhi <[email protected]>
1 parent 0ac912c commit 36dc928

File tree

5 files changed

+52
-64
lines changed

5 files changed

+52
-64
lines changed

components/compositing/webview_renderer.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use embedder_traits::{
1717
AnimationState, CompositorHitTestResult, InputEvent, InputEventAndId, InputEventId,
1818
InputEventResult, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, Scroll,
1919
ScrollEvent as EmbedderScrollEvent, TouchEvent, TouchEventType, ViewportDetails, WebViewPoint,
20+
WheelEvent,
2021
};
2122
use euclid::{Scale, Vector2D};
2223
use log::{debug, warn};
@@ -25,7 +26,7 @@ use rustc_hash::FxHashMap;
2526
use servo_geometry::DeviceIndependentPixel;
2627
use style_traits::CSSPixel;
2728
use webrender::RenderApi;
28-
use webrender_api::units::{DevicePixel, DevicePoint, DeviceRect, LayoutVector2D};
29+
use webrender_api::units::{DevicePixel, DevicePoint, DeviceRect, DeviceVector2D, LayoutVector2D};
2930
use webrender_api::{DocumentId, ExternalScrollId, ScrollLocation};
3031

3132
use crate::painter::Painter;
@@ -359,9 +360,28 @@ impl WebViewRenderer {
359360
return;
360361
}
361362

363+
if let InputEvent::Wheel(wheel_event) = event_and_id.event {
364+
self.on_wheel_event(render_api, wheel_event, event_and_id);
365+
return;
366+
}
367+
362368
self.dispatch_input_event_with_hit_testing(render_api, event_and_id);
363369
}
364370

371+
fn on_wheel_event(
372+
&mut self,
373+
render_api: &RenderApi,
374+
wheel_event: WheelEvent,
375+
event_and_id: InputEventAndId,
376+
) {
377+
self.dispatch_input_event_with_hit_testing(render_api, event_and_id);
378+
379+
// A scroll delta for a wheel event is the inverse of the wheel delta.
380+
let scroll_delta =
381+
DeviceVector2D::new(-wheel_event.delta.x as f32, -wheel_event.delta.y as f32);
382+
self.notify_scroll_event(Scroll::Delta(scroll_delta.into()), wheel_event.point);
383+
}
384+
365385
fn send_touch_event(
366386
&mut self,
367387
render_api: &RenderApi,

components/servo/examples/winit_minimal.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ use std::rc::Rc;
88

99
use euclid::{Scale, Size2D};
1010
use servo::{
11-
RenderingContext, Scroll, Servo, ServoBuilder, WebView, WebViewBuilder, WindowRenderingContext,
11+
InputEvent, RenderingContext, Servo, ServoBuilder, WebView, WebViewBuilder, WheelDelta,
12+
WheelEvent, WheelMode, WindowRenderingContext,
1213
};
1314
use tracing::warn;
1415
use url::Url;
15-
use webrender_api::units::{DevicePixel, DevicePoint, LayoutVector2D};
16+
use webrender_api::units::{DevicePixel, DevicePoint};
1617
use winit::application::ApplicationHandler;
1718
use winit::dpi::PhysicalSize;
1819
use winit::event::{MouseScrollDelta, WindowEvent};
@@ -151,18 +152,24 @@ impl ApplicationHandler<WakerEvent> for App {
151152
WindowEvent::MouseWheel { delta, .. } => {
152153
if let Self::Running(state) = self {
153154
if let Some(webview) = state.webviews.borrow().last() {
154-
let moved_by = match delta {
155-
MouseScrollDelta::LineDelta(horizontal, vertical) => {
156-
LayoutVector2D::new(20. * horizontal, 20. * vertical)
155+
let (delta_x, delta_y, mode) = match delta {
156+
MouseScrollDelta::LineDelta(dx, dy) => {
157+
((dx * 76.0) as f64, (dy * 76.0) as f64, WheelMode::DeltaLine)
157158
},
158-
MouseScrollDelta::PixelDelta(pos) => {
159-
LayoutVector2D::new(pos.x as f32, pos.y as f32)
159+
MouseScrollDelta::PixelDelta(delta) => {
160+
(delta.x, delta.y, WheelMode::DeltaPixel)
160161
},
161162
};
162-
webview.notify_scroll_event(
163-
Scroll::Delta(moved_by.into()),
164-
DevicePoint::new(10.0, 10.0).into(),
165-
);
163+
164+
webview.notify_input_event(InputEvent::Wheel(WheelEvent::new(
165+
WheelDelta {
166+
x: delta_x,
167+
y: delta_y,
168+
z: 0.0,
169+
mode,
170+
},
171+
DevicePoint::default().into(),
172+
)));
166173
}
167174
}
168175
},

ports/servoshell/desktop/headed_window.rs

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ use servo::servo_geometry::{
2121
DeviceIndependentIntRect, DeviceIndependentPixel, convert_rect_to_css_pixel,
2222
};
2323
use servo::webrender_api::units::{
24-
DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel, DevicePoint, DeviceVector2D,
24+
DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel, DevicePoint,
2525
};
2626
use servo::{
2727
Cursor, ImeEvent, InputEvent, InputEventId, InputEventResult, InputMethodControl, Key,
2828
KeyState, KeyboardEvent, Modifiers, MouseButton as ServoMouseButton, MouseButtonAction,
2929
MouseButtonEvent, MouseLeftViewportEvent, MouseMoveEvent, NamedKey, OffscreenRenderingContext,
30-
RenderingContext, ScreenGeometry, Scroll, Theme, TouchEvent, TouchEventType, TouchId,
30+
RenderingContext, ScreenGeometry, Theme, TouchEvent, TouchEventType, TouchId,
3131
WebRenderDebugOption, WebView, WheelDelta, WheelEvent, WheelMode, WindowRenderingContext,
3232
};
3333
use url::Url;
@@ -50,7 +50,7 @@ use {
5050
use super::app_state::RunningAppState;
5151
use super::geometry::{winit_position_to_euclid_point, winit_size_to_euclid_size};
5252
use super::keyutils::{CMD_OR_ALT, keyboard_event_from_winit};
53-
use super::window_trait::{LINE_HEIGHT, LINE_WIDTH, PIXEL_DELTA_FACTOR, WindowPortsMethods};
53+
use super::window_trait::{LINE_HEIGHT, LINE_WIDTH, WindowPortsMethods};
5454
use crate::desktop::accelerated_gl_media::setup_gl_accelerated_media;
5555
use crate::desktop::keyutils::CMD_OR_CONTROL;
5656
use crate::desktop::window_trait::MIN_WINDOW_INNER_SIZE;
@@ -650,44 +650,26 @@ impl WindowPortsMethods for Window {
650650
}
651651
},
652652
WindowEvent::MouseWheel { delta, .. } => {
653-
let (mut dx, mut dy, mode) = match delta {
654-
MouseScrollDelta::LineDelta(dx, dy) => (
655-
(dx * LINE_WIDTH) as f64,
656-
(dy * LINE_HEIGHT) as f64,
653+
let (delta_x, delta_y, mode) = match delta {
654+
MouseScrollDelta::LineDelta(delta_x, delta_y) => (
655+
(delta_x * LINE_WIDTH) as f64,
656+
(delta_y * LINE_HEIGHT) as f64,
657657
WheelMode::DeltaLine,
658658
),
659-
MouseScrollDelta::PixelDelta(position) => {
660-
let position: LogicalPosition<f64> =
661-
position.to_logical(self.device_hidpi_scale_factor().get() as f64);
662-
(
663-
position.x * PIXEL_DELTA_FACTOR,
664-
position.y * PIXEL_DELTA_FACTOR,
665-
WheelMode::DeltaPixel,
666-
)
659+
MouseScrollDelta::PixelDelta(delta) => {
660+
(delta.x, delta.y, WheelMode::DeltaPixel)
667661
},
668662
};
669663

670664
// Create wheel event before snapping to the major axis of movement
671665
let delta = WheelDelta {
672-
x: dx,
673-
y: dy,
666+
x: delta_x,
667+
y: delta_y,
674668
z: 0.0,
675669
mode,
676670
};
677671
let point = self.webview_relative_mouse_point.get();
678-
679-
// Scroll events snap to the major axis of movement, with vertical
680-
// preferred over horizontal.
681-
if dy.abs() >= dx.abs() {
682-
dx = 0.0;
683-
} else {
684-
dy = 0.0;
685-
}
686-
687-
// Send events
688672
webview.notify_input_event(InputEvent::Wheel(WheelEvent::new(delta, point.into())));
689-
let scroll = Scroll::Delta((-DeviceVector2D::new(dx as f32, dy as f32)).into());
690-
webview.notify_scroll_event(scroll, point.into());
691673
},
692674
WindowEvent::Touch(touch) => {
693675
webview.notify_input_event(InputEvent::Touch(TouchEvent::new(

ports/servoshell/desktop/window_trait.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ use super::app_state::RunningAppState;
2121
pub(crate) const LINE_HEIGHT: f32 = 76.0;
2222
pub(crate) const LINE_WIDTH: f32 = 76.0;
2323

24-
// MouseScrollDelta::PixelDelta is default for MacOS, which is high precision and very slow
25-
// in winit. Therefore we use a factor of 4.0 to make it more usable.
26-
// See https://github.com/servo/servo/pull/34063#discussion_r2197729507
27-
pub(crate) const PIXEL_DELTA_FACTOR: f64 = 4.0;
28-
2924
/// <https://github.com/web-platform-tests/wpt/blob/9320b1f724632c52929a3fdb11bdaf65eafc7611/webdriver/tests/classic/set_window_rect/set.py#L287-L290>
3025
/// "A window size of 10x10px shouldn't be supported by any browser."
3126
pub(crate) const MIN_WINDOW_INNER_SIZE: DeviceIntSize = DeviceIntSize::new(100, 100);

ports/servoshell/running_app_state.rs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ use crossbeam_channel::Sender;
1111
use servo::base::generic_channel::GenericSender;
1212
use servo::base::id::WebViewId;
1313
use servo::ipc_channel::ipc::IpcSender;
14-
use servo::webrender_api::units::DeviceVector2D;
1514
use servo::{
16-
InputEvent, InputEventId, Scroll, TraversalId, WebDriverJSResult, WebDriverLoadStatus,
17-
WebDriverSenders, WebView, WheelEvent,
15+
InputEvent, InputEventId, TraversalId, WebDriverJSResult, WebDriverLoadStatus,
16+
WebDriverSenders, WebView,
1817
};
1918

2019
pub struct RunningAppStateBase {
@@ -86,27 +85,12 @@ pub trait RunningAppStateTrait {
8685
input_event: InputEvent,
8786
response_sender: Option<Sender<()>>,
8887
) {
89-
// TODO: Scroll events triggered by wheel events should happen as
90-
// a default event action in the compositor.
91-
let scroll_event = match &input_event {
92-
InputEvent::Wheel(WheelEvent { delta, point }) => {
93-
let scroll =
94-
Scroll::Delta(DeviceVector2D::new(-delta.x as f32, -delta.y as f32).into());
95-
Some((scroll, *point))
96-
},
97-
_ => None,
98-
};
99-
10088
let event_id = webview.notify_input_event(input_event);
10189
if let Some(response_sender) = response_sender {
10290
self.base()
10391
.pending_webdriver_events
10492
.borrow_mut()
10593
.insert(event_id, response_sender);
10694
}
107-
108-
if let Some((scroll, scroll_point)) = scroll_event {
109-
webview.notify_scroll_event(scroll, scroll_point);
110-
}
11195
}
11296
}

0 commit comments

Comments
 (0)