diff options
Diffstat (limited to 'ports')
-rw-r--r-- | ports/servoshell/desktop/app_state.rs | 45 | ||||
-rw-r--r-- | ports/servoshell/desktop/dialog.rs | 79 | ||||
-rw-r--r-- | ports/servoshell/egl/android.rs | 55 | ||||
-rw-r--r-- | ports/servoshell/egl/android/simpleservo.rs | 2 | ||||
-rw-r--r-- | ports/servoshell/egl/app_state.rs | 38 | ||||
-rw-r--r-- | ports/servoshell/egl/host_trait.rs | 24 | ||||
-rw-r--r-- | ports/servoshell/egl/ohos.rs | 81 |
7 files changed, 163 insertions, 161 deletions
diff --git a/ports/servoshell/desktop/app_state.rs b/ports/servoshell/desktop/app_state.rs index c2d6c656e28..e4fa041d1fc 100644 --- a/ports/servoshell/desktop/app_state.rs +++ b/ports/servoshell/desktop/app_state.rs @@ -18,8 +18,8 @@ use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; use servo::webrender_api::ScrollLocation; use servo::{ AllowOrDenyRequest, AuthenticationRequest, FilterPattern, GamepadHapticEffectType, LoadStatus, - PermissionRequest, PromptDefinition, PromptOrigin, PromptResult, Servo, ServoDelegate, - ServoError, TouchEventType, WebView, WebViewDelegate, + PermissionRequest, Servo, ServoDelegate, ServoError, SimpleDialog, TouchEventType, WebView, + WebViewDelegate, }; use url::Url; @@ -415,36 +415,25 @@ impl WebViewDelegate for RunningAppState { self.inner().window.request_resize(&webview, new_size); } - fn show_prompt( - &self, - webview: servo::WebView, - definition: PromptDefinition, - _origin: PromptOrigin, - ) { + fn show_simple_dialog(&self, webview: servo::WebView, dialog: SimpleDialog) { if self.servoshell_preferences.headless { - let _ = match definition { - PromptDefinition::Alert(_message, sender) => sender.send(()), - PromptDefinition::OkCancel(_message, sender) => sender.send(PromptResult::Primary), - PromptDefinition::Input(_message, default, sender) => { - sender.send(Some(default.to_owned())) - }, + // TODO: Avoid copying this from the default trait impl? + // Return the DOM-specified default value for when we **cannot show simple dialogs**. + let _ = match dialog { + SimpleDialog::Alert { + response_sender, .. + } => response_sender.send(Default::default()), + SimpleDialog::Confirm { + response_sender, .. + } => response_sender.send(Default::default()), + SimpleDialog::Prompt { + response_sender, .. + } => response_sender.send(Default::default()), }; return; } - match definition { - PromptDefinition::Alert(message, sender) => { - let alert_dialog = Dialog::new_alert_dialog(message, sender); - self.add_dialog(webview, alert_dialog); - }, - PromptDefinition::OkCancel(message, sender) => { - let okcancel_dialog = Dialog::new_okcancel_dialog(message, sender); - self.add_dialog(webview, okcancel_dialog); - }, - PromptDefinition::Input(message, default, sender) => { - let input_dialog = Dialog::new_input_dialog(message, default, sender); - self.add_dialog(webview, input_dialog); - }, - } + let dialog = Dialog::new_simple_dialog(dialog); + self.add_dialog(webview, dialog); } fn request_authentication( diff --git a/ports/servoshell/desktop/dialog.rs b/ports/servoshell/desktop/dialog.rs index 3b277b6a424..b1cd00deff4 100644 --- a/ports/servoshell/desktop/dialog.rs +++ b/ports/servoshell/desktop/dialog.rs @@ -9,7 +9,10 @@ use egui::Modal; use egui_file_dialog::{DialogState, FileDialog as EguiFileDialog}; use log::warn; use servo::ipc_channel::ipc::IpcSender; -use servo::{AuthenticationRequest, FilterPattern, PermissionRequest, PromptResult}; +use servo::{ + AlertResponse, AuthenticationRequest, ConfirmResponse, FilterPattern, PermissionRequest, + PromptResponse, SimpleDialog, +}; pub enum Dialog { File { @@ -17,19 +20,8 @@ pub enum Dialog { multiple: bool, response_sender: IpcSender<Option<Vec<PathBuf>>>, }, - Alert { - message: String, - sender: IpcSender<()>, - }, - OkCancel { - message: String, - sender: IpcSender<PromptResult>, - }, - Input { - message: String, - input_text: String, - sender: IpcSender<Option<String>>, - }, + #[allow(clippy::enum_variant_names, reason = "spec terminology")] + SimpleDialog(SimpleDialog), Authentication { username: String, password: String, @@ -76,24 +68,8 @@ impl Dialog { } } - pub fn new_alert_dialog(message: String, sender: IpcSender<()>) -> Self { - Dialog::Alert { message, sender } - } - - pub fn new_okcancel_dialog(message: String, sender: IpcSender<PromptResult>) -> Self { - Dialog::OkCancel { message, sender } - } - - pub fn new_input_dialog( - message: String, - default: String, - sender: IpcSender<Option<String>>, - ) -> Self { - Dialog::Input { - message, - input_text: default, - sender, - } + pub fn new_simple_dialog(dialog: SimpleDialog) -> Self { + Self::SimpleDialog(dialog) } pub fn new_authentication_dialog(authentication_request: AuthenticationRequest) -> Self { @@ -165,9 +141,12 @@ impl Dialog { DialogState::Closed => false, } }, - Dialog::Alert { message, sender } => { + Dialog::SimpleDialog(SimpleDialog::Alert { + message, + response_sender, + }) => { let mut is_open = true; - let modal = Modal::new("alert".into()); + let modal = Modal::new("Alert".into()); modal.show(ctx, |ui| { make_dialog_label(message, ui, None); egui::Sides::new().show( @@ -176,7 +155,7 @@ impl Dialog { |ui| { if ui.button("Close").clicked() { is_open = false; - if let Err(e) = sender.send(()) { + if let Err(e) = response_sender.send(AlertResponse::Ok) { warn!("Failed to send alert dialog response: {}", e); } } @@ -185,9 +164,12 @@ impl Dialog { }); is_open }, - Dialog::OkCancel { message, sender } => { + Dialog::SimpleDialog(SimpleDialog::Confirm { + message, + response_sender, + }) => { let mut is_open = true; - let modal = Modal::new("OkCancel".into()); + let modal = Modal::new("Confirm".into()); modal.show(ctx, |ui| { make_dialog_label(message, ui, None); egui::Sides::new().show( @@ -196,13 +178,13 @@ impl Dialog { |ui| { if ui.button("Ok").clicked() { is_open = false; - if let Err(e) = sender.send(PromptResult::Primary) { + if let Err(e) = response_sender.send(ConfirmResponse::Ok) { warn!("Failed to send alert dialog response: {}", e); } } if ui.button("Cancel").clicked() { is_open = false; - if let Err(e) = sender.send(PromptResult::Secondary) { + if let Err(e) = response_sender.send(ConfirmResponse::Cancel) { warn!("Failed to send alert dialog response: {}", e); } } @@ -211,27 +193,30 @@ impl Dialog { }); is_open }, - Dialog::Input { + Dialog::SimpleDialog(SimpleDialog::Prompt { message, - input_text, - sender, - } => { + // The `default` field gets reused as the input buffer. + default: input, + response_sender, + }) => { let mut is_open = true; - Modal::new("input".into()).show(ctx, |ui| { - make_dialog_label(message, ui, Some(input_text)); + Modal::new("Prompt".into()).show(ctx, |ui| { + make_dialog_label(message, ui, Some(input)); egui::Sides::new().show( ui, |_ui| {}, |ui| { if ui.button("Ok").clicked() { is_open = false; - if let Err(e) = sender.send(Some(input_text.clone())) { + if let Err(e) = + response_sender.send(PromptResponse::Ok(input.clone())) + { warn!("Failed to send input dialog response: {}", e); } } if ui.button("Cancel").clicked() { is_open = false; - if let Err(e) = sender.send(None) { + if let Err(e) = response_sender.send(PromptResponse::Cancel) { warn!("Failed to send input dialog response: {}", e); } } diff --git a/ports/servoshell/egl/android.rs b/ports/servoshell/egl/android.rs index f195cc2c910..0f84dadfc14 100644 --- a/ports/servoshell/egl/android.rs +++ b/ports/servoshell/egl/android.rs @@ -19,10 +19,11 @@ use log::{debug, error, info, warn}; use raw_window_handle::{ AndroidDisplayHandle, AndroidNdkWindowHandle, RawDisplayHandle, RawWindowHandle, }; -use servo::{LoadStatus, MediaSessionActionType}; +use servo::{ + AlertResponse, LoadStatus, MediaSessionActionType, PermissionRequest, SimpleDialog, WebView, +}; use simpleservo::{ - DeviceIntRect, EventLoopWaker, InitOptions, InputMethodType, MediaSessionPlaybackState, - PromptResult, APP, + DeviceIntRect, EventLoopWaker, InitOptions, InputMethodType, MediaSessionPlaybackState, APP, }; use super::app_state::{Coordinates, RunningAppState}; @@ -461,11 +462,8 @@ impl HostCallbacks { let jvm = env.get_java_vm().unwrap(); HostCallbacks { callbacks, jvm } } -} -impl HostTrait for HostCallbacks { - fn prompt_alert(&self, message: String, _trusted: bool) { - debug!("prompt_alert"); + fn show_alert(&self, message: String) { let mut env = self.jvm.get_env().unwrap(); let Ok(string) = new_string_as_jvalue(&mut env, &message) else { return; @@ -478,20 +476,41 @@ impl HostTrait for HostCallbacks { ) .unwrap(); } +} - fn prompt_ok_cancel(&self, message: String, _trusted: bool) -> PromptResult { - warn!("Prompt not implemented. Cancelled. {}", message); - PromptResult::Secondary - } - - fn prompt_yes_no(&self, message: String, _trusted: bool) -> PromptResult { - warn!("Prompt not implemented. Cancelled. {}", message); - PromptResult::Secondary +impl HostTrait for HostCallbacks { + fn request_permission(&self, _webview: WebView, request: PermissionRequest) { + warn!("Permissions prompt not implemented. Denied."); + request.deny(); } - fn prompt_input(&self, message: String, default: String, _trusted: bool) -> Option<String> { - warn!("Input prompt not implemented. {}", message); - Some(default) + fn show_simple_dialog(&self, _webview: WebView, dialog: SimpleDialog) { + let _ = match dialog { + SimpleDialog::Alert { + message, + response_sender, + } => { + debug!("SimpleDialog::Alert"); + // TODO: Indicate that this message is untrusted, and what origin it came from. + self.show_alert(message); + response_sender.send(AlertResponse::Ok) + }, + SimpleDialog::Confirm { + message, + response_sender, + } => { + warn!("Confirm dialog not implemented. Cancelled. {}", message); + response_sender.send(Default::default()) + }, + SimpleDialog::Prompt { + message, + response_sender, + .. + } => { + warn!("Prompt dialog not implemented. Cancelled. {}", message); + response_sender.send(Default::default()) + }, + }; } fn notify_load_status_changed(&self, load_status: LoadStatus) { diff --git a/ports/servoshell/egl/android/simpleservo.rs b/ports/servoshell/egl/android/simpleservo.rs index 369e583af08..1dd255402d9 100644 --- a/ports/servoshell/egl/android/simpleservo.rs +++ b/ports/servoshell/egl/android/simpleservo.rs @@ -14,7 +14,7 @@ pub use servo::webrender_api::units::DeviceIntRect; /// and that perform_updates need to be called pub use servo::EventLoopWaker; use servo::{self, resources, Servo}; -pub use servo::{InputMethodType, MediaSessionPlaybackState, PromptResult, WindowRenderingContext}; +pub use servo::{InputMethodType, MediaSessionPlaybackState, WindowRenderingContext}; use crate::egl::android::resources::ResourceReaderInstance; use crate::egl::app_state::{ diff --git a/ports/servoshell/egl/app_state.rs b/ports/servoshell/egl/app_state.rs index a62ee308f7a..d7b2e0a5333 100644 --- a/ports/servoshell/egl/app_state.rs +++ b/ports/servoshell/egl/app_state.rs @@ -22,9 +22,9 @@ use servo::{ AllowOrDenyRequest, ContextMenuResult, EmbedderProxy, EventLoopWaker, ImeEvent, InputEvent, InputMethodType, Key, KeyState, KeyboardEvent, LoadStatus, MediaSessionActionType, MediaSessionEvent, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, - NavigationRequest, PermissionRequest, PromptDefinition, PromptOrigin, PromptResult, - RenderingContext, Servo, ServoDelegate, ServoError, TouchEvent, TouchEventType, TouchId, - WebView, WebViewDelegate, WindowRenderingContext, + NavigationRequest, PermissionRequest, RenderingContext, Servo, ServoDelegate, ServoError, + SimpleDialog, TouchEvent, TouchEventType, TouchId, WebView, WebViewDelegate, + WindowRenderingContext, }; use url::Url; @@ -198,15 +198,10 @@ impl WebViewDelegate for RunningAppState { Some(new_webview) } - fn request_permission(&self, _webview: WebView, request: PermissionRequest) { - let message = format!( - "Do you want to grant permission for {:?}?", - request.feature() - ); - let result = match self.callbacks.host_callbacks.prompt_yes_no(message, true) { - PromptResult::Primary => request.allow(), - PromptResult::Secondary | PromptResult::Dismissed => request.deny(), - }; + fn request_permission(&self, webview: WebView, request: PermissionRequest) { + self.callbacks + .host_callbacks + .request_permission(webview, request); } fn request_resize_to(&self, _webview: WebView, size: DeviceIntSize) { @@ -231,21 +226,10 @@ impl WebViewDelegate for RunningAppState { } } - fn show_prompt(&self, _webview: WebView, prompt: PromptDefinition, origin: PromptOrigin) { - let cb = &self.callbacks.host_callbacks; - let trusted = origin == PromptOrigin::Trusted; - let _ = match prompt { - PromptDefinition::Alert(message, response_sender) => { - cb.prompt_alert(message, trusted); - response_sender.send(()) - }, - PromptDefinition::OkCancel(message, response_sender) => { - response_sender.send(cb.prompt_ok_cancel(message, trusted)) - }, - PromptDefinition::Input(message, default, response_sender) => { - response_sender.send(cb.prompt_input(message, default, trusted)) - }, - }; + fn show_simple_dialog(&self, webview: WebView, dialog: SimpleDialog) { + self.callbacks + .host_callbacks + .show_simple_dialog(webview, dialog); } fn show_ime( diff --git a/ports/servoshell/egl/host_trait.rs b/ports/servoshell/egl/host_trait.rs index 1171cf8912a..fe4e8974af5 100644 --- a/ports/servoshell/egl/host_trait.rs +++ b/ports/servoshell/egl/host_trait.rs @@ -3,18 +3,22 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use servo::webrender_api::units::DeviceIntRect; -use servo::{InputMethodType, LoadStatus, MediaSessionPlaybackState, PromptResult}; +use servo::{ + InputMethodType, LoadStatus, MediaSessionPlaybackState, PermissionRequest, SimpleDialog, + WebView, +}; -/// Callbacks. Implemented by embedder. Called by Servo. +/// Callbacks implemented by embedder. Called by our RunningAppState, generally on behalf of Servo. pub trait HostTrait { - /// Show alert. - fn prompt_alert(&self, msg: String, trusted: bool); - /// Ask Yes/No question. - fn prompt_yes_no(&self, msg: String, trusted: bool) -> PromptResult; - /// Ask Ok/Cancel question. - fn prompt_ok_cancel(&self, msg: String, trusted: bool) -> PromptResult; - /// Ask for string - fn prompt_input(&self, msg: String, default: String, trusted: bool) -> Option<String>; + /// Content in a [`WebView`] is requesting permission to access a feature requiring + /// permission from the user. The embedder should allow or deny the request, either by + /// reading a cached value or querying the user for permission via the user interface. + fn request_permission(&self, _webview: WebView, _: PermissionRequest); + /// Show the user a [simple dialog](https://html.spec.whatwg.org/multipage/#simple-dialogs) (`alert()`, `confirm()`, + /// or `prompt()`). Since their messages are controlled by web content, they should be presented to the user in a + /// way that makes them impossible to mistake for browser UI. + /// TODO: This API needs to be reworked to match the new model of how responses are sent. + fn show_simple_dialog(&self, _webview: WebView, dialog: SimpleDialog); /// Show context menu fn show_context_menu(&self, title: Option<String>, items: Vec<String>); /// Notify that the load status of the page has changed. diff --git a/ports/servoshell/egl/ohos.rs b/ports/servoshell/egl/ohos.rs index ed95324e913..ebaab2c4d33 100644 --- a/ports/servoshell/egl/ohos.rs +++ b/ports/servoshell/egl/ohos.rs @@ -21,7 +21,10 @@ use napi_ohos::{Env, JsObject, JsString, NapiRaw}; use ohos_ime::{AttachOptions, Ime, ImeProxy, RawTextEditorProxy}; use ohos_ime_sys::types::InputMethod_EnterKeyType; use servo::style::Zero; -use servo::{InputMethodType, LoadStatus, MediaSessionPlaybackState, PromptResult}; +use servo::{ + AlertResponse, InputMethodType, LoadStatus, MediaSessionPlaybackState, PermissionRequest, + SimpleDialog, WebView, +}; use simpleservo::EventLoopWaker; use xcomponent_sys::{ OH_NativeXComponent, OH_NativeXComponent_Callback, OH_NativeXComponent_GetKeyEvent, @@ -671,6 +674,19 @@ impl HostCallbacks { ime_proxy: RefCell::new(None), } } + + pub fn show_alert(&self, message: String) { + match PROMPT_TOAST.get() { + Some(prompt_fn) => { + let status = prompt_fn.call(message, ThreadsafeFunctionCallMode::NonBlocking); + if status != napi_ohos::Status::Ok { + // Queue could be full. + error!("show_alert failed with {status}"); + } + }, + None => error!("PROMPT_TOAST not set. Dropping message {message}"), + } + } } struct ServoIme { @@ -698,33 +714,38 @@ impl Ime for ServoIme { #[allow(unused)] impl HostTrait for HostCallbacks { - fn prompt_alert(&self, msg: String, _trusted: bool) { - debug!("prompt_alert: {msg}"); - match PROMPT_TOAST.get() { - Some(prompt_fn) => { - let status = prompt_fn.call(msg, ThreadsafeFunctionCallMode::NonBlocking); - if status != napi_ohos::Status::Ok { - // Queue could be full. - error!("prompt_alert failed with {status}"); - } + fn request_permission(&self, _webview: WebView, request: PermissionRequest) { + warn!("Permissions prompt not implemented. Denied."); + request.deny(); + } + + fn show_simple_dialog(&self, _webview: WebView, dialog: SimpleDialog) { + let _ = match dialog { + SimpleDialog::Alert { + message, + response_sender, + } => { + debug!("SimpleDialog::Alert"); + // TODO: Indicate that this message is untrusted, and what origin it came from. + self.show_alert(message); + response_sender.send(AlertResponse::Ok) }, - None => error!("PROMPT_TOAST not set. Dropping msg {msg}"), - } - } - - fn prompt_yes_no(&self, msg: String, trusted: bool) -> PromptResult { - warn!("Prompt not implemented. Cancelled. {}", msg); - PromptResult::Secondary - } - - fn prompt_ok_cancel(&self, msg: String, trusted: bool) -> PromptResult { - warn!("Prompt not implemented. Cancelled. {}", msg); - PromptResult::Secondary - } - - fn prompt_input(&self, msg: String, default: String, trusted: bool) -> Option<String> { - warn!("Input prompt not implemented. Cancelled. {}", msg); - Some(default) + SimpleDialog::Confirm { + message, + response_sender, + } => { + warn!("Confirm dialog not implemented. Cancelled. {}", message); + response_sender.send(Default::default()) + }, + SimpleDialog::Prompt { + message, + response_sender, + .. + } => { + warn!("Prompt dialog not implemented. Cancelled. {}", message); + response_sender.send(Default::default()) + }, + }; } fn show_context_menu(&self, title: Option<String>, items: Vec<String>) { @@ -740,7 +761,7 @@ impl HostTrait for HostCallbacks { if load_status == LoadStatus::Complete { #[cfg(feature = "tracing-hitrace")] let _scope = hitrace::ScopedTrace::start_trace(&c"PageLoadEndedPrompt"); - self.prompt_alert("Page finished loading!".to_string(), true); + self.show_alert("Page finished loading!".to_string()); } } @@ -838,7 +859,7 @@ impl HostTrait for HostCallbacks { if let Some(bt) = backtrace { error!("Backtrace: {bt:?}") } - self.prompt_alert("Servo crashed!".to_string(), true); - self.prompt_alert(reason, true); + self.show_alert("Servo crashed!".to_string()); + self.show_alert(reason); } } |