Bug 1858788 - Implement ClipboardItem.supports; r=nika

See https://w3c.github.io/clipboard-apis/#dom-clipboarditem-supports and we
currently support mandatory types only.

Differential Revision: https://phabricator.services.mozilla.com/D205651
This commit is contained in:
Edgar Chen 2024-04-18 22:32:54 +00:00
parent d3b59ee280
commit cd503d19cf
8 changed files with 69 additions and 34 deletions

View File

@ -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<const nsLiteralCString> Clipboard::MandatoryDataTypes() {
return Span<const nsLiteralCString>(kMandatoryDataTypes);
}
namespace {
/**
@ -87,16 +100,6 @@ class ClipboardGetCallback : public nsIAsyncClipboardGetCallback {
RefPtr<Promise> mPromise;
};
static nsTArray<nsCString> 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<nsCString>{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<RefPtr<ClipboardItem::ItemEntry>, 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<ClipboardItem::ItemEntry>(
mGlobal, NS_ConvertUTF8toUTF16(format));
@ -287,10 +290,13 @@ void Clipboard::RequestRead(Promise* aPromise, ReadRequestType aType,
return;
}
AutoTArray<nsCString, ArrayLength(kMandatoryDataTypes)> types;
types.AppendElements(Span<const nsLiteralCString>(kMandatoryDataTypes));
callback = MakeRefPtr<ClipboardGetCallbackForRead>(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: {

View File

@ -51,6 +51,8 @@ class Clipboard : public DOMEventTargetHelper {
// testing purposes.
static bool ReadTextEnabled(JSContext* aCx, JSObject* aGlobal);
static Span<const nsLiteralCString> MandatoryDataTypes();
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;

View File

@ -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> 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<nsString>& aTypes) const {
for (const auto& item : mItems) {
aTypes.AppendElement(item->Type());

View File

@ -107,6 +107,8 @@ class ClipboardItem final : public nsWrapperCache {
const Record<nsString, OwningNonNull<Promise>>& aItems,
const ClipboardItemOptions& aOptions, ErrorResult& aRv);
static bool Supports(const GlobalObject& aGlobal, const nsAString& aType);
dom::PresentationStyle PresentationStyle() const {
return mPresentationStyle;
};

View File

@ -53,6 +53,8 @@ interface ClipboardItem {
[NewObject]
Promise<Blob> getType(DOMString type);
static boolean supports(DOMString type);
};
enum PresentationStyle { "unspecified", "inline", "attachment" };

View File

@ -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

View File

@ -1,5 +1,3 @@
[idlharness.https.window.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[ClipboardItem interface: operation supports(DOMString)]
expected: FAIL

View File

@ -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"}`);
});
</script>