diff --git a/dom/events/Clipboard.cpp b/dom/events/Clipboard.cpp index 1e6ae0d1b9c0..3574d0836521 100644 --- a/dom/events/Clipboard.cpp +++ b/dom/events/Clipboard.cpp @@ -59,6 +59,19 @@ bool Clipboard::IsTestingPrefEnabledOrHasReadPermission( nsGkAtoms::clipboardRead); } +// Mandatory data types defined in +// https://w3c.github.io/clipboard-apis/#mandatory-data-types-x. The types +// should be in the same order as kNonPlainTextExternalFormats in +// DataTransfer. +static const nsLiteralCString kMandatoryDataTypes[] = { + nsLiteralCString(kHTMLMime), nsLiteralCString(kTextMime), + nsLiteralCString(kPNGImageMime)}; + +// static +Span Clipboard::MandatoryDataTypes() { + return Span(kMandatoryDataTypes); +} + namespace { /** @@ -87,16 +100,6 @@ class ClipboardGetCallback : public nsIAsyncClipboardGetCallback { RefPtr mPromise; }; -static nsTArray MandatoryDataTypesAsCStrings() { - // Mandatory data types defined in - // https://w3c.github.io/clipboard-apis/#mandatory-data-types-x. The types - // should be in the same order as kNonPlainTextExternalFormats in - // DataTransfer. - return nsTArray{nsLiteralCString(kHTMLMime), - nsLiteralCString(kTextMime), - nsLiteralCString(kPNGImageMime)}; -} - class ClipboardGetCallbackForRead final : public ClipboardGetCallback { public: explicit ClipboardGetCallbackForRead(nsIGlobalObject* aGlobal, @@ -122,7 +125,7 @@ class ClipboardGetCallbackForRead final : public ClipboardGetCallback { AutoTArray, 3> entries; // We might reuse the request from DataTransfer created for paste event, // which could contain more types that are not in the mandatory list. - for (const auto& format : MandatoryDataTypesAsCStrings()) { + for (const auto& format : kMandatoryDataTypes) { if (flavorList.Contains(format)) { auto entry = MakeRefPtr( mGlobal, NS_ConvertUTF8toUTF16(format)); @@ -287,10 +290,13 @@ void Clipboard::RequestRead(Promise* aPromise, ReadRequestType aType, return; } + AutoTArray types; + types.AppendElements(Span(kMandatoryDataTypes)); + callback = MakeRefPtr(global, std::move(p)); - rv = clipboardService->AsyncGetData( - MandatoryDataTypesAsCStrings(), nsIClipboard::kGlobalClipboard, - owner->GetWindowContext(), &aPrincipal, callback); + rv = clipboardService->AsyncGetData(types, nsIClipboard::kGlobalClipboard, + owner->GetWindowContext(), + &aPrincipal, callback); break; } case ReadRequestType::eReadText: { diff --git a/dom/events/Clipboard.h b/dom/events/Clipboard.h index a9952e60520b..f4d44c25dbad 100644 --- a/dom/events/Clipboard.h +++ b/dom/events/Clipboard.h @@ -51,6 +51,8 @@ class Clipboard : public DOMEventTargetHelper { // testing purposes. static bool ReadTextEnabled(JSContext* aCx, JSObject* aGlobal); + static Span MandatoryDataTypes(); + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; diff --git a/dom/events/ClipboardItem.cpp b/dom/events/ClipboardItem.cpp index 76196be3b6b0..0d5df854921f 100644 --- a/dom/events/ClipboardItem.cpp +++ b/dom/events/ClipboardItem.cpp @@ -6,6 +6,7 @@ #include "mozilla/dom/ClipboardItem.h" +#include "mozilla/dom/Clipboard.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/Record.h" #include "nsComponentManagerUtils.h" @@ -290,6 +291,17 @@ already_AddRefed ClipboardItem::Constructor( return item.forget(); } +// static +bool ClipboardItem::Supports(const GlobalObject& aGlobal, + const nsAString& aType) { + for (const auto& mandatoryType : Clipboard::MandatoryDataTypes()) { + if (CompareUTF8toUTF16(mandatoryType, aType) == 0) { + return true; + } + } + return false; +} + void ClipboardItem::GetTypes(nsTArray& aTypes) const { for (const auto& item : mItems) { aTypes.AppendElement(item->Type()); diff --git a/dom/events/ClipboardItem.h b/dom/events/ClipboardItem.h index 9fe45bf93643..53b914745cc6 100644 --- a/dom/events/ClipboardItem.h +++ b/dom/events/ClipboardItem.h @@ -107,6 +107,8 @@ class ClipboardItem final : public nsWrapperCache { const Record>& aItems, const ClipboardItemOptions& aOptions, ErrorResult& aRv); + static bool Supports(const GlobalObject& aGlobal, const nsAString& aType); + dom::PresentationStyle PresentationStyle() const { return mPresentationStyle; }; diff --git a/dom/webidl/Clipboard.webidl b/dom/webidl/Clipboard.webidl index 5bc5cd51bc24..d793916c1a3e 100644 --- a/dom/webidl/Clipboard.webidl +++ b/dom/webidl/Clipboard.webidl @@ -53,6 +53,8 @@ interface ClipboardItem { [NewObject] Promise getType(DOMString type); + + static boolean supports(DOMString type); }; enum PresentationStyle { "unspecified", "inline", "attachment" }; diff --git a/testing/web-platform/meta/clipboard-apis/clipboard-item.https.html.ini b/testing/web-platform/meta/clipboard-apis/clipboard-item.https.html.ini index 6d3b91351bc2..4f872f918769 100644 --- a/testing/web-platform/meta/clipboard-apis/clipboard-item.https.html.ini +++ b/testing/web-platform/meta/clipboard-apis/clipboard-item.https.html.ini @@ -1,5 +1,11 @@ [clipboard-item.https.html] expected: if (os == "android") and fission: [OK, TIMEOUT] - [supports(DOMString) returns true for types that are supported, false otherwise] + [supports(image/svg+xml) returns true] + expected: FAIL + + [supports(web foo/bar) returns true] + expected: FAIL + + [supports(web text/html) returns true] expected: FAIL diff --git a/testing/web-platform/meta/clipboard-apis/idlharness.https.window.js.ini b/testing/web-platform/meta/clipboard-apis/idlharness.https.window.js.ini index 29856f82da1d..8e35006d6dfd 100644 --- a/testing/web-platform/meta/clipboard-apis/idlharness.https.window.js.ini +++ b/testing/web-platform/meta/clipboard-apis/idlharness.https.window.js.ini @@ -1,5 +1,3 @@ [idlharness.https.window.html] expected: if (os == "android") and fission: [OK, TIMEOUT] - [ClipboardItem interface: operation supports(DOMString)] - expected: FAIL diff --git a/testing/web-platform/tests/clipboard-apis/clipboard-item.https.html b/testing/web-platform/tests/clipboard-apis/clipboard-item.https.html index 7e148703a267..78acd1104a96 100644 --- a/testing/web-platform/tests/clipboard-apis/clipboard-item.https.html +++ b/testing/web-platform/tests/clipboard-apis/clipboard-item.https.html @@ -96,21 +96,28 @@ promise_test(async () => { assert_equals(text, 'xxx'); }, "getType(DOMString invalid type) converts DOMString to Blob"); -promise_test(async () => { - assert_true(ClipboardItem.supports('text/plain')); - assert_true(ClipboardItem.supports('text/html')); - assert_true(ClipboardItem.supports('image/png')); - assert_true(ClipboardItem.supports('image/svg+xml')); - assert_false(ClipboardItem.supports('web ')); - assert_false(ClipboardItem.supports('web')); // without space. - assert_false(ClipboardItem.supports('web foo')); - assert_false(ClipboardItem.supports('foo/bar')); - assert_true(ClipboardItem.supports('web foo/bar')); - assert_true(ClipboardItem.supports('web text/html')); - assert_false(ClipboardItem.supports('weB text/html')); - assert_false(ClipboardItem.supports(' web text/html')); - assert_false(ClipboardItem.supports('not a/real type')); - assert_false(ClipboardItem.supports('')); - assert_false(ClipboardItem.supports(' ')); -}, "supports(DOMString) returns true for types that are supported, false otherwise"); +[ + // mandatory data types + ['text/plain', true], + ['text/html', true], + ['image/png', true], + // optional data types + ['image/svg+xml', true], + ['web foo/bar', true], + ['web text/html', true], + // invalid types + ['web ', false], + ['web', false], + ['web foo', false], + ['foo/bar', false], + ['weB text/html', false], + [' web text/html', false], + ['not a/real type', false], + ['', false], + [' ', false], +].forEach(([type, result]) => { + promise_test(async () => { + assert_equals(ClipboardItem.supports(type), result); + }, `supports(${type}) returns ${result ? "true" : "false"}`); +});