Skip to content

Commit 9fe53e5

Browse files
authored
servoshell: Support WebDriverCommandMsg::InputEvent for egl (servo#40280)
- Support `WebDriverCommandMsg::InputEvent` for egl - Move `pending_webdriver_events` and related handlers to `RunningAppStateBase` Testing: Manually tested on Ohos device. Element click now scrolls into view + click. Fixes: Part of servo#40279 --------- Signed-off-by: Euclid Ye <[email protected]>
1 parent 5921718 commit 9fe53e5

File tree

4 files changed

+98
-62
lines changed

4 files changed

+98
-62
lines changed

ports/servoshell/desktop/app.rs

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,15 @@ use std::{env, fs};
1313

1414
use ::servo::ServoBuilder;
1515
use crossbeam_channel::unbounded;
16-
use log::{info, trace, warn};
16+
use log::{error, info, trace, warn};
1717
use net::protocols::ProtocolRegistry;
1818
use servo::config::opts::Opts;
1919
use servo::config::prefs::Preferences;
2020
use servo::servo_url::ServoUrl;
2121
use servo::user_content_manager::{UserContentManager, UserScript};
22-
use servo::webrender_api::units::DeviceVector2D;
2322
use servo::{
24-
EventLoopWaker, InputEvent, ScreenshotCaptureError, Scroll, WebDriverCommandMsg,
25-
WebDriverScriptCommand, WebDriverUserPromptAction, WheelEvent,
23+
EventLoopWaker, ScreenshotCaptureError, WebDriverCommandMsg, WebDriverScriptCommand,
24+
WebDriverUserPromptAction,
2625
};
2726
use url::Url;
2827
use winit::application::ApplicationHandler;
@@ -474,28 +473,16 @@ impl App {
474473
},
475474
WebDriverCommandMsg::InputEvent(webview_id, input_event, response_sender) => {
476475
if let Some(webview) = running_state.webview_by_id(webview_id) {
477-
// TODO: Scroll events triggered by wheel events should happen as
478-
// a default event action in the compositor.
479-
let scroll_event = match &input_event {
480-
InputEvent::Wheel(WheelEvent { delta, point }) => {
481-
let scroll = Scroll::Delta(
482-
DeviceVector2D::new(-delta.x as f32, -delta.y as f32).into(),
483-
);
484-
Some((scroll, *point))
485-
},
486-
_ => None,
487-
};
488-
489476
running_state.handle_webdriver_input_event(
490-
webview_id,
477+
webview,
491478
input_event,
492479
response_sender,
493480
);
494-
495-
if let Some((scroll, scroll_point)) = scroll_event {
496-
webview.notify_scroll_event(scroll, scroll_point);
497-
}
498-
}
481+
} else {
482+
error!(
483+
"Could not find WebView ({webview_id:?}) for WebDriver event: {input_event:?}"
484+
);
485+
};
499486
},
500487
WebDriverCommandMsg::ScriptCommand(_, ref webdriver_script_command) => {
501488
self.handle_webdriver_script_command(webdriver_script_command, running_state);

ports/servoshell/desktop/app_state.rs

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::collections::hash_map::Entry;
88
use std::mem;
99
use std::rc::Rc;
1010

11-
use crossbeam_channel::{Receiver, Sender};
11+
use crossbeam_channel::Receiver;
1212
use image::{DynamicImage, ImageFormat};
1313
use log::{error, info};
1414
use servo::base::generic_channel::GenericSender;
@@ -18,7 +18,7 @@ use servo::ipc_channel::ipc::IpcSender;
1818
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
1919
use servo::{
2020
AllowOrDenyRequest, AuthenticationRequest, EmbedderControl, EmbedderControlId,
21-
GamepadHapticEffectType, InputEvent, InputEventId, InputEventResult, JSValue, LoadStatus,
21+
GamepadHapticEffectType, InputEventId, InputEventResult, JSValue, LoadStatus,
2222
PermissionRequest, Servo, ServoDelegate, ServoError, SimpleDialog, TraversalId,
2323
WebDriverCommandMsg, WebDriverLoadStatus, WebDriverUserPrompt, WebView, WebViewBuilder,
2424
WebViewDelegate,
@@ -94,11 +94,6 @@ pub struct RunningAppStateInner {
9494
/// for the `exit_after_stable_image` option.
9595
achieved_stable_image: Rc<Cell<bool>>,
9696

97-
/// A [`HashMap`] of pending WebDriver events. It is the WebDriver embedder's responsibility
98-
/// to inform the WebDriver server when the event has been fully handled. This map is used
99-
/// to report back to WebDriver when that happens.
100-
pending_webdriver_events: HashMap<InputEventId, Sender<()>>,
101-
10297
/// A list of showing [`InputMethod`] interfaces.
10398
visible_input_methods: Vec<EmbedderControlId>,
10499
}
@@ -149,7 +144,6 @@ impl RunningAppState {
149144
dialog_amount_changed: false,
150145
pending_favicon_loads: Default::default(),
151146
achieved_stable_image: Default::default(),
152-
pending_webdriver_events: Default::default(),
153147
visible_input_methods: Default::default(),
154148
}),
155149
}
@@ -535,26 +529,6 @@ impl RunningAppState {
535529
}
536530
});
537531
}
538-
539-
pub(crate) fn handle_webdriver_input_event(
540-
&self,
541-
webview_id: WebViewId,
542-
input_event: InputEvent,
543-
response_sender: Option<Sender<()>>,
544-
) {
545-
let Some(webview) = self.webview_by_id(webview_id) else {
546-
error!("Could not find WebView ({webview_id:?}) for WebDriver event: {input_event:?}");
547-
return;
548-
};
549-
550-
let event_id = webview.notify_input_event(input_event);
551-
552-
if let Some(response_sender) = response_sender {
553-
self.inner_mut()
554-
.pending_webdriver_events
555-
.insert(event_id, response_sender);
556-
}
557-
}
558532
}
559533

560534
struct ServoShellServoDelegate;
@@ -674,7 +648,12 @@ impl WebViewDelegate for RunningAppState {
674648
.window
675649
.notify_input_event_handled(&webview, id, result);
676650

677-
if let Some(response_sender) = self.inner_mut().pending_webdriver_events.remove(&id) {
651+
if let Some(response_sender) = self
652+
.base()
653+
.pending_webdriver_events
654+
.borrow_mut()
655+
.remove(&id)
656+
{
678657
let _ = response_sender.send(());
679658
}
680659
}

ports/servoshell/egl/app_state.rs

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,25 @@ use std::rc::Rc;
77

88
use crossbeam_channel::Receiver;
99
use dpi::PhysicalSize;
10-
use euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
10+
use euclid::{Point2D, Rect, Scale, Size2D};
1111
use image::{DynamicImage, ImageFormat};
1212
use keyboard_types::{CompositionEvent, CompositionState, Key, KeyState, NamedKey};
1313
use log::{debug, error, info, warn};
1414
use raw_window_handle::{RawWindowHandle, WindowHandle};
1515
use servo::base::generic_channel::GenericSender;
1616
use servo::base::id::WebViewId;
17-
use servo::ipc_channel::ipc::IpcSender;
1817
use servo::servo_geometry::DeviceIndependentPixel;
1918
use servo::webrender_api::units::{
2019
DeviceIntRect, DeviceIntSize, DevicePixel, DevicePoint, DeviceVector2D,
2120
};
2221
use servo::{
2322
AllowOrDenyRequest, ContextMenuResult, EmbedderControl, EmbedderControlId, ImeEvent,
24-
InputEvent, KeyboardEvent, LoadStatus, MediaSessionActionType, MediaSessionEvent, MouseButton,
25-
MouseButtonAction, MouseButtonEvent, MouseMoveEvent, NavigationRequest, PermissionRequest,
26-
RefreshDriver, RenderingContext, ScreenGeometry, Scroll, Servo, ServoDelegate, ServoError,
27-
SimpleDialog, TouchEvent, TouchEventType, TouchId, TraversalId, WebDriverCommandMsg,
28-
WebDriverJSResult, WebDriverLoadStatus, WebDriverScriptCommand, WebDriverSenders, WebView,
29-
WebViewBuilder, WebViewDelegate, WindowRenderingContext,
23+
InputEvent, InputEventId, InputEventResult, KeyboardEvent, LoadStatus, MediaSessionActionType,
24+
MediaSessionEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent,
25+
NavigationRequest, PermissionRequest, RefreshDriver, RenderingContext, ScreenGeometry, Scroll,
26+
Servo, ServoDelegate, ServoError, TouchEvent, TouchEventType, TouchId, TraversalId,
27+
WebDriverCommandMsg, WebDriverLoadStatus, WebDriverScriptCommand, WebView, WebViewBuilder,
28+
WebViewDelegate, WindowRenderingContext,
3029
};
3130
use url::Url;
3231

@@ -266,6 +265,22 @@ impl WebViewDelegate for RunningAppState {
266265
self.inner_mut().need_present = true;
267266
}
268267

268+
fn notify_input_event_handled(
269+
&self,
270+
_webview: WebView,
271+
id: InputEventId,
272+
_result: InputEventResult,
273+
) {
274+
if let Some(response_sender) = self
275+
.base()
276+
.pending_webdriver_events
277+
.borrow_mut()
278+
.remove(&id)
279+
{
280+
let _ = response_sender.send(());
281+
}
282+
}
283+
269284
fn request_navigation(&self, _webview: WebView, navigation_request: NavigationRequest) {
270285
if self
271286
.callbacks
@@ -617,7 +632,7 @@ impl RunningAppState {
617632
}
618633

619634
/// WebDriver message handling methods
620-
pub fn webview_by_id(&self, id: WebViewId) -> Option<WebView> {
635+
fn webview_by_id(&self, id: WebViewId) -> Option<WebView> {
621636
self.inner().webviews.get(&id).cloned()
622637
}
623638

@@ -756,8 +771,21 @@ impl RunningAppState {
756771
info!("Handling GetViewportSize for webview {}", webview_id);
757772
let _ = response_sender.send(self.rendering_context.size2d());
758773
},
774+
WebDriverCommandMsg::InputEvent(webview_id, input_event, response_sender) => {
775+
if let Some(webview) = self.webview_by_id(webview_id) {
776+
self.handle_webdriver_input_event(
777+
webview,
778+
input_event,
779+
response_sender,
780+
);
781+
} else {
782+
error!(
783+
"Could not find WebView ({webview_id:?}) for WebDriver event: {input_event:?}"
784+
);
785+
};
786+
},
759787
_ => {
760-
info!("Received WebDriver command: {:?}", msg);
788+
info!("Received unsupported WebDriver command: {:?}", msg);
761789
},
762790
}
763791
}

ports/servoshell/running_app_state.rs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,32 @@
55
//! Shared state and methods for desktop and EGL implementations.
66
77
use std::cell::RefCell;
8+
use std::collections::HashMap;
89

10+
use crossbeam_channel::Sender;
911
use servo::base::generic_channel::GenericSender;
1012
use servo::base::id::WebViewId;
1113
use servo::ipc_channel::ipc::IpcSender;
12-
use servo::{TraversalId, WebDriverJSResult, WebDriverLoadStatus, WebDriverSenders};
14+
use servo::webrender_api::units::DeviceVector2D;
15+
use servo::{
16+
InputEvent, InputEventId, Scroll, TraversalId, WebDriverJSResult, WebDriverLoadStatus,
17+
WebDriverSenders, WebView, WheelEvent,
18+
};
1319

1420
pub struct RunningAppStateBase {
1521
pub(crate) webdriver_senders: RefCell<WebDriverSenders>,
22+
23+
/// A [`HashMap`] of pending WebDriver events. It is the WebDriver embedder's responsibility
24+
/// to inform the WebDriver server when the event has been fully handled. This map is used
25+
/// to report back to WebDriver when that happens.
26+
pub(crate) pending_webdriver_events: RefCell<HashMap<InputEventId, Sender<()>>>,
1627
}
1728

1829
impl RunningAppStateBase {
1930
pub fn new() -> Self {
2031
Self {
2132
webdriver_senders: RefCell::default(),
33+
pending_webdriver_events: Default::default(),
2234
}
2335
}
2436
}
@@ -67,4 +79,34 @@ pub trait RunningAppStateTrait {
6779
.borrow_mut()
6880
.script_evaluation_interrupt_sender = sender;
6981
}
82+
83+
fn handle_webdriver_input_event(
84+
&self,
85+
webview: WebView,
86+
input_event: InputEvent,
87+
response_sender: Option<Sender<()>>,
88+
) {
89+
// TODO: Scroll events triggered by wheel events should happen as
90+
// a default event action in the compositor.
91+
let scroll_event = match &input_event {
92+
InputEvent::Wheel(WheelEvent { delta, point }) => {
93+
let scroll =
94+
Scroll::Delta(DeviceVector2D::new(-delta.x as f32, -delta.y as f32).into());
95+
Some((scroll, *point))
96+
},
97+
_ => None,
98+
};
99+
100+
let event_id = webview.notify_input_event(input_event);
101+
if let Some(response_sender) = response_sender {
102+
self.base()
103+
.pending_webdriver_events
104+
.borrow_mut()
105+
.insert(event_id, response_sender);
106+
}
107+
108+
if let Some((scroll, scroll_point)) = scroll_event {
109+
webview.notify_scroll_event(scroll, scroll_point);
110+
}
111+
}
70112
}

0 commit comments

Comments
 (0)