From d3bd244ed4d1284c8a4787cc26554f7b501a2b34 Mon Sep 17 00:00:00 2001 From: Tony Date: Thu, 21 Nov 2024 16:34:27 +0800 Subject: [PATCH 1/2] Allow setting init script through cli --- src/config.rs | 10 +++++++++ src/verso.rs | 3 +++ src/webview.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++---- src/window.rs | 9 ++++++++ 4 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/config.rs b/src/config.rs index cfdcb05..e9686e3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -41,6 +41,8 @@ pub struct CliArgs { pub resource_dir: Option, /// Override the user agent pub user_agent: Option, + /// Script to run on document started to load + pub init_script: Option, /// Initial window's zoom level pub zoom_level: Option, } @@ -101,6 +103,12 @@ fn parse_cli_args() -> Result { "Override the user agent", "'VersoView/1.0'", ); + opts.optopt( + "", + "init-script", + "Script to run on document started to load", + "console.log('hello world')", + ); opts.optopt( "w", @@ -173,6 +181,7 @@ fn parse_cli_args() -> Result { }; let user_agent = matches.opt_str("user-agent"); + let init_script = matches.opt_str("init-script"); let mut window_attributes = winit::window::Window::default_attributes(); @@ -237,6 +246,7 @@ fn parse_cli_args() -> Result { devtools_port, profiler_settings, user_agent, + init_script, zoom_level, }) } diff --git a/src/verso.rs b/src/verso.rs index 75e5cb9..803b6cd 100644 --- a/src/verso.rs +++ b/src/verso.rs @@ -114,6 +114,7 @@ impl Verso { .clone() .unwrap_or_else(|| default_user_agent_string().to_string()) .into(); + let init_script = config.args.init_script.clone(); let zoom_level = config.args.zoom_level; config.init(); @@ -391,6 +392,8 @@ impl Verso { window.create_webview(&constellation_sender, initial_url.into()); } + window.set_init_script(init_script); + let mut windows = HashMap::new(); windows.insert(window.id(), (window, webrender_document)); diff --git a/src/webview.rs b/src/webview.rs index 68513a0..54bd893 100644 --- a/src/webview.rs +++ b/src/webview.rs @@ -5,7 +5,9 @@ use crossbeam_channel::Sender; use embedder_traits::{CompositorEventVariant, EmbedderMsg, PromptDefinition}; use ipc_channel::ipc; use script_traits::{ - webdriver_msg::{WebDriverJSResult, WebDriverScriptCommand}, + webdriver_msg::{ + WebDriverJSError, WebDriverJSResult, WebDriverJSValue, WebDriverScriptCommand, + }, TraversalDirection, WebDriverCommandMsg, }; use servo_url::ServoUrl; @@ -27,7 +29,7 @@ pub struct WebView { } impl WebView { - /// Create a web view from Winit window. + /// Create a web view. pub fn new(webview_id: WebViewId, rect: DeviceIntRect) -> Self { Self { webview_id, rect } } @@ -68,8 +70,7 @@ impl Window { ) { log::trace!("Verso WebView {webview_id:?} is handling Embedder message: {message:?}",); match message { - EmbedderMsg::LoadStart - | EmbedderMsg::HeadParsed + EmbedderMsg::HeadParsed | EmbedderMsg::WebViewOpened(_) | EmbedderMsg::WebViewClosed(_) => { // Most WebView messages are ignored because it's done by compositor. @@ -82,6 +83,11 @@ impl Window { w ); } + EmbedderMsg::LoadStart => { + if let Some(init_script) = &self.init_script { + execute_script_async(&sender, &webview_id, init_script); + } + } EmbedderMsg::LoadComplete => { self.window.request_redraw(); send_to_constellation(sender, ConstellationMsg::FocusWebView(webview_id)); @@ -326,3 +332,47 @@ impl Window { false } } + +/// Blocking execute a script on this webview +pub fn execute_script( + constellation_sender: &Sender, + webview: &WebViewId, + js: impl ToString, +) -> Result { + let (result_sender, result_receiver) = ipc::channel::().unwrap(); + send_to_constellation( + constellation_sender, + ConstellationMsg::WebDriverCommand(script_traits::WebDriverCommandMsg::ScriptCommand( + webview.0, + WebDriverScriptCommand::ExecuteScript(js.to_string(), result_sender), + )), + ); + result_receiver.recv().unwrap() +} + +/// Execute a script asynchronous on this webview +pub fn execute_script_async( + constellation_sender: &Sender, + webview: &WebViewId, + js: impl ToString, +) { + execute_script_async_with_callback(constellation_sender, webview, js, |_| {}) +} + +/// Execute a script asynchronous on this webview with a callback processing the result +pub fn execute_script_async_with_callback( + constellation_sender: &Sender, + webview: &WebViewId, + js: impl ToString, + callback: impl FnOnce(Result) + Send + 'static, +) { + let (result_sender, result_receiver) = ipc::channel::().unwrap(); + send_to_constellation( + constellation_sender, + ConstellationMsg::WebDriverCommand(script_traits::WebDriverCommandMsg::ScriptCommand( + webview.0, + WebDriverScriptCommand::ExecuteAsyncScript(js.to_string(), result_sender), + )), + ); + std::thread::spawn(move || callback(result_receiver.recv().unwrap())); +} diff --git a/src/window.rs b/src/window.rs index 35eeb74..6003225 100644 --- a/src/window.rs +++ b/src/window.rs @@ -52,6 +52,8 @@ pub struct Window { pub(crate) panel: Option, /// The WebView of this window. pub(crate) webview: Option, + /// Script to run on document started to load + pub(crate) init_script: Option, /// The mouse physical position in the web view. mouse_position: Cell>>, /// Modifiers state of the keyboard. @@ -118,6 +120,7 @@ impl Window { surface, panel: None, webview: None, + init_script: None, mouse_position: Default::default(), modifiers_state: Cell::new(ModifiersState::default()), history: vec![], @@ -162,6 +165,7 @@ impl Window { surface, panel: None, webview: None, + init_script: None, mouse_position: Default::default(), modifiers_state: Cell::new(ModifiersState::default()), history: vec![], @@ -232,6 +236,11 @@ impl Window { log::debug!("Verso Window {:?} adds webview {}", self.id(), webview_id); } + /// Set the init script that runs on document started to load. + pub fn set_init_script(&mut self, init_script: Option) { + self.init_script = init_script; + } + /// Handle Winit window event and return a boolean to indicate if the compositor should repaint immediately. pub fn handle_winit_window_event( &mut self, From 15d0643b5796ff2c80e8dbac353f8fe770c2d881 Mon Sep 17 00:00:00 2001 From: Tony Date: Thu, 21 Nov 2024 19:21:53 +0800 Subject: [PATCH 2/2] Add userscripts directory as well --- src/config.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/config.rs b/src/config.rs index e9686e3..ac78436 100644 --- a/src/config.rs +++ b/src/config.rs @@ -43,6 +43,8 @@ pub struct CliArgs { pub user_agent: Option, /// Script to run on document started to load pub init_script: Option, + /// The directory to load userscripts from + pub userscripts_directory: Option, /// Initial window's zoom level pub zoom_level: Option, } @@ -109,6 +111,12 @@ fn parse_cli_args() -> Result { "Script to run on document started to load", "console.log('hello world')", ); + opts.optopt( + "", + "userscripts-directory", + "The directory to load userscripts from", + "resources/user-agent-js/", + ); opts.optopt( "w", @@ -182,6 +190,7 @@ fn parse_cli_args() -> Result { let user_agent = matches.opt_str("user-agent"); let init_script = matches.opt_str("init-script"); + let userscripts_directory = matches.opt_str("userscripts-directory"); let mut window_attributes = winit::window::Window::default_attributes(); @@ -247,6 +256,7 @@ fn parse_cli_args() -> Result { profiler_settings, user_agent, init_script, + userscripts_directory, zoom_level, }) } @@ -267,6 +277,10 @@ impl Config { opts.time_profiler_trace_path = profiler_settings.trace_path.clone(); } + if let Some(ref userscripts_directory) = args.userscripts_directory { + opts.userscripts = Some(userscripts_directory.clone()); + } + let resource_dir = args.resource_dir.clone().unwrap_or(resources_dir_path()); Self {