diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/script/dom/clipboard.rs | 138 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 1 | ||||
-rw-r--r-- | components/script/dom/navigator.rs | 9 | ||||
-rw-r--r-- | components/script/task_manager.rs | 1 | ||||
-rw-r--r-- | components/script/task_source.rs | 2 | ||||
-rw-r--r-- | components/script_bindings/codegen/Bindings.conf | 4 | ||||
-rw-r--r-- | components/script_bindings/webidls/Clipboard.webidl | 12 | ||||
-rw-r--r-- | components/script_bindings/webidls/Navigator.webidl | 5 |
8 files changed, 171 insertions, 1 deletions
diff --git a/components/script/dom/clipboard.rs b/components/script/dom/clipboard.rs new file mode 100644 index 00000000000..94c8b3c0f19 --- /dev/null +++ b/components/script/dom/clipboard.rs @@ -0,0 +1,138 @@ +/* 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::rc::Rc; + +use constellation_traits::BlobImpl; +use dom_struct::dom_struct; +use embedder_traits::EmbedderMsg; + +use crate::dom::bindings::codegen::Bindings::ClipboardBinding::{ + ClipboardMethods, PresentationStyle, +}; +use crate::dom::bindings::refcounted::TrustedPromise; +use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::str::DOMString; +use crate::dom::blob::Blob; +use crate::dom::eventtarget::EventTarget; +use crate::dom::globalscope::GlobalScope; +use crate::dom::promise::Promise; +use crate::dom::window::Window; +use crate::script_runtime::CanGc; + +#[dom_struct] +pub(crate) struct Clipboard { + event_target: EventTarget, +} + +impl Clipboard { + fn new_inherited() -> Clipboard { + Clipboard { + event_target: EventTarget::new_inherited(), + } + } + + pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<Clipboard> { + reflect_dom_object(Box::new(Clipboard::new_inherited()), global, can_gc) + } +} + +impl ClipboardMethods<crate::DomTypeHolder> for Clipboard { + /// <https://w3c.github.io/clipboard-apis/#dom-clipboard-writetext> + fn WriteText(&self, data: DOMString, can_gc: CanGc) -> Rc<Promise> { + // Step 1 Let realm be this's relevant realm. + // Step 2 Let p be a new promise in realm. + let p = Promise::new(&self.global(), can_gc); + + // Step 3 Run the following steps in parallel: + + // TODO write permission could be removed from spec + // Step 3.1 Let r be the result of running check clipboard write permission. + // Step 3.2 If r is false, then: + // Step 3.2.1 Queue a global task on the permission task source, given realm’s global object, + // to reject p with "NotAllowedError" DOMException in realm. + // Step 3.2.2 Abort these steps. + + let trusted_promise = TrustedPromise::new(p.clone()); + let bytes = Vec::from(data); + + // Step 3.3 Queue a global task on the clipboard task source, + // given realm’s global object, to perform the below steps: + self.global().task_manager().clipboard_task_source().queue( + task!(write_to_system_clipboard: move || { + let promise = trusted_promise.root(); + let global = promise.global(); + + // Step 3.3.1 Let itemList be an empty sequence<Blob>. + let mut item_list = Vec::new(); + + // Step 3.3.2 Let textBlob be a new Blob created with: type attribute set to "text/plain;charset=utf-8", + // and its underlying byte sequence set to the UTF-8 encoding of data. + let text_blob = Blob::new( + &global, + BlobImpl::new_from_bytes(bytes, "text/plain;charset=utf-8".into()), + CanGc::note(), + ); + + // Step 3.3.3 Add textBlob to itemList. + item_list.push(text_blob); + + // Step 3.3.4 Let option be set to "unspecified". + let option = PresentationStyle::Unspecified; + + // Step 3.3.5 Write blobs and option to the clipboard with itemList and option. + write_blobs_and_option_to_the_clipboard(global.as_window(), item_list, option); + + // Step 3.3.6 Resolve p. + promise.resolve_native(&(), CanGc::note()); + }), + ); + + // Step 3.4 Return p. + p + } +} + +/// <https://w3c.github.io/clipboard-apis/#write-blobs-and-option-to-the-clipboard> +fn write_blobs_and_option_to_the_clipboard( + window: &Window, + items: Vec<DomRoot<Blob>>, + _presentation_style: PresentationStyle, +) { + // TODO Step 1 Let webCustomFormats be a sequence<Blob>. + + // Step 2 For each item in items: + for item in items { + // TODO support more formats than just text/plain + // Step 2.1 Let formatString be the result of running os specific well-known format given item’s type. + + // Step 2.2 If formatString is empty then follow the below steps: + + // Step 2.2.1 Let webCustomFormatString be the item’s type. + // Step 2.2.2 Let webCustomFormat be an empty type. + // Step 2.2.3 If webCustomFormatString starts with "web " prefix, + // then remove the "web " prefix and store the remaining string in webMimeTypeString. + // Step 2.2.4 Let webMimeType be the result of parsing a MIME type given webMimeTypeString. + // Step 2.2.5 If webMimeType is failure, then abort all steps. + // Step 2.2.6 Let webCustomFormat’s type's essence equal to webMimeType. + // Step 2.2.7 Set item’s type to webCustomFormat. + // Step 2.2.8 Append webCustomFormat to webCustomFormats. + + // Step 2.3 Let payload be the result of UTF-8 decoding item’s underlying byte sequence. + // Step 2.4 Insert payload and presentationStyle into the system clipboard + // using formatString as the native clipboard format. + window.send_to_embedder(EmbedderMsg::SetClipboardText( + window.webview_id(), + String::from_utf8( + item.get_bytes() + .expect("No bytes found for Blob created by caller"), + ) + .expect("DOMString contained invalid bytes"), + )); + } + + // TODO Step 3 Write web custom formats given webCustomFormats. + // Needs support to arbitrary formats inside arboard +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index d7bd3c450c7..4bc272db8dd 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -250,6 +250,7 @@ pub(crate) mod channelmergernode; pub(crate) mod channelsplitternode; pub(crate) mod characterdata; pub(crate) mod client; +pub(crate) mod clipboard; pub(crate) mod clipboardevent; pub(crate) mod clipboarditem; pub(crate) mod closeevent; diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs index 05eaf4f83c0..ffbf2546a80 100644 --- a/components/script/dom/navigator.rs +++ b/components/script/dom/navigator.rs @@ -19,6 +19,7 @@ use crate::dom::bindings::str::DOMString; use crate::dom::bindings::utils::to_frozen_array; #[cfg(feature = "bluetooth")] use crate::dom::bluetooth::Bluetooth; +use crate::dom::clipboard::Clipboard; use crate::dom::gamepad::Gamepad; use crate::dom::gamepadevent::GamepadEventType; use crate::dom::mediadevices::MediaDevices; @@ -57,6 +58,7 @@ pub(crate) struct Navigator { gamepads: DomRefCell<Vec<MutNullableDom<Gamepad>>>, permissions: MutNullableDom<Permissions>, mediasession: MutNullableDom<MediaSession>, + clipboard: MutNullableDom<Clipboard>, #[cfg(feature = "webgpu")] gpu: MutNullableDom<GPU>, /// <https://www.w3.org/TR/gamepad/#dfn-hasgamepadgesture> @@ -79,6 +81,7 @@ impl Navigator { gamepads: Default::default(), permissions: Default::default(), mediasession: Default::default(), + clipboard: Default::default(), #[cfg(feature = "webgpu")] gpu: Default::default(), has_gamepad_gesture: Cell::new(false), @@ -306,6 +309,12 @@ impl NavigatorMethods<crate::DomTypeHolder> for Navigator { hardware_concurrency() } + /// <https://w3c.github.io/clipboard-apis/#h-navigator-clipboard> + fn Clipboard(&self) -> DomRoot<Clipboard> { + self.clipboard + .or_init(|| Clipboard::new(&self.global(), CanGc::note())) + } + /// <https://servo.org/internal-no-spec> fn Servo(&self) -> DomRoot<ServoInternals> { self.servo_internals diff --git a/components/script/task_manager.rs b/components/script/task_manager.rs index 2d4463e0c38..768d78bcb24 100644 --- a/components/script/task_manager.rs +++ b/components/script/task_manager.rs @@ -133,6 +133,7 @@ impl TaskManager { } task_source_functions!(self, canvas_blob_task_source, Canvas); + task_source_functions!(self, clipboard_task_source, Clipboard); task_source_functions!(self, dom_manipulation_task_source, DOMManipulation); task_source_functions!(self, file_reading_task_source, FileReading); task_source_functions!(self, font_loading_task_source, FontLoading); diff --git a/components/script/task_source.rs b/components/script/task_source.rs index 4bb6a5c110c..2aaa15609f1 100644 --- a/components/script/task_source.rs +++ b/components/script/task_source.rs @@ -23,6 +23,7 @@ use crate::task_manager::TaskManager; #[derive(Clone, Copy, Debug, Eq, Hash, JSTraceable, MallocSizeOf, PartialEq, VariantArray)] pub(crate) enum TaskSourceName { Canvas, + Clipboard, DOMManipulation, FileReading, /// <https://drafts.csswg.org/css-font-loading/#task-source> @@ -48,6 +49,7 @@ impl From<TaskSourceName> for ScriptThreadEventCategory { fn from(value: TaskSourceName) -> Self { match value { TaskSourceName::Canvas => ScriptThreadEventCategory::ScriptEvent, + TaskSourceName::Clipboard => ScriptThreadEventCategory::ScriptEvent, TaskSourceName::DOMManipulation => ScriptThreadEventCategory::ScriptEvent, TaskSourceName::FileReading => ScriptThreadEventCategory::FileRead, TaskSourceName::FontLoading => ScriptThreadEventCategory::FontLoading, diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf index 26a38d03561..f9ab745e4ea 100644 --- a/components/script_bindings/codegen/Bindings.conf +++ b/components/script_bindings/codegen/Bindings.conf @@ -87,6 +87,10 @@ DOMInterfaces = { 'canGc': ['Before', 'After', 'Remove', 'ReplaceWith'] }, +'Clipboard': { + 'canGc': ['WriteText'] +}, + 'ClipboardItem': { 'canGc': ['Types'] }, diff --git a/components/script_bindings/webidls/Clipboard.webidl b/components/script_bindings/webidls/Clipboard.webidl index 2d2bb409e1a..7562adbfa38 100644 --- a/components/script_bindings/webidls/Clipboard.webidl +++ b/components/script_bindings/webidls/Clipboard.webidl @@ -2,7 +2,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -// https://w3c.github.io/clipboard-apis/#clipboard-item-interface +// https://w3c.github.io/clipboard-apis + +typedef sequence<ClipboardItem> ClipboardItems; + +[SecureContext, Exposed=Window, Pref="dom_async_clipboard_enabled"] +interface Clipboard : EventTarget { + // Promise<ClipboardItems> read(); + // Promise<DOMString> readText(); + // Promise<undefined> write(ClipboardItems data); + Promise<undefined> writeText(DOMString data); +}; typedef Promise<(DOMString or Blob)> ClipboardItemData; diff --git a/components/script_bindings/webidls/Navigator.webidl b/components/script_bindings/webidls/Navigator.webidl index a612d42ae99..92f37baa95b 100644 --- a/components/script_bindings/webidls/Navigator.webidl +++ b/components/script_bindings/webidls/Navigator.webidl @@ -70,3 +70,8 @@ partial interface Navigator { interface mixin NavigatorConcurrentHardware { readonly attribute unsigned long long hardwareConcurrency; }; + +// https://w3c.github.io/clipboard-apis/#navigator-interface +partial interface Navigator { + [SecureContext, SameObject, Pref="dom_async_clipboard_enabled"] readonly attribute Clipboard clipboard; +}; |