webdriver: Focus WebView asynchronously (#39241)

#38160 added a webdriver-specific API to support waiting on focus
operations to complete. Later, #38243 added a unique id to track each
focus operation.

Back then we wait on focusing webview in webdriver hoping to improve
stability, but it does not matter as it turns out later. #39086 also
focuses browsing context asynchronously.

This PR would make webdriver's focusing-webview behaviour same as human
interaction.

Testing: 
[Before 1](https://github.com/yezhizhen/servo/actions/runs/17598288280),
[Before 2](https://github.com/yezhizhen/servo/actions/runs/17598289360),
[Before 3](https://github.com/yezhizhen/servo/actions/runs/17598290532)
[After 1](https://github.com/yezhizhen/servo/actions/runs/17598282988),
[After 2](https://github.com/yezhizhen/servo/actions/runs/17598280603),
[After 3](https://github.com/yezhizhen/servo/actions/runs/17589228530)

---------

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
This commit is contained in:
Euclid Ye 2025-09-10 15:36:53 +08:00 committed by GitHub
parent 433a6bf47b
commit 726b456120
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 42 additions and 124 deletions

View file

@ -381,10 +381,9 @@ impl App {
warn!("Failed to send response of CloseWebView: {error}");
}
},
WebDriverCommandMsg::FocusWebView(webview_id, response_sender) => {
WebDriverCommandMsg::FocusWebView(webview_id) => {
if let Some(webview) = running_state.webview_by_id(webview_id) {
let focus_id = webview.focus_and_raise_to_top(true);
running_state.set_pending_focus(focus_id, response_sender);
webview.focus_and_raise_to_top(true);
}
},
WebDriverCommandMsg::FocusBrowsingContext(..) => {

View file

@ -21,10 +21,10 @@ use servo::ipc_channel::ipc::IpcSender;
use servo::webrender_api::ScrollLocation;
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
use servo::{
AllowOrDenyRequest, AuthenticationRequest, FilterPattern, FocusId, FormControl,
GamepadHapticEffectType, JSValue, KeyboardEvent, LoadStatus, PermissionRequest, Servo,
ServoDelegate, ServoError, SimpleDialog, TraversalId, WebDriverCommandMsg, WebDriverJSResult,
WebDriverLoadStatus, WebDriverUserPrompt, WebView, WebViewBuilder, WebViewDelegate,
AllowOrDenyRequest, AuthenticationRequest, FilterPattern, FormControl, GamepadHapticEffectType,
JSValue, KeyboardEvent, LoadStatus, PermissionRequest, Servo, ServoDelegate, ServoError,
SimpleDialog, TraversalId, WebDriverCommandMsg, WebDriverJSResult, WebDriverLoadStatus,
WebDriverUserPrompt, WebView, WebViewBuilder, WebViewDelegate,
};
use url::Url;
@ -466,13 +466,6 @@ impl RunningAppState {
});
}
pub(crate) fn set_pending_focus(&self, focus_id: FocusId, sender: IpcSender<bool>) {
self.webdriver_senders
.borrow_mut()
.pending_focus
.insert(focus_id, sender);
}
pub(crate) fn set_pending_traversal(
&self,
traversal_id: TraversalId,
@ -668,14 +661,6 @@ impl WebViewDelegate for RunningAppState {
self.close_webview(webview.id());
}
fn notify_focus_complete(&self, webview: servo::WebView, focus_id: FocusId) {
let mut webdriver_state = self.webdriver_senders.borrow_mut();
if let Entry::Occupied(entry) = webdriver_state.pending_focus.entry(focus_id) {
let sender = entry.remove();
let _ = sender.send(webview.focused());
}
}
fn notify_focus_changed(&self, webview: servo::WebView, focused: bool) {
let mut inner_mut = self.inner_mut();
if focused {