1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/base/clipboard/test/test_clipboard.h"
6
7 #include <stddef.h>
8 #include <memory>
9 #include <utility>
10 #include "base/memory/ptr_util.h"
11 #include "base/numerics/safe_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "build/build_config.h"
14 #include "skia/ext/skia_utils_base.h"
15 #include "ui/base/clipboard/clipboard_constants.h"
16 #include "ui/base/clipboard/clipboard_monitor.h"
17 #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
18 #include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
19
20 namespace ui {
21
22 namespace {
IsDataReadAllowed(const DataTransferEndpoint * src,const DataTransferEndpoint * dst)23 bool IsDataReadAllowed(const DataTransferEndpoint* src,
24 const DataTransferEndpoint* dst) {
25 auto* policy_controller = DataTransferPolicyController::Get();
26 if (!policy_controller)
27 return true;
28 return policy_controller->IsDataReadAllowed(src, dst);
29 }
30 } // namespace
31
TestClipboard()32 TestClipboard::TestClipboard()
33 : default_store_buffer_(ClipboardBuffer::kCopyPaste) {}
34
35 TestClipboard::~TestClipboard() = default;
36
CreateForCurrentThread()37 TestClipboard* TestClipboard::CreateForCurrentThread() {
38 base::AutoLock lock(Clipboard::ClipboardMapLock());
39 auto* clipboard = new TestClipboard;
40 (*Clipboard::ClipboardMapPtr())[base::PlatformThread::CurrentId()] =
41 base::WrapUnique(clipboard);
42 return clipboard;
43 }
44
SetLastModifiedTime(const base::Time & time)45 void TestClipboard::SetLastModifiedTime(const base::Time& time) {
46 last_modified_time_ = time;
47 }
48
OnPreShutdown()49 void TestClipboard::OnPreShutdown() {}
50
GetSequenceNumber(ClipboardBuffer buffer) const51 uint64_t TestClipboard::GetSequenceNumber(ClipboardBuffer buffer) const {
52 return GetStore(buffer).sequence_number;
53 }
54
IsFormatAvailable(const ClipboardFormatType & format,ClipboardBuffer buffer,const ui::DataTransferEndpoint * data_dst) const55 bool TestClipboard::IsFormatAvailable(
56 const ClipboardFormatType& format,
57 ClipboardBuffer buffer,
58 const ui::DataTransferEndpoint* data_dst) const {
59 if (!IsDataReadAllowed(GetStore(buffer).data_src.get(), data_dst))
60 return false;
61 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
62 // The linux clipboard treats the presence of text on the clipboard
63 // as the url format being available.
64 if (format == ClipboardFormatType::GetUrlType())
65 return IsFormatAvailable(ClipboardFormatType::GetPlainTextType(), buffer,
66 data_dst);
67 #endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
68 const DataStore& store = GetStore(buffer);
69 return base::Contains(store.data, format);
70 }
71
Clear(ClipboardBuffer buffer)72 void TestClipboard::Clear(ClipboardBuffer buffer) {
73 GetStore(buffer).Clear();
74 }
75
ReadAvailableTypes(ClipboardBuffer buffer,const DataTransferEndpoint * data_dst,std::vector<base::string16> * types) const76 void TestClipboard::ReadAvailableTypes(
77 ClipboardBuffer buffer,
78 const DataTransferEndpoint* data_dst,
79 std::vector<base::string16>* types) const {
80 DCHECK(types);
81 types->clear();
82 if (!IsDataReadAllowed(GetStore(buffer).data_src.get(), data_dst))
83 return;
84
85 if (IsFormatAvailable(ClipboardFormatType::GetPlainTextType(), buffer,
86 data_dst))
87 types->push_back(base::UTF8ToUTF16(kMimeTypeText));
88 if (IsFormatAvailable(ClipboardFormatType::GetHtmlType(), buffer, data_dst))
89 types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
90
91 if (IsFormatAvailable(ClipboardFormatType::GetRtfType(), buffer, data_dst))
92 types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
93 if (IsFormatAvailable(ClipboardFormatType::GetBitmapType(), buffer, data_dst))
94 types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
95 }
96
97 std::vector<base::string16>
ReadAvailablePlatformSpecificFormatNames(ClipboardBuffer buffer,const ui::DataTransferEndpoint * data_dst) const98 TestClipboard::ReadAvailablePlatformSpecificFormatNames(
99 ClipboardBuffer buffer,
100 const ui::DataTransferEndpoint* data_dst) const {
101 const DataStore& store = GetStore(buffer);
102 if (!IsDataReadAllowed(store.data_src.get(), data_dst))
103 return {};
104
105 const auto& data = store.data;
106 std::vector<base::string16> types;
107 types.reserve(data.size());
108 for (const auto& it : data)
109 types.push_back(base::UTF8ToUTF16(it.first.GetName()));
110
111 // Some platforms add additional raw types to represent text, or offer them
112 // as available formats by automatically converting between them.
113 if (IsFormatAvailable(ClipboardFormatType::GetPlainTextType(), buffer,
114 data_dst)) {
115 #if defined(USE_X11)
116 types.push_back(base::ASCIIToUTF16("TEXT"));
117 types.push_back(base::ASCIIToUTF16("STRING"));
118 types.push_back(base::ASCIIToUTF16("UTF8_STRING"));
119 #elif defined(OS_WIN)
120 types.push_back(base::ASCIIToUTF16("CF_OEMTEXT"));
121 #elif defined(OS_APPLE)
122 types.push_back(base::ASCIIToUTF16("NSStringPboardType"));
123 #endif
124 }
125
126 return types;
127 }
128
ReadText(ClipboardBuffer buffer,const DataTransferEndpoint * data_dst,base::string16 * result) const129 void TestClipboard::ReadText(ClipboardBuffer buffer,
130 const DataTransferEndpoint* data_dst,
131 base::string16* result) const {
132 if (!IsDataReadAllowed(GetStore(buffer).data_src.get(), data_dst))
133 return;
134
135 std::string result8;
136 ReadAsciiText(buffer, data_dst, &result8);
137 *result = base::UTF8ToUTF16(result8);
138 }
139
140 // TODO(crbug.com/1103215): |data_dst| should be supported.
ReadAsciiText(ClipboardBuffer buffer,const DataTransferEndpoint * data_dst,std::string * result) const141 void TestClipboard::ReadAsciiText(ClipboardBuffer buffer,
142 const DataTransferEndpoint* data_dst,
143 std::string* result) const {
144 const DataStore& store = GetStore(buffer);
145 if (!IsDataReadAllowed(store.data_src.get(), data_dst))
146 return;
147
148 result->clear();
149 auto it = store.data.find(ClipboardFormatType::GetPlainTextType());
150 if (it != store.data.end())
151 *result = it->second;
152 }
153
ReadHTML(ClipboardBuffer buffer,const DataTransferEndpoint * data_dst,base::string16 * markup,std::string * src_url,uint32_t * fragment_start,uint32_t * fragment_end) const154 void TestClipboard::ReadHTML(ClipboardBuffer buffer,
155 const DataTransferEndpoint* data_dst,
156 base::string16* markup,
157 std::string* src_url,
158 uint32_t* fragment_start,
159 uint32_t* fragment_end) const {
160 const DataStore& store = GetStore(buffer);
161 if (!IsDataReadAllowed(store.data_src.get(), data_dst))
162 return;
163
164 markup->clear();
165 src_url->clear();
166 auto it = store.data.find(ClipboardFormatType::GetHtmlType());
167 if (it != store.data.end())
168 *markup = base::UTF8ToUTF16(it->second);
169 *src_url = store.html_src_url;
170 *fragment_start = 0;
171 *fragment_end = base::checked_cast<uint32_t>(markup->size());
172 }
173
ReadSvg(ClipboardBuffer buffer,const DataTransferEndpoint * data_dst,base::string16 * result) const174 void TestClipboard::ReadSvg(ClipboardBuffer buffer,
175 const DataTransferEndpoint* data_dst,
176 base::string16* result) const {
177 const DataStore& store = GetStore(buffer);
178 if (!IsDataReadAllowed(store.data_src.get(), data_dst))
179 return;
180
181 result->clear();
182 auto it = store.data.find(ClipboardFormatType::GetSvgType());
183 if (it != store.data.end())
184 *result = base::UTF8ToUTF16(it->second);
185 }
186
ReadRTF(ClipboardBuffer buffer,const DataTransferEndpoint * data_dst,std::string * result) const187 void TestClipboard::ReadRTF(ClipboardBuffer buffer,
188 const DataTransferEndpoint* data_dst,
189 std::string* result) const {
190 const DataStore& store = GetStore(buffer);
191 if (!IsDataReadAllowed(store.data_src.get(), data_dst))
192 return;
193
194 result->clear();
195 auto it = store.data.find(ClipboardFormatType::GetRtfType());
196 if (it != store.data.end())
197 *result = it->second;
198 }
199
ReadImage(ClipboardBuffer buffer,const DataTransferEndpoint * data_dst,ReadImageCallback callback) const200 void TestClipboard::ReadImage(ClipboardBuffer buffer,
201 const DataTransferEndpoint* data_dst,
202 ReadImageCallback callback) const {
203 const DataStore& store = GetStore(buffer);
204 if (!IsDataReadAllowed(store.data_src.get(), data_dst)) {
205 std::move(callback).Run(SkBitmap());
206 return;
207 }
208 std::move(callback).Run(store.image);
209 }
210
211 // TODO(crbug.com/1103215): |data_dst| should be supported.
ReadCustomData(ClipboardBuffer buffer,const base::string16 & type,const DataTransferEndpoint * data_dst,base::string16 * result) const212 void TestClipboard::ReadCustomData(ClipboardBuffer buffer,
213 const base::string16& type,
214 const DataTransferEndpoint* data_dst,
215 base::string16* result) const {}
216
217 // TODO(crbug.com/1103215): |data_dst| should be supported.
ReadBookmark(const DataTransferEndpoint * data_dst,base::string16 * title,std::string * url) const218 void TestClipboard::ReadBookmark(const DataTransferEndpoint* data_dst,
219 base::string16* title,
220 std::string* url) const {
221 const DataStore& store = GetDefaultStore();
222 if (!IsDataReadAllowed(store.data_src.get(), data_dst))
223 return;
224
225 if (url) {
226 auto it = store.data.find(ClipboardFormatType::GetUrlType());
227 if (it != store.data.end())
228 *url = it->second;
229 }
230 if (title)
231 *title = base::UTF8ToUTF16(store.url_title);
232 }
233
ReadData(const ClipboardFormatType & format,const DataTransferEndpoint * data_dst,std::string * result) const234 void TestClipboard::ReadData(const ClipboardFormatType& format,
235 const DataTransferEndpoint* data_dst,
236 std::string* result) const {
237 const DataStore& store = GetDefaultStore();
238 if (!IsDataReadAllowed(store.data_src.get(), data_dst))
239 return;
240
241 result->clear();
242 auto it = store.data.find(format);
243 if (it != store.data.end())
244 *result = it->second;
245 }
246
GetLastModifiedTime() const247 base::Time TestClipboard::GetLastModifiedTime() const {
248 return last_modified_time_;
249 }
250
ClearLastModifiedTime()251 void TestClipboard::ClearLastModifiedTime() {
252 last_modified_time_ = base::Time();
253 }
254
255 #if defined(USE_OZONE)
IsSelectionBufferAvailable() const256 bool TestClipboard::IsSelectionBufferAvailable() const {
257 return true;
258 }
259 #endif // defined(USE_OZONE)
260
WritePortableRepresentations(ClipboardBuffer buffer,const ObjectMap & objects,std::unique_ptr<DataTransferEndpoint> data_src)261 void TestClipboard::WritePortableRepresentations(
262 ClipboardBuffer buffer,
263 const ObjectMap& objects,
264 std::unique_ptr<DataTransferEndpoint> data_src) {
265 Clear(buffer);
266 default_store_buffer_ = buffer;
267 for (const auto& kv : objects)
268 DispatchPortableRepresentation(kv.first, kv.second);
269 default_store_buffer_ = ClipboardBuffer::kCopyPaste;
270 GetStore(buffer).SetDataSource(std::move(data_src));
271 }
272
WritePlatformRepresentations(ClipboardBuffer buffer,std::vector<Clipboard::PlatformRepresentation> platform_representations,std::unique_ptr<DataTransferEndpoint> data_src)273 void TestClipboard::WritePlatformRepresentations(
274 ClipboardBuffer buffer,
275 std::vector<Clipboard::PlatformRepresentation> platform_representations,
276 std::unique_ptr<DataTransferEndpoint> data_src) {
277 Clear(buffer);
278 default_store_buffer_ = buffer;
279 DispatchPlatformRepresentations(std::move(platform_representations));
280 default_store_buffer_ = ClipboardBuffer::kCopyPaste;
281 GetStore(buffer).SetDataSource(std::move(data_src));
282 }
283
WriteText(const char * text_data,size_t text_len)284 void TestClipboard::WriteText(const char* text_data, size_t text_len) {
285 std::string text(text_data, text_len);
286 GetDefaultStore().data[ClipboardFormatType::GetPlainTextType()] = text;
287 #if defined(OS_WIN)
288 // Create a dummy entry.
289 GetDefaultStore().data[ClipboardFormatType::GetPlainTextAType()];
290 #endif
291 if (IsSupportedClipboardBuffer(ClipboardBuffer::kSelection))
292 GetStore(ClipboardBuffer::kSelection)
293 .data[ClipboardFormatType::GetPlainTextType()] = text;
294 ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();
295 }
296
WriteHTML(const char * markup_data,size_t markup_len,const char * url_data,size_t url_len)297 void TestClipboard::WriteHTML(const char* markup_data,
298 size_t markup_len,
299 const char* url_data,
300 size_t url_len) {
301 base::string16 markup;
302 base::UTF8ToUTF16(markup_data, markup_len, &markup);
303 GetDefaultStore().data[ClipboardFormatType::GetHtmlType()] =
304 base::UTF16ToUTF8(markup);
305 GetDefaultStore().html_src_url = std::string(url_data, url_len);
306 }
307
WriteSvg(const char * markup_data,size_t markup_len)308 void TestClipboard::WriteSvg(const char* markup_data, size_t markup_len) {
309 base::string16 markup;
310 base::UTF8ToUTF16(markup_data, markup_len, &markup);
311 GetDefaultStore().data[ClipboardFormatType::GetSvgType()] =
312 base::UTF16ToUTF8(markup);
313 }
314
WriteRTF(const char * rtf_data,size_t data_len)315 void TestClipboard::WriteRTF(const char* rtf_data, size_t data_len) {
316 GetDefaultStore().data[ClipboardFormatType::GetRtfType()] =
317 std::string(rtf_data, data_len);
318 }
319
WriteBookmark(const char * title_data,size_t title_len,const char * url_data,size_t url_len)320 void TestClipboard::WriteBookmark(const char* title_data,
321 size_t title_len,
322 const char* url_data,
323 size_t url_len) {
324 GetDefaultStore().data[ClipboardFormatType::GetUrlType()] =
325 std::string(url_data, url_len);
326 GetDefaultStore().url_title = std::string(title_data, title_len);
327 }
328
WriteWebSmartPaste()329 void TestClipboard::WriteWebSmartPaste() {
330 // Create a dummy entry.
331 GetDefaultStore().data[ClipboardFormatType::GetWebKitSmartPasteType()];
332 }
333
WriteBitmap(const SkBitmap & bitmap)334 void TestClipboard::WriteBitmap(const SkBitmap& bitmap) {
335 // We expect callers to sanitize `bitmap` to be N32 color type, to avoid
336 // out-of-bounds issues due to unexpected bits-per-pixel while copying the
337 // bitmap's pixel buffer. This DCHECK is to help alert us if we've missed
338 // something.
339 DCHECK_EQ(bitmap.colorType(), kN32_SkColorType);
340
341 // Create a dummy entry.
342 GetDefaultStore().data[ClipboardFormatType::GetBitmapType()];
343 GetDefaultStore().image = bitmap;
344 ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();
345 }
346
WriteData(const ClipboardFormatType & format,const char * data_data,size_t data_len)347 void TestClipboard::WriteData(const ClipboardFormatType& format,
348 const char* data_data,
349 size_t data_len) {
350 GetDefaultStore().data[format] = std::string(data_data, data_len);
351 }
352
353 TestClipboard::DataStore::DataStore() = default;
354
DataStore(const DataStore & other)355 TestClipboard::DataStore::DataStore(const DataStore& other) {
356 sequence_number = other.sequence_number;
357 data = other.data;
358 url_title = other.url_title;
359 html_src_url = other.html_src_url;
360 image = other.image;
361 data_src = other.data_src ? std::make_unique<DataTransferEndpoint>(
362 DataTransferEndpoint(*(other.data_src)))
363 : nullptr;
364 }
365
operator =(const DataStore & other)366 TestClipboard::DataStore& TestClipboard::DataStore::operator=(
367 const DataStore& other) {
368 sequence_number = other.sequence_number;
369 data = other.data;
370 url_title = other.url_title;
371 html_src_url = other.html_src_url;
372 image = other.image;
373 data_src = other.data_src ? std::make_unique<DataTransferEndpoint>(
374 DataTransferEndpoint(*(other.data_src)))
375 : nullptr;
376 return *this;
377 }
378
379 TestClipboard::DataStore::~DataStore() = default;
380
Clear()381 void TestClipboard::DataStore::Clear() {
382 data.clear();
383 url_title.clear();
384 html_src_url.clear();
385 image = SkBitmap();
386 }
387
SetDataSource(std::unique_ptr<DataTransferEndpoint> data_src)388 void TestClipboard::DataStore::SetDataSource(
389 std::unique_ptr<DataTransferEndpoint> data_src) {
390 this->data_src = std::move(data_src);
391 }
392
GetStore(ClipboardBuffer buffer) const393 const TestClipboard::DataStore& TestClipboard::GetStore(
394 ClipboardBuffer buffer) const {
395 CHECK(IsSupportedClipboardBuffer(buffer));
396 return stores_[buffer];
397 }
398
GetStore(ClipboardBuffer buffer)399 TestClipboard::DataStore& TestClipboard::GetStore(ClipboardBuffer buffer) {
400 CHECK(IsSupportedClipboardBuffer(buffer));
401 DataStore& store = stores_[buffer];
402 ++store.sequence_number;
403 return store;
404 }
405
GetDefaultStore() const406 const TestClipboard::DataStore& TestClipboard::GetDefaultStore() const {
407 return GetStore(default_store_buffer_);
408 }
409
GetDefaultStore()410 TestClipboard::DataStore& TestClipboard::GetDefaultStore() {
411 return GetStore(default_store_buffer_);
412 }
413
414 } // namespace ui
415