OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "build/build_config.h" | 5 #include "ui/base/clipboard/clipboard.h" |
6 | 6 |
7 #include <string> | |
8 | |
9 #include "base/basictypes.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "base/message_loop/message_loop.h" | |
12 #include "base/pickle.h" | |
13 #include "base/run_loop.h" | |
14 #include "base/strings/string_util.h" | |
15 #include "base/strings/utf_string_conversions.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | 7 #include "testing/gtest/include/gtest/gtest.h" |
17 #include "testing/platform_test.h" | |
18 #include "third_party/skia/include/core/SkBitmap.h" | |
19 #include "third_party/skia/include/core/SkColor.h" | |
20 #include "third_party/skia/include/core/SkScalar.h" | |
21 #include "third_party/skia/include/core/SkUnPreMultiply.h" | |
22 #include "ui/base/clipboard/clipboard.h" | |
23 #include "ui/base/clipboard/scoped_clipboard_writer.h" | |
24 #include "ui/gfx/size.h" | |
25 | |
26 #if defined(OS_WIN) | |
27 #include "ui/base/clipboard/clipboard_util_win.h" | |
28 #endif | |
29 | |
30 #if defined(OS_ANDROID) | |
31 #include "base/android/jni_android.h" | |
32 #include "base/android/jni_string.h" | |
33 #endif | |
34 | |
35 #if defined(USE_AURA) | |
36 #include "ui/events/platform/platform_event_source.h" | |
37 #endif | |
38 | |
39 using base::ASCIIToUTF16; | |
40 using base::UTF8ToUTF16; | |
41 using base::UTF16ToUTF8; | |
42 | 8 |
43 namespace ui { | 9 namespace ui { |
44 | 10 |
45 template <typename ClipboardTraits> | |
46 class ClipboardTest : public PlatformTest { | |
47 public: | |
48 #if defined(USE_AURA) | |
49 ClipboardTest() | |
50 : event_source_(PlatformEventSource::CreateDefault()), | |
51 clipboard_(ClipboardTraits::Create()) {} | |
52 #else | |
53 ClipboardTest() : clipboard_(ClipboardTraits::Create()) {} | |
54 #endif | |
55 | |
56 ~ClipboardTest() override { ClipboardTraits::Destroy(clipboard_); } | |
57 | |
58 static void WriteObjectsToClipboard(ui::Clipboard* clipboard, | |
59 const Clipboard::ObjectMap& objects) { | |
60 clipboard->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects); | |
61 } | |
62 | |
63 protected: | |
64 Clipboard& clipboard() { return *clipboard_; } | |
65 | |
66 void WriteObjectsToClipboard(const Clipboard::ObjectMap& objects) { | |
67 WriteObjectsToClipboard(&clipboard(), objects); | |
68 } | |
69 | |
70 private: | |
71 base::MessageLoopForUI message_loop_; | |
72 #if defined(USE_AURA) | |
73 scoped_ptr<PlatformEventSource> event_source_; | |
74 #endif | |
75 // ui::Clipboard has a protected destructor, so scoped_ptr doesn't work here. | |
76 Clipboard* const clipboard_; | |
77 }; | |
78 | |
79 namespace { | |
80 | |
81 bool MarkupMatches(const base::string16& expected_markup, | |
82 const base::string16& actual_markup) { | |
83 return actual_markup.find(expected_markup) != base::string16::npos; | |
84 } | |
85 | |
86 } // namespace | |
87 | |
88 struct PlatformClipboardTraits { | 11 struct PlatformClipboardTraits { |
89 static Clipboard* Create() { | 12 static Clipboard* Create() { return Clipboard::GetForCurrentThread(); } |
90 return Clipboard::GetForCurrentThread(); | |
91 } | |
92 | 13 |
93 static void Destroy(Clipboard* clipboard) { | 14 static void Destroy(Clipboard* clipboard) { |
94 ASSERT_EQ(Clipboard::GetForCurrentThread(), clipboard); | 15 ASSERT_EQ(Clipboard::GetForCurrentThread(), clipboard); |
95 Clipboard::DestroyClipboardForCurrentThread(); | 16 Clipboard::DestroyClipboardForCurrentThread(); |
96 } | 17 } |
97 }; | 18 }; |
98 | 19 |
99 TYPED_TEST_CASE(ClipboardTest, PlatformClipboardTraits); | 20 typedef PlatformClipboardTraits TypesToTest; |
100 | |
101 TYPED_TEST(ClipboardTest, ClearTest) { | |
102 { | |
103 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
104 clipboard_writer.WriteText(ASCIIToUTF16("clear me")); | |
105 } | |
106 | |
107 this->clipboard().Clear(CLIPBOARD_TYPE_COPY_PASTE); | |
108 | |
109 EXPECT_FALSE(this->clipboard().IsFormatAvailable( | |
110 Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
111 EXPECT_FALSE(this->clipboard().IsFormatAvailable( | |
112 Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
113 } | |
114 | |
115 TYPED_TEST(ClipboardTest, TextTest) { | |
116 base::string16 text(ASCIIToUTF16("This is a base::string16!#$")), text_result; | |
117 std::string ascii_text; | |
118 | |
119 { | |
120 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
121 clipboard_writer.WriteText(text); | |
122 } | |
123 | |
124 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
125 Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
126 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
127 Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
128 this->clipboard().ReadText(CLIPBOARD_TYPE_COPY_PASTE, &text_result); | |
129 | |
130 EXPECT_EQ(text, text_result); | |
131 this->clipboard().ReadAsciiText(CLIPBOARD_TYPE_COPY_PASTE, &ascii_text); | |
132 EXPECT_EQ(UTF16ToUTF8(text), ascii_text); | |
133 } | |
134 | |
135 TYPED_TEST(ClipboardTest, HTMLTest) { | |
136 base::string16 markup(ASCIIToUTF16("<string>Hi!</string>")), markup_result; | |
137 base::string16 plain(ASCIIToUTF16("Hi!")), plain_result; | |
138 std::string url("http://www.example.com/"), url_result; | |
139 | |
140 { | |
141 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
142 clipboard_writer.WriteText(plain); | |
143 clipboard_writer.WriteHTML(markup, url); | |
144 } | |
145 | |
146 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
147 Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
148 uint32 ignored; | |
149 this->clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result, | |
150 &url_result, &ignored, &ignored); | |
151 EXPECT_PRED2(MarkupMatches, markup, markup_result); | |
152 #if defined(OS_WIN) | |
153 // TODO(playmobil): It's not clear that non windows clipboards need to support | |
154 // this. | |
155 EXPECT_EQ(url, url_result); | |
156 #endif // defined(OS_WIN) | |
157 } | |
158 | |
159 TYPED_TEST(ClipboardTest, RTFTest) { | |
160 std::string rtf = | |
161 "{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\n" | |
162 "This is some {\\b bold} text.\\par\n" | |
163 "}"; | |
164 | |
165 { | |
166 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
167 clipboard_writer.WriteRTF(rtf); | |
168 } | |
169 | |
170 EXPECT_TRUE(this->clipboard().IsFormatAvailable(Clipboard::GetRtfFormatType(), | |
171 CLIPBOARD_TYPE_COPY_PASTE)); | |
172 std::string result; | |
173 this->clipboard().ReadRTF(CLIPBOARD_TYPE_COPY_PASTE, &result); | |
174 EXPECT_EQ(rtf, result); | |
175 } | |
176 | |
177 // TODO(dnicoara) Enable test once Ozone implements clipboard support: | |
178 // crbug.com/361707 | |
179 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(USE_OZONE) | |
180 TYPED_TEST(ClipboardTest, MultipleBufferTest) { | |
181 base::string16 text(ASCIIToUTF16("Standard")), text_result; | |
182 base::string16 markup(ASCIIToUTF16("<string>Selection</string>")); | |
183 std::string url("http://www.example.com/"), url_result; | |
184 | |
185 { | |
186 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
187 clipboard_writer.WriteText(text); | |
188 } | |
189 | |
190 { | |
191 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_SELECTION); | |
192 clipboard_writer.WriteHTML(markup, url); | |
193 } | |
194 | |
195 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
196 Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
197 EXPECT_FALSE(this->clipboard().IsFormatAvailable( | |
198 Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_SELECTION)); | |
199 | |
200 EXPECT_FALSE(this->clipboard().IsFormatAvailable( | |
201 Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
202 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
203 Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_SELECTION)); | |
204 | |
205 this->clipboard().ReadText(CLIPBOARD_TYPE_COPY_PASTE, &text_result); | |
206 EXPECT_EQ(text, text_result); | |
207 | |
208 uint32 ignored; | |
209 base::string16 markup_result; | |
210 this->clipboard().ReadHTML(CLIPBOARD_TYPE_SELECTION, &markup_result, | |
211 &url_result, &ignored, &ignored); | |
212 EXPECT_PRED2(MarkupMatches, markup, markup_result); | |
213 } | |
214 #endif | |
215 | |
216 TYPED_TEST(ClipboardTest, TrickyHTMLTest) { | |
217 base::string16 markup(ASCIIToUTF16("<em>Bye!<!--EndFragment --></em>")), | |
218 markup_result; | |
219 std::string url, url_result; | |
220 base::string16 plain(ASCIIToUTF16("Bye!")), plain_result; | |
221 | |
222 { | |
223 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
224 clipboard_writer.WriteText(plain); | |
225 clipboard_writer.WriteHTML(markup, url); | |
226 } | |
227 | |
228 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
229 Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
230 uint32 ignored; | |
231 this->clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result, | |
232 &url_result, &ignored, &ignored); | |
233 EXPECT_PRED2(MarkupMatches, markup, markup_result); | |
234 #if defined(OS_WIN) | |
235 // TODO(playmobil): It's not clear that non windows clipboards need to support | |
236 // this. | |
237 EXPECT_EQ(url, url_result); | |
238 #endif // defined(OS_WIN) | |
239 } | |
240 | |
241 #if defined(OS_WIN) | |
242 TYPED_TEST(ClipboardTest, UniodeHTMLTest) { | |
243 base::string16 markup(UTF8ToUTF16("<div>A \xc3\xb8 \xe6\xb0\xb4</div>")), | |
244 markup_result; | |
245 std::string url, url_result; | |
246 | |
247 { | |
248 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
249 clipboard_writer.WriteHTML(markup, url); | |
250 } | |
251 | |
252 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
253 Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
254 uint32 fragment_start; | |
255 uint32 fragment_end; | |
256 this->clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result, | |
257 &url_result, &fragment_start, &fragment_end); | |
258 EXPECT_PRED2(MarkupMatches, markup, markup_result); | |
259 EXPECT_EQ(url, url_result); | |
260 // Make sure that fragment indices were adjusted when converting. | |
261 EXPECT_EQ(36, fragment_start); | |
262 EXPECT_EQ(52, fragment_end); | |
263 } | |
264 #endif // defined(OS_WIN) | |
265 | |
266 // TODO(estade): Port the following test (decide what target we use for urls) | |
267 #if !defined(OS_POSIX) || defined(OS_MACOSX) | |
268 TYPED_TEST(ClipboardTest, BookmarkTest) { | |
269 base::string16 title(ASCIIToUTF16("The Example Company")), title_result; | |
270 std::string url("http://www.example.com/"), url_result; | |
271 | |
272 { | |
273 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
274 clipboard_writer.WriteBookmark(title, url); | |
275 } | |
276 | |
277 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
278 Clipboard::GetUrlWFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
279 this->clipboard().ReadBookmark(&title_result, &url_result); | |
280 EXPECT_EQ(title, title_result); | |
281 EXPECT_EQ(url, url_result); | |
282 } | |
283 #endif // !defined(OS_POSIX) || defined(OS_MACOSX) | |
284 | |
285 TYPED_TEST(ClipboardTest, MultiFormatTest) { | |
286 base::string16 text(ASCIIToUTF16("Hi!")), text_result; | |
287 base::string16 markup(ASCIIToUTF16("<strong>Hi!</string>")), markup_result; | |
288 std::string url("http://www.example.com/"), url_result; | |
289 std::string ascii_text; | |
290 | |
291 { | |
292 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
293 clipboard_writer.WriteHTML(markup, url); | |
294 clipboard_writer.WriteText(text); | |
295 } | |
296 | |
297 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
298 Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
299 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
300 Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
301 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
302 Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
303 uint32 ignored; | |
304 this->clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result, | |
305 &url_result, &ignored, &ignored); | |
306 EXPECT_PRED2(MarkupMatches, markup, markup_result); | |
307 #if defined(OS_WIN) | |
308 // TODO(playmobil): It's not clear that non windows clipboards need to support | |
309 // this. | |
310 EXPECT_EQ(url, url_result); | |
311 #endif // defined(OS_WIN) | |
312 this->clipboard().ReadText(CLIPBOARD_TYPE_COPY_PASTE, &text_result); | |
313 EXPECT_EQ(text, text_result); | |
314 this->clipboard().ReadAsciiText(CLIPBOARD_TYPE_COPY_PASTE, &ascii_text); | |
315 EXPECT_EQ(UTF16ToUTF8(text), ascii_text); | |
316 } | |
317 | |
318 TYPED_TEST(ClipboardTest, URLTest) { | |
319 base::string16 url(ASCIIToUTF16("http://www.google.com/")); | |
320 | |
321 { | |
322 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
323 clipboard_writer.WriteURL(url); | |
324 } | |
325 | |
326 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
327 Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
328 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
329 Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
330 base::string16 text_result; | |
331 this->clipboard().ReadText(CLIPBOARD_TYPE_COPY_PASTE, &text_result); | |
332 | |
333 EXPECT_EQ(text_result, url); | |
334 | |
335 std::string ascii_text; | |
336 this->clipboard().ReadAsciiText(CLIPBOARD_TYPE_COPY_PASTE, &ascii_text); | |
337 EXPECT_EQ(UTF16ToUTF8(url), ascii_text); | |
338 | |
339 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | |
340 ascii_text.clear(); | |
341 this->clipboard().ReadAsciiText(CLIPBOARD_TYPE_SELECTION, &ascii_text); | |
342 EXPECT_EQ(UTF16ToUTF8(url), ascii_text); | |
343 #endif | |
344 } | |
345 | |
346 // TODO(dcheng): The tests for copying to the clipboard also test IPC | |
347 // interaction... consider moving them to a different layer so we can | |
348 // consolidate the validation logic. | |
349 // Note that |bitmap_data| is not premultiplied! | |
350 static void TestBitmapWrite(Clipboard* clipboard, | |
351 const uint32* bitmap_data, | |
352 size_t bitmap_data_size, | |
353 const gfx::Size& size) { | |
354 // Create shared memory region. | |
355 base::SharedMemory shared_buf; | |
356 ASSERT_TRUE(shared_buf.CreateAndMapAnonymous(bitmap_data_size)); | |
357 memcpy(shared_buf.memory(), bitmap_data, bitmap_data_size); | |
358 // CBF_SMBITMAP expects premultiplied bitmap data so do that now. | |
359 uint32* pixel_buffer = static_cast<uint32*>(shared_buf.memory()); | |
360 for (int j = 0; j < size.height(); ++j) { | |
361 for (int i = 0; i < size.width(); ++i) { | |
362 uint32& pixel = pixel_buffer[i + j * size.width()]; | |
363 pixel = SkPreMultiplyColor(pixel); | |
364 } | |
365 } | |
366 base::SharedMemoryHandle handle_to_share; | |
367 base::ProcessHandle current_process = base::kNullProcessHandle; | |
368 #if defined(OS_WIN) | |
369 current_process = GetCurrentProcess(); | |
370 #endif | |
371 shared_buf.ShareToProcess(current_process, &handle_to_share); | |
372 ASSERT_TRUE(shared_buf.Unmap()); | |
373 | |
374 // Setup data for clipboard(). | |
375 Clipboard::ObjectMapParam placeholder_param; | |
376 Clipboard::ObjectMapParam size_param; | |
377 const char* size_data = reinterpret_cast<const char*>(&size); | |
378 for (size_t i = 0; i < sizeof(size); ++i) | |
379 size_param.push_back(size_data[i]); | |
380 | |
381 Clipboard::ObjectMapParams params; | |
382 params.push_back(placeholder_param); | |
383 params.push_back(size_param); | |
384 | |
385 Clipboard::ObjectMap objects; | |
386 objects[Clipboard::CBF_SMBITMAP] = params; | |
387 ASSERT_TRUE(Clipboard::ReplaceSharedMemHandle( | |
388 &objects, handle_to_share, current_process)); | |
389 | |
390 // This is pretty ugly, but the template type parameter is irrelevant... and | |
391 // this test will be going away anyway. | |
392 ClipboardTest<PlatformClipboardTraits>::WriteObjectsToClipboard(clipboard, | |
393 objects); | |
394 | |
395 EXPECT_TRUE(clipboard->IsFormatAvailable(Clipboard::GetBitmapFormatType(), | |
396 CLIPBOARD_TYPE_COPY_PASTE)); | |
397 const SkBitmap& image = clipboard->ReadImage(CLIPBOARD_TYPE_COPY_PASTE); | |
398 EXPECT_EQ(size, gfx::Size(image.width(), image.height())); | |
399 SkAutoLockPixels image_lock(image); | |
400 for (int j = 0; j < image.height(); ++j) { | |
401 const uint32* row_address = image.getAddr32(0, j); | |
402 for (int i = 0; i < image.width(); ++i) { | |
403 int offset = i + j * image.width(); | |
404 uint32 pixel = SkPreMultiplyColor(bitmap_data[offset]); | |
405 EXPECT_EQ(pixel, row_address[i]) | |
406 << "i = " << i << ", j = " << j; | |
407 } | |
408 } | |
409 } | |
410 | |
411 TYPED_TEST(ClipboardTest, SharedBitmapTest) { | |
412 const uint32 fake_bitmap_1[] = { | |
413 0x46155189, 0xF6A55C8D, 0x79845674, 0xFA57BD89, | |
414 0x78FD46AE, 0x87C64F5A, 0x36EDC5AF, 0x4378F568, | |
415 0x91E9F63A, 0xC31EA14F, 0x69AB32DF, 0x643A3FD1, | |
416 }; | |
417 { | |
418 SCOPED_TRACE("first bitmap"); | |
419 TestBitmapWrite(&this->clipboard(), fake_bitmap_1, sizeof(fake_bitmap_1), | |
420 gfx::Size(4, 3)); | |
421 } | |
422 | |
423 const uint32 fake_bitmap_2[] = { | |
424 0x46155189, 0xF6A55C8D, | |
425 0x79845674, 0xFA57BD89, | |
426 0x78FD46AE, 0x87C64F5A, | |
427 0x36EDC5AF, 0x4378F568, | |
428 0x91E9F63A, 0xC31EA14F, | |
429 0x69AB32DF, 0x643A3FD1, | |
430 0xA6DF041D, 0x83046278, | |
431 }; | |
432 { | |
433 SCOPED_TRACE("second bitmap"); | |
434 TestBitmapWrite(&this->clipboard(), fake_bitmap_2, sizeof(fake_bitmap_2), | |
435 gfx::Size(2, 7)); | |
436 } | |
437 } | |
438 | |
439 namespace { | |
440 // A size class that just happens to have the same layout as gfx::Size! | |
441 struct UnsafeSize { | |
442 int width; | |
443 int height; | |
444 }; | |
445 COMPILE_ASSERT(sizeof(UnsafeSize) == sizeof(gfx::Size), | |
446 UnsafeSize_must_be_same_size_as_gfx_Size); | |
447 } // namespace | |
448 | |
449 TYPED_TEST(ClipboardTest, SharedBitmapWithTwoNegativeSizes) { | |
450 Clipboard::ObjectMapParam placeholder_param; | |
451 void* crash_me = reinterpret_cast<void*>(57); | |
452 placeholder_param.resize(sizeof(crash_me)); | |
453 memcpy(&placeholder_param.front(), &crash_me, sizeof(crash_me)); | |
454 | |
455 Clipboard::ObjectMapParam size_param; | |
456 UnsafeSize size = {-100, -100}; | |
457 size_param.resize(sizeof(size)); | |
458 memcpy(&size_param.front(), &size, sizeof(size)); | |
459 | |
460 Clipboard::ObjectMapParams params; | |
461 params.push_back(placeholder_param); | |
462 params.push_back(size_param); | |
463 | |
464 Clipboard::ObjectMap objects; | |
465 objects[Clipboard::CBF_SMBITMAP] = params; | |
466 | |
467 this->WriteObjectsToClipboard(objects); | |
468 EXPECT_FALSE(this->clipboard().IsFormatAvailable( | |
469 Clipboard::GetBitmapFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
470 } | |
471 | |
472 TYPED_TEST(ClipboardTest, SharedBitmapWithOneNegativeSize) { | |
473 Clipboard::ObjectMapParam placeholder_param; | |
474 void* crash_me = reinterpret_cast<void*>(57); | |
475 placeholder_param.resize(sizeof(crash_me)); | |
476 memcpy(&placeholder_param.front(), &crash_me, sizeof(crash_me)); | |
477 | |
478 Clipboard::ObjectMapParam size_param; | |
479 UnsafeSize size = {-100, 100}; | |
480 size_param.resize(sizeof(size)); | |
481 memcpy(&size_param.front(), &size, sizeof(size)); | |
482 | |
483 Clipboard::ObjectMapParams params; | |
484 params.push_back(placeholder_param); | |
485 params.push_back(size_param); | |
486 | |
487 Clipboard::ObjectMap objects; | |
488 objects[Clipboard::CBF_SMBITMAP] = params; | |
489 | |
490 this->WriteObjectsToClipboard(objects); | |
491 EXPECT_FALSE(this->clipboard().IsFormatAvailable( | |
492 Clipboard::GetBitmapFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
493 } | |
494 | |
495 TYPED_TEST(ClipboardTest, BitmapWithSuperSize) { | |
496 Clipboard::ObjectMapParam placeholder_param; | |
497 void* crash_me = reinterpret_cast<void*>(57); | |
498 placeholder_param.resize(sizeof(crash_me)); | |
499 memcpy(&placeholder_param.front(), &crash_me, sizeof(crash_me)); | |
500 | |
501 Clipboard::ObjectMapParam size_param; | |
502 // Width just big enough that bytes per row won't fit in a 32-bit | |
503 // representation. | |
504 gfx::Size size(0x20000000, 1); | |
505 size_param.resize(sizeof(size)); | |
506 memcpy(&size_param.front(), &size, sizeof(size)); | |
507 | |
508 Clipboard::ObjectMapParams params; | |
509 params.push_back(placeholder_param); | |
510 params.push_back(size_param); | |
511 | |
512 Clipboard::ObjectMap objects; | |
513 objects[Clipboard::CBF_SMBITMAP] = params; | |
514 | |
515 this->WriteObjectsToClipboard(objects); | |
516 EXPECT_FALSE(this->clipboard().IsFormatAvailable( | |
517 Clipboard::GetBitmapFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
518 } | |
519 | |
520 TYPED_TEST(ClipboardTest, BitmapWithSuperSize2) { | |
521 Clipboard::ObjectMapParam placeholder_param; | |
522 void* crash_me = reinterpret_cast<void*>(57); | |
523 placeholder_param.resize(sizeof(crash_me)); | |
524 memcpy(&placeholder_param.front(), &crash_me, sizeof(crash_me)); | |
525 | |
526 Clipboard::ObjectMapParam size_param; | |
527 // Width and height large enough that SkBitmap::getSize() will be truncated. | |
528 gfx::Size size(0x0fffffff, 0x0fffffff); | |
529 size_param.resize(sizeof(size)); | |
530 memcpy(&size_param.front(), &size, sizeof(size)); | |
531 | |
532 Clipboard::ObjectMapParams params; | |
533 params.push_back(placeholder_param); | |
534 params.push_back(size_param); | |
535 | |
536 Clipboard::ObjectMap objects; | |
537 objects[Clipboard::CBF_SMBITMAP] = params; | |
538 | |
539 this->WriteObjectsToClipboard(objects); | |
540 EXPECT_FALSE(this->clipboard().IsFormatAvailable( | |
541 Clipboard::GetBitmapFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
542 } | |
543 | |
544 TYPED_TEST(ClipboardTest, DataTest) { | |
545 const ui::Clipboard::FormatType kFormat = | |
546 ui::Clipboard::GetFormatType("chromium/x-test-format"); | |
547 std::string payload("test string"); | |
548 Pickle write_pickle; | |
549 write_pickle.WriteString(payload); | |
550 | |
551 { | |
552 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
553 clipboard_writer.WritePickledData(write_pickle, kFormat); | |
554 } | |
555 | |
556 ASSERT_TRUE( | |
557 this->clipboard().IsFormatAvailable(kFormat, CLIPBOARD_TYPE_COPY_PASTE)); | |
558 std::string output; | |
559 this->clipboard().ReadData(kFormat, &output); | |
560 ASSERT_FALSE(output.empty()); | |
561 | |
562 Pickle read_pickle(output.data(), output.size()); | |
563 PickleIterator iter(read_pickle); | |
564 std::string unpickled_string; | |
565 ASSERT_TRUE(read_pickle.ReadString(&iter, &unpickled_string)); | |
566 EXPECT_EQ(payload, unpickled_string); | |
567 } | |
568 | |
569 TYPED_TEST(ClipboardTest, MultipleDataTest) { | |
570 const ui::Clipboard::FormatType kFormat1 = | |
571 ui::Clipboard::GetFormatType("chromium/x-test-format1"); | |
572 std::string payload1("test string1"); | |
573 Pickle write_pickle1; | |
574 write_pickle1.WriteString(payload1); | |
575 | |
576 const ui::Clipboard::FormatType kFormat2 = | |
577 ui::Clipboard::GetFormatType("chromium/x-test-format2"); | |
578 std::string payload2("test string2"); | |
579 Pickle write_pickle2; | |
580 write_pickle2.WriteString(payload2); | |
581 | |
582 { | |
583 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
584 clipboard_writer.WritePickledData(write_pickle1, kFormat1); | |
585 // overwrite the previous pickle for fun | |
586 clipboard_writer.WritePickledData(write_pickle2, kFormat2); | |
587 } | |
588 | |
589 ASSERT_TRUE( | |
590 this->clipboard().IsFormatAvailable(kFormat2, CLIPBOARD_TYPE_COPY_PASTE)); | |
591 | |
592 // Check string 2. | |
593 std::string output2; | |
594 this->clipboard().ReadData(kFormat2, &output2); | |
595 ASSERT_FALSE(output2.empty()); | |
596 | |
597 Pickle read_pickle2(output2.data(), output2.size()); | |
598 PickleIterator iter2(read_pickle2); | |
599 std::string unpickled_string2; | |
600 ASSERT_TRUE(read_pickle2.ReadString(&iter2, &unpickled_string2)); | |
601 EXPECT_EQ(payload2, unpickled_string2); | |
602 | |
603 { | |
604 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
605 clipboard_writer.WritePickledData(write_pickle2, kFormat2); | |
606 // overwrite the previous pickle for fun | |
607 clipboard_writer.WritePickledData(write_pickle1, kFormat1); | |
608 } | |
609 | |
610 ASSERT_TRUE( | |
611 this->clipboard().IsFormatAvailable(kFormat1, CLIPBOARD_TYPE_COPY_PASTE)); | |
612 | |
613 // Check string 1. | |
614 std::string output1; | |
615 this->clipboard().ReadData(kFormat1, &output1); | |
616 ASSERT_FALSE(output1.empty()); | |
617 | |
618 Pickle read_pickle1(output1.data(), output1.size()); | |
619 PickleIterator iter1(read_pickle1); | |
620 std::string unpickled_string1; | |
621 ASSERT_TRUE(read_pickle1.ReadString(&iter1, &unpickled_string1)); | |
622 EXPECT_EQ(payload1, unpickled_string1); | |
623 } | |
624 | |
625 #if !defined(OS_MACOSX) && !defined(OS_ANDROID) | |
626 TYPED_TEST(ClipboardTest, HyperlinkTest) { | |
627 const std::string kTitle("The <Example> Company's \"home page\""); | |
628 const std::string kUrl("http://www.example.com?x=3<=3#\"'<>"); | |
629 const std::string kExpectedHtml( | |
630 "<a href=\"http://www.example.com?x=3&lt=3#"'<>\">" | |
631 "The <Example> Company's "home page"</a>"); | |
632 | |
633 std::string url_result; | |
634 base::string16 html_result; | |
635 { | |
636 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
637 clipboard_writer.WriteHyperlink(ASCIIToUTF16(kTitle), kUrl); | |
638 } | |
639 | |
640 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
641 Clipboard::GetHtmlFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
642 uint32 ignored; | |
643 this->clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &html_result, | |
644 &url_result, &ignored, &ignored); | |
645 EXPECT_PRED2(MarkupMatches, ASCIIToUTF16(kExpectedHtml), html_result); | |
646 } | |
647 #endif | |
648 | |
649 TYPED_TEST(ClipboardTest, WebSmartPasteTest) { | |
650 { | |
651 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
652 clipboard_writer.WriteWebSmartPaste(); | |
653 } | |
654 | |
655 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
656 Clipboard::GetWebKitSmartPasteFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
657 } | |
658 | |
659 #if defined(OS_WIN) // Windows only tests. | |
660 void HtmlTestHelper(const std::string& cf_html, | |
661 const std::string& expected_html) { | |
662 std::string html; | |
663 ClipboardUtil::CFHtmlToHtml(cf_html, &html, NULL); | |
664 EXPECT_EQ(html, expected_html); | |
665 } | |
666 | |
667 TYPED_TEST(ClipboardTest, HtmlTest) { | |
668 // Test converting from CF_HTML format data with <!--StartFragment--> and | |
669 // <!--EndFragment--> comments, like from MS Word. | |
670 HtmlTestHelper("Version:1.0\r\n" | |
671 "StartHTML:0000000105\r\n" | |
672 "EndHTML:0000000199\r\n" | |
673 "StartFragment:0000000123\r\n" | |
674 "EndFragment:0000000161\r\n" | |
675 "\r\n" | |
676 "<html>\r\n" | |
677 "<body>\r\n" | |
678 "<!--StartFragment-->\r\n" | |
679 "\r\n" | |
680 "<p>Foo</p>\r\n" | |
681 "\r\n" | |
682 "<!--EndFragment-->\r\n" | |
683 "</body>\r\n" | |
684 "</html>\r\n\r\n", | |
685 "<p>Foo</p>"); | |
686 | |
687 // Test converting from CF_HTML format data without <!--StartFragment--> and | |
688 // <!--EndFragment--> comments, like from OpenOffice Writer. | |
689 HtmlTestHelper("Version:1.0\r\n" | |
690 "StartHTML:0000000105\r\n" | |
691 "EndHTML:0000000151\r\n" | |
692 "StartFragment:0000000121\r\n" | |
693 "EndFragment:0000000131\r\n" | |
694 "<html>\r\n" | |
695 "<body>\r\n" | |
696 "<p>Foo</p>\r\n" | |
697 "</body>\r\n" | |
698 "</html>\r\n\r\n", | |
699 "<p>Foo</p>"); | |
700 } | |
701 #endif // defined(OS_WIN) | |
702 | |
703 // Test writing all formats we have simultaneously. | |
704 TYPED_TEST(ClipboardTest, WriteEverything) { | |
705 { | |
706 ScopedClipboardWriter writer(CLIPBOARD_TYPE_COPY_PASTE); | |
707 writer.WriteText(UTF8ToUTF16("foo")); | |
708 writer.WriteURL(UTF8ToUTF16("foo")); | |
709 writer.WriteHTML(UTF8ToUTF16("foo"), "bar"); | |
710 writer.WriteBookmark(UTF8ToUTF16("foo"), "bar"); | |
711 writer.WriteHyperlink(ASCIIToUTF16("foo"), "bar"); | |
712 writer.WriteWebSmartPaste(); | |
713 // Left out: WriteFile, WriteFiles, WriteBitmapFromPixels, WritePickledData. | |
714 } | |
715 | |
716 // Passes if we don't crash. | |
717 } | |
718 | |
719 // TODO(dcheng): Fix this test for Android. It's rather involved, since the | |
720 // clipboard change listener is posted to the Java message loop, and spinning | |
721 // that loop from C++ to trigger the callback in the test requires a non-trivial | |
722 // amount of additional work. | |
723 #if !defined(OS_ANDROID) | |
724 // Simple test that the sequence number appears to change when the clipboard is | |
725 // written to. | |
726 // TODO(dcheng): Add a version to test CLIPBOARD_TYPE_SELECTION. | |
727 TYPED_TEST(ClipboardTest, GetSequenceNumber) { | |
728 const uint64 first_sequence_number = | |
729 this->clipboard().GetSequenceNumber(CLIPBOARD_TYPE_COPY_PASTE); | |
730 | |
731 { | |
732 ScopedClipboardWriter writer(CLIPBOARD_TYPE_COPY_PASTE); | |
733 writer.WriteText(UTF8ToUTF16("World")); | |
734 } | |
735 | |
736 // On some platforms, the sequence number is updated by a UI callback so pump | |
737 // the message loop to make sure we get the notification. | |
738 base::RunLoop().RunUntilIdle(); | |
739 | |
740 const uint64 second_sequence_number = | |
741 this->clipboard().GetSequenceNumber(CLIPBOARD_TYPE_COPY_PASTE); | |
742 | |
743 EXPECT_NE(first_sequence_number, second_sequence_number); | |
744 } | |
745 #endif | |
746 | |
747 #if defined(OS_ANDROID) | |
748 | |
749 // Test that if another application writes some text to the pasteboard the | |
750 // clipboard properly invalidates other types. | |
751 TYPED_TEST(ClipboardTest, InternalClipboardInvalidation) { | |
752 // Write a Webkit smart paste tag to our clipboard. | |
753 { | |
754 ScopedClipboardWriter clipboard_writer(CLIPBOARD_TYPE_COPY_PASTE); | |
755 clipboard_writer.WriteWebSmartPaste(); | |
756 } | |
757 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
758 Clipboard::GetWebKitSmartPasteFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
759 | |
760 // | |
761 // Simulate that another application copied something in the Clipboard | |
762 // | |
763 std::string new_value("Some text copied by some other app"); | |
764 using base::android::ConvertUTF8ToJavaString; | |
765 using base::android::MethodID; | |
766 using base::android::ScopedJavaLocalRef; | |
767 | |
768 JNIEnv* env = base::android::AttachCurrentThread(); | |
769 ASSERT_TRUE(env); | |
770 | |
771 jobject context = base::android::GetApplicationContext(); | |
772 ASSERT_TRUE(context); | |
773 | |
774 ScopedJavaLocalRef<jclass> context_class = | |
775 base::android::GetClass(env, "android/content/Context"); | |
776 | |
777 jmethodID get_system_service = MethodID::Get<MethodID::TYPE_INSTANCE>( | |
778 env, context_class.obj(), "getSystemService", | |
779 "(Ljava/lang/String;)Ljava/lang/Object;"); | |
780 | |
781 // Retrieve the system service. | |
782 ScopedJavaLocalRef<jstring> service_name = ConvertUTF8ToJavaString( | |
783 env, "clipboard"); | |
784 ScopedJavaLocalRef<jobject> clipboard_manager( | |
785 env, env->CallObjectMethod( | |
786 context, get_system_service, service_name.obj())); | |
787 ASSERT_TRUE(clipboard_manager.obj() && !base::android::ClearException(env)); | |
788 | |
789 ScopedJavaLocalRef<jclass> clipboard_class = | |
790 base::android::GetClass(env, "android/text/ClipboardManager"); | |
791 jmethodID set_text = MethodID::Get<MethodID::TYPE_INSTANCE>( | |
792 env, clipboard_class.obj(), "setText", "(Ljava/lang/CharSequence;)V"); | |
793 ScopedJavaLocalRef<jstring> new_value_string = ConvertUTF8ToJavaString( | |
794 env, new_value.c_str()); | |
795 | |
796 // Will need to call toString as CharSequence is not always a String. | |
797 env->CallVoidMethod(clipboard_manager.obj(), | |
798 set_text, | |
799 new_value_string.obj()); | |
800 | |
801 // The WebKit smart paste tag should now be gone. | |
802 EXPECT_FALSE(this->clipboard().IsFormatAvailable( | |
803 Clipboard::GetWebKitSmartPasteFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
804 | |
805 // Make sure some text is available | |
806 EXPECT_TRUE(this->clipboard().IsFormatAvailable( | |
807 Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); | |
808 | |
809 // Make sure the text is what we inserted while simulating the other app | |
810 std::string contents; | |
811 this->clipboard().ReadAsciiText(CLIPBOARD_TYPE_COPY_PASTE, &contents); | |
812 EXPECT_EQ(contents, new_value); | |
813 } | |
814 #endif | |
815 | 21 |
816 } // namespace ui | 22 } // namespace ui |
| 23 |
| 24 #include "ui/base/clipboard/clipboard_test_template.h" |
OLD | NEW |