mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
webdriver: Greatly improve execution speed for all tests using SetWindowSize
(#37712)
1. Remove the unnecessary new thread which use GetWindowRect command and blocks for 500ms. Previously this is necessary because constellation forward "resize" to embedder, and WebDriver wait for a constant sufficient time to `GetWindowRect` in the new thread. This caused long delay because there are many subtests and SetWindowRect is called between each. 2. Remove `resize_timeout` 3. Return current dimension instead of 0 from embedder when it fails to resize. 4. Do resizing as long as one of width/height is `Some`, according to spec. Testing: All Conformance test with new passing cases. Fixes: https://github.com/servo/servo/pull/37663#issuecomment-2999120615 --------- Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
This commit is contained in:
parent
0774025d89
commit
9543482f51
4 changed files with 82 additions and 50 deletions
|
@ -10,7 +10,7 @@ mod actions;
|
||||||
mod capabilities;
|
mod capabilities;
|
||||||
|
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, LazyCell, RefCell};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::net::{SocketAddr, SocketAddrV4};
|
use std::net::{SocketAddr, SocketAddrV4};
|
||||||
|
@ -253,8 +253,6 @@ struct Handler {
|
||||||
|
|
||||||
current_action_id: Cell<Option<WebDriverMessageId>>,
|
current_action_id: Cell<Option<WebDriverMessageId>>,
|
||||||
|
|
||||||
resize_timeout: u32,
|
|
||||||
|
|
||||||
/// Number of pending actions of which WebDriver is waiting for responses.
|
/// Number of pending actions of which WebDriver is waiting for responses.
|
||||||
num_pending_actions: Cell<u32>,
|
num_pending_actions: Cell<u32>,
|
||||||
}
|
}
|
||||||
|
@ -466,6 +464,11 @@ impl<'de> Visitor<'de> for TupleVecMapVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum VerifyBrowsingContextIsOpen {
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
|
||||||
impl Handler {
|
impl Handler {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
constellation_chan: Sender<EmbedderToConstellationMessage>,
|
constellation_chan: Sender<EmbedderToConstellationMessage>,
|
||||||
|
@ -494,7 +497,6 @@ impl Handler {
|
||||||
constellation_receiver,
|
constellation_receiver,
|
||||||
id_generator: WebDriverMessageIdGenerator::new(),
|
id_generator: WebDriverMessageIdGenerator::new(),
|
||||||
current_action_id: Cell::new(None),
|
current_action_id: Cell::new(None),
|
||||||
resize_timeout: 500,
|
|
||||||
num_pending_actions: Cell::new(0),
|
num_pending_actions: Cell::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -796,12 +798,18 @@ impl Handler {
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_window_size(&self) -> WebDriverResult<WebDriverResponse> {
|
/// <https://w3c.github.io/webdriver/#get-window-rect>
|
||||||
|
fn handle_window_size(
|
||||||
|
&self,
|
||||||
|
verify: VerifyBrowsingContextIsOpen,
|
||||||
|
) -> WebDriverResult<WebDriverResponse> {
|
||||||
let (sender, receiver) = ipc::channel().unwrap();
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
let webview_id = self.session()?.webview_id;
|
let webview_id = self.session()?.webview_id;
|
||||||
|
// Step 1. If session's current top-level browsing context is no longer open,
|
||||||
|
// return error with error code no such window.
|
||||||
|
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::GetWindowSize(webview_id, sender))?;
|
||||||
|
|
||||||
let window_size = wait_for_script_response(receiver)?;
|
let window_size = wait_for_script_response(receiver)?;
|
||||||
|
@ -814,46 +822,58 @@ impl Handler {
|
||||||
Ok(WebDriverResponse::WindowRect(window_size_response))
|
Ok(WebDriverResponse::WindowRect(window_size_response))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <https://w3c.github.io/webdriver/#set-window-rect>
|
||||||
fn handle_set_window_size(
|
fn handle_set_window_size(
|
||||||
&self,
|
&self,
|
||||||
params: &WindowRectParameters,
|
params: &WindowRectParameters,
|
||||||
) -> WebDriverResult<WebDriverResponse> {
|
) -> WebDriverResult<WebDriverResponse> {
|
||||||
let (sender, receiver) = ipc::channel().unwrap();
|
// Step 9 - 10. Input Validation. Already done when deserialize.
|
||||||
|
|
||||||
// We don't current allow modifying the window x/y positions, so we can just
|
// Step 11. In case the Set Window Rect command is partially supported
|
||||||
// return the current window rectangle.
|
// (i.e. some combinations of arguments are supported but not others),
|
||||||
if params.width.is_none() || params.height.is_none() {
|
// the implmentation is expected to continue with the remaining steps.
|
||||||
return self.handle_window_size();
|
// DO NOT return "unsupported operation".
|
||||||
}
|
|
||||||
|
|
||||||
let width = params.width.unwrap_or(0);
|
|
||||||
let height = params.height.unwrap_or(0);
|
|
||||||
let size = Size2D::new(width as u32, height as u32);
|
|
||||||
let webview_id = self.session()?.webview_id;
|
let webview_id = self.session()?.webview_id;
|
||||||
// TODO: Return some other error earlier if the size is invalid.
|
|
||||||
|
|
||||||
// Step 12. If session's current top-level browsing context is no longer open,
|
// Step 12. If session's current top-level browsing context is no longer open,
|
||||||
// return error with error code no such window.
|
// return error with error code no such window.
|
||||||
self.verify_top_level_browsing_context_is_open(webview_id)?;
|
self.verify_top_level_browsing_context_is_open(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_size(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_size(VerifyBrowsingContextIsOpen::No)
|
||||||
|
.unwrap()
|
||||||
|
else {
|
||||||
|
unreachable!("handle_window_size() must return WindowRect");
|
||||||
|
};
|
||||||
|
current
|
||||||
|
});
|
||||||
|
|
||||||
|
let (width, height) = (
|
||||||
|
params.width.unwrap_or_else(|| current.width),
|
||||||
|
params.height.unwrap_or_else(|| current.height),
|
||||||
|
);
|
||||||
|
|
||||||
self.send_message_to_embedder(WebDriverCommandMsg::SetWindowSize(
|
self.send_message_to_embedder(WebDriverCommandMsg::SetWindowSize(
|
||||||
webview_id,
|
webview_id,
|
||||||
size.to_i32(),
|
Size2D::new(width, height),
|
||||||
sender.clone(),
|
sender.clone(),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let timeout = self.resize_timeout;
|
|
||||||
let embedder_sender = self.embedder_sender.clone();
|
|
||||||
let waker = self.event_loop_waker.clone();
|
|
||||||
thread::spawn(move || {
|
|
||||||
// On timeout, we send a GetWindowSize message to the constellation,
|
|
||||||
// which will give the current window size.
|
|
||||||
thread::sleep(Duration::from_millis(timeout as u64));
|
|
||||||
let _ = embedder_sender.send(WebDriverCommandMsg::GetWindowSize(webview_id, sender));
|
|
||||||
waker.wake();
|
|
||||||
});
|
|
||||||
|
|
||||||
let window_size = wait_for_script_response(receiver)?;
|
let window_size = wait_for_script_response(receiver)?;
|
||||||
|
debug!("window_size after resizing: {window_size:?}");
|
||||||
let window_size_response = WindowRectResponse {
|
let window_size_response = WindowRectResponse {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
|
@ -2139,7 +2159,9 @@ impl WebDriverHandler<ServoExtensionRoute> for Handler {
|
||||||
WebDriverCommand::AddCookie(ref parameters) => self.handle_add_cookie(parameters),
|
WebDriverCommand::AddCookie(ref parameters) => self.handle_add_cookie(parameters),
|
||||||
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 => self.handle_window_size(),
|
WebDriverCommand::GetWindowRect => {
|
||||||
|
self.handle_window_size(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),
|
||||||
WebDriverCommand::IsSelected(ref element) => self.handle_is_selected(element),
|
WebDriverCommand::IsSelected(ref element) => self.handle_is_selected(element),
|
||||||
|
|
|
@ -373,7 +373,7 @@ impl App {
|
||||||
warn!("Failed to send response of GetWindowSize: {error}");
|
warn!("Failed to send response of GetWindowSize: {error}");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
WebDriverCommandMsg::SetWindowSize(webview_id, size, size_sender) => {
|
WebDriverCommandMsg::SetWindowSize(webview_id, requested_size, 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;
|
||||||
};
|
};
|
||||||
|
@ -384,8 +384,12 @@ impl App {
|
||||||
.next()
|
.next()
|
||||||
.expect("Should have at least one window in servoshell");
|
.expect("Should have at least one window in servoshell");
|
||||||
|
|
||||||
let size = window.request_resize(&webview, size);
|
// When None is returned, it means that the request went to the display system,
|
||||||
if let Err(error) = size_sender.send(size.unwrap_or_default()) {
|
// and the actual size will be delivered later with the WindowEvent::Resized.
|
||||||
|
let returned_size = window.request_resize(&webview, requested_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)) {
|
||||||
warn!("Failed to send window size: {error}");
|
warn!("Failed to send window size: {error}");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,17 +29,32 @@
|
||||||
[test_set_to_screen_size]
|
[test_set_to_screen_size]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_set_larger_than_screen_size]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_width_height_floats]
|
[test_width_height_floats]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_height_width_as_current]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_height_as_current]
|
[test_height_as_current]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_width_as_current]
|
[test_width_as_current]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_no_change[rect12\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_no_change[rect13\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_no_change[rect16\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_no_change[rect17\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_no_change[rect18\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_no_change[rect19\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_larger_than_screen_size]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
[iframe.py]
|
|
||||||
[test_always_captures_top_browsing_context]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_source_origin[same_origin\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_source_origin[cross_origin\]]
|
|
||||||
expected: FAIL
|
|
Loading…
Add table
Add a link
Reference in a new issue