mirror of
https://github.com/servo/servo.git
synced 2025-08-01 11:40:30 +01:00
Implement setting position through webdriver for headed window (#38209)
Previously, we pretend we are able to set position in response. Now we can really do it. Testing: Able to set position accurately when tested locally. Fixes: Task 5 of #37804. --------- Signed-off-by: Euclid Ye <euclid.ye@huawei.com>
This commit is contained in:
parent
cff48d4910
commit
4ff6b1d4a7
7 changed files with 64 additions and 36 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -9422,6 +9422,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"servo_config",
|
"servo_config",
|
||||||
|
"servo_geometry",
|
||||||
"servo_url",
|
"servo_url",
|
||||||
"stylo_traits",
|
"stylo_traits",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
|
|
@ -4461,7 +4461,7 @@ where
|
||||||
WebDriverCommandMsg::IsWebViewOpen(..) |
|
WebDriverCommandMsg::IsWebViewOpen(..) |
|
||||||
WebDriverCommandMsg::GetWindowRect(..) |
|
WebDriverCommandMsg::GetWindowRect(..) |
|
||||||
WebDriverCommandMsg::GetViewportSize(..) |
|
WebDriverCommandMsg::GetViewportSize(..) |
|
||||||
WebDriverCommandMsg::SetWindowSize(..) |
|
WebDriverCommandMsg::SetWindowRect(..) |
|
||||||
WebDriverCommandMsg::LoadUrl(..) |
|
WebDriverCommandMsg::LoadUrl(..) |
|
||||||
WebDriverCommandMsg::Refresh(..) |
|
WebDriverCommandMsg::Refresh(..) |
|
||||||
WebDriverCommandMsg::SendKeys(..) |
|
WebDriverCommandMsg::SendKeys(..) |
|
||||||
|
|
|
@ -16,7 +16,7 @@ use keyboard_types::KeyboardEvent;
|
||||||
use keyboard_types::webdriver::Event as WebDriverInputEvent;
|
use keyboard_types::webdriver::Event as WebDriverInputEvent;
|
||||||
use pixels::RasterImage;
|
use pixels::RasterImage;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize, DeviceIndependentPixel};
|
use servo_geometry::DeviceIndependentIntRect;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
use webdriver::common::{WebElement, WebFrame, WebWindow};
|
use webdriver::common::{WebElement, WebFrame, WebWindow};
|
||||||
|
@ -132,11 +132,11 @@ pub enum WebDriverCommandMsg {
|
||||||
// expect one response from constellation for each tick actions.
|
// expect one response from constellation for each tick actions.
|
||||||
Option<WebDriverMessageId>,
|
Option<WebDriverMessageId>,
|
||||||
),
|
),
|
||||||
/// Set the window size.
|
/// Set the outer window rectangle.
|
||||||
SetWindowSize(
|
SetWindowRect(
|
||||||
WebViewId,
|
WebViewId,
|
||||||
DeviceIndependentIntSize,
|
DeviceIndependentIntRect,
|
||||||
IpcSender<Size2D<i32, DeviceIndependentPixel>>,
|
IpcSender<DeviceIndependentIntRect>,
|
||||||
),
|
),
|
||||||
/// Take a screenshot of the viewport.
|
/// Take a screenshot of the viewport.
|
||||||
TakeScreenshot(
|
TakeScreenshot(
|
||||||
|
|
|
@ -28,6 +28,7 @@ pixels = { path = "../pixels" }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
servo_config = { path = "../config" }
|
servo_config = { path = "../config" }
|
||||||
|
servo_geometry = { path = "../geometry" }
|
||||||
servo_url = { path = "../url" }
|
servo_url = { path = "../url" }
|
||||||
stylo_traits = { workspace = true }
|
stylo_traits = { workspace = true }
|
||||||
uuid = { workspace = true }
|
uuid = { workspace = true }
|
||||||
|
|
|
@ -28,7 +28,7 @@ use embedder_traits::{
|
||||||
WebDriverJSError, WebDriverJSResult, WebDriverJSValue, WebDriverLoadStatus, WebDriverMessageId,
|
WebDriverJSError, WebDriverJSResult, WebDriverJSValue, WebDriverLoadStatus, WebDriverMessageId,
|
||||||
WebDriverScriptCommand,
|
WebDriverScriptCommand,
|
||||||
};
|
};
|
||||||
use euclid::{Rect, Size2D};
|
use euclid::{Point2D, Rect, Size2D};
|
||||||
use http::method::Method;
|
use http::method::Method;
|
||||||
use image::{DynamicImage, ImageFormat, RgbaImage};
|
use image::{DynamicImage, ImageFormat, RgbaImage};
|
||||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||||
|
@ -41,6 +41,7 @@ use serde::ser::Serializer;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use servo_config::prefs::{self, PrefValue, Preferences};
|
use servo_config::prefs::{self, PrefValue, Preferences};
|
||||||
|
use servo_geometry::DeviceIndependentIntRect;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -889,7 +890,7 @@ impl Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://w3c.github.io/webdriver/#set-window-rect>
|
/// <https://w3c.github.io/webdriver/#set-window-rect>
|
||||||
fn handle_set_window_size(
|
fn handle_set_window_rect(
|
||||||
&self,
|
&self,
|
||||||
params: &WindowRectParameters,
|
params: &WindowRectParameters,
|
||||||
) -> WebDriverResult<WebDriverResponse> {
|
) -> WebDriverResult<WebDriverResponse> {
|
||||||
|
@ -908,18 +909,10 @@ impl Handler {
|
||||||
// Step 13. Handle any user prompt.
|
// Step 13. Handle any user prompt.
|
||||||
self.handle_any_user_prompts(webview_id)?;
|
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 14. Fully exit fullscreen.
|
||||||
// (TODO) Step 15. Restore the window.
|
// (TODO) Step 15. Restore the window.
|
||||||
let (sender, receiver) = ipc::channel().unwrap();
|
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 current = LazyCell::new(|| {
|
||||||
let WebDriverResponse::WindowRect(current) = self
|
let WebDriverResponse::WindowRect(current) = self
|
||||||
.handle_window_rect(VerifyBrowsingContextIsOpen::No)
|
.handle_window_rect(VerifyBrowsingContextIsOpen::No)
|
||||||
|
@ -930,24 +923,34 @@ impl Handler {
|
||||||
current
|
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.width.unwrap_or_else(|| current.width),
|
||||||
params.height.unwrap_or_else(|| current.height),
|
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,
|
webview_id,
|
||||||
Size2D::new(width, height),
|
DeviceIndependentIntRect::from_origin_and_size(
|
||||||
|
Point2D::new(x, y),
|
||||||
|
Size2D::new(width, height),
|
||||||
|
),
|
||||||
sender.clone(),
|
sender.clone(),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let window_size = wait_for_script_response(receiver)?;
|
let window_rect = wait_for_script_response(receiver)?;
|
||||||
debug!("window_size after resizing: {window_size:?}");
|
debug!("Result window_rect: {window_rect:?}");
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
@ -2449,7 +2452,7 @@ impl WebDriverHandler<ServoExtensionRoute> for Handler {
|
||||||
WebDriverCommand::GetWindowRect => {
|
WebDriverCommand::GetWindowRect => {
|
||||||
self.handle_window_rect(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_rect(size),
|
||||||
WebDriverCommand::IsEnabled(ref element) => self.handle_is_enabled(element),
|
WebDriverCommand::IsEnabled(ref element) => self.handle_is_enabled(element),
|
||||||
WebDriverCommand::IsSelected(ref element) => self.handle_is_selected(element),
|
WebDriverCommand::IsSelected(ref element) => self.handle_is_selected(element),
|
||||||
WebDriverCommand::GoBack => self.handle_go_back(),
|
WebDriverCommand::GoBack => self.handle_go_back(),
|
||||||
|
|
|
@ -21,10 +21,11 @@ use log::{info, trace, warn};
|
||||||
use net::protocols::ProtocolRegistry;
|
use net::protocols::ProtocolRegistry;
|
||||||
use servo::config::opts::Opts;
|
use servo::config::opts::Opts;
|
||||||
use servo::config::prefs::Preferences;
|
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::servo_url::ServoUrl;
|
||||||
use servo::user_content_manager::{UserContentManager, UserScript};
|
use servo::user_content_manager::{UserContentManager, UserScript};
|
||||||
use servo::webrender_api::ScrollLocation;
|
use servo::webrender_api::ScrollLocation;
|
||||||
|
use servo::webrender_api::units::DeviceIntRect;
|
||||||
use servo::{
|
use servo::{
|
||||||
EventLoopWaker, ImeEvent, InputEvent, KeyboardEvent, MouseButtonEvent, MouseMoveEvent,
|
EventLoopWaker, ImeEvent, InputEvent, KeyboardEvent, MouseButtonEvent, MouseMoveEvent,
|
||||||
WebDriverCommandMsg, WebDriverScriptCommand, WebDriverUserPromptAction, WheelDelta, WheelEvent,
|
WebDriverCommandMsg, WebDriverScriptCommand, WebDriverUserPromptAction, WheelDelta, WheelEvent,
|
||||||
|
@ -38,6 +39,7 @@ use winit::window::WindowId;
|
||||||
|
|
||||||
use super::app_state::AppState;
|
use super::app_state::AppState;
|
||||||
use super::events_loop::{AppEvent, EventLoopProxy, EventsLoop};
|
use super::events_loop::{AppEvent, EventLoopProxy, EventsLoop};
|
||||||
|
use super::geometry::winit_position_to_euclid_point;
|
||||||
use super::minibrowser::{Minibrowser, MinibrowserEvent};
|
use super::minibrowser::{Minibrowser, MinibrowserEvent};
|
||||||
use super::{headed_window, headless_window};
|
use super::{headed_window, headless_window};
|
||||||
use crate::desktop::app_state::RunningAppState;
|
use crate::desktop::app_state::RunningAppState;
|
||||||
|
@ -392,7 +394,7 @@ impl App {
|
||||||
warn!("Failed to send response of GetWindowSize: {error}");
|
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 {
|
let Some(webview) = running_state.webview_by_id(webview_id) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
@ -404,20 +406,35 @@ impl App {
|
||||||
.expect("Should have at least one window in servoshell");
|
.expect("Should have at least one window in servoshell");
|
||||||
let scale = window.hidpi_scale_factor();
|
let scale = window.hidpi_scale_factor();
|
||||||
|
|
||||||
let requested_physical_size =
|
let requested_physical_rect =
|
||||||
(requested_size.to_f32() * scale).round().to_i32();
|
(requested_rect.to_f32() * scale).round().to_i32();
|
||||||
|
|
||||||
// When None is returned, it means that the request went to the display system,
|
// 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.
|
// 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.
|
// TODO: Handle None case. For now, we assume always succeed.
|
||||||
// In reality, the request may exceed available screen size.
|
// In reality, the request may exceed available screen size.
|
||||||
|
|
||||||
if let Err(error) = size_sender.send(
|
// Step 18. Set position of the window.
|
||||||
returned_size
|
window.set_position(requested_physical_rect.min);
|
||||||
.map(|size| convert_size_to_css_pixel(size, scale))
|
|
||||||
.unwrap_or(requested_size),
|
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}");
|
warn!("Failed to send window size: {error}");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -480,6 +480,12 @@ impl WindowPortsMethods for Window {
|
||||||
|
|
||||||
fn request_resize(&self, _: &WebView, new_outer_size: DeviceIntSize) -> Option<DeviceIntSize> {
|
fn request_resize(&self, _: &WebView, new_outer_size: DeviceIntSize) -> Option<DeviceIntSize> {
|
||||||
let outer_size = self.winit_window.outer_size();
|
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 inner_size = self.winit_window.inner_size();
|
||||||
let decoration_height = outer_size.height - inner_size.height;
|
let decoration_height = outer_size.height - inner_size.height;
|
||||||
let decoration_width = outer_size.width - inner_size.width;
|
let decoration_width = outer_size.width - inner_size.width;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue