зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1689886 - Add a test-only clipboard.read implementation with ClipboardItem. r=nika
Differential Revision: https://phabricator.services.mozilla.com/D103588
This commit is contained in:
Родитель
c1b72d4f7a
Коммит
be7f4c6ca9
|
@ -65,27 +65,78 @@ already_AddRefed<Promise> Clipboard::ReadHelper(
|
||||||
RefPtr<DataTransfer> dataTransfer = new DataTransfer(
|
RefPtr<DataTransfer> dataTransfer = new DataTransfer(
|
||||||
this, ePaste, /* is external */ true, nsIClipboard::kGlobalClipboard);
|
this, ePaste, /* is external */ true, nsIClipboard::kGlobalClipboard);
|
||||||
|
|
||||||
|
RefPtr<nsPIDOMWindowInner> owner = GetOwner();
|
||||||
|
|
||||||
// Create a new runnable
|
// Create a new runnable
|
||||||
RefPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
RefPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
||||||
"Clipboard::Read",
|
"Clipboard::Read", [p, dataTransfer, aClipboardReadType, owner,
|
||||||
[p, dataTransfer, &aSubjectPrincipal, aClipboardReadType]() {
|
principal = RefPtr{&aSubjectPrincipal}]() {
|
||||||
IgnoredErrorResult ier;
|
IgnoredErrorResult ier;
|
||||||
switch (aClipboardReadType) {
|
switch (aClipboardReadType) {
|
||||||
case eRead:
|
case eRead: {
|
||||||
MOZ_LOG(GetClipboardLog(), LogLevel::Debug,
|
MOZ_LOG(GetClipboardLog(), LogLevel::Debug,
|
||||||
("Clipboard, ReadHelper, read case\n"));
|
("Clipboard, ReadHelper, read case\n"));
|
||||||
dataTransfer->FillAllExternalData();
|
dataTransfer->FillAllExternalData();
|
||||||
// If there are items on the clipboard, data transfer will contain
|
|
||||||
// those, else, data transfer will be empty and we will be resolving
|
// Convert the DataTransferItems to ClipboardItems.
|
||||||
// with an empty data transfer
|
// FIXME(bug 1691825): This is only suitable for testing!
|
||||||
p->MaybeResolve(dataTransfer);
|
// A real implementation would only read from the clipboard
|
||||||
|
// in ClipboardItem::getType instead of doing it here.
|
||||||
|
nsTArray<ClipboardItem::ItemEntry> entries;
|
||||||
|
DataTransferItemList* items = dataTransfer->Items();
|
||||||
|
for (size_t i = 0; i < items->Length(); i++) {
|
||||||
|
bool found = false;
|
||||||
|
DataTransferItem* item = items->IndexedGetter(i, found);
|
||||||
|
|
||||||
|
// Only allow strings and files.
|
||||||
|
if (!found || item->Kind() == DataTransferItem::KIND_OTHER) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoString type;
|
||||||
|
item->GetType(type);
|
||||||
|
|
||||||
|
if (item->Kind() == DataTransferItem::KIND_STRING) {
|
||||||
|
// We just ignore items that we can't access.
|
||||||
|
IgnoredErrorResult ignored;
|
||||||
|
nsCOMPtr<nsIVariant> data = item->Data(principal, ignored);
|
||||||
|
if (NS_WARN_IF(!data || ignored.Failed())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoString string;
|
||||||
|
if (NS_WARN_IF(NS_FAILED(data->GetAsAString(string)))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClipboardItem::ItemEntry* entry = entries.AppendElement();
|
||||||
|
entry->mType = type;
|
||||||
|
entry->mData.SetAsString() = string;
|
||||||
|
} else {
|
||||||
|
IgnoredErrorResult ignored;
|
||||||
|
RefPtr<File> file = item->GetAsFile(*principal, ignored);
|
||||||
|
if (NS_WARN_IF(!file || ignored.Failed())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClipboardItem::ItemEntry* entry = entries.AppendElement();
|
||||||
|
entry->mType = type;
|
||||||
|
entry->mData.SetAsBlob() = file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsTArray<RefPtr<ClipboardItem>> sequence;
|
||||||
|
sequence.AppendElement(MakeRefPtr<ClipboardItem>(
|
||||||
|
owner, PresentationStyle::Unspecified, std::move(entries)));
|
||||||
|
p->MaybeResolve(sequence);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case eReadText:
|
case eReadText:
|
||||||
MOZ_LOG(GetClipboardLog(), LogLevel::Debug,
|
MOZ_LOG(GetClipboardLog(), LogLevel::Debug,
|
||||||
("Clipboard, ReadHelper, read text case\n"));
|
("Clipboard, ReadHelper, read text case\n"));
|
||||||
nsAutoString str;
|
nsAutoString str;
|
||||||
dataTransfer->GetData(NS_LITERAL_STRING_FROM_CSTRING(kTextMime),
|
dataTransfer->GetData(NS_LITERAL_STRING_FROM_CSTRING(kTextMime),
|
||||||
str, aSubjectPrincipal, ier);
|
str, *principal, ier);
|
||||||
// Either resolve with a string extracted from data transfer item
|
// Either resolve with a string extracted from data transfer item
|
||||||
// or resolve with an empty string if nothing was found
|
// or resolve with an empty string if nothing was found
|
||||||
p->MaybeResolve(str);
|
p->MaybeResolve(str);
|
||||||
|
|
|
@ -14,8 +14,8 @@ typedef sequence<ClipboardItem> ClipboardItems;
|
||||||
|
|
||||||
[SecureContext, Exposed=Window, Pref="dom.events.asyncClipboard"]
|
[SecureContext, Exposed=Window, Pref="dom.events.asyncClipboard"]
|
||||||
interface Clipboard : EventTarget {
|
interface Clipboard : EventTarget {
|
||||||
[Pref="dom.events.asyncClipboard.dataTransfer", Throws, NeedsSubjectPrincipal]
|
[Pref="dom.events.asyncClipboard.clipboardItem", Throws, NeedsSubjectPrincipal]
|
||||||
Promise<DataTransfer> read();
|
Promise<ClipboardItems> read();
|
||||||
[Func="Clipboard::ReadTextEnabled", Throws, NeedsSubjectPrincipal]
|
[Func="Clipboard::ReadTextEnabled", Throws, NeedsSubjectPrincipal]
|
||||||
Promise<DOMString> readText();
|
Promise<DOMString> readText();
|
||||||
|
|
||||||
|
|
|
@ -1805,13 +1805,7 @@
|
||||||
value: true
|
value: true
|
||||||
mirror: always
|
mirror: always
|
||||||
|
|
||||||
# Disable clipboard read() by default
|
# Disable ClipboardItem and clipboard.read/write by default
|
||||||
- name: dom.events.asyncClipboard.dataTransfer
|
|
||||||
type: bool
|
|
||||||
value: false
|
|
||||||
mirror: always
|
|
||||||
|
|
||||||
# Disable ClipboardItem and clipboard.write by default
|
|
||||||
- name: dom.events.asyncClipboard.clipboardItem
|
- name: dom.events.asyncClipboard.clipboardItem
|
||||||
type: bool
|
type: bool
|
||||||
value: false
|
value: false
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
prefs: [dom.events.asyncClipboard:true, dom.events.asyncClipboard.dataTransfer:true, dom.events.asyncClipboard.clipboardItem: true, dom.events.testing.asyncClipboard:true]
|
prefs: [dom.events.asyncClipboard:true, dom.events.asyncClipboard.clipboardItem: true,
|
||||||
|
dom.events.testing.asyncClipboard:true]
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[async-navigator-clipboard-basics.https.html]
|
|
||||||
[navigator.clipboard.read() succeeds]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -59,7 +59,6 @@ function clearClipboard() {
|
||||||
add_task(async function setup() {
|
add_task(async function setup() {
|
||||||
await SpecialPowers.pushPrefEnv({"set": [
|
await SpecialPowers.pushPrefEnv({"set": [
|
||||||
["dom.events.asyncClipboard", true],
|
["dom.events.asyncClipboard", true],
|
||||||
["dom.events.asyncClipboard.dataTransfer", true],
|
|
||||||
["dom.events.asyncClipboard.clipboardItem", true],
|
["dom.events.asyncClipboard.clipboardItem", true],
|
||||||
]});
|
]});
|
||||||
});
|
});
|
||||||
|
@ -241,8 +240,9 @@ add_task(async function test_contentscript_clipboard_permission_write() {
|
||||||
// Test that with enough permissions, we are allowed to use read in content script
|
// Test that with enough permissions, we are allowed to use read in content script
|
||||||
add_task(async function test_contentscript_clipboard_permission_read() {
|
add_task(async function test_contentscript_clipboard_permission_read() {
|
||||||
function contentScript() {
|
function contentScript() {
|
||||||
clipboardRead().then(function(dt) {
|
clipboardRead().then(async function(items) {
|
||||||
let s = dt.getData("text/plain");
|
let blob = await items[0].getType("text/plain");
|
||||||
|
let s = await blob.text();
|
||||||
if (s == "HELLO") {
|
if (s == "HELLO") {
|
||||||
browser.test.succeed("Read promise successfully read the right thing");
|
browser.test.succeed("Read promise successfully read the right thing");
|
||||||
} else {
|
} else {
|
||||||
|
@ -323,24 +323,15 @@ add_task(async function test_contentscript_clipboard_nocontents_readtext() {
|
||||||
await extension.unload();
|
await extension.unload();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test that performing read(...) when the clipboard is empty returns an empty data transfer
|
// Test that performing read(...) when the clipboard is empty returns an empty ClipboardItem
|
||||||
add_task(async function test_contentscript_clipboard_nocontents_read() {
|
add_task(async function test_contentscript_clipboard_nocontents_read() {
|
||||||
function contentScript() {
|
function contentScript() {
|
||||||
clipboardRead().then(function(dataT) {
|
clipboardRead().then(function(items) {
|
||||||
// On macOS if we clear the clipboard and read from it, there will be
|
if (items[0].types.length) {
|
||||||
// no items in the data transfer object.
|
|
||||||
// On linux with e10s enabled clearing of the clipboard does not happen in
|
|
||||||
// the same way as it does on other platforms. So when we clear the clipboard
|
|
||||||
// and read from it, the data transfer object contains an item of type
|
|
||||||
// text/plain and kind string, but we can't call getAsString on it to verify
|
|
||||||
// that at least it is an empty string because the callback never gets invoked.
|
|
||||||
if (!dataT.items.length ||
|
|
||||||
(dataT.items.length == 1 && dataT.items[0].type == "text/plain" &&
|
|
||||||
dataT.items[0].kind == "string")) {
|
|
||||||
browser.test.succeed("Read promise successfully resolved");
|
|
||||||
} else {
|
|
||||||
browser.test.fail("Read read the wrong thing from clipboard, " +
|
browser.test.fail("Read read the wrong thing from clipboard, " +
|
||||||
"data transfer has this many items:" + dataT.items.length);
|
"ClipboardItem has this many entries: " + items[0].types.length);
|
||||||
|
} else {
|
||||||
|
browser.test.succeed("Read promise successfully resolved");
|
||||||
}
|
}
|
||||||
browser.test.sendMessage("ready");
|
browser.test.sendMessage("ready");
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче