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