webdriver: Move NewWebView, FocusWebView, GetWindowSize, and SetWindowSize to servoshell (#37555)

Follow up to: https://github.com/servo/servo/pull/36714
Moving webdriver [context
commands](https://www.w3.org/TR/webdriver2/#contexts) to be handled in
embedder:

- [x] New Window command - `WebdriverCommandMsg::NewWebView`
- [x]  Switch To Window command - `WebdriverCommandMsg::FocusWebView`
- [x] Resizing commands

cc: @xiaochengh

---------

Signed-off-by: batu_hoang <longvatrong111@gmail.com>
This commit is contained in:
batu_hoang 2025-06-25 18:29:34 +08:00 committed by GitHub
parent 5ea003752a
commit d970584332
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 148 additions and 97 deletions

View file

@ -4542,41 +4542,11 @@ where
WebDriverCommandMsg::CloseWebView(..) => {
unreachable!("This command should be send directly to the embedder.");
},
WebDriverCommandMsg::NewWebView(
originating_webview_id,
response_sender,
load_status_sender,
) => {
let (embedder_sender, receiver) = match ipc::channel() {
Ok(result) => result,
Err(error) => return warn!("Failed to create channel: {error:?}"),
};
self.embedder_proxy.send(EmbedderMsg::AllowOpeningWebView(
originating_webview_id,
embedder_sender,
));
let (new_webview_id, viewport_details) = match receiver.recv() {
Ok(Some((new_webview_id, viewport_details))) => {
(new_webview_id, viewport_details)
},
Ok(None) => return warn!("Embedder refused to allow opening webview"),
Err(error) => return warn!("Failed to receive webview id: {error:?}"),
};
self.handle_new_top_level_browsing_context(
ServoUrl::parse_with_base(None, "about:blank").expect("Infallible parse"),
new_webview_id,
viewport_details,
Some(load_status_sender),
);
if let Err(error) = response_sender.send(new_webview_id) {
error!(
"WebDriverCommandMsg::NewWebView: IPC error when sending new_webview_id \
to webdriver server: {error}"
);
}
WebDriverCommandMsg::NewWebView(..) => {
unreachable!("This command should be send directly to the embedder.");
},
WebDriverCommandMsg::FocusWebView(webview_id) => {
self.handle_focus_web_view(webview_id);
WebDriverCommandMsg::FocusWebView(..) => {
unreachable!("This command should be send directly to the embedder.");
},
WebDriverCommandMsg::IsWebViewOpen(..) => {
unreachable!("This command should be send directly to the embedder.");
@ -4585,7 +4555,10 @@ where
let is_open = self.browsing_contexts.contains_key(&browsing_context_id);
let _ = response_sender.send(is_open);
},
WebDriverCommandMsg::GetWindowSize(webview_id, response_sender) => {
WebDriverCommandMsg::GetWindowSize(..) => {
unreachable!("This command should be send directly to the embedder.");
},
WebDriverCommandMsg::GetViewportSize(webview_id, response_sender) => {
let browsing_context_id = BrowsingContextId::from(webview_id);
let size = self
.browsing_contexts
@ -4594,10 +4567,8 @@ where
.unwrap_or_default();
let _ = response_sender.send(size);
},
WebDriverCommandMsg::SetWindowSize(webview_id, size, response_sender) => {
self.webdriver.resize_channel = Some(response_sender);
self.embedder_proxy
.send(EmbedderMsg::ResizeTo(webview_id, size));
WebDriverCommandMsg::SetWindowSize(..) => {
unreachable!("This command should be send directly to the embedder.");
},
WebDriverCommandMsg::LoadUrl(webview_id, url, response_sender) => {
let load_data = LoadData::new(
@ -4767,6 +4738,9 @@ where
response_sender,
));
},
_ => {
warn!("Unhandled WebDriver command: {:?}", msg);
},
}
}

View file

@ -20,7 +20,7 @@ use servo_url::ServoUrl;
use style_traits::CSSPixel;
use webdriver::common::{WebElement, WebFrame, WebWindow};
use webdriver::error::ErrorStatus;
use webrender_api::units::DeviceIntSize;
use webrender_api::units::{DeviceIntSize, DevicePixel};
use crate::{MouseButton, MouseButtonAction};
@ -31,7 +31,9 @@ pub struct WebDriverMessageId(pub usize);
#[derive(Debug, Deserialize, Serialize)]
pub enum WebDriverCommandMsg {
/// Get the window size.
GetWindowSize(WebViewId, IpcSender<Size2D<f32, CSSPixel>>),
GetWindowSize(WebViewId, IpcSender<Size2D<i32, DevicePixel>>),
/// Get the viewport size.
GetViewportSize(WebViewId, IpcSender<Size2D<f32, CSSPixel>>),
/// Load a URL in the top-level browsing context with the given ID.
LoadUrl(WebViewId, ServoUrl, IpcSender<WebDriverLoadStatus>),
/// Refresh the top-level browsing context with the given ID.
@ -83,7 +85,11 @@ pub enum WebDriverCommandMsg {
IpcSender<WebDriverCommandResponse>,
),
/// Set the window size.
SetWindowSize(WebViewId, DeviceIntSize, IpcSender<Size2D<f32, CSSPixel>>),
SetWindowSize(
WebViewId,
DeviceIntSize,
IpcSender<Size2D<i32, DevicePixel>>,
),
/// Take a screenshot of the window.
TakeScreenshot(
WebViewId,
@ -94,15 +100,13 @@ pub enum WebDriverCommandMsg {
/// the provided channels to return the top level browsing context id
/// associated with the new webview, and a notification when the initial
/// load is complete.
NewWebView(
WebViewId,
IpcSender<WebViewId>,
IpcSender<WebDriverLoadStatus>,
),
NewWebView(IpcSender<WebViewId>, IpcSender<WebDriverLoadStatus>),
/// Close the webview associated with the provided id.
CloseWebView(WebViewId),
/// Focus the webview associated with the provided id.
FocusWebView(WebViewId),
/// Get focused webview.
GetFocusedWebView(IpcSender<Option<WebViewId>>),
/// Check whether top-level browsing context is open.
IsWebViewOpen(WebViewId, IpcSender<bool>),
/// Check whether browsing context is open.

View file

@ -517,11 +517,8 @@ impl Handler {
}
fn focus_webview_id(&self) -> WebDriverResult<WebViewId> {
debug!("Getting focused context.");
let (sender, receiver) = ipc::channel().unwrap();
let msg = EmbedderToConstellationMessage::GetFocusTopLevelBrowsingContext(sender.clone());
self.constellation_chan.send(msg).unwrap();
self.send_message_to_embedder(WebDriverCommandMsg::GetFocusedWebView(sender.clone()))?;
// Wait until the document is ready before returning the top-level browsing context id.
match wait_for_script_response(receiver)? {
Some(webview_id) => Ok(webview_id),
@ -807,18 +804,14 @@ impl Handler {
self.verify_top_level_browsing_context_is_open(webview_id)?;
let cmd_msg = WebDriverCommandMsg::GetWindowSize(webview_id, sender);
self.constellation_chan
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
.unwrap();
self.send_message_to_embedder(WebDriverCommandMsg::GetWindowSize(webview_id, sender))?;
let window_size = wait_for_script_response(receiver)?;
let window_size_response = WindowRectResponse {
x: 0,
y: 0,
width: window_size.width as i32,
height: window_size.height as i32,
width: window_size.width,
height: window_size.height,
};
Ok(WebDriverResponse::WindowRect(window_size_response))
}
@ -844,30 +837,30 @@ impl Handler {
// Step 12. If session's current top-level browsing context is no longer open,
// return error with error code no such window.
self.verify_top_level_browsing_context_is_open(webview_id)?;
let cmd_msg = WebDriverCommandMsg::SetWindowSize(webview_id, size.to_i32(), sender.clone());
self.constellation_chan
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
.unwrap();
self.send_message_to_embedder(WebDriverCommandMsg::SetWindowSize(
webview_id,
size.to_i32(),
sender.clone(),
))?;
let timeout = self.resize_timeout;
let constellation_chan = self.constellation_chan.clone();
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 cmd_msg = WebDriverCommandMsg::GetWindowSize(webview_id, sender);
constellation_chan
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
.unwrap();
let _ = embedder_sender.send(WebDriverCommandMsg::GetWindowSize(webview_id, sender));
waker.wake();
});
let window_size = wait_for_script_response(receiver)?;
let window_size_response = WindowRectResponse {
x: 0,
y: 0,
width: window_size.width as i32,
height: window_size.height as i32,
width: window_size.width,
height: window_size.height,
};
Ok(WebDriverResponse::WindowRect(window_size_response))
}
@ -1071,16 +1064,10 @@ impl Handler {
let session = self.session().unwrap();
self.verify_top_level_browsing_context_is_open(session.webview_id)?;
let cmd_msg = WebDriverCommandMsg::NewWebView(
session.webview_id,
sender,
self.load_status_sender.clone(),
);
let cmd_msg = WebDriverCommandMsg::NewWebView(sender, self.load_status_sender.clone());
// Step 5. Create a new top-level browsing context by running the window open steps.
// This MUST be done without invoking the focusing steps.
self.constellation_chan
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
.unwrap();
self.send_message_to_embedder(cmd_msg)?;
let mut handle = self.session.as_ref().unwrap().id.to_string();
if let Ok(new_webview_id) = receiver.recv() {
@ -1145,8 +1132,8 @@ impl Handler {
session.webview_id = webview_id;
session.browsing_context_id = BrowsingContextId::from(webview_id);
let msg = EmbedderToConstellationMessage::FocusWebView(webview_id);
self.constellation_chan.send(msg).unwrap();
let msg = WebDriverCommandMsg::FocusWebView(webview_id);
self.send_message_to_embedder(msg)?;
Ok(WebDriverResponse::Void)
} else {
Err(WebDriverError::new(