From e534c7d4610807fb1a93f17085ec6ada61a4a342 Mon Sep 17 00:00:00 2001 From: Jonathan Schwender <55576758+jschwe@users.noreply.github.com> Date: Wed, 2 Oct 2024 06:27:18 +0200 Subject: [PATCH] ohos: Allow passing arguments to servoshell (#33588) * ohos: Bump minimum CMake version By bumping the minimum CMake version, we avoid a deprecation warning. The OH 4.0 SDK ships with CMake 3.16, so we can be sure that we have CMake 3.16 or newer available. Signed-off-by: Jonathan Schwender * ohos: Allow passing arguments to servoshell Allows passing options passed via `wants` to the Ability through to servoshell. This allows easier debugging, either by calling servoshell from a test app, or from the commandline, e.g. ``` hdc shell aa start -a EntryAbility -b org.servo.servoshell -U "https://www.wikipedia.org" \ --pb dom.webgpu.enabled true \ --ps dom.webgpu.wgpu_backend "gl" \ --pi layout.threads 4 ``` Note: While the OH `wants` API differentiates between boolean, string and integer values, we convert everything back to strings, so we can reuse the same parsing code as the desktop servoshell. Signed-off-by: Jonathan Schwender Signed-off-by: Jonathan Schwender --------- Signed-off-by: Jonathan Schwender Signed-off-by: Jonathan Schwender --- ports/servoshell/egl/ohos.rs | 1 + ports/servoshell/egl/ohos/simpleservo.rs | 54 +++++++++++++++++++ .../entry/src/main/cpp/CMakeLists.txt | 2 +- .../main/ets/entryability/EntryAbility.ets | 25 ++++++++- .../entry/src/main/ets/pages/Index.ets | 14 +++-- 5 files changed, 90 insertions(+), 6 deletions(-) diff --git a/ports/servoshell/egl/ohos.rs b/ports/servoshell/egl/ohos.rs index 363125dc287..188b359080e 100644 --- a/ports/servoshell/egl/ohos.rs +++ b/ports/servoshell/egl/ohos.rs @@ -51,6 +51,7 @@ pub struct InitOpts { /// Path to application data bundled with the servo app, e.g. web-pages. pub resource_dir: String, pub display_density: f64, + pub commandline_args: String, } #[derive(Debug)] diff --git a/ports/servoshell/egl/ohos/simpleservo.rs b/ports/servoshell/egl/ohos/simpleservo.rs index 4dad52c0c75..35ab6028d8b 100644 --- a/ports/servoshell/egl/ohos/simpleservo.rs +++ b/ports/servoshell/egl/ohos/simpleservo.rs @@ -17,6 +17,8 @@ use servo::embedder_traits::resources; /// and that perform_updates need to be called pub use servo::embedder_traits::EventLoopWaker; use servo::euclid::Size2D; +use servo::servo_config::opts; +use servo::servo_config::opts::ArgumentParsingResult; use servo::servo_url::ServoUrl; use servo::webrender_traits::RenderingContext; use servo::{self, gl, Servo}; @@ -43,6 +45,58 @@ pub fn init( crate::init_tracing(); let resource_dir = PathBuf::from(&options.resource_dir).join("servo"); resources::set(Box::new(ResourceReaderInstance::new(resource_dir))); + let mut args = vec!["servoshell".to_string()]; + // It would be nice if `from_cmdline_args()` could accept str slices, to avoid allocations here. + // Then again, this code could and maybe even should be disabled in production builds. + let split_args: Vec = options + .commandline_args + .split("\u{1f}") + .map(|arg| arg.to_string()) + .collect(); + args.extend(split_args); + debug!("Servo commandline args: {:?}", args); + + let mut opts = getopts::Options::new(); + opts.optopt( + "u", + "user-agent", + "Set custom user agent string (or ios / android / desktop for platform default)", + "NCSA Mosaic/1.0 (X11;SunOS 4.1.4 sun4m)", + ); + opts.optmulti( + "", + "pref", + "A preference to set to enable", + "dom.bluetooth.enabled", + ); + opts.optmulti( + "", + "pref", + "A preference to set to disable", + "dom.webgpu.enabled=false", + ); + opts.optmulti( + "", + "prefs-file", + "Load in additional prefs from a file.", + "--prefs-file /path/to/prefs.json", + ); + + let opts_matches; + let content_process_token; + match opts::from_cmdline_args(opts, &args) { + ArgumentParsingResult::ContentProcess(matches, token) => { + error!("Content Process mode not supported / tested yet on OpenHarmony!"); + opts_matches = matches; + content_process_token = Some(token); + }, + ArgumentParsingResult::ChromeProcess(matches) => { + opts_matches = matches; + content_process_token = None; + }, + }; + + crate::prefs::register_user_prefs(&opts_matches); gl.clear_color(1.0, 1.0, 1.0, 1.0); gl.clear(gl::COLOR_BUFFER_BIT); diff --git a/support/openharmony/entry/src/main/cpp/CMakeLists.txt b/support/openharmony/entry/src/main/cpp/CMakeLists.txt index 3c68b0d074b..aa55b3baa39 100644 --- a/support/openharmony/entry/src/main/cpp/CMakeLists.txt +++ b/support/openharmony/entry/src/main/cpp/CMakeLists.txt @@ -1,3 +1,3 @@ # the minimum version of CMake. -cmake_minimum_required(VERSION 3.4.1) +cmake_minimum_required(VERSION 3.16.0) project(servoshell) diff --git a/support/openharmony/entry/src/main/ets/entryability/EntryAbility.ets b/support/openharmony/entry/src/main/ets/entryability/EntryAbility.ets index bd1f2320984..c64c9867391 100644 --- a/support/openharmony/entry/src/main/ets/entryability/EntryAbility.ets +++ b/support/openharmony/entry/src/main/ets/entryability/EntryAbility.ets @@ -5,8 +5,29 @@ import Want from '@ohos.app.ability.Want'; import window from '@ohos.window'; export default class EntryAbility extends UIAbility { + init_params: LocalStorage = new LocalStorage(); onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { - hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + let uri: string = want.uri || "https://servo.org" + let params: string[] = [] + if (typeof want.parameters !== "undefined") { + Object.entries(want.parameters).forEach((entry) => { + let key = entry[0] + // Skip some default parameters, since servo is not interested in those + if (key.startsWith("ohos.") + || key.startsWith("component.") + || key === "isCallBySCB" + || key === "moduleName" + ) { + return + } + let value = entry[1] + params.push("--" + key + "=" + value.toString()) + }) + } + let servoshell_params = params.join("\u{001f}") + hilog.debug(0x0000, 'Servo EntryAbility', 'Servoshell parameters: %{public}s', servoshell_params); + this.init_params.setOrCreate('InitialURI', uri) + this.init_params.setOrCreate('CommandlineArgs', servoshell_params) } onDestroy() { @@ -17,7 +38,7 @@ export default class EntryAbility extends UIAbility { // Main window is created, set main page for this ability hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); - windowStage.loadContent('pages/Index', (err, data) => { + windowStage.loadContent('pages/Index', this.init_params, (err, data) => { if (err.code) { hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); return; diff --git a/support/openharmony/entry/src/main/ets/pages/Index.ets b/support/openharmony/entry/src/main/ets/pages/Index.ets index f9eda7854a7..277fcc826e2 100644 --- a/support/openharmony/entry/src/main/ets/pages/Index.ets +++ b/support/openharmony/entry/src/main/ets/pages/Index.ets @@ -16,6 +16,7 @@ interface InitOpts { osFullName: string, resourceDir: string, displayDensity: number, + commandlineArgs: string, } function get_density(): number { @@ -39,7 +40,10 @@ function get_device_type(): string { return device_type; } -@Entry +// Use the getShared API to obtain the LocalStorage instance shared by stage. +let storage = LocalStorage.getShared() + +@Entry(storage) @Component struct Index { xComponentContext: ServoXComponentInterface | undefined = undefined; @@ -48,8 +52,11 @@ struct Index { type: XComponentType.SURFACE, libraryname: 'servoshell', } - @State urlToLoad: string = 'https://servo.org' + private context = getContext(this) as common.UIAbilityContext; + @LocalStorageProp('InitialURI') InitialURI: string = "unused" + @LocalStorageProp('CommandlineArgs') CommandlineArgs: string = "" + @State urlToLoad: string = this.InitialURI build() { Column() { @@ -86,13 +93,14 @@ struct Index { .onLoad((xComponentContext) => { this.xComponentContext = xComponentContext as ServoXComponentInterface; let resource_dir: string = this.context.resourceDir; - console.debug("Resources are located at %s", resource_dir); + console.debug("Resources are located at %{public}s", resource_dir); let init_options: InitOpts = { url: this.urlToLoad, deviceType: get_device_type(), osFullName: deviceInfo.osFullName, displayDensity: get_density(), resourceDir: resource_dir, + commandlineArgs: this.CommandlineArgs } this.xComponentContext.initServo(init_options) this.xComponentContext.registerURLcallback((new_url) => {