mirror of
https://github.com/servo/servo.git
synced 2025-08-02 20:20:14 +01:00
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 <mrobinson@igalia.com>
This commit is contained in:
parent
b5b69988cc
commit
19e41ab9f9
20 changed files with 212 additions and 127 deletions
|
@ -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<String, String>;
|
||||
/// 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<String, String> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -890,20 +890,21 @@ impl<T: ClipboardProvider> TextInput<T> {
|
|||
})
|
||||
.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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue