diff options
Diffstat (limited to 'components/servo/webview_delegate.rs')
-rw-r--r-- | components/servo/webview_delegate.rs | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/components/servo/webview_delegate.rs b/components/servo/webview_delegate.rs new file mode 100644 index 00000000000..5648294b2c6 --- /dev/null +++ b/components/servo/webview_delegate.rs @@ -0,0 +1,262 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use std::path::PathBuf; + +use base::id::PipelineId; +use compositing_traits::ConstellationMsg; +use embedder_traits::{ + CompositorEventVariant, ContextMenuResult, Cursor, FilterPattern, GamepadHapticEffectType, + InputMethodType, LoadStatus, MediaSessionEvent, PermissionPrompt, PermissionRequest, + PromptDefinition, PromptOrigin, WebResourceRequest, WebResourceResponseMsg, +}; +use ipc_channel::ipc::IpcSender; +use keyboard_types::KeyboardEvent; +use url::Url; +use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; + +use crate::{ConstellationProxy, WebView}; + +/// A request to navigate a [`WebView`] or one of its inner frames. This can be handled +/// asynchronously. If not handled, the request will automatically be allowed. +pub struct NavigationRequest { + pub url: Url, + pub(crate) pipeline_id: PipelineId, + pub(crate) constellation_proxy: ConstellationProxy, + pub(crate) response_sent: bool, +} + +impl NavigationRequest { + pub fn allow(mut self) { + self.constellation_proxy + .send(ConstellationMsg::AllowNavigationResponse( + self.pipeline_id, + true, + )); + self.response_sent = true; + } + + pub fn deny(mut self) { + self.constellation_proxy + .send(ConstellationMsg::AllowNavigationResponse( + self.pipeline_id, + false, + )); + self.response_sent = true; + } +} + +impl Drop for NavigationRequest { + fn drop(&mut self) { + if !self.response_sent { + self.constellation_proxy + .send(ConstellationMsg::AllowNavigationResponse( + self.pipeline_id, + true, + )); + } + } +} + +pub struct AllowOrDenyRequest { + pub(crate) response_sender: IpcSender<bool>, + pub(crate) response_sent: bool, + pub(crate) default_response: bool, +} + +impl AllowOrDenyRequest { + pub fn allow(mut self) { + let _ = self.response_sender.send(true); + self.response_sent = true; + } + + pub fn deny(mut self) { + let _ = self.response_sender.send(false); + self.response_sent = true; + } +} + +impl Drop for AllowOrDenyRequest { + fn drop(&mut self) { + if !self.response_sent { + let _ = self.response_sender.send(self.default_response); + } + } +} + +pub trait WebViewDelegate { + /// The URL of the currently loaded page in this [`WebView`] has changed. The new + /// URL can accessed via [`WebView::url`]. + fn notify_url_changed(&self, _webview: WebView, _url: Url) {} + /// The page title of the currently loaded page in this [`WebView`] has changed. The new + /// title can accessed via [`WebView::page_title`]. + fn notify_page_title_changed(&self, _webview: WebView, _title: Option<String>) {} + /// The status text of the currently loaded page in this [`WebView`] has changed. The new + /// status text can accessed via [`WebView::status_text`]. + fn notify_status_text_changed(&self, _webview: WebView, _status: Option<String>) {} + /// This [`WebView`] has either become focused or lost focus. Whether or not the + /// [`WebView`] is focused can be accessed via [`WebView::focused`]. + fn notify_focus_changed(&self, _webview: WebView, _focused: bool) {} + /// The `LoadStatus` of the currently loading or loaded page in this [`WebView`] has changed. The new + /// status can accessed via [`WebView::load_status`]. + fn notify_load_status_changed(&self, _webview: WebView, _status: LoadStatus) {} + /// The [`Cursor`] of the currently loaded page in this [`WebView`] has changed. The new + /// cursor can accessed via [`WebView::cursor`]. + fn notify_cursor_changed(&self, _webview: WebView, _: Cursor) {} + /// The favicon [`Url`] of the currently loaded page in this [`WebView`] has changed. The new + /// favicon [`Url`] can accessed via [`WebView::favicon_url`]. + fn notify_favicon_url_changed(&self, _webview: WebView, _: Url) {} + + /// A [`WebView`] was created and is now ready to show in the user interface. + fn notify_ready_to_show(&self, _webview: WebView) {} + /// Notify the embedder that it needs to present a new frame. + fn notify_new_frame_ready(&self, _webview: WebView) {} + /// The given event was delivered to a pipeline in the given webview. + fn notify_event_delivered(&self, _webview: WebView, _event: CompositorEventVariant) {} + /// The history state has changed. + // changed pattern; maybe wasteful if embedder doesn’t care? + fn notify_history_changed(&self, _webview: WebView, _: Vec<Url>, _: usize) {} + + /// A keyboard event has been sent to Servo, but remains unprocessed. This allows the + /// embedding application to handle key events while first letting the [`WebView`] + /// have an opportunity to handle it first. Apart from builtin keybindings, page + /// content may expose custom keybindings as well. + fn notify_keyboard_event(&self, _webview: WebView, _: KeyboardEvent) {} + /// A pipeline in the webview panicked. First string is the reason, second one is the backtrace. + fn notify_crashed(&self, _webview: WebView, _reason: String, _backtrace: Option<String>) {} + /// Notifies the embedder about media session events + /// (i.e. when there is metadata for the active media session, playback state changes...). + fn notify_media_session_event(&self, _webview: WebView, _event: MediaSessionEvent) {} + + /// Whether or not to allow a [`WebView`] to load a URL in its main frame or one of its + /// nested `<iframe>`s. [`NavigationRequest`]s are accepted by default. + fn request_navigation(&self, _webview: WebView, _navigation_request: NavigationRequest) {} + /// Whether or not to allow a [`WebView`] to unload a `Document` in its main frame or one + /// of its nested `<iframe>`s. By default, unloads are allowed. + fn request_unload(&self, _webview: WebView, _unload_request: AllowOrDenyRequest) {} + /// Move the window to a point + fn request_move_to(&self, _webview: WebView, _: DeviceIntPoint) {} + /// Resize the window to size + fn request_resize_to(&self, _webview: WebView, _: DeviceIntSize) {} + /// Whether or not to allow script to open a new `WebView`. If not handled by the + /// embedder, these requests are automatically denied. + fn request_open_auxiliary_webview(&self, _parent_webview: WebView) -> Option<WebView> { + None + } + /// Page content has requested that this [`WebView`] be closed. It's the embedder's + /// responsibility to either ignore this request or to remove the [`WebView`] from the + /// interface. + fn request_close(&self, _webview: WebView) {} + /// Open interface to request permission specified by prompt. + fn request_permission( + &self, + _webview: WebView, + _: PermissionPrompt, + result_sender: IpcSender<PermissionRequest>, + ) { + let _ = result_sender.send(PermissionRequest::Denied); + } + + /// Show dialog to user + /// TODO: This API needs to be reworked to match the new model of how responses are sent. + fn show_prompt(&self, _webview: WebView, prompt: PromptDefinition, _: PromptOrigin) { + let _ = match prompt { + PromptDefinition::Alert(_, response_sender) => response_sender.send(()), + PromptDefinition::OkCancel(_, response_sender) => { + response_sender.send(embedder_traits::PromptResult::Dismissed) + }, + PromptDefinition::Input(_, _, response_sender) => response_sender.send(None), + PromptDefinition::Credentials(response_sender) => { + response_sender.send(Default::default()) + }, + }; + } + /// Show a context menu to the user + fn show_context_menu( + &self, + _webview: WebView, + result_sender: IpcSender<ContextMenuResult>, + _: Option<String>, + _: Vec<String>, + ) { + let _ = result_sender.send(ContextMenuResult::Ignored); + } + + /// Inform embedder to clear the clipboard + fn clear_clipboard_contents(&self, _webview: WebView) {} + /// Gets system clipboard contents + fn get_clipboard_contents(&self, _webview: WebView, _: IpcSender<String>) {} + /// Sets system clipboard contents + fn set_clipboard_contents(&self, _webview: WebView, _: String) {} + + /// Enter or exit fullscreen + fn request_fullscreen_state_change(&self, _webview: WebView, _: bool) {} + /// Open dialog to select bluetooth device. + /// TODO: This API needs to be reworked to match the new model of how responses are sent. + fn show_bluetooth_device_dialog( + &self, + _webview: WebView, + _: Vec<String>, + response_sender: IpcSender<Option<String>>, + ) { + let _ = response_sender.send(None); + } + + /// Open file dialog to select files. Set boolean flag to true allows to select multiple files. + fn show_file_selection_dialog( + &self, + _webview: WebView, + _filter_pattern: Vec<FilterPattern>, + _allow_select_mutiple: bool, + response_sender: IpcSender<Option<Vec<PathBuf>>>, + ) { + let _ = response_sender.send(None); + } + + /// Request to present an IME to the user when an editable element is focused. + /// If `type` is [`InputMethodType::Text`], then the `text` parameter specifies + /// the pre-existing text content and the zero-based index into the string + /// of the insertion point. + fn show_ime( + &self, + _webview: WebView, + _type: InputMethodType, + _text: Option<(String, i32)>, + _multiline: bool, + _position: DeviceIntRect, + ) { + } + + /// Request to hide the IME when the editable element is blurred. + fn hide_ime(&self, _webview: WebView) {} + + /// Request to play a haptic effect on a connected gamepad. + fn play_gamepad_haptic_effect( + &self, + _webview: WebView, + _: usize, + _: GamepadHapticEffectType, + _: IpcSender<bool>, + ) { + } + /// Request to stop a haptic effect on a connected gamepad. + fn stop_gamepad_haptic_effect(&self, _webview: WebView, _: usize, _: IpcSender<bool>) {} + + /// Potentially intercept a resource request. If not handled, the request will not be intercepted. + /// + /// Note: The `ServoDelegate` will also receive this notification and have a chance to intercept + /// the request. + /// + /// TODO: This API needs to be reworked to match the new model of how responses are sent. + fn intercept_web_resource_load( + &self, + _webview: WebView, + _request: &WebResourceRequest, + _response_sender: IpcSender<WebResourceResponseMsg>, + ) { + } +} + +pub(crate) struct DefaultWebViewDelegate; +impl WebViewDelegate for DefaultWebViewDelegate {} |