From 19e41ab9f9b4217f5d07f8ab84a15e0454251a1a Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Fri, 7 Feb 2025 11:43:46 +0100 Subject: [PATCH] libservo: Add a `ClipboardDelegate` and a default implementation (#35297) Add a `ClipboardDelegate` to the `WebView` API and a default implementation in libservo for this delegate that works on Mac, Windows, and Linux. Support for Android will be added in the future. This means that embedders do not need to do anything special to get clipboard support, but can choose to override it or implement it for other platforms. In addition, this adds support for handling fetches of clipboard contents and renames things to reflect that eventually other types of clipboard content will be supported. Part of this is removing the string argument from the `ClipboardEventType::Paste` enum because script will need to get other types of content from the clipboard than just a string. It now talks to the embedder to get this information directly. Signed-off-by: Martin Robinson --- Cargo.lock | 3 +- Cargo.toml | 1 + components/constellation/tracing.rs | 6 +- components/script/clipboard_provider.rs | 28 +++-- components/script/dom/document.rs | 20 +++- components/script/textinput.rs | 19 ++-- components/servo/Cargo.toml | 4 + components/servo/clipboard_delegate.rs | 131 ++++++++++++++++++++++ components/servo/lib.rs | 16 +-- components/servo/webview.rs | 11 ++ components/servo/webview_delegate.rs | 7 -- components/shared/embedder/lib.rs | 16 +-- ports/servoshell/Cargo.toml | 1 - ports/servoshell/desktop/app_state.rs | 34 +----- ports/servoshell/desktop/headed_window.rs | 8 +- ports/servoshell/egl/android.rs | 6 - ports/servoshell/egl/app_state.rs | 9 -- ports/servoshell/egl/host_trait.rs | 4 - ports/servoshell/egl/ohos.rs | 9 -- tests/unit/script/textinput.rs | 6 +- 20 files changed, 212 insertions(+), 127 deletions(-) create mode 100644 components/servo/clipboard_delegate.rs diff --git a/Cargo.lock b/Cargo.lock index a6add640719..456f18c1156 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4308,6 +4308,7 @@ dependencies = [ name = "libservo" version = "0.0.1" dependencies = [ + "arboard", "background_hang_monitor", "base", "bluetooth", @@ -4338,6 +4339,7 @@ dependencies = [ "mozangle", "net", "net_traits", + "parking_lot", "profile", "profile_traits", "rayon", @@ -6864,7 +6866,6 @@ name = "servoshell" version = "0.0.1" dependencies = [ "android_logger", - "arboard", "backtrace", "cc", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index f9afd74877c..7593c40b6de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ aes = "0.8.4" aes-gcm = "0.10.3" aes-kw = { version = "0.2.1", features = ["alloc"] } app_units = "0.7" +arboard = "3" arrayvec = "0.7" async-tungstenite = { version = "0.28", features = ["tokio-rustls-webpki-roots"] } atomic_refcell = "0.1.13" diff --git a/components/constellation/tracing.rs b/components/constellation/tracing.rs index cbedd2da872..08451cd804d 100644 --- a/components/constellation/tracing.rs +++ b/components/constellation/tracing.rs @@ -219,9 +219,9 @@ mod from_script { Self::WebResourceRequested(..) => target_variant!("WebResourceRequested"), Self::AllowUnload(..) => target_variant!("AllowUnload"), Self::Keyboard(..) => target_variant!("Keyboard"), - Self::ClearClipboardContents(..) => target_variant!("ClearClipboardContents"), - Self::GetClipboardContents(..) => target_variant!("GetClipboardContents"), - Self::SetClipboardContents(..) => target_variant!("SetClipboardContents"), + Self::ClearClipboard(..) => target_variant!("ClearClipboard"), + Self::GetClipboardText(..) => target_variant!("GetClipboardText"), + Self::SetClipboardText(..) => target_variant!("SetClipboardText"), Self::SetCursor(..) => target_variant!("SetCursor"), Self::NewFavicon(..) => target_variant!("NewFavicon"), Self::HistoryChanged(..) => target_variant!("HistoryChanged"), diff --git a/components/script/clipboard_provider.rs b/components/script/clipboard_provider.rs index 32d80bb3f32..c734d5addba 100644 --- a/components/script/clipboard_provider.rs +++ b/components/script/clipboard_provider.rs @@ -7,11 +7,13 @@ use embedder_traits::EmbedderMsg; use ipc_channel::ipc::channel; use script_traits::{ScriptMsg, ScriptToConstellationChan}; +/// A trait which abstracts access to the embedder's clipboard in order to allow unit +/// testing clipboard-dependent parts of `script`. pub trait ClipboardProvider { - // blocking method to get the clipboard contents - fn clipboard_contents(&mut self) -> String; - // blocking method to set the clipboard contents - fn set_clipboard_contents(&mut self, _: String); + /// Get the text content of the clipboard. + fn get_text(&mut self) -> Result; + /// Set the text content of the clipboard. + fn set_text(&mut self, _: String); } pub(crate) struct EmbedderClipboardProvider { @@ -20,20 +22,22 @@ pub(crate) struct EmbedderClipboardProvider { } impl ClipboardProvider for EmbedderClipboardProvider { - fn clipboard_contents(&mut self) -> String { + fn get_text(&mut self) -> Result { let (tx, rx) = channel().unwrap(); self.constellation_sender - .send(ScriptMsg::ForwardToEmbedder( - EmbedderMsg::GetClipboardContents(self.webview_id, tx), - )) + .send(ScriptMsg::ForwardToEmbedder(EmbedderMsg::GetClipboardText( + self.webview_id, + tx, + ))) .unwrap(); rx.recv().unwrap() } - fn set_clipboard_contents(&mut self, s: String) { + fn set_text(&mut self, s: String) { self.constellation_sender - .send(ScriptMsg::ForwardToEmbedder( - EmbedderMsg::SetClipboardContents(self.webview_id, s), - )) + .send(ScriptMsg::ForwardToEmbedder(EmbedderMsg::SetClipboardText( + self.webview_id, + s, + ))) .unwrap(); } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 201df933a18..c8e71aa01a4 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -1576,7 +1576,17 @@ impl Document { // Step 7.2.1 drag_data_store.set_mode(Mode::ReadWrite); }, - ClipboardEventType::Paste(ref contents) => { + ClipboardEventType::Paste => { + let (sender, receiver) = ipc::channel().unwrap(); + self.window + .send_to_constellation(ScriptMsg::ForwardToEmbedder( + EmbedderMsg::GetClipboardText(self.window.webview_id(), sender), + )); + let text_contents = receiver + .recv() + .map(Result::unwrap_or_default) + .unwrap_or_default(); + // Step 7.1.1 drag_data_store.set_mode(Mode::ReadOnly); // Step 7.1.2 If trusted or the implementation gives script-generated events access to the clipboard @@ -1585,7 +1595,7 @@ impl Document { // Step 7.1.2.1.1 If clipboard-part contains plain text, then let plain_string = PlainString::new( - DOMString::from_string(contents.to_string()), + DOMString::from_string(text_contents.to_string()), DOMString::from("text/plain"), ); let _ = drag_data_store.add(Kind::Text(plain_string)); @@ -1636,7 +1646,7 @@ impl Document { // Step 1 if drag_data_store.list_len() > 0 { // Step 1.1 Clear the clipboard. - self.send_to_embedder(EmbedderMsg::ClearClipboardContents(self.webview_id())); + self.send_to_embedder(EmbedderMsg::ClearClipboard(self.webview_id())); // Step 1.2 for item in drag_data_store.iter_item_list() { match item { @@ -1644,7 +1654,7 @@ impl Document { // Step 1.2.1.1 Ensure encoding is correct per OS and locale conventions // Step 1.2.1.2 Normalize line endings according to platform conventions // Step 1.2.1.3 - self.send_to_embedder(EmbedderMsg::SetClipboardContents( + self.send_to_embedder(EmbedderMsg::SetClipboardText( self.webview_id(), string.data(), )); @@ -1660,7 +1670,7 @@ impl Document { // Step 2.1 if drag_data_store.clear_was_called { // Step 2.1.1 If types-to-clear list is empty, clear the clipboard - self.send_to_embedder(EmbedderMsg::ClearClipboardContents(self.webview_id())); + self.send_to_embedder(EmbedderMsg::ClearClipboard(self.webview_id())); // Step 2.1.2 Else remove the types in the list from the clipboard // As of now this can't be done with Arboard, and it's possible that will be removed from the spec } diff --git a/components/script/textinput.rs b/components/script/textinput.rs index 9cffd6dede1..a2194b60751 100644 --- a/components/script/textinput.rs +++ b/components/script/textinput.rs @@ -890,20 +890,21 @@ impl TextInput { }) .shortcut(CMD_OR_CONTROL, 'X', || { if let Some(text) = self.get_selection_text() { - self.clipboard_provider.set_clipboard_contents(text); + self.clipboard_provider.set_text(text); self.delete_char(Direction::Backward); } KeyReaction::DispatchInput }) .shortcut(CMD_OR_CONTROL, 'C', || { if let Some(text) = self.get_selection_text() { - self.clipboard_provider.set_clipboard_contents(text); + self.clipboard_provider.set_text(text); } KeyReaction::DispatchInput }) .shortcut(CMD_OR_CONTROL, 'V', || { - let contents = self.clipboard_provider.clipboard_contents(); - self.insert_string(contents); + if let Ok(text_content) = self.clipboard_provider.get_text() { + self.insert_string(text_content); + } KeyReaction::DispatchInput }) .shortcut(Modifiers::empty(), Key::Delete, || { @@ -1166,10 +1167,7 @@ pub(crate) fn handle_text_clipboard_action( // Step 3.1 Copy the selected contents, if any, to the clipboard if let Some(text) = selection { - textinput - .borrow_mut() - .clipboard_provider - .set_clipboard_contents(text); + textinput.borrow_mut().clipboard_provider.set_text(text); } // Step 3.2 Fire a clipboard event named clipboardchange @@ -1183,10 +1181,7 @@ pub(crate) fn handle_text_clipboard_action( // Step 3.1 If there is a selection in an editable context where cutting is enabled, then if let Some(text) = selection { // Step 3.1.1 Copy the selected contents, if any, to the clipboard - textinput - .borrow_mut() - .clipboard_provider - .set_clipboard_contents(text); + textinput.borrow_mut().clipboard_provider.set_text(text); // Step 3.1.2 Remove the contents of the selection from the document and collapse the selection. textinput.borrow_mut().delete_char(Direction::Backward); diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index 6efc9c6b51b..3bce5b97934 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -13,6 +13,8 @@ path = "lib.rs" crate-type = ["rlib"] [features] +default = ["clipboard"] +clipboard = ["dep:arboard"] crown = ["script/crown"] debugmozjs = ["script/debugmozjs"] background_hang_monitor = ["background_hang_monitor/sampler"] @@ -76,6 +78,7 @@ mozangle = { workspace = true } net = { path = "../net" } net_traits = { workspace = true } rayon = { workspace = true } +parking_lot = { workspace = true } profile = { path = "../profile" } profile_traits = { workspace = true } script = { path = "../script" } @@ -103,6 +106,7 @@ surfman = { workspace = true, features = ["sm-angle-default"] } webxr = { path = "../webxr", optional = true } [target.'cfg(not(any(target_os = "android", target_env = "ohos")))'.dependencies] +arboard = { workspace = true, optional = true } surfman = { workspace = true, features = ["sm-x11", "sm-raw-window-handle-06"] } webxr = { path = "../webxr", features = ["ipc", "glwindow", "headless"] } diff --git a/components/servo/clipboard_delegate.rs b/components/servo/clipboard_delegate.rs new file mode 100644 index 00000000000..5d10bb17b09 --- /dev/null +++ b/components/servo/clipboard_delegate.rs @@ -0,0 +1,131 @@ +/* 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 ipc_channel::ipc::IpcSender; + +use crate::WebView; + +pub struct StringRequest { + pub(crate) result_sender: IpcSender>, + response_sent: bool, +} + +impl StringRequest { + pub fn success(mut self, string: String) { + let _ = self.result_sender.send(Ok(string)); + self.response_sent = true; + } + + pub fn failure(mut self, message: String) { + let _ = self.result_sender.send(Err(message)); + self.response_sent = true; + } +} + +impl From>> for StringRequest { + fn from(result_sender: IpcSender>) -> Self { + Self { + result_sender, + response_sent: false, + } + } +} + +impl Drop for StringRequest { + fn drop(&mut self) { + if !self.response_sent { + let _ = self + .result_sender + .send(Err("No response sent to request.".into())); + } + } +} + +/// A delegate that is responsible for accessing the system clipboard. On Mac, Windows, and +/// Linux if the `clipboard` feature is enabled, a default delegate is automatically used +/// that implements clipboard support. An embedding application can override this delegate +/// by using this trait. +pub trait ClipboardDelegate { + /// A request to clear all contents of the system clipboard. + fn clear(&self, _webview: WebView) {} + + /// A request to get the text contents of the system clipboard. Once the contents are + /// retrieved the embedder should call [`StringRequest::success`] with the text or + /// [`StringRequest::failure`] with a failure message. + fn get_text(&self, _webview: WebView, _request: StringRequest) {} + + /// A request to set the text contents of the system clipboard to `new_contents`. + fn set_text(&self, _webview: WebView, _new_contents: String) {} +} + +pub(crate) struct DefaultClipboardDelegate; + +impl ClipboardDelegate for DefaultClipboardDelegate { + fn clear(&self, _webview: WebView) { + clipboard::clear(); + } + + fn get_text(&self, _webview: WebView, request: StringRequest) { + clipboard::get_text(request); + } + + fn set_text(&self, _webview: WebView, new_contents: String) { + clipboard::set_text(new_contents); + } +} + +#[cfg(all( + feature = "clipboard", + not(any(target_os = "android", target_env = "ohos")) +))] +mod clipboard { + use std::sync::OnceLock; + + use arboard::Clipboard; + use parking_lot::Mutex; + + use super::StringRequest; + + /// A shared clipboard for use by the [`DefaultClipboardDelegate`]. This is protected by + /// a mutex so that it can only be used by one thread at a time. The `arboard` documentation + /// suggests that more than one thread shouldn't try to access the Windows clipboard at a + /// time. See . + static SHARED_CLIPBOARD: OnceLock>> = OnceLock::new(); + + fn with_shared_clipboard(callback: impl FnOnce(&mut Clipboard)) { + if let Some(clipboard_mutex) = + SHARED_CLIPBOARD.get_or_init(|| Clipboard::new().ok().map(Mutex::new)) + { + callback(&mut clipboard_mutex.lock()) + } + } + + pub(super) fn clear() { + with_shared_clipboard(|clipboard| { + let _ = clipboard.clear(); + }); + } + + pub(super) fn get_text(request: StringRequest) { + with_shared_clipboard(move |clipboard| match clipboard.get_text() { + Ok(text) => request.success(text), + Err(error) => request.failure(format!("{error:?}")), + }); + } + + pub(super) fn set_text(new_contents: String) { + with_shared_clipboard(move |clipboard| { + let _ = clipboard.set_text(new_contents); + }); + } +} + +#[cfg(any(not(feature = "clipboard"), target_os = "android", target_env = "ohos"))] +mod clipboard { + use super::StringRequest; + + pub(super) fn clear() {} + pub(super) fn get_text(_: StringRequest) {} + pub(super) fn set_text(_: String) {} +} diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 795e1038074..f32151e27e8 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -17,6 +17,7 @@ //! `Servo` is fed events from a generic type that implements the //! `WindowMethods` trait. +mod clipboard_delegate; mod proxies; mod servo_delegate; mod webview; @@ -38,6 +39,7 @@ use bluetooth_traits::BluetoothRequest; use canvas::canvas_paint_thread::CanvasPaintThread; use canvas::WebGLComm; use canvas_traits::webgl::{GlType, WebGLThreads}; +use clipboard_delegate::StringRequest; use compositing::webview::UnknownWebView; use compositing::windowing::{EmbedderEvent, EmbedderMethods, WindowMethods}; use compositing::{CompositeTarget, IOCompositor, InitialCompositorState, ShutdownState}; @@ -1126,21 +1128,21 @@ impl Servo { .notify_keyboard_event(webview, keyboard_event); } }, - EmbedderMsg::ClearClipboardContents(webview_id) => { + EmbedderMsg::ClearClipboard(webview_id) => { if let Some(webview) = self.get_webview_handle(webview_id) { - webview.delegate().clear_clipboard_contents(webview); + webview.clipboard_delegate().clear(webview); } }, - EmbedderMsg::GetClipboardContents(webview_id, ipc_sender) => { + EmbedderMsg::GetClipboardText(webview_id, result_sender) => { if let Some(webview) = self.get_webview_handle(webview_id) { webview - .delegate() - .get_clipboard_contents(webview, ipc_sender); + .clipboard_delegate() + .get_text(webview, StringRequest::from(result_sender)); } }, - EmbedderMsg::SetClipboardContents(webview_id, string) => { + EmbedderMsg::SetClipboardText(webview_id, string) => { if let Some(webview) = self.get_webview_handle(webview_id) { - webview.delegate().set_clipboard_contents(webview, string); + webview.clipboard_delegate().set_text(webview, string); } }, EmbedderMsg::SetCursor(webview_id, cursor) => { diff --git a/components/servo/webview.rs b/components/servo/webview.rs index ab9a193438c..491590defb3 100644 --- a/components/servo/webview.rs +++ b/components/servo/webview.rs @@ -20,6 +20,7 @@ use url::Url; use webrender_api::units::{DeviceIntPoint, DevicePoint, DeviceRect}; use webrender_api::ScrollLocation; +use crate::clipboard_delegate::{ClipboardDelegate, DefaultClipboardDelegate}; use crate::webview_delegate::{DefaultWebViewDelegate, WebViewDelegate}; use crate::ConstellationProxy; @@ -44,6 +45,7 @@ pub(crate) struct WebViewInner { pub(crate) constellation_proxy: ConstellationProxy, pub(crate) compositor: Rc>, pub(crate) delegate: Rc, + pub(crate) clipboard_delegate: Rc, rect: DeviceRect, load_status: LoadStatus, @@ -78,6 +80,7 @@ impl WebView { constellation_proxy: constellation_proxy.clone(), compositor, delegate: Rc::new(DefaultWebViewDelegate), + clipboard_delegate: Rc::new(DefaultClipboardDelegate), rect: DeviceRect::zero(), load_status: LoadStatus::Complete, url: None, @@ -113,6 +116,14 @@ impl WebView { self.inner_mut().delegate = delegate; } + pub fn clipboard_delegate(&self) -> Rc { + self.inner().clipboard_delegate.clone() + } + + pub fn set_clipboard_delegate(&self, delegate: Rc) { + self.inner_mut().clipboard_delegate = delegate; + } + pub fn id(&self) -> WebViewId { self.inner().id } diff --git a/components/servo/webview_delegate.rs b/components/servo/webview_delegate.rs index 846c62d7439..6a6608a5d6a 100644 --- a/components/servo/webview_delegate.rs +++ b/components/servo/webview_delegate.rs @@ -183,13 +183,6 @@ pub trait WebViewDelegate { 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) {} - /// 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. diff --git a/components/shared/embedder/lib.rs b/components/shared/embedder/lib.rs index 1ba259274e6..5ca911ff05a 100644 --- a/components/shared/embedder/lib.rs +++ b/components/shared/embedder/lib.rs @@ -183,11 +183,11 @@ pub enum EmbedderMsg { /// Sends an unconsumed key event back to the embedder. Keyboard(WebViewId, KeyboardEvent), /// Inform embedder to clear the clipboard - ClearClipboardContents(WebViewId), + ClearClipboard(WebViewId), /// Gets system clipboard contents - GetClipboardContents(WebViewId, IpcSender), + GetClipboardText(WebViewId, IpcSender>), /// Sets system clipboard contents - SetClipboardContents(WebViewId, String), + SetClipboardText(WebViewId, String), /// Changes the cursor. SetCursor(WebViewId, Cursor), /// A favicon was detected @@ -276,9 +276,9 @@ impl Debug for EmbedderMsg { EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"), EmbedderMsg::AllowNavigationRequest(..) => write!(f, "AllowNavigationRequest"), EmbedderMsg::Keyboard(..) => write!(f, "Keyboard"), - EmbedderMsg::ClearClipboardContents(..) => write!(f, "ClearClipboardContents"), - EmbedderMsg::GetClipboardContents(..) => write!(f, "GetClipboardContents"), - EmbedderMsg::SetClipboardContents(..) => write!(f, "SetClipboardContents"), + EmbedderMsg::ClearClipboard(..) => write!(f, "ClearClipboard"), + EmbedderMsg::GetClipboardText(..) => write!(f, "GetClipboardText"), + EmbedderMsg::SetClipboardText(..) => write!(f, "SetClipboardText"), EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"), EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"), EmbedderMsg::HistoryChanged(..) => write!(f, "HistoryChanged"), @@ -671,7 +671,7 @@ pub enum ClipboardEventType { /// Cut Cut, /// Paste - Paste(String), + Paste, } impl ClipboardEventType { @@ -681,7 +681,7 @@ impl ClipboardEventType { ClipboardEventType::Change => "clipboardchange", ClipboardEventType::Copy => "copy", ClipboardEventType::Cut => "cut", - ClipboardEventType::Paste(..) => "paste", + ClipboardEventType::Paste => "paste", } } } diff --git a/ports/servoshell/Cargo.toml b/ports/servoshell/Cargo.toml index 396ef64cc0b..dfc58f538bc 100644 --- a/ports/servoshell/Cargo.toml +++ b/ports/servoshell/Cargo.toml @@ -105,7 +105,6 @@ serde_json = { workspace = true } [target.'cfg(not(any(target_os = "android", target_env = "ohos")))'.dependencies] # For optional feature servo_allocator/use-system-allocator servo_allocator = { path = "../../components/allocator" } -arboard = { version = "3" } dirs = "5.0" egui = { version = "0.31.0" } egui_glow = { version = "0.31.0", features = ["winit"] } diff --git a/ports/servoshell/desktop/app_state.rs b/ports/servoshell/desktop/app_state.rs index 4c3650df836..501b92024cc 100644 --- a/ports/servoshell/desktop/app_state.rs +++ b/ports/servoshell/desktop/app_state.rs @@ -8,10 +8,9 @@ use std::path::PathBuf; use std::rc::Rc; use std::thread; -use arboard::Clipboard; use euclid::Vector2D; use keyboard_types::{Key, KeyboardEvent, Modifiers, ShortcutMatcher}; -use log::{error, info, warn}; +use log::{error, info}; use servo::base::id::WebViewId; use servo::config::pref; use servo::ipc_channel::ipc::IpcSender; @@ -49,9 +48,6 @@ pub struct RunningAppStateInner { /// Whether or not this is a headless servoshell window. headless: bool, - /// The clipboard to use for this collection of [`WebView`]s. - pub(crate) clipboard: Option, - /// List of top-level browsing contexts. /// Modified by EmbedderMsg::WebViewOpened and EmbedderMsg::WebViewClosed, /// and we exit if it ever becomes empty. @@ -96,7 +92,6 @@ impl RunningAppState { servo, inner: RefCell::new(RunningAppStateInner { headless, - clipboard: Clipboard::new().ok(), webviews: HashMap::default(), creation_order: Default::default(), focused_webview_id: None, @@ -467,33 +462,6 @@ impl WebViewDelegate for RunningAppState { self.handle_overridable_key_bindings(webview, keyboard_event); } - fn clear_clipboard_contents(&self, _webview: servo::WebView) { - self.inner_mut() - .clipboard - .as_mut() - .and_then(|clipboard| clipboard.clear().ok()); - } - - fn get_clipboard_contents(&self, _webview: servo::WebView, result_sender: IpcSender) { - let contents = self - .inner_mut() - .clipboard - .as_mut() - .and_then(|clipboard| clipboard.get_text().ok()) - .unwrap_or_default(); - if let Err(e) = result_sender.send(contents) { - warn!("Failed to send clipboard ({})", e); - } - } - - fn set_clipboard_contents(&self, _webview: servo::WebView, text: String) { - if let Some(clipboard) = self.inner_mut().clipboard.as_mut() { - if let Err(e) = clipboard.set_text(text) { - warn!("Error setting clipboard contents ({})", e); - } - } - } - fn notify_cursor_changed(&self, _webview: servo::WebView, cursor: servo::Cursor) { self.inner().window.set_cursor(cursor); } diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs index 4a103d0e38b..6aa86281389 100644 --- a/ports/servoshell/desktop/headed_window.rs +++ b/ports/servoshell/desktop/headed_window.rs @@ -320,13 +320,7 @@ impl Window { focused_webview.notify_clipboard_event(ClipboardEventType::Copy); }) .shortcut(CMD_OR_CONTROL, 'V', || { - let text = state - .inner_mut() - .clipboard - .as_mut() - .and_then(|clipboard| clipboard.get_text().ok()) - .unwrap_or_default(); - focused_webview.notify_clipboard_event(ClipboardEventType::Paste(text)); + focused_webview.notify_clipboard_event(ClipboardEventType::Paste); }) .shortcut(Modifiers::CONTROL, Key::F9, || { focused_webview.capture_webrender(); diff --git a/ports/servoshell/egl/android.rs b/ports/servoshell/egl/android.rs index ea54155a7e2..c3711a4a5b6 100644 --- a/ports/servoshell/egl/android.rs +++ b/ports/servoshell/egl/android.rs @@ -605,12 +605,6 @@ impl HostTrait for HostCallbacks { } fn on_ime_hide(&self) {} - fn get_clipboard_contents(&self) -> Option { - None - } - - fn set_clipboard_contents(&self, _contents: String) {} - fn on_media_session_metadata(&self, title: String, artist: String, album: String) { info!("on_media_session_metadata"); let mut env = self.jvm.get_env().unwrap(); diff --git a/ports/servoshell/egl/app_state.rs b/ports/servoshell/egl/app_state.rs index 293810948a6..f4299a612a4 100644 --- a/ports/servoshell/egl/app_state.rs +++ b/ports/servoshell/egl/app_state.rs @@ -295,15 +295,6 @@ impl WebViewDelegate for RunningAppState { fn hide_ime(&self, _webview: WebView) { self.callbacks.host_callbacks.on_ime_hide(); } - - fn get_clipboard_contents(&self, _webview: WebView, sender: IpcSender) { - let contents = self.callbacks.host_callbacks.get_clipboard_contents(); - let _ = sender.send(contents.unwrap_or("".to_owned())); - } - - fn set_clipboard_contents(&self, _webview: WebView, text: String) { - self.callbacks.host_callbacks.set_clipboard_contents(text); - } } #[allow(unused)] diff --git a/ports/servoshell/egl/host_trait.rs b/ports/servoshell/egl/host_trait.rs index eb80976ef88..1171cf8912a 100644 --- a/ports/servoshell/egl/host_trait.rs +++ b/ports/servoshell/egl/host_trait.rs @@ -64,10 +64,6 @@ pub trait HostTrait { ); /// Input lost focus fn on_ime_hide(&self); - /// Gets sytem clipboard contents. - fn get_clipboard_contents(&self) -> Option; - /// Sets system clipboard contents. - fn set_clipboard_contents(&self, contents: String); /// Called when we get the media session metadata/ fn on_media_session_metadata(&self, title: String, artist: String, album: String); /// Called when the media session playback state changes. diff --git a/ports/servoshell/egl/ohos.rs b/ports/servoshell/egl/ohos.rs index 383a71af01f..96457ffed27 100644 --- a/ports/servoshell/egl/ohos.rs +++ b/ports/servoshell/egl/ohos.rs @@ -818,15 +818,6 @@ impl HostTrait for HostCallbacks { } } - fn get_clipboard_contents(&self) -> Option { - warn!("get_clipboard_contents not implemented"); - None - } - - fn set_clipboard_contents(&self, contents: String) { - warn!("set_clipboard_contents not implemented"); - } - fn on_media_session_metadata(&self, title: String, artist: String, album: String) { warn!("on_media_session_metadata not implemented"); } diff --git a/tests/unit/script/textinput.rs b/tests/unit/script/textinput.rs index 9d8c0dda3a9..7822dbd785e 100644 --- a/tests/unit/script/textinput.rs +++ b/tests/unit/script/textinput.rs @@ -27,10 +27,10 @@ impl DummyClipboardContext { } impl ClipboardProvider for DummyClipboardContext { - fn clipboard_contents(&mut self) -> String { - self.content.clone() + fn get_text(&mut self) -> Result { + Ok(self.content.clone()) } - fn set_clipboard_contents(&mut self, s: String) { + fn set_text(&mut self, s: String) { self.content = s; } }