diff --git a/Cargo.lock b/Cargo.lock index d73513a3af2..fa690cd9df0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9422,6 +9422,7 @@ dependencies = [ "serde", "serde_json", "servo_config", + "servo_geometry", "servo_url", "stylo_traits", "uuid", diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 235710fbeb7..a82f70991b0 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -4461,7 +4461,7 @@ where WebDriverCommandMsg::IsWebViewOpen(..) | WebDriverCommandMsg::GetWindowRect(..) | WebDriverCommandMsg::GetViewportSize(..) | - WebDriverCommandMsg::SetWindowSize(..) | + WebDriverCommandMsg::SetWindowRect(..) | WebDriverCommandMsg::LoadUrl(..) | WebDriverCommandMsg::Refresh(..) | WebDriverCommandMsg::SendKeys(..) | diff --git a/components/shared/embedder/webdriver.rs b/components/shared/embedder/webdriver.rs index 2b69f0cf656..f1e5646bc11 100644 --- a/components/shared/embedder/webdriver.rs +++ b/components/shared/embedder/webdriver.rs @@ -16,7 +16,7 @@ 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_geometry::DeviceIndependentIntRect; use servo_url::ServoUrl; use style_traits::CSSPixel; use webdriver::common::{WebElement, WebFrame, WebWindow}; @@ -132,11 +132,11 @@ pub enum WebDriverCommandMsg { // expect one response from constellation for each tick actions. Option, ), - /// Set the window size. - SetWindowSize( + /// Set the outer window rectangle. + SetWindowRect( WebViewId, - DeviceIndependentIntSize, - IpcSender>, + DeviceIndependentIntRect, + IpcSender, ), /// Take a screenshot of the viewport. TakeScreenshot( diff --git a/components/webdriver_server/Cargo.toml b/components/webdriver_server/Cargo.toml index 47c77e0e9a0..5a9ff27c0cd 100644 --- a/components/webdriver_server/Cargo.toml +++ b/components/webdriver_server/Cargo.toml @@ -28,6 +28,7 @@ pixels = { path = "../pixels" } serde = { workspace = true } serde_json = { workspace = true } servo_config = { path = "../config" } +servo_geometry = { path = "../geometry" } servo_url = { path = "../url" } stylo_traits = { workspace = true } uuid = { workspace = true } diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index 831b13e0890..601d82e8998 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -28,7 +28,7 @@ use embedder_traits::{ WebDriverJSError, WebDriverJSResult, WebDriverJSValue, WebDriverLoadStatus, WebDriverMessageId, WebDriverScriptCommand, }; -use euclid::{Rect, Size2D}; +use euclid::{Point2D, Rect, Size2D}; use http::method::Method; use image::{DynamicImage, ImageFormat, RgbaImage}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; @@ -41,6 +41,7 @@ use serde::ser::Serializer; use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; use servo_config::prefs::{self, PrefValue, Preferences}; +use servo_geometry::DeviceIndependentIntRect; use servo_url::ServoUrl; use style_traits::CSSPixel; use uuid::Uuid; @@ -889,7 +890,7 @@ impl Handler { } /// - fn handle_set_window_size( + fn handle_set_window_rect( &self, params: &WindowRectParameters, ) -> WebDriverResult { @@ -908,18 +909,10 @@ impl Handler { // Step 13. Handle any user prompt. self.handle_any_user_prompts(webview_id)?; - // We don't current allow modifying the window x/y positions, so we can just - // return the current window rectangle if not changing dimension. - if params.width.is_none() && params.height.is_none() { - return self.handle_window_rect(VerifyBrowsingContextIsOpen::No); - } // (TODO) Step 14. Fully exit fullscreen. // (TODO) Step 15. Restore the window. let (sender, receiver) = ipc::channel().unwrap(); - // Step 16 - 17. Set the width/height in CSS pixels. - // This should be done as long as one of width/height is not null. - let current = LazyCell::new(|| { let WebDriverResponse::WindowRect(current) = self .handle_window_rect(VerifyBrowsingContextIsOpen::No) @@ -930,24 +923,34 @@ impl Handler { current }); - let (width, height) = ( + let (x, y, width, height) = ( + params.x.unwrap_or_else(|| current.x), + params.y.unwrap_or_else(|| current.y), params.width.unwrap_or_else(|| current.width), params.height.unwrap_or_else(|| current.height), ); - self.send_message_to_embedder(WebDriverCommandMsg::SetWindowSize( + // Step 16 - 17. Set the width/height in CSS pixels. + // This should be done as long as one of width/height is not null. + + // Step 18 - 19. Set the screen x/y in CSS pixels. + // This should be done as long as one of width/height is not null. + self.send_message_to_embedder(WebDriverCommandMsg::SetWindowRect( webview_id, - Size2D::new(width, height), + DeviceIndependentIntRect::from_origin_and_size( + Point2D::new(x, y), + Size2D::new(width, height), + ), sender.clone(), ))?; - let window_size = wait_for_script_response(receiver)?; - debug!("window_size after resizing: {window_size:?}"); + let window_rect = wait_for_script_response(receiver)?; + debug!("Result window_rect: {window_rect:?}"); let window_size_response = WindowRectResponse { - x: 0, - y: 0, - width: window_size.width, - height: window_size.height, + x: window_rect.min.x, + y: window_rect.min.y, + width: window_rect.width(), + height: window_rect.height(), }; Ok(WebDriverResponse::WindowRect(window_size_response)) } @@ -2449,7 +2452,7 @@ impl WebDriverHandler for Handler { WebDriverCommand::GetWindowRect => { self.handle_window_rect(VerifyBrowsingContextIsOpen::Yes) }, - WebDriverCommand::SetWindowRect(ref size) => self.handle_set_window_size(size), + WebDriverCommand::SetWindowRect(ref size) => self.handle_set_window_rect(size), WebDriverCommand::IsEnabled(ref element) => self.handle_is_enabled(element), WebDriverCommand::IsSelected(ref element) => self.handle_is_selected(element), WebDriverCommand::GoBack => self.handle_go_back(), diff --git a/ports/servoshell/desktop/app.rs b/ports/servoshell/desktop/app.rs index 97f1403af8f..95ef0e0fa07 100644 --- a/ports/servoshell/desktop/app.rs +++ b/ports/servoshell/desktop/app.rs @@ -21,10 +21,11 @@ use log::{info, trace, warn}; use net::protocols::ProtocolRegistry; use servo::config::opts::Opts; use servo::config::prefs::Preferences; -use servo::servo_geometry::convert_size_to_css_pixel; +use servo::servo_geometry::convert_rect_to_css_pixel; use servo::servo_url::ServoUrl; use servo::user_content_manager::{UserContentManager, UserScript}; use servo::webrender_api::ScrollLocation; +use servo::webrender_api::units::DeviceIntRect; use servo::{ EventLoopWaker, ImeEvent, InputEvent, KeyboardEvent, MouseButtonEvent, MouseMoveEvent, WebDriverCommandMsg, WebDriverScriptCommand, WebDriverUserPromptAction, WheelDelta, WheelEvent, @@ -38,6 +39,7 @@ use winit::window::WindowId; use super::app_state::AppState; use super::events_loop::{AppEvent, EventLoopProxy, EventsLoop}; +use super::geometry::winit_position_to_euclid_point; use super::minibrowser::{Minibrowser, MinibrowserEvent}; use super::{headed_window, headless_window}; use crate::desktop::app_state::RunningAppState; @@ -392,7 +394,7 @@ impl App { warn!("Failed to send response of GetWindowSize: {error}"); } }, - WebDriverCommandMsg::SetWindowSize(webview_id, requested_size, size_sender) => { + WebDriverCommandMsg::SetWindowRect(webview_id, requested_rect, size_sender) => { let Some(webview) = running_state.webview_by_id(webview_id) else { continue; }; @@ -404,20 +406,35 @@ impl App { .expect("Should have at least one window in servoshell"); let scale = window.hidpi_scale_factor(); - let requested_physical_size = - (requested_size.to_f32() * scale).round().to_i32(); + let requested_physical_rect = + (requested_rect.to_f32() * scale).round().to_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_physical_size); + // Step 17. Set Width/Height. + let returned_size = + window.request_resize(&webview, requested_physical_rect.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 - .map(|size| convert_size_to_css_pixel(size, scale)) - .unwrap_or(requested_size), - ) { + // Step 18. Set position of the window. + window.set_position(requested_physical_rect.min); + + let result_physical_position = window + .winit_window() + .and_then(|window| window.outer_position().ok()) + .map(winit_position_to_euclid_point) + .unwrap_or(requested_physical_rect.min); + + let reply_rect = convert_rect_to_css_pixel( + DeviceIntRect::from_origin_and_size( + result_physical_position, + returned_size.unwrap_or(requested_physical_rect.size()), + ), + scale, + ); + + if let Err(error) = size_sender.send(reply_rect) { warn!("Failed to send window size: {error}"); } }, diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs index 5e3dc8d9bf1..1f648edda83 100644 --- a/ports/servoshell/desktop/headed_window.rs +++ b/ports/servoshell/desktop/headed_window.rs @@ -480,6 +480,12 @@ impl WindowPortsMethods for Window { fn request_resize(&self, _: &WebView, new_outer_size: DeviceIntSize) -> Option { let outer_size = self.winit_window.outer_size(); + if outer_size.width == new_outer_size.width as u32 && + outer_size.height == new_outer_size.height as u32 + { + return Some(new_outer_size); + } + let inner_size = self.winit_window.inner_size(); let decoration_height = outer_size.height - inner_size.height; let decoration_width = outer_size.width - inner_size.width;