servoshell: Use DeviceIndependentPixel for WebDriver Rect related requests (#37893)

[Spec](https://w3c.github.io/webdriver/#set-window-rect) expects CSS
pixel for input and output. Previously, we use Device Pixel for them
instead.

Testing: Tested manually with different screen DPR and compared with
other browsers.
Fixes: Task 4 of https://github.com/servo/servo/issues/37804

---------

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
This commit is contained in:
Euclid Ye 2025-07-09 11:56:27 +08:00 committed by GitHub
parent 0db02702e7
commit 3526b7e86e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 66 additions and 269 deletions

1
Cargo.lock generated
View file

@ -2252,6 +2252,7 @@ dependencies = [
"num-traits",
"pixels",
"serde",
"servo_geometry",
"servo_malloc_size_of",
"servo_url",
"strum_macros",

View file

@ -39,3 +39,4 @@ stylo = { workspace = true }
url = { workspace = true }
webdriver = { workspace = true }
webrender_api = { workspace = true }
servo_geometry = { path = "../../geometry" }

View file

@ -16,11 +16,12 @@ use keyboard_types::KeyboardEvent;
use keyboard_types::webdriver::Event as WebDriverInputEvent;
use pixels::RasterImage;
use serde::{Deserialize, Serialize};
use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize, DeviceIndependentPixel};
use servo_url::ServoUrl;
use style_traits::CSSPixel;
use webdriver::common::{WebElement, WebFrame, WebWindow};
use webdriver::error::ErrorStatus;
use webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePixel};
use webrender_api::units::DevicePixel;
use crate::{MouseButton, MouseButtonAction};
@ -34,7 +35,7 @@ pub enum WebDriverCommandMsg {
/// back to the WebDriver client. It is set to constellation for now
SetWebDriverResponseSender(IpcSender<WebDriverCommandResponse>),
/// Get the window size.
GetWindowRect(WebViewId, IpcSender<DeviceIntRect>),
GetWindowRect(WebViewId, IpcSender<DeviceIndependentIntRect>),
/// Get the viewport size.
GetViewportSize(WebViewId, IpcSender<Size2D<u32, DevicePixel>>),
/// Load a URL in the top-level browsing context with the given ID.
@ -90,8 +91,8 @@ pub enum WebDriverCommandMsg {
/// Set the window size.
SetWindowSize(
WebViewId,
DeviceIntSize,
IpcSender<Size2D<i32, DevicePixel>>,
DeviceIndependentIntSize,
IpcSender<Size2D<i32, DeviceIndependentPixel>>,
),
/// Take a screenshot of the window.
TakeScreenshot(

View file

@ -20,9 +20,11 @@ use log::{info, trace, warn};
use net::protocols::ProtocolRegistry;
use servo::config::opts::Opts;
use servo::config::prefs::Preferences;
use servo::servo_geometry::DeviceIndependentIntSize;
use servo::servo_url::ServoUrl;
use servo::user_content_manager::{UserContentManager, UserScript};
use servo::webrender_api::ScrollLocation;
use servo::webrender_api::units::DeviceIntSize;
use servo::{
EventLoopWaker, InputEvent, KeyboardEvent, MouseButtonEvent, MouseMoveEvent,
WebDriverCommandMsg, WheelDelta, WheelEvent, WheelMode,
@ -403,13 +405,31 @@ impl App {
.values()
.next()
.expect("Should have at least one window in servoshell");
let scale = window.hidpi_scale_factor().get() as f64;
// TODO: Find a universal way to convert.
// See https://github.com/servo/servo/issues/37937
let requested_physical_size = DeviceIntSize::new(
(requested_size.width as f64 * scale).round() as i32,
(requested_size.height as f64 * scale).round() as i32,
);
// When None is returned, it means that the request went to the display system,
// and the actual size will be delivered later with the WindowEvent::Resized.
let returned_size = window.request_resize(&webview, requested_size);
let returned_size = window.request_resize(&webview, requested_physical_size);
// TODO: Handle None case. For now, we assume always succeed.
// In reality, the request may exceed available screen size.
if let Err(error) = size_sender.send(returned_size.unwrap_or(requested_size)) {
// TODO: Find a universal way to convert.
// See https://github.com/servo/servo/issues/37937
if let Err(error) = size_sender.send(
returned_size
.map(|size| {
DeviceIndependentIntSize::new(
(size.width as f64 / scale).round() as i32,
(size.height as f64 / scale).round() as i32,
)
})
.unwrap_or(requested_size),
) {
warn!("Failed to send window size: {error}");
}
},

View file

@ -15,9 +15,9 @@ use keyboard_types::{Modifiers, ShortcutMatcher};
use log::{debug, info};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
use servo::servo_config::pref;
use servo::servo_geometry::DeviceIndependentPixel;
use servo::servo_geometry::{DeviceIndependentIntRect, DeviceIndependentPixel};
use servo::webrender_api::ScrollLocation;
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel};
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel};
use servo::{
Cursor, ImeEvent, InputEvent, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton,
MouseButtonAction, MouseButtonEvent, MouseLeaveEvent, MouseMoveEvent,
@ -484,15 +484,28 @@ impl WindowPortsMethods for Window {
})
}
fn window_rect(&self) -> DeviceIntRect {
fn window_rect(&self) -> DeviceIndependentIntRect {
let outer_size = self.winit_window.outer_size();
let total_size = Size2D::new(outer_size.width as i32, outer_size.height as i32);
let hidpi_scale = self.hidpi_scale_factor().get() as f64;
// TODO: Find a universal way to convert.
// See https://github.com/servo/servo/issues/37937
let total_size = Size2D::new(
(outer_size.width as f64 / hidpi_scale).round() as i32,
(outer_size.height as f64 / hidpi_scale).round() as i32,
);
// TODO: Find a universal way to convert.
// See https://github.com/servo/servo/issues/37937
let origin = self
.winit_window
.outer_position()
.map(|point| Point2D::new(point.x, point.y))
.map(|point| {
Point2D::new(
(point.x as f64 / hidpi_scale).round() as i32,
(point.y as f64 / hidpi_scale).round() as i32,
)
})
.unwrap_or_default();
DeviceIntRect::from_origin_and_size(origin, total_size)
DeviceIndependentIntRect::from_origin_and_size(origin, total_size)
}
fn set_position(&self, point: DeviceIntPoint) {

View file

@ -9,8 +9,8 @@ use std::rc::Rc;
use euclid::num::Zero;
use euclid::{Length, Point2D, Scale, Size2D};
use servo::servo_geometry::DeviceIndependentPixel;
use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePixel};
use servo::servo_geometry::{DeviceIndependentIntRect, DeviceIndependentPixel};
use servo::webrender_api::units::{DeviceIntSize, DevicePixel};
use servo::{RenderingContext, ScreenGeometry, SoftwareRenderingContext};
use winit::dpi::PhysicalSize;
@ -135,8 +135,18 @@ impl WindowPortsMethods for Window {
Length::zero()
}
fn window_rect(&self) -> DeviceIntRect {
DeviceIntRect::from_origin_and_size(Point2D::zero(), self.inner_size.get())
fn window_rect(&self) -> DeviceIndependentIntRect {
let inner_size = self.inner_size.get().to_f64();
let scale = self.hidpi_scale_factor().get() as f64;
// TODO: Find a universal way to convert.
// See https://github.com/servo/servo/issues/37937
DeviceIndependentIntRect::from_origin_and_size(
Point2D::zero(),
Size2D::new(
(inner_size.width / scale).round() as i32,
(inner_size.height / scale).round() as i32,
),
)
}
fn set_toolbar_height(&self, _height: Length<f32, DeviceIndependentPixel>) {

View file

@ -8,8 +8,8 @@
use std::rc::Rc;
use euclid::{Length, Scale};
use servo::servo_geometry::DeviceIndependentPixel;
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel};
use servo::servo_geometry::{DeviceIndependentIntRect, DeviceIndependentPixel};
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel};
use servo::{Cursor, RenderingContext, ScreenGeometry, WebView};
use super::app_state::RunningAppState;
@ -53,5 +53,5 @@ pub trait WindowPortsMethods {
fn theme(&self) -> servo::Theme {
servo::Theme::Light
}
fn window_rect(&self) -> DeviceIntRect;
fn window_rect(&self) -> DeviceIndependentIntRect;
}

View file

@ -22,252 +22,3 @@
[test_modifier_key_sends_correct_events[\\ue052-R_ALT\]]
expected: FAIL
[test_modifier_key_sends_correct_events[\\ue051-R_CONTROL\]]
expected: FAIL
[test_modifier_key_sends_correct_events[\\ue053-R_META\]]
expected: FAIL
[test_modifier_key_sends_correct_events[\\ue050-R_SHIFT\]]
expected: FAIL
[test_non_printable_key_sends_events[\\ue014-RIGHT\]]
expected: FAIL
[test_printable_key_sends_correct_events[a-KeyA0\]]
expected: FAIL
[test_printable_key_sends_correct_events[a-KeyA1\]]
expected: FAIL
[test_printable_key_sends_correct_events["-Quote\]]
expected: FAIL
[test_printable_key_sends_correct_events[,-Comma\]]
expected: FAIL
[test_printable_key_sends_correct_events[\\xe0-\]]
expected: FAIL
[test_printable_key_sends_correct_events[\\u0416-\]]
expected: FAIL
[test_printable_key_sends_correct_events[@-Digit2\]]
expected: FAIL
[test_printable_key_sends_correct_events[\\u2603-\]]
expected: FAIL
[test_printable_key_sends_correct_events[\\uf6c2-\]]
expected: FAIL
[test_sequence_of_keydown_printable_keys_sends_events]
expected: FAIL
[test_sequence_of_keydown_printable_characters_sends_events]
expected: FAIL
[test_special_key_sends_keydown[ADD-expected0\]]
expected: FAIL
[test_special_key_sends_keydown[ALT-expected1\]]
expected: FAIL
[test_special_key_sends_keydown[BACKSPACE-expected2\]]
expected: FAIL
[test_special_key_sends_keydown[CANCEL-expected3\]]
expected: FAIL
[test_special_key_sends_keydown[CLEAR-expected4\]]
expected: FAIL
[test_special_key_sends_keydown[CONTROL-expected5\]]
expected: FAIL
[test_special_key_sends_keydown[DECIMAL-expected6\]]
expected: FAIL
[test_special_key_sends_keydown[DELETE-expected7\]]
expected: FAIL
[test_special_key_sends_keydown[DIVIDE-expected8\]]
expected: FAIL
[test_special_key_sends_keydown[DOWN-expected9\]]
expected: FAIL
[test_special_key_sends_keydown[END-expected10\]]
expected: FAIL
[test_special_key_sends_keydown[ENTER-expected11\]]
expected: FAIL
[test_special_key_sends_keydown[ESCAPE-expected13\]]
expected: FAIL
[test_special_key_sends_keydown[F1-expected14\]]
expected: FAIL
[test_special_key_sends_keydown[F10-expected15\]]
expected: FAIL
[test_special_key_sends_keydown[F11-expected16\]]
expected: FAIL
[test_special_key_sends_keydown[F12-expected17\]]
expected: FAIL
[test_special_key_sends_keydown[F2-expected18\]]
expected: FAIL
[test_special_key_sends_keydown[F3-expected19\]]
expected: FAIL
[test_special_key_sends_keydown[F4-expected20\]]
expected: FAIL
[test_special_key_sends_keydown[F5-expected21\]]
expected: FAIL
[test_special_key_sends_keydown[F6-expected22\]]
expected: FAIL
[test_special_key_sends_keydown[F7-expected23\]]
expected: FAIL
[test_special_key_sends_keydown[F8-expected24\]]
expected: FAIL
[test_special_key_sends_keydown[F9-expected25\]]
expected: FAIL
[test_special_key_sends_keydown[HELP-expected26\]]
expected: FAIL
[test_special_key_sends_keydown[HOME-expected27\]]
expected: FAIL
[test_special_key_sends_keydown[INSERT-expected28\]]
expected: FAIL
[test_special_key_sends_keydown[LEFT-expected29\]]
expected: FAIL
[test_special_key_sends_keydown[META-expected30\]]
expected: FAIL
[test_special_key_sends_keydown[MULTIPLY-expected31\]]
expected: FAIL
[test_special_key_sends_keydown[NULL-expected32\]]
expected: FAIL
[test_special_key_sends_keydown[NUMPAD0-expected33\]]
expected: FAIL
[test_special_key_sends_keydown[NUMPAD1-expected34\]]
expected: FAIL
[test_special_key_sends_keydown[NUMPAD2-expected35\]]
expected: FAIL
[test_special_key_sends_keydown[NUMPAD3-expected36\]]
expected: FAIL
[test_special_key_sends_keydown[NUMPAD4-expected37\]]
expected: FAIL
[test_special_key_sends_keydown[NUMPAD5-expected38\]]
expected: FAIL
[test_special_key_sends_keydown[NUMPAD6-expected39\]]
expected: FAIL
[test_special_key_sends_keydown[NUMPAD7-expected40\]]
expected: FAIL
[test_special_key_sends_keydown[NUMPAD8-expected41\]]
expected: FAIL
[test_special_key_sends_keydown[NUMPAD9-expected42\]]
expected: FAIL
[test_special_key_sends_keydown[PAGE_DOWN-expected43\]]
expected: FAIL
[test_special_key_sends_keydown[PAGE_UP-expected44\]]
expected: FAIL
[test_special_key_sends_keydown[RETURN-expected46\]]
expected: FAIL
[test_special_key_sends_keydown[RIGHT-expected47\]]
expected: FAIL
[test_special_key_sends_keydown[R_ALT-expected48\]]
expected: FAIL
[test_special_key_sends_keydown[R_ARROWDOWN-expected49\]]
expected: FAIL
[test_special_key_sends_keydown[R_ARROWLEFT-expected50\]]
expected: FAIL
[test_special_key_sends_keydown[R_ARROWRIGHT-expected51\]]
expected: FAIL
[test_special_key_sends_keydown[R_ARROWUP-expected52\]]
expected: FAIL
[test_special_key_sends_keydown[R_CONTROL-expected53\]]
expected: FAIL
[test_special_key_sends_keydown[R_DELETE-expected54\]]
expected: FAIL
[test_special_key_sends_keydown[R_END-expected55\]]
expected: FAIL
[test_special_key_sends_keydown[R_HOME-expected56\]]
expected: FAIL
[test_special_key_sends_keydown[R_INSERT-expected57\]]
expected: FAIL
[test_special_key_sends_keydown[R_META-expected58\]]
expected: FAIL
[test_special_key_sends_keydown[R_PAGEDOWN-expected59\]]
expected: FAIL
[test_special_key_sends_keydown[R_PAGEUP-expected60\]]
expected: FAIL
[test_special_key_sends_keydown[R_SHIFT-expected61\]]
expected: FAIL
[test_special_key_sends_keydown[SEMICOLON-expected62\]]
expected: FAIL
[test_special_key_sends_keydown[SEPARATOR-expected63\]]
expected: FAIL
[test_special_key_sends_keydown[SHIFT-expected64\]]
expected: FAIL
[test_special_key_sends_keydown[SPACE-expected65\]]
expected: FAIL
[test_special_key_sends_keydown[SUBTRACT-expected66\]]
expected: FAIL
[test_special_key_sends_keydown[TAB-expected67\]]
expected: FAIL
[test_special_key_sends_keydown[UP-expected68\]]
expected: FAIL
[test_special_key_sends_keydown[ZENKAKUHANKAKU-expected69\]]
expected: FAIL