diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 7be3b333563..fa8f6966bb4 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -27,10 +27,10 @@ use constellation_traits::{EmbedderToConstellationMessage, PaintMetricEvent}; use crossbeam_channel::{Receiver, Sender}; use dpi::PhysicalSize; use embedder_traits::{ - CompositorHitTestResult, Cursor, InputEvent, MouseButtonEvent, MouseMoveEvent, ShutdownState, - UntrustedNodeAddress, ViewportDetails, WheelDelta, WheelEvent, WheelMode, + CompositorHitTestResult, Cursor, InputEvent, ShutdownState, UntrustedNodeAddress, + ViewportDetails, }; -use euclid::{Point2D, Rect, Scale, Size2D, Transform3D, Vector2D}; +use euclid::{Point2D, Rect, Scale, Size2D, Transform3D}; use ipc_channel::ipc::{self, IpcSharedMemory}; use libc::c_void; use log::{debug, info, trace, warn}; @@ -672,64 +672,6 @@ impl IOCompositor { } }, - CompositorMsg::WebDriverMouseButtonEvent( - webview_id, - action, - button, - x, - y, - message_id, - ) => { - let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else { - warn!("Handling input event for unknown webview: {webview_id}"); - return; - }; - let dppx = webview_renderer.device_pixels_per_page_pixel(); - let point = dppx.transform_point(Point2D::new(x, y)); - webview_renderer.dispatch_point_input_event( - InputEvent::MouseButton(MouseButtonEvent::new(action, button, point)) - .with_webdriver_message_id(message_id), - ); - }, - - CompositorMsg::WebDriverMouseMoveEvent(webview_id, x, y, message_id) => { - let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else { - warn!("Handling input event for unknown webview: {webview_id}"); - return; - }; - let dppx = webview_renderer.device_pixels_per_page_pixel(); - let point = dppx.transform_point(Point2D::new(x, y)); - webview_renderer.dispatch_point_input_event( - InputEvent::MouseMove(MouseMoveEvent::new(point)) - .with_webdriver_message_id(message_id), - ); - }, - - CompositorMsg::WebDriverWheelScrollEvent(webview_id, x, y, dx, dy, message_id) => { - let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else { - warn!("Handling input event for unknown webview: {webview_id}"); - return; - }; - // The sign of wheel delta value definition in uievent - // is inverted compared to `winit`s wheel delta. Hence, - // here we invert the sign to mimic wheel scroll - // implementation in `headed_window.rs`. - let delta = WheelDelta { - x: -dx, - y: -dy, - z: 0.0, - mode: WheelMode::DeltaPixel, - }; - let dppx = webview_renderer.device_pixels_per_page_pixel(); - let point = dppx.transform_point(Point2D::new(x, y)); - let scroll_delta = dppx.transform_vector(Vector2D::new(dx as f32, dy as f32)); - webview_renderer.dispatch_point_input_event( - InputEvent::Wheel(WheelEvent::new(delta, point)) - .with_webdriver_message_id(message_id), - ); - webview_renderer.on_webdriver_wheel_action(scroll_delta, point); - }, - CompositorMsg::SendInitialTransaction(pipeline) => { let mut txn = Transaction::new(); txn.set_display_list(WebRenderEpoch(0), (pipeline, Default::default())); diff --git a/components/compositing/tracing.rs b/components/compositing/tracing.rs index f51bf77013d..c4cf76c1e2b 100644 --- a/components/compositing/tracing.rs +++ b/components/compositing/tracing.rs @@ -40,9 +40,6 @@ mod from_constellation { Self::NewWebRenderFrameReady(..) => target!("NewWebRenderFrameReady"), Self::PipelineExited(..) => target!("PipelineExited"), Self::LoadComplete(..) => target!("LoadComplete"), - Self::WebDriverMouseButtonEvent(..) => target!("WebDriverMouseButtonEvent"), - Self::WebDriverMouseMoveEvent(..) => target!("WebDriverMouseMoveEvent"), - Self::WebDriverWheelScrollEvent(..) => target!("WebDriverWheelScrollEvent"), Self::SendInitialTransaction(..) => target!("SendInitialTransaction"), Self::SendScrollNode(..) => target!("SendScrollNode"), Self::SendDisplayList { .. } => target!("SendDisplayList"), diff --git a/components/compositing/webview_renderer.rs b/components/compositing/webview_renderer.rs index 108ab13c95c..8a55634cbd4 100644 --- a/components/compositing/webview_renderer.rs +++ b/components/compositing/webview_renderer.rs @@ -792,22 +792,6 @@ impl WebViewRenderer { })); } - /// Push scroll pending event when receiving wheel action from webdriver - pub(crate) fn on_webdriver_wheel_action( - &mut self, - scroll_delta: Vector2D, - point: Point2D, - ) { - if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown { - return; - } - - let scroll_location = - ScrollLocation::Delta(LayoutVector2D::from_untyped(scroll_delta.to_untyped())); - let cursor = DeviceIntPoint::new(point.x as i32, point.y as i32); - self.on_scroll_window_event(scroll_location, cursor) - } - /// Process pending scroll events for this [`WebViewRenderer`]. Returns a tuple containing: /// /// - A boolean that is true if a zoom occurred. diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 19d273d84c8..25ad7c775de 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -1468,6 +1468,9 @@ where ) } }, + EmbedderToConstellationMessage::SetWebDriverResponseSender(sender) => { + self.webdriver.input_command_response_sender = Some(sender); + }, } } @@ -1850,7 +1853,6 @@ where .send(WebDriverCommandResponse { id: msg_id }) .unwrap_or_else(|_| { warn!("Failed to send WebDriverInputComplete {:?}", msg_id); - self.webdriver.input_command_response_sender = None; }); } else { warn!("No WebDriver input_command_response_sender"); @@ -4616,14 +4618,7 @@ where } } }, - WebDriverCommandMsg::KeyboardAction( - browsing_context_id, - key_event, - msg_id, - response_sender, - ) => { - self.webdriver.input_command_response_sender = Some(response_sender); - + WebDriverCommandMsg::KeyboardAction(browsing_context_id, key_event, msg_id) => { let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) { Some(browsing_context) => browsing_context.pipeline_id, None => { @@ -4649,50 +4644,14 @@ where self.handle_send_error(pipeline_id, e) } }, - WebDriverCommandMsg::MouseButtonAction( - webview_id, - mouse_event_type, - mouse_button, - x, - y, - msg_id, - response_sender, - ) => { - self.webdriver.input_command_response_sender = Some(response_sender); - - self.compositor_proxy - .send(CompositorMsg::WebDriverMouseButtonEvent( - webview_id, - mouse_event_type, - mouse_button, - x, - y, - msg_id, - )); + WebDriverCommandMsg::MouseButtonAction(..) => { + unreachable!("This command should be send directly to the embedder."); }, - WebDriverCommandMsg::MouseMoveAction(webview_id, x, y, msg_id, response_sender) => { - self.webdriver.input_command_response_sender = Some(response_sender); - - self.compositor_proxy - .send(CompositorMsg::WebDriverMouseMoveEvent( - webview_id, x, y, msg_id, - )); + WebDriverCommandMsg::MouseMoveAction(..) => { + unreachable!("This command should be send directly to the embedder."); }, - WebDriverCommandMsg::WheelScrollAction( - webview_id, - x, - y, - delta_x, - delta_y, - msg_id, - response_sender, - ) => { - self.webdriver.input_command_response_sender = Some(response_sender); - - self.compositor_proxy - .send(CompositorMsg::WebDriverWheelScrollEvent( - webview_id, x, y, delta_x, delta_y, msg_id, - )); + WebDriverCommandMsg::WheelScrollAction(..) => { + unreachable!("This command should be send directly to the embedder."); }, WebDriverCommandMsg::TakeScreenshot(webview_id, rect, response_sender) => { self.compositor_proxy.send(CompositorMsg::CreatePng( diff --git a/components/constellation/tracing.rs b/components/constellation/tracing.rs index d164319a733..d7bc03595ab 100644 --- a/components/constellation/tracing.rs +++ b/components/constellation/tracing.rs @@ -77,6 +77,7 @@ mod from_compositor { Self::EvaluateJavaScript(..) => target!("EvaluateJavaScript"), Self::CreateMemoryReport(..) => target!("CreateMemoryReport"), Self::SendImageKeysForPipeline(..) => target!("SendImageKeysForPipeline"), + Self::SetWebDriverResponseSender(..) => target!("SetWebDriverResponseSender"), } } } diff --git a/components/shared/compositing/lib.rs b/components/shared/compositing/lib.rs index 513ba116c4c..12507c74ea0 100644 --- a/components/shared/compositing/lib.rs +++ b/components/shared/compositing/lib.rs @@ -8,10 +8,7 @@ use std::fmt::{Debug, Error, Formatter}; use base::id::{PipelineId, WebViewId}; use crossbeam_channel::Sender; -use embedder_traits::{ - AnimationState, EventLoopWaker, MouseButton, MouseButtonAction, TouchEventResult, - WebDriverMessageId, -}; +use embedder_traits::{AnimationState, EventLoopWaker, TouchEventResult}; use euclid::Rect; use ipc_channel::ipc::IpcSender; use log::warn; @@ -105,20 +102,6 @@ pub enum CompositorMsg { PipelineExited(WebViewId, PipelineId, PipelineExitSource), /// The load of a page has completed LoadComplete(WebViewId), - /// WebDriver mouse button event - WebDriverMouseButtonEvent( - WebViewId, - MouseButtonAction, - MouseButton, - f32, - f32, - Option, - ), - /// WebDriver mouse move event - WebDriverMouseMoveEvent(WebViewId, f32, f32, Option), - // Webdriver wheel scroll event - WebDriverWheelScrollEvent(WebViewId, f32, f32, f64, f64, Option), - /// Inform WebRender of the existence of this pipeline. SendInitialTransaction(WebRenderPipelineId), /// Perform a scroll operation. diff --git a/components/shared/constellation/lib.rs b/components/shared/constellation/lib.rs index 9e31e99c58b..225b6ab5f17 100644 --- a/components/shared/constellation/lib.rs +++ b/components/shared/constellation/lib.rs @@ -20,7 +20,7 @@ use base::cross_process_instant::CrossProcessInstant; use base::id::{MessagePortId, PipelineId, WebViewId}; use embedder_traits::{ CompositorHitTestResult, Cursor, InputEvent, JavaScriptEvaluationId, MediaSessionActionType, - Theme, ViewportDetails, WebDriverCommandMsg, + Theme, ViewportDetails, WebDriverCommandMsg, WebDriverCommandResponse, }; pub use from_script_message::*; use ipc_channel::ipc::IpcSender; @@ -96,6 +96,8 @@ pub enum EmbedderToConstellationMessage { CreateMemoryReport(IpcSender), /// Sends the generated image key to the image cache associated with this pipeline. SendImageKeysForPipeline(PipelineId, Vec), + /// Set WebDriver input event handled sender. + SetWebDriverResponseSender(IpcSender), } /// A description of a paint metric that is sent from the Servo renderer to the diff --git a/components/shared/embedder/webdriver.rs b/components/shared/embedder/webdriver.rs index 8a29cabb5df..0d6e982869f 100644 --- a/components/shared/embedder/webdriver.rs +++ b/components/shared/embedder/webdriver.rs @@ -30,6 +30,9 @@ pub struct WebDriverMessageId(pub usize); /// Messages to the constellation originating from the WebDriver server. #[derive(Debug, Deserialize, Serialize)] pub enum WebDriverCommandMsg { + /// Used in the initialization of the WebDriver server to set the sender for sending responses + /// back to the WebDriver client. It is set to constellation for now + SetWebDriverResponseSender(IpcSender), /// Get the window size. GetWindowRect(WebViewId, IpcSender), /// Get the viewport size. @@ -53,7 +56,6 @@ pub enum WebDriverCommandMsg { KeyboardEvent, // Should never be None. Option, - IpcSender, ), /// Act as if the mouse was clicked in the browsing context with the given ID. MouseButtonAction( @@ -64,7 +66,6 @@ pub enum WebDriverCommandMsg { f32, // Should never be None. Option, - IpcSender, ), /// Act as if the mouse was moved in the browsing context with the given ID. MouseMoveAction( @@ -74,7 +75,6 @@ pub enum WebDriverCommandMsg { // None if it's not the last `perform_pointer_move` since we only // expect one response from constellation for each tick actions. Option, - IpcSender, ), /// Act as if the mouse wheel is scrolled in the browsing context given the given ID. WheelScrollAction( @@ -86,7 +86,6 @@ pub enum WebDriverCommandMsg { // None if it's not the last `perform_wheel_scroll` since we only // expect one response from constellation for each tick actions. Option, - IpcSender, ), /// Set the window size. SetWindowSize( diff --git a/components/webdriver_server/actions.rs b/components/webdriver_server/actions.rs index 8c67c392074..8b2f59e5dbc 100644 --- a/components/webdriver_server/actions.rs +++ b/components/webdriver_server/actions.rs @@ -7,7 +7,6 @@ use std::thread; use std::time::{Duration, Instant}; use base::id::BrowsingContextId; -use constellation_traits::EmbedderToConstellationMessage; use embedder_traits::{MouseButtonAction, WebDriverCommandMsg, WebDriverScriptCommand}; use ipc_channel::ipc; use keyboard_types::webdriver::KeyInputState; @@ -178,7 +177,7 @@ impl Handler { // // Wait for num_pending_actions number of responses for _ in 0..self.num_pending_actions.get() { - match self.constellation_receiver.recv() { + match self.webdriver_response_receiver.recv() { Ok(response) => { let current_waiting_id = self .current_action_id @@ -316,11 +315,8 @@ impl Handler { self.session().unwrap().browsing_context_id, keyboard_event, msg_id, - self.constellation_sender.clone(), ); - self.constellation_chan - .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) - .unwrap(); + let _ = self.send_message_to_embedder(cmd_msg); } /// @@ -358,11 +354,8 @@ impl Handler { self.session().unwrap().browsing_context_id, keyboard_event, msg_id, - self.constellation_sender.clone(), ); - self.constellation_chan - .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) - .unwrap(); + let _ = self.send_message_to_embedder(cmd_msg); } } @@ -390,11 +383,8 @@ impl Handler { pointer_input_state.x as f32, pointer_input_state.y as f32, msg_id, - self.constellation_sender.clone(), ); - self.constellation_chan - .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) - .unwrap(); + let _ = self.send_message_to_embedder(cmd_msg); } /// @@ -439,11 +429,8 @@ impl Handler { pointer_input_state.x as f32, pointer_input_state.y as f32, msg_id, - self.constellation_sender.clone(), ); - self.constellation_chan - .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) - .unwrap(); + let _ = self.send_message_to_embedder(cmd_msg); } /// @@ -567,11 +554,8 @@ impl Handler { x as f32, y as f32, msg_id, - self.constellation_sender.clone(), ); - self.constellation_chan - .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) - .unwrap(); + let _ = self.send_message_to_embedder(cmd_msg); // Step 7.3 pointer_input_state.x = x; pointer_input_state.y = y; @@ -707,11 +691,8 @@ impl Handler { delta_x as f64, delta_y as f64, msg_id, - self.constellation_sender.clone(), ); - self.constellation_chan - .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) - .unwrap(); + let _ = self.send_message_to_embedder(cmd_msg); curr_delta_x += delta_x; curr_delta_y += delta_y; diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index e06879cab60..4710c23dd26 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -127,12 +127,15 @@ pub fn start_server( constellation_chan_deprecated: Sender, embedder_sender: Sender, event_loop_waker: Box, + webdriver_response_receiver: IpcReceiver, ) { let handler = Handler::new( constellation_chan_deprecated, embedder_sender, event_loop_waker, + webdriver_response_receiver, ); + thread::Builder::new() .name("WebDriverHttpServer".to_owned()) .spawn(move || { @@ -242,12 +245,8 @@ struct Handler { /// TODO: change name to constellation_sender constellation_chan: Sender, - /// The IPC sender which we can clone and pass along to the constellation - /// TODO: change name to webdriver_response_sender - constellation_sender: IpcSender, - /// Receiver notification from the constellation when a command is completed - constellation_receiver: IpcReceiver, + webdriver_response_receiver: IpcReceiver, id_generator: WebDriverMessageIdGenerator, @@ -474,6 +473,7 @@ impl Handler { constellation_chan: Sender, embedder_sender: Sender, event_loop_waker: Box, + webdriver_response_receiver: IpcReceiver, ) -> Handler { // Create a pair of both an IPC and a threaded channel, // keep the IPC sender to clone and pass to the constellation for each load, @@ -484,8 +484,6 @@ impl Handler { let (sender, load_status_receiver) = unbounded(); ROUTER.route_ipc_receiver_to_crossbeam_sender(receiver, sender); - let (constellation_sender, constellation_receiver) = ipc::channel().unwrap(); - Handler { load_status_sender, load_status_receiver, @@ -493,8 +491,7 @@ impl Handler { embedder_sender, event_loop_waker, constellation_chan, - constellation_sender, - constellation_receiver, + webdriver_response_receiver, id_generator: WebDriverMessageIdGenerator::new(), current_action_id: Cell::new(None), num_pending_actions: Cell::new(0), @@ -1836,9 +1833,7 @@ impl Handler { sender, ); let cmd_msg = WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd); - self.constellation_chan - .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) - .unwrap(); + self.send_message_to_embedder(cmd_msg)?; // TODO: distinguish the not found and not focusable cases // File input and non-typeable form control should have @@ -1853,9 +1848,7 @@ impl Handler { // send keys command being two separate messages, // so the constellation may have changed state between them. let cmd_msg = WebDriverCommandMsg::SendKeys(browsing_context_id, input_events); - self.constellation_chan - .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) - .unwrap(); + self.send_message_to_embedder(cmd_msg)?; Ok(WebDriverResponse::Void) } diff --git a/ports/servoshell/Cargo.toml b/ports/servoshell/Cargo.toml index 91f8754ead8..ba63ef419a8 100644 --- a/ports/servoshell/Cargo.toml +++ b/ports/servoshell/Cargo.toml @@ -62,6 +62,7 @@ euclid = { workspace = true } getopts = { workspace = true } hitrace = { workspace = true, optional = true } image = { workspace = true } +ipc-channel = { workspace = true } keyboard-types = { workspace = true } libc = { workspace = true } libservo = { path = "../../components/servo", features = ["background_hang_monitor", "bluetooth", "testbinding"] } @@ -78,7 +79,6 @@ webdriver_server = { path = "../../components/webdriver_server" } [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.15" -ipc-channel = { workspace = true } jni = "0.21.1" [target.'cfg(not(target_os = "android"))'.dependencies] diff --git a/ports/servoshell/desktop/app.rs b/ports/servoshell/desktop/app.rs index 8e811d28513..d2e010bc88d 100644 --- a/ports/servoshell/desktop/app.rs +++ b/ports/servoshell/desktop/app.rs @@ -12,14 +12,21 @@ use std::time::Instant; use std::{env, fs}; use ::servo::ServoBuilder; +use constellation_traits::EmbedderToConstellationMessage; use crossbeam_channel::unbounded; +use euclid::{Point2D, Vector2D}; +use ipc_channel::ipc; use log::{info, trace, warn}; use net::protocols::ProtocolRegistry; use servo::config::opts::Opts; use servo::config::prefs::Preferences; use servo::servo_url::ServoUrl; use servo::user_content_manager::{UserContentManager, UserScript}; -use servo::{EventLoopWaker, WebDriverCommandMsg}; +use servo::webrender_api::ScrollLocation; +use servo::{ + EventLoopWaker, InputEvent, MouseButtonEvent, MouseMoveEvent, WebDriverCommandMsg, WheelDelta, + WheelEvent, WheelMode, +}; use url::Url; use winit::application::ApplicationHandler; use winit::event::WindowEvent; @@ -162,15 +169,25 @@ impl App { // Initialize WebDriver server here before `servo` is moved. let webdriver_receiver = self.servoshell_preferences.webdriver_port.map(|port| { let (embedder_sender, embedder_receiver) = unbounded(); + let (webdriver_response_sender, webdriver_response_receiver) = ipc::channel().unwrap(); + + // Set the WebDriver response sender to constellation. + // TODO: consider using Servo API to notify embedder about input events completions + servo + .constellation_sender() + .send(EmbedderToConstellationMessage::SetWebDriverResponseSender( + webdriver_response_sender, + )) + .unwrap_or_else(|_| { + warn!("Failed to set WebDriver response sender in constellation"); + }); - // TODO: WebDriver will no longer need this channel once all WebDriver - // commands are executed via the Servo API. - let constellation_sender_deprecated = servo.constellation_sender(); webdriver_server::start_server( port, - constellation_sender_deprecated, + servo.constellation_sender(), embedder_sender, self.waker.clone(), + webdriver_response_receiver, ); embedder_receiver @@ -331,6 +348,9 @@ impl App { while let Ok(msg) = webdriver_receiver.try_recv() { match msg { + WebDriverCommandMsg::SetWebDriverResponseSender(..) => { + running_state.forward_webdriver_command(msg); + }, WebDriverCommandMsg::IsWebViewOpen(webview_id, sender) => { let context = running_state.webview_by_id(webview_id); @@ -338,8 +358,8 @@ impl App { warn!("Failed to send response of IsWebViewOpein: {error}"); } }, - webdriver_msg @ WebDriverCommandMsg::IsBrowsingContextOpen(..) => { - running_state.forward_webdriver_command(webdriver_msg); + WebDriverCommandMsg::IsBrowsingContextOpen(..) => { + running_state.forward_webdriver_command(msg); }, WebDriverCommandMsg::NewWebView(response_sender, load_status_sender) => { let new_webview = @@ -434,11 +454,68 @@ impl App { webview.go_forward(1); } }, - WebDriverCommandMsg::SendKeys(..) | - WebDriverCommandMsg::KeyboardAction(..) | - WebDriverCommandMsg::MouseButtonAction(..) | - WebDriverCommandMsg::MouseMoveAction(..) | - WebDriverCommandMsg::WheelScrollAction(..) | + // Key events don't need hit test so can be forwarded to constellation for now + WebDriverCommandMsg::SendKeys(..) => { + running_state.forward_webdriver_command(msg); + }, + WebDriverCommandMsg::KeyboardAction(..) => { + running_state.forward_webdriver_command(msg); + }, + WebDriverCommandMsg::MouseButtonAction( + webview_id, + mouse_event_type, + mouse_button, + x, + y, + webdriver_message_id, + ) => { + if let Some(webview) = running_state.webview_by_id(webview_id) { + webview.notify_input_event( + InputEvent::MouseButton(MouseButtonEvent::new( + mouse_event_type, + mouse_button, + Point2D::new(x, y), + )) + .with_webdriver_message_id(webdriver_message_id), + ); + } + }, + WebDriverCommandMsg::MouseMoveAction(webview_id, x, y, webdriver_message_id) => { + if let Some(webview) = running_state.webview_by_id(webview_id) { + webview.notify_input_event( + InputEvent::MouseMove(MouseMoveEvent::new(Point2D::new(x, y))) + .with_webdriver_message_id(webdriver_message_id), + ); + } + }, + WebDriverCommandMsg::WheelScrollAction( + webview_id, + x, + y, + dx, + dy, + webdriver_message_id, + ) => { + if let Some(webview) = running_state.webview_by_id(webview_id) { + let delta = WheelDelta { + x: -dx, + y: -dy, + z: 0.0, + mode: WheelMode::DeltaPixel, + }; + + let point = Point2D::new(x, y); + let scroll_location = + ScrollLocation::Delta(Vector2D::new(dx as f32, dy as f32)); + + webview.notify_input_event( + InputEvent::Wheel(WheelEvent::new(delta, point)) + .with_webdriver_message_id(webdriver_message_id), + ); + + webview.notify_scroll_event(scroll_location, point.to_i32()); + } + }, WebDriverCommandMsg::ScriptCommand(..) | WebDriverCommandMsg::TakeScreenshot(..) => { warn!(