webdriver: Move navigation commands to servoshell (#37665)

- Move webdriver `GetViewportSize`, `LoadURL` and `Refresh` to
servoshell.
- Add `GoBack` and `GoFoward` commands.

Testing: Need to finish moving webdriver to servoshell then evaluate
again
Fixes: https://github.com/servo/servo/issues/37370

Signed-off-by: batu_hoang <longvatrong111@gmail.com>
This commit is contained in:
batu_hoang 2025-06-25 20:35:13 +08:00 committed by GitHub
parent 0346a62214
commit 62a009399f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 61 additions and 98 deletions

View file

@ -4558,53 +4558,17 @@ where
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
.get(&browsing_context_id)
.map(|browsing_context| browsing_context.viewport_details.size)
.unwrap_or_default();
let _ = response_sender.send(size);
WebDriverCommandMsg::GetViewportSize(..) => {
unreachable!("This command should be send directly to the embedder.");
},
WebDriverCommandMsg::SetWindowSize(..) => {
unreachable!("This command should be send directly to the embedder.");
},
WebDriverCommandMsg::LoadUrl(webview_id, url, response_sender) => {
let load_data = LoadData::new(
LoadOrigin::WebDriver,
url,
None,
Referrer::NoReferrer,
ReferrerPolicy::EmptyString,
None,
None,
false,
);
self.load_url_for_webdriver(
webview_id,
load_data,
response_sender,
NavigationHistoryBehavior::Push,
);
WebDriverCommandMsg::LoadUrl(..) => {
unreachable!("This command should be send directly to the embedder.");
},
WebDriverCommandMsg::Refresh(webview_id, response_sender) => {
let browsing_context_id = BrowsingContextId::from(webview_id);
let pipeline_id = self
.browsing_contexts
.get(&browsing_context_id)
.expect("Refresh: Browsing context must exist at this point")
.pipeline_id;
let load_data = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => pipeline.load_data.clone(),
None => return warn!("{}: Refresh after closure", pipeline_id),
};
self.load_url_for_webdriver(
webview_id,
load_data,
response_sender,
NavigationHistoryBehavior::Replace,
);
WebDriverCommandMsg::Refresh(..) => {
unreachable!("This command should be send directly to the embedder.");
},
// TODO: This should use the ScriptThreadMessage::EvaluateJavaScript command
WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd) => {
@ -4873,38 +4837,6 @@ where
));
}
#[servo_tracing::instrument(skip_all)]
fn load_url_for_webdriver(
&mut self,
webview_id: WebViewId,
load_data: LoadData,
response_sender: IpcSender<WebDriverLoadStatus>,
history_handling: NavigationHistoryBehavior,
) {
let browsing_context_id = BrowsingContextId::from(webview_id);
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
Some(browsing_context) => browsing_context.pipeline_id,
None => {
return warn!(
"{}: Webdriver load for closed browsing context",
browsing_context_id
);
},
};
if let Some(new_pipeline_id) =
self.load_url(webview_id, pipeline_id, load_data, history_handling)
{
debug!(
"Setting up webdriver load notification for {:?}",
new_pipeline_id
);
self.webdriver.load_channel = Some((new_pipeline_id, response_sender));
} else {
let _ = response_sender.send(WebDriverLoadStatus::Canceled);
}
}
#[servo_tracing::instrument(skip_all)]
fn change_session_history(&mut self, change: SessionHistoryChange) {
debug!(

View file

@ -33,11 +33,15 @@ pub enum WebDriverCommandMsg {
/// Get the window size.
GetWindowSize(WebViewId, IpcSender<Size2D<i32, DevicePixel>>),
/// Get the viewport size.
GetViewportSize(WebViewId, IpcSender<Size2D<f32, CSSPixel>>),
GetViewportSize(WebViewId, IpcSender<Size2D<u32, DevicePixel>>),
/// 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.
Refresh(WebViewId, IpcSender<WebDriverLoadStatus>),
/// Navigate the webview with the given ID to the previous page in the browsing context's history.
GoBack(WebViewId),
/// Navigate the webview with the given ID to the next page in the browsing context's history.
GoForward(WebViewId),
/// Pass a webdriver command to the script thread of the current pipeline
/// of a browsing context.
ScriptCommand(BrowsingContextId, WebDriverScriptCommand),

View file

@ -743,10 +743,9 @@ impl Handler {
fn check_viewport_bound(&self, x: f64, y: f64) -> Result<(), ErrorStatus> {
let (sender, receiver) = ipc::channel().unwrap();
let cmd_msg =
WebDriverCommandMsg::GetWindowSize(self.session.as_ref().unwrap().webview_id, sender);
self.constellation_chan
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
.unwrap();
WebDriverCommandMsg::GetViewportSize(self.session.as_ref().unwrap().webview_id, sender);
self.send_message_to_embedder(cmd_msg)
.map_err(|_| ErrorStatus::UnknownError)?;
let viewport_size = match wait_for_script_response(receiver) {
Ok(response) => response,

View file

@ -20,7 +20,7 @@ use std::{env, fmt, process, thread};
use base::id::{BrowsingContextId, WebViewId};
use base64::Engine;
use capabilities::ServoCapabilities;
use constellation_traits::{EmbedderToConstellationMessage, TraversalDirection};
use constellation_traits::EmbedderToConstellationMessage;
use cookie::{CookieBuilder, Expiration};
use crossbeam_channel::{Receiver, Sender, after, select, unbounded};
use embedder_traits::{
@ -767,9 +767,7 @@ impl Handler {
let cmd_msg =
WebDriverCommandMsg::LoadUrl(webview_id, url, self.load_status_sender.clone());
self.constellation_chan
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
.unwrap();
self.send_message_to_embedder(cmd_msg)?;
self.wait_for_load()
}
@ -902,9 +900,8 @@ impl Handler {
// Step 1. 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 direction = TraversalDirection::Back(1);
let msg = EmbedderToConstellationMessage::TraverseHistory(webview_id, direction);
self.constellation_chan.send(msg).unwrap();
self.send_message_to_embedder(WebDriverCommandMsg::GoBack(webview_id))?;
Ok(WebDriverResponse::Void)
}
@ -913,9 +910,8 @@ impl Handler {
// Step 1. 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 direction = TraversalDirection::Forward(1);
let msg = EmbedderToConstellationMessage::TraverseHistory(webview_id, direction);
self.constellation_chan.send(msg).unwrap();
self.send_message_to_embedder(WebDriverCommandMsg::GoForward(webview_id))?;
Ok(WebDriverResponse::Void)
}
@ -926,9 +922,7 @@ impl Handler {
self.verify_top_level_browsing_context_is_open(webview_id)?;
let cmd_msg = WebDriverCommandMsg::Refresh(webview_id, self.load_status_sender.clone());
self.constellation_chan
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
.unwrap();
self.send_message_to_embedder(cmd_msg)?;
self.wait_for_load()
}
@ -2354,6 +2348,8 @@ fn webdriver_value_to_js_argument(v: &Value) -> String {
}
}
// TODO: This waits for not only the script response
// need to make another name
fn wait_for_script_response<T>(receiver: IpcReceiver<T>) -> Result<T, WebDriverError>
where
T: for<'de> Deserialize<'de> + Serialize,

View file

@ -343,7 +343,7 @@ impl App {
},
WebDriverCommandMsg::NewWebView(response_sender, load_status_sender) => {
let new_webview =
running_state.create_toplevel_webview(Url::parse("auto:blank").unwrap());
running_state.create_toplevel_webview(Url::parse("about:blank").unwrap());
if let Err(error) = response_sender.send(new_webview.id()) {
warn!("Failed to send response of NewWebview: {error}");
@ -389,22 +389,54 @@ impl App {
warn!("Failed to send window size: {error}");
}
},
WebDriverCommandMsg::GetViewportSize(_webview_id, response_sender) => {
let window = self
.windows
.values()
.next()
.expect("Should have at least one window in servoshell");
let size = window.rendering_context().size2d();
if let Err(error) = response_sender.send(size) {
warn!("Failed to send response of GetViewportSize: {error}");
}
},
WebDriverCommandMsg::GetFocusedWebView(sender) => {
let focused_webview = running_state.focused_webview();
if let Err(error) = sender.send(focused_webview.map(|w| w.id())) {
warn!("Failed to send response of GetFocusedWebView: {error}");
};
},
WebDriverCommandMsg::GetViewportSize(..) |
WebDriverCommandMsg::LoadUrl(..) |
WebDriverCommandMsg::ScriptCommand(..) |
WebDriverCommandMsg::LoadUrl(webview_id, url, load_status_sender) => {
if let Some(webview) = running_state.webview_by_id(webview_id) {
webview.load(url.into_url());
running_state.set_load_status_sender(webview_id, load_status_sender);
}
},
WebDriverCommandMsg::Refresh(webview_id, load_status_sender) => {
if let Some(webview) = running_state.webview_by_id(webview_id) {
webview.reload();
running_state.set_load_status_sender(webview_id, load_status_sender);
}
},
WebDriverCommandMsg::GoBack(webview_id) => {
if let Some(webview) = running_state.webview_by_id(webview_id) {
webview.go_back(1);
}
},
WebDriverCommandMsg::GoForward(webview_id) => {
if let Some(webview) = running_state.webview_by_id(webview_id) {
webview.go_forward(1);
}
},
WebDriverCommandMsg::SendKeys(..) |
WebDriverCommandMsg::KeyboardAction(..) |
WebDriverCommandMsg::MouseButtonAction(..) |
WebDriverCommandMsg::MouseMoveAction(..) |
WebDriverCommandMsg::WheelScrollAction(..) |
WebDriverCommandMsg::TakeScreenshot(..) |
WebDriverCommandMsg::Refresh(..) => {
WebDriverCommandMsg::ScriptCommand(..) |
WebDriverCommandMsg::TakeScreenshot(..) => {
warn!(
"WebDriverCommand {:?} is still not moved from constellation to embedder",
msg