1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/clipboard/clipboard_item.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/clipboard/clipboard.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/modules/clipboard/clipboard.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "ui/base/clipboard/clipboard_constants.h"
namespace blink {
class UnionToBlobResolverFunction final
: public ThenCallable<V8UnionBlobOrString,
UnionToBlobResolverFunction,
Blob> {
public:
explicit UnionToBlobResolverFunction(const String& mime_type)
: mime_type_(mime_type) {}
Blob* React(ScriptState* script_state, V8UnionBlobOrString* union_value) {
if (union_value->IsBlob()) {
return union_value->GetAsBlob();
} else if (union_value->IsString()) {
// ClipboardItem::getType() returns a Blob, so we need to convert the
// string to a Blob here.
return Blob::Create(union_value->GetAsString().Span8(), mime_type_);
}
return nullptr;
}
private:
String mime_type_;
};
// static
ClipboardItem* ClipboardItem::Create(
const HeapVector<
std::pair<String, MemberScriptPromise<V8UnionBlobOrString>>>&
representations,
ExceptionState& exception_state) {
// Check that incoming dictionary isn't empty. If it is, it's possible that
// Javascript bindings implicitly converted an Object (like a
// ScriptPromise<V8UnionBlobOrString>) into {}, an empty dictionary.
if (!representations.size()) {
exception_state.ThrowTypeError("Empty dictionary argument");
return nullptr;
}
return MakeGarbageCollected<ClipboardItem>(representations);
}
ClipboardItem::ClipboardItem(
const HeapVector<
std::pair<String, MemberScriptPromise<V8UnionBlobOrString>>>&
representations) {
for (const auto& representation : representations) {
String web_custom_format =
Clipboard::ParseWebCustomFormat(representation.first);
if (web_custom_format.empty()) {
// Any arbitrary type can be added to ClipboardItem, but there may not be
// any read/write support for that type.
// TODO(caseq,japhet): we can't pass typed promises from bindings yet, but
// when we can, the type cast below should go away.
representations_.emplace_back(representation.first,
representation.second);
} else {
// Types with "web " prefix are special, so we do some level of MIME type
// parsing here to get a valid web custom format type.
// We want to ensure that the string after removing the "web " prefix is
// a valid MIME type.
// e.g. "web text/html" is a web custom MIME type & "text/html" is a
// well-known MIME type. Removing the "web " prefix makes it hard to
// differentiate between the two.
// TODO(caseq,japhet): we can't pass typed promises from bindings yet, but
// when we can, the type cast below should go away.
String web_custom_format_string =
String::Format("%s%s", ui::kWebClipboardFormatPrefix,
web_custom_format.Utf8().c_str());
representations_.emplace_back(web_custom_format_string,
representation.second);
custom_format_types_.push_back(web_custom_format_string);
}
}
}
Vector<String> ClipboardItem::types() const {
Vector<String> types;
types.ReserveInitialCapacity(representations_.size());
for (const auto& item : representations_) {
types.push_back(item.first);
}
return types;
}
ScriptPromise<Blob> ClipboardItem::getType(
ScriptState* script_state,
const String& type,
ExceptionState& exception_state) const {
for (const auto& item : representations_) {
if (type == item.first) {
return item.second.Unwrap().Then(
script_state,
MakeGarbageCollected<UnionToBlobResolverFunction>(type));
}
}
exception_state.ThrowDOMException(DOMExceptionCode::kNotFoundError,
"The type was not found");
return ScriptPromise<Blob>();
}
// static
bool ClipboardItem::supports(const String& type) {
if (type.length() >= mojom::blink::ClipboardHost::kMaxFormatSize) {
return false;
}
if (!Clipboard::ParseWebCustomFormat(type).empty()) {
return true;
}
// TODO(https://crbug.com/1029857): Add support for other types.
return type == ui::kMimeTypePng || type == ui::kMimeTypePlainText ||
type == ui::kMimeTypeHtml || type == ui::kMimeTypeSvg;
}
void ClipboardItem::Trace(Visitor* visitor) const {
visitor->Trace(representations_);
ScriptWrappable::Trace(visitor);
}
} // namespace blink
|