mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
dom: Implement ClipboardItem
(#36336)
implement the `ClipboardItem` interface Testing: covered by existing wpt tests part of #36084 --------- Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>
This commit is contained in:
parent
33b00dbe40
commit
d1243a1867
12 changed files with 219 additions and 38 deletions
|
@ -69,6 +69,7 @@ pub struct Preferences {
|
||||||
/// List of comma-separated backends to be used by wgpu.
|
/// List of comma-separated backends to be used by wgpu.
|
||||||
pub dom_webgpu_wgpu_backend: String,
|
pub dom_webgpu_wgpu_backend: String,
|
||||||
pub dom_abort_controller_enabled: bool,
|
pub dom_abort_controller_enabled: bool,
|
||||||
|
pub dom_async_clipboard_enabled: bool,
|
||||||
pub dom_bluetooth_enabled: bool,
|
pub dom_bluetooth_enabled: bool,
|
||||||
pub dom_bluetooth_testing_enabled: bool,
|
pub dom_bluetooth_testing_enabled: bool,
|
||||||
pub dom_allow_scripts_to_close_windows: bool,
|
pub dom_allow_scripts_to_close_windows: bool,
|
||||||
|
@ -246,6 +247,7 @@ impl Preferences {
|
||||||
devtools_server_port: 0,
|
devtools_server_port: 0,
|
||||||
dom_abort_controller_enabled: false,
|
dom_abort_controller_enabled: false,
|
||||||
dom_allow_scripts_to_close_windows: false,
|
dom_allow_scripts_to_close_windows: false,
|
||||||
|
dom_async_clipboard_enabled: false,
|
||||||
dom_bluetooth_enabled: false,
|
dom_bluetooth_enabled: false,
|
||||||
dom_bluetooth_testing_enabled: false,
|
dom_bluetooth_testing_enabled: false,
|
||||||
dom_canvas_capture_enabled: false,
|
dom_canvas_capture_enabled: false,
|
||||||
|
|
181
components/script/dom/clipboarditem.rs
Normal file
181
components/script/dom/clipboarditem.rs
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
/* 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::ops::Deref;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use data_url::mime::Mime;
|
||||||
|
use dom_struct::dom_struct;
|
||||||
|
use js::rust::{HandleObject, MutableHandleValue};
|
||||||
|
use script_bindings::record::Record;
|
||||||
|
|
||||||
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::ClipboardBinding::{
|
||||||
|
ClipboardItemMethods, ClipboardItemOptions, PresentationStyle,
|
||||||
|
};
|
||||||
|
use crate::dom::bindings::error::{Error, Fallible};
|
||||||
|
use crate::dom::bindings::frozenarray::CachedFrozenArray;
|
||||||
|
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
|
||||||
|
use crate::dom::bindings::root::DomRoot;
|
||||||
|
use crate::dom::bindings::str::DOMString;
|
||||||
|
use crate::dom::promise::Promise;
|
||||||
|
use crate::dom::window::Window;
|
||||||
|
use crate::script_runtime::{CanGc, JSContext};
|
||||||
|
|
||||||
|
/// <https://w3c.github.io/clipboard-apis/#web-custom-format>
|
||||||
|
const CUSTOM_FORMAT_PREFIX: &str = "web ";
|
||||||
|
|
||||||
|
/// <https://w3c.github.io/clipboard-apis/#representation>
|
||||||
|
#[derive(JSTraceable, MallocSizeOf)]
|
||||||
|
struct Representation {
|
||||||
|
#[no_trace]
|
||||||
|
#[ignore_malloc_size_of = "Extern type"]
|
||||||
|
mime_type: Mime,
|
||||||
|
is_custom: bool,
|
||||||
|
#[ignore_malloc_size_of = "Rc is hard"]
|
||||||
|
data: Rc<Promise>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dom_struct]
|
||||||
|
pub(crate) struct ClipboardItem {
|
||||||
|
reflector_: Reflector,
|
||||||
|
representations: DomRefCell<Vec<Representation>>,
|
||||||
|
presentation_style: DomRefCell<PresentationStyle>,
|
||||||
|
#[ignore_malloc_size_of = "mozjs"]
|
||||||
|
frozen_types: CachedFrozenArray,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClipboardItem {
|
||||||
|
fn new_inherited() -> ClipboardItem {
|
||||||
|
ClipboardItem {
|
||||||
|
reflector_: Reflector::new(),
|
||||||
|
representations: Default::default(),
|
||||||
|
presentation_style: Default::default(),
|
||||||
|
frozen_types: CachedFrozenArray::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(window: &Window, proto: Option<HandleObject>, can_gc: CanGc) -> DomRoot<ClipboardItem> {
|
||||||
|
reflect_dom_object_with_proto(
|
||||||
|
Box::new(ClipboardItem::new_inherited()),
|
||||||
|
window,
|
||||||
|
proto,
|
||||||
|
can_gc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClipboardItemMethods<crate::DomTypeHolder> for ClipboardItem {
|
||||||
|
/// <https://w3c.github.io/clipboard-apis/#dom-clipboarditem-clipboarditem>
|
||||||
|
fn Constructor(
|
||||||
|
global: &Window,
|
||||||
|
proto: Option<HandleObject>,
|
||||||
|
can_gc: CanGc,
|
||||||
|
items: Record<DOMString, Rc<Promise>>,
|
||||||
|
options: &ClipboardItemOptions,
|
||||||
|
) -> Fallible<DomRoot<ClipboardItem>> {
|
||||||
|
// Step 1 If items is empty, then throw a TypeError.
|
||||||
|
if items.is_empty() {
|
||||||
|
return Err(Error::Type(String::from("No item provided")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2 If options is empty, then set options["presentationStyle"] = "unspecified".
|
||||||
|
// NOTE: This is done inside bindings
|
||||||
|
|
||||||
|
// Step 3 Set this's clipboard item to a new clipboard item.
|
||||||
|
let clipboard_item = ClipboardItem::new(global, proto, can_gc);
|
||||||
|
|
||||||
|
// Step 4 Set this's clipboard item's presentation style to options["presentationStyle"].
|
||||||
|
*clipboard_item.presentation_style.borrow_mut() = options.presentationStyle;
|
||||||
|
|
||||||
|
// Step 6 For each (key, value) in items:
|
||||||
|
for (key, value) in items.deref() {
|
||||||
|
// Step 6.2 Let isCustom be false.
|
||||||
|
|
||||||
|
// Step 6.3 If key starts with `"web "` prefix, then
|
||||||
|
// Step 6.3.1 Remove `"web "` prefix and assign the remaining string to key.
|
||||||
|
let (key, is_custom) = match key.strip_prefix(CUSTOM_FORMAT_PREFIX) {
|
||||||
|
None => (key.str(), false),
|
||||||
|
// Step 6.3.2 Set isCustom true
|
||||||
|
Some(stripped) => (stripped, true),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 6.5 Let mimeType be the result of parsing a MIME type given key.
|
||||||
|
// Step 6.6 If mimeType is failure, then throw a TypeError.
|
||||||
|
let mime_type =
|
||||||
|
Mime::from_str(key).map_err(|_| Error::Type(String::from("Invalid mime type")))?;
|
||||||
|
|
||||||
|
// Step 6.7 If this's clipboard item's list of representations contains a representation
|
||||||
|
// whose MIME type is mimeType and whose [representation/isCustom] is isCustom, then throw a TypeError.
|
||||||
|
if clipboard_item
|
||||||
|
.representations
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.any(|representation| {
|
||||||
|
representation.mime_type == mime_type && representation.is_custom == is_custom
|
||||||
|
})
|
||||||
|
{
|
||||||
|
return Err(Error::Type(String::from("Tried to add a duplicate mime")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6.1 Let representation be a new representation.
|
||||||
|
// Step 6.4 Set representation’s isCustom flag to isCustom.
|
||||||
|
// Step 6.8 Set representation’s MIME type to mimeType.
|
||||||
|
// Step 6.9 Set representation’s data to value.
|
||||||
|
let representation = Representation {
|
||||||
|
mime_type,
|
||||||
|
is_custom,
|
||||||
|
data: value.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 6.10 Append representation to this's clipboard item's list of representations.
|
||||||
|
clipboard_item
|
||||||
|
.representations
|
||||||
|
.borrow_mut()
|
||||||
|
.push(representation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: The steps for creating a frozen array from the list of mimeType are done in the Types() method
|
||||||
|
|
||||||
|
Ok(clipboard_item)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://w3c.github.io/clipboard-apis/#dom-clipboarditem-presentationstyle>
|
||||||
|
fn PresentationStyle(&self) -> PresentationStyle {
|
||||||
|
*self.presentation_style.borrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://w3c.github.io/clipboard-apis/#dom-clipboarditem-types>
|
||||||
|
fn Types(&self, cx: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
|
||||||
|
self.frozen_types.get_or_init(
|
||||||
|
|| {
|
||||||
|
// Step 5 Let types be a list of DOMString.
|
||||||
|
let mut types = Vec::new();
|
||||||
|
|
||||||
|
self.representations
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.for_each(|representation| {
|
||||||
|
// Step 6.11 Let mimeTypeString be the result of serializing a MIME type with mimeType.
|
||||||
|
let mime_type_string = representation.mime_type.to_string();
|
||||||
|
|
||||||
|
// Step 6.12 If isCustom is true, prefix mimeTypeString with `"web "`.
|
||||||
|
let mime_type_string = if representation.is_custom {
|
||||||
|
format!("{}{}", CUSTOM_FORMAT_PREFIX, mime_type_string)
|
||||||
|
} else {
|
||||||
|
mime_type_string
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 6.13 Add mimeTypeString to types.
|
||||||
|
types.push(DOMString::from(mime_type_string));
|
||||||
|
});
|
||||||
|
types
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
retval,
|
||||||
|
can_gc,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -251,6 +251,7 @@ pub(crate) mod channelsplitternode;
|
||||||
pub(crate) mod characterdata;
|
pub(crate) mod characterdata;
|
||||||
pub(crate) mod client;
|
pub(crate) mod client;
|
||||||
pub(crate) mod clipboardevent;
|
pub(crate) mod clipboardevent;
|
||||||
|
pub(crate) mod clipboarditem;
|
||||||
pub(crate) mod closeevent;
|
pub(crate) mod closeevent;
|
||||||
pub(crate) mod comment;
|
pub(crate) mod comment;
|
||||||
pub(crate) mod compositionevent;
|
pub(crate) mod compositionevent;
|
||||||
|
|
|
@ -87,6 +87,10 @@ DOMInterfaces = {
|
||||||
'canGc': ['Before', 'After', 'Remove', 'ReplaceWith']
|
'canGc': ['Before', 'After', 'Remove', 'ReplaceWith']
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'ClipboardItem': {
|
||||||
|
'canGc': ['Types']
|
||||||
|
},
|
||||||
|
|
||||||
'CountQueuingStrategy': {
|
'CountQueuingStrategy': {
|
||||||
'canGc': ['GetSize'],
|
'canGc': ['GetSize'],
|
||||||
},
|
},
|
||||||
|
|
26
components/script_bindings/webidls/Clipboard.webidl
Normal file
26
components/script_bindings/webidls/Clipboard.webidl
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// https://w3c.github.io/clipboard-apis/#clipboard-item-interface
|
||||||
|
|
||||||
|
typedef Promise<(DOMString or Blob)> ClipboardItemData;
|
||||||
|
|
||||||
|
[SecureContext, Exposed=Window, Pref="dom_async_clipboard_enabled"]
|
||||||
|
interface ClipboardItem {
|
||||||
|
[Throws] constructor(record<DOMString, ClipboardItemData> items,
|
||||||
|
optional ClipboardItemOptions options = {});
|
||||||
|
|
||||||
|
readonly attribute PresentationStyle presentationStyle;
|
||||||
|
readonly attribute /* FrozenArray<DOMString> */ any types;
|
||||||
|
|
||||||
|
// Promise<Blob> getType(DOMString type);
|
||||||
|
|
||||||
|
// static boolean supports(DOMString type);
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PresentationStyle { "unspecified", "inline", "attachment" };
|
||||||
|
|
||||||
|
dictionary ClipboardItemOptions {
|
||||||
|
PresentationStyle presentationStyle = "unspecified";
|
||||||
|
};
|
|
@ -548,6 +548,7 @@ pub(crate) fn parse_command_line_arguments(args: Vec<String>) -> ArgumentParsing
|
||||||
|
|
||||||
if opt_match.opt_present("enable-experimental-web-platform-features") {
|
if opt_match.opt_present("enable-experimental-web-platform-features") {
|
||||||
vec![
|
vec![
|
||||||
|
"dom_async_clipboard_enabled",
|
||||||
"dom_fontface_enabled",
|
"dom_fontface_enabled",
|
||||||
"dom_imagebitmap_enabled",
|
"dom_imagebitmap_enabled",
|
||||||
"dom_intersection_observer_enabled",
|
"dom_intersection_observer_enabled",
|
||||||
|
|
1
tests/wpt/meta/__dir__.ini
vendored
1
tests/wpt/meta/__dir__.ini
vendored
|
@ -1,4 +1,5 @@
|
||||||
prefs: [
|
prefs: [
|
||||||
|
"dom_async_clipboard_enabled:true",
|
||||||
"dom_fontface_enabled:true",
|
"dom_fontface_enabled:true",
|
||||||
"dom_imagebitmap_enabled:true",
|
"dom_imagebitmap_enabled:true",
|
||||||
"dom_intersection_observer_enabled:true",
|
"dom_intersection_observer_enabled:true",
|
||||||
|
|
|
@ -5,18 +5,6 @@
|
||||||
[ClipboardItem() succeeds with empty options]
|
[ClipboardItem() succeeds with empty options]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[ClipboardItem({}) fails with empty dictionary input]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ClipboardItem(Blob) fails]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ClipboardItem() fails with null input]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ClipboardItem() fails with no input]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[types() returns correct values]
|
[types() returns correct values]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,4 @@
|
||||||
[idlharness.https.window.html]
|
[idlharness.https.window.html]
|
||||||
[ClipboardItem interface: existence and properties of interface object]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ClipboardItem interface object length]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ClipboardItem interface object name]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ClipboardItem interface: existence and properties of interface prototype object]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ClipboardItem interface: existence and properties of interface prototype object's "constructor" property]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ClipboardItem interface: existence and properties of interface prototype object's @@unscopables property]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ClipboardItem interface: attribute presentationStyle]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ClipboardItem interface: attribute types]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[ClipboardItem interface: operation getType(DOMString)]
|
[ClipboardItem interface: operation getType(DOMString)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
2
tests/wpt/mozilla/meta/MANIFEST.json
vendored
2
tests/wpt/mozilla/meta/MANIFEST.json
vendored
|
@ -13503,7 +13503,7 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"interfaces.https.html": [
|
"interfaces.https.html": [
|
||||||
"dce05a55fd33326768635c6b3cdb193d526fccdd",
|
"cc6e99d8da7cd82edefd1c0b0fce984ae85462de",
|
||||||
[
|
[
|
||||||
null,
|
null,
|
||||||
{}
|
{}
|
||||||
|
|
2
tests/wpt/mozilla/meta/__dir__.ini
vendored
2
tests/wpt/mozilla/meta/__dir__.ini
vendored
|
@ -1 +1 @@
|
||||||
prefs: ["dom_imagebitmap_enabled:true", "dom_offscreen_canvas_enabled:true", "dom_xpath_enabled:true", "dom_intersection_observer_enabled:true", "dom_resize_observer_enabled:true", "dom_notification_enabled:true", "dom_fontface_enabled:true", "dom_urlpattern_enabled:true", "dom_serviceworker_enabled:true"]
|
prefs: ["dom_imagebitmap_enabled:true", "dom_offscreen_canvas_enabled:true", "dom_xpath_enabled:true", "dom_intersection_observer_enabled:true", "dom_resize_observer_enabled:true", "dom_notification_enabled:true", "dom_fontface_enabled:true", "dom_urlpattern_enabled:true", "dom_serviceworker_enabled:true", "dom_async_clipboard_enabled:true"]
|
||||||
|
|
|
@ -39,6 +39,7 @@ test_interfaces([
|
||||||
"ChannelSplitterNode",
|
"ChannelSplitterNode",
|
||||||
"CharacterData",
|
"CharacterData",
|
||||||
"ClipboardEvent",
|
"ClipboardEvent",
|
||||||
|
"ClipboardItem",
|
||||||
"CloseEvent",
|
"CloseEvent",
|
||||||
"ConstantSourceNode",
|
"ConstantSourceNode",
|
||||||
"CryptoKey",
|
"CryptoKey",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue