webdriver: Get the window position as well as the size when resolving "Get Window Rect" (#37812)

1. Rename `GetWindowSize` to `GetWindowRect`
2. Return the WindowRect in device pixels correctly. Previously, it
returns `(0, 0, ScreenWidth, ScreenHeight)` which is a static value.
3. Add `fn window_rect` to `WindowPortsMethods`. Implement it for both
Headless Window and Headed Window.

Testing: Tested manually with powershell script. Result is now dynamic
and reflects the truth.
Fixes: Task 1 & 2 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-02 18:01:27 +08:00 committed by GitHub
parent 95d9d3a412
commit 94f35ba998
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 35 additions and 19 deletions

View file

@ -4534,7 +4534,7 @@ where
let is_open = self.browsing_contexts.contains_key(&browsing_context_id); let is_open = self.browsing_contexts.contains_key(&browsing_context_id);
let _ = response_sender.send(is_open); let _ = response_sender.send(is_open);
}, },
WebDriverCommandMsg::GetWindowSize(..) => { WebDriverCommandMsg::GetWindowRect(..) => {
unreachable!("This command should be send directly to the embedder."); unreachable!("This command should be send directly to the embedder.");
}, },
WebDriverCommandMsg::GetViewportSize(..) => { WebDriverCommandMsg::GetViewportSize(..) => {

View file

@ -20,7 +20,7 @@ use servo_url::ServoUrl;
use style_traits::CSSPixel; use style_traits::CSSPixel;
use webdriver::common::{WebElement, WebFrame, WebWindow}; use webdriver::common::{WebElement, WebFrame, WebWindow};
use webdriver::error::ErrorStatus; use webdriver::error::ErrorStatus;
use webrender_api::units::{DeviceIntSize, DevicePixel}; use webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePixel};
use crate::{MouseButton, MouseButtonAction}; use crate::{MouseButton, MouseButtonAction};
@ -31,7 +31,7 @@ pub struct WebDriverMessageId(pub usize);
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub enum WebDriverCommandMsg { pub enum WebDriverCommandMsg {
/// Get the window size. /// Get the window size.
GetWindowSize(WebViewId, IpcSender<Size2D<i32, DevicePixel>>), GetWindowRect(WebViewId, IpcSender<DeviceIntRect>),
/// Get the viewport size. /// Get the viewport size.
GetViewportSize(WebViewId, IpcSender<Size2D<u32, DevicePixel>>), GetViewportSize(WebViewId, IpcSender<Size2D<u32, DevicePixel>>),
/// Load a URL in the top-level browsing context with the given ID. /// Load a URL in the top-level browsing context with the given ID.

View file

@ -799,7 +799,7 @@ impl Handler {
} }
/// <https://w3c.github.io/webdriver/#get-window-rect> /// <https://w3c.github.io/webdriver/#get-window-rect>
fn handle_window_size( fn handle_window_rect(
&self, &self,
verify: VerifyBrowsingContextIsOpen, verify: VerifyBrowsingContextIsOpen,
) -> WebDriverResult<WebDriverResponse> { ) -> WebDriverResult<WebDriverResponse> {
@ -810,14 +810,14 @@ impl Handler {
if let VerifyBrowsingContextIsOpen::Yes = verify { if let VerifyBrowsingContextIsOpen::Yes = verify {
self.verify_top_level_browsing_context_is_open(webview_id)?; self.verify_top_level_browsing_context_is_open(webview_id)?;
} }
self.send_message_to_embedder(WebDriverCommandMsg::GetWindowSize(webview_id, sender))?; self.send_message_to_embedder(WebDriverCommandMsg::GetWindowRect(webview_id, sender))?;
let window_size = wait_for_script_response(receiver)?; let window_rect = wait_for_script_response(receiver)?;
let window_size_response = WindowRectResponse { let window_size_response = WindowRectResponse {
x: 0, x: window_rect.min.x,
y: 0, y: window_rect.min.y,
width: window_size.width, width: window_rect.width(),
height: window_size.height, height: window_rect.height(),
}; };
Ok(WebDriverResponse::WindowRect(window_size_response)) Ok(WebDriverResponse::WindowRect(window_size_response))
} }
@ -842,7 +842,7 @@ impl Handler {
// We don't current allow modifying the window x/y positions, so we can just // We don't current allow modifying the window x/y positions, so we can just
// return the current window rectangle if not changing dimension. // return the current window rectangle if not changing dimension.
if params.width.is_none() && params.height.is_none() { if params.width.is_none() && params.height.is_none() {
return self.handle_window_size(VerifyBrowsingContextIsOpen::No); return self.handle_window_rect(VerifyBrowsingContextIsOpen::No);
} }
// (TODO) Step 14. Fully exit fullscreen. // (TODO) Step 14. Fully exit fullscreen.
// (TODO) Step 15. Restore the window. // (TODO) Step 15. Restore the window.
@ -853,7 +853,7 @@ impl Handler {
let current = LazyCell::new(|| { let current = LazyCell::new(|| {
let WebDriverResponse::WindowRect(current) = self let WebDriverResponse::WindowRect(current) = self
.handle_window_size(VerifyBrowsingContextIsOpen::No) .handle_window_rect(VerifyBrowsingContextIsOpen::No)
.unwrap() .unwrap()
else { else {
unreachable!("handle_window_size() must return WindowRect"); unreachable!("handle_window_size() must return WindowRect");
@ -2160,7 +2160,7 @@ impl WebDriverHandler<ServoExtensionRoute> for Handler {
WebDriverCommand::Get(ref parameters) => self.handle_get(parameters), WebDriverCommand::Get(ref parameters) => self.handle_get(parameters),
WebDriverCommand::GetCurrentUrl => self.handle_current_url(), WebDriverCommand::GetCurrentUrl => self.handle_current_url(),
WebDriverCommand::GetWindowRect => { WebDriverCommand::GetWindowRect => {
self.handle_window_size(VerifyBrowsingContextIsOpen::Yes) self.handle_window_rect(VerifyBrowsingContextIsOpen::Yes)
}, },
WebDriverCommand::SetWindowRect(ref size) => self.handle_set_window_size(size), WebDriverCommand::SetWindowRect(ref size) => self.handle_set_window_size(size),
WebDriverCommand::IsEnabled(ref element) => self.handle_is_enabled(element), WebDriverCommand::IsEnabled(ref element) => self.handle_is_enabled(element),

View file

@ -362,14 +362,14 @@ impl App {
// TODO: send a response to the WebDriver // TODO: send a response to the WebDriver
// so it knows when the focus has finished. // so it knows when the focus has finished.
}, },
WebDriverCommandMsg::GetWindowSize(_webview_id, response_sender) => { WebDriverCommandMsg::GetWindowRect(_webview_id, response_sender) => {
let window = self let window = self
.windows .windows
.values() .values()
.next() .next()
.expect("Should have at least one window in servoshell"); .expect("Should have at least one window in servoshell");
if let Err(error) = response_sender.send(window.screen_geometry().size) { if let Err(error) = response_sender.send(window.window_rect()) {
warn!("Failed to send response of GetWindowSize: {error}"); warn!("Failed to send response of GetWindowSize: {error}");
} }
}, },

View file

@ -17,7 +17,7 @@ use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
use servo::servo_config::pref; use servo::servo_config::pref;
use servo::servo_geometry::DeviceIndependentPixel; use servo::servo_geometry::DeviceIndependentPixel;
use servo::webrender_api::ScrollLocation; use servo::webrender_api::ScrollLocation;
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePixel}; use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel};
use servo::{ use servo::{
Cursor, ImeEvent, InputEvent, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton, Cursor, ImeEvent, InputEvent, Key, KeyState, KeyboardEvent, MouseButton as ServoMouseButton,
MouseButtonAction, MouseButtonEvent, MouseLeaveEvent, MouseMoveEvent, MouseButtonAction, MouseButtonEvent, MouseLeaveEvent, MouseMoveEvent,
@ -483,6 +483,17 @@ impl WindowPortsMethods for Window {
}) })
} }
fn window_rect(&self) -> DeviceIntRect {
let outer_size = self.winit_window.outer_size();
let total_size = Size2D::new(outer_size.width as i32, outer_size.height as i32);
let origin = self
.winit_window
.outer_position()
.map(|point| Point2D::new(point.x, point.y))
.unwrap_or_default();
DeviceIntRect::from_origin_and_size(origin, total_size)
}
fn set_position(&self, point: DeviceIntPoint) { fn set_position(&self, point: DeviceIntPoint) {
self.winit_window self.winit_window
.set_outer_position::<PhysicalPosition<i32>>(PhysicalPosition::new(point.x, point.y)) .set_outer_position::<PhysicalPosition<i32>>(PhysicalPosition::new(point.x, point.y))

View file

@ -8,9 +8,9 @@ use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
use euclid::num::Zero; use euclid::num::Zero;
use euclid::{Length, Scale, Size2D}; use euclid::{Length, Point2D, Scale, Size2D};
use servo::servo_geometry::DeviceIndependentPixel; use servo::servo_geometry::DeviceIndependentPixel;
use servo::webrender_api::units::{DeviceIntSize, DevicePixel}; use servo::webrender_api::units::{DeviceIntRect, DeviceIntSize, DevicePixel};
use servo::{RenderingContext, ScreenGeometry, SoftwareRenderingContext}; use servo::{RenderingContext, ScreenGeometry, SoftwareRenderingContext};
use winit::dpi::PhysicalSize; use winit::dpi::PhysicalSize;
@ -135,6 +135,10 @@ impl WindowPortsMethods for Window {
Length::zero() Length::zero()
} }
fn window_rect(&self) -> DeviceIntRect {
DeviceIntRect::from_origin_and_size(Point2D::zero(), self.inner_size.get())
}
fn set_toolbar_height(&self, _height: Length<f32, DeviceIndependentPixel>) { fn set_toolbar_height(&self, _height: Length<f32, DeviceIndependentPixel>) {
unimplemented!("headless Window only") unimplemented!("headless Window only")
} }

View file

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