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 // Many of these functions are based on those found in 6 // webkit/port/platform/PasteboardWin.cpp 7 8 #include "ui/base/clipboard/clipboard.h" 9 10 #include <shlobj.h> 11 #include <shellapi.h> 12 13 #include "base/basictypes.h" 14 #include "base/bind.h" 15 #include "base/files/file_path.h" 16 #include "base/logging.h" 17 #include "base/memory/shared_memory.h" 18 #include "base/message_loop/message_loop.h" 19 #include "base/safe_numerics.h" 20 #include "base/stl_util.h" 21 #include "base/strings/string_number_conversions.h" 22 #include "base/strings/string_util.h" 23 #include "base/strings/utf_offset_string_conversions.h" 24 #include "base/strings/utf_string_conversions.h" 25 #include "base/win/message_window.h" 26 #include "base/win/scoped_gdi_object.h" 27 #include "base/win/scoped_hdc.h" 28 #include "third_party/skia/include/core/SkBitmap.h" 29 #include "ui/base/clipboard/clipboard_util_win.h" 30 #include "ui/base/clipboard/custom_data_helper.h" 31 #include "ui/gfx/canvas.h" 32 #include "ui/gfx/size.h" 33 34 namespace ui { 35 36 namespace { 37 38 // A scoper to manage acquiring and automatically releasing the clipboard. 39 class ScopedClipboard { 40 public: 41 ScopedClipboard() : opened_(false) { } 42 43 ~ScopedClipboard() { 44 if (opened_) 45 Release(); 46 } 47 48 bool Acquire(HWND owner) { 49 const int kMaxAttemptsToOpenClipboard = 5; 50 51 if (opened_) { 52 NOTREACHED(); 53 return false; 54 } 55 56 // Attempt to open the clipboard, which will acquire the Windows clipboard 57 // lock. This may fail if another process currently holds this lock. 58 // We're willing to try a few times in the hopes of acquiring it. 59 // 60 // This turns out to be an issue when using remote desktop because the 61 // rdpclip.exe process likes to read what we've written to the clipboard and 62 // send it to the RDP client. If we open and close the clipboard in quick 63 // succession, we might be trying to open it while rdpclip.exe has it open, 64 // See Bug 815425. 65 // 66 // In fact, we believe we'll only spin this loop over remote desktop. In 67 // normal situations, the user is initiating clipboard operations and there 68 // shouldn't be contention. 69 70 for (int attempts = 0; attempts < kMaxAttemptsToOpenClipboard; ++attempts) { 71 // If we didn't manage to open the clipboard, sleep a bit and be hopeful. 72 if (attempts != 0) 73 ::Sleep(5); 74 75 if (::OpenClipboard(owner)) { 76 opened_ = true; 77 return true; 78 } 79 } 80 81 // We failed to acquire the clipboard. 82 return false; 83 } 84 85 void Release() { 86 if (opened_) { 87 ::CloseClipboard(); 88 opened_ = false; 89 } else { 90 NOTREACHED(); 91 } 92 } 93 94 private: 95 bool opened_; 96 }; 97 98 bool ClipboardOwnerWndProc(UINT message, 99 WPARAM wparam, 100 LPARAM lparam, 101 LRESULT* result) { 102 switch (message) { 103 case WM_RENDERFORMAT: 104 // This message comes when SetClipboardData was sent a null data handle 105 // and now it's come time to put the data on the clipboard. 106 // We always set data, so there isn't a need to actually do anything here. 107 break; 108 case WM_RENDERALLFORMATS: 109 // This message comes when SetClipboardData was sent a null data handle 110 // and now this application is about to quit, so it must put data on 111 // the clipboard before it exits. 112 // We always set data, so there isn't a need to actually do anything here. 113 break; 114 case WM_DRAWCLIPBOARD: 115 break; 116 case WM_DESTROY: 117 break; 118 case WM_CHANGECBCHAIN: 119 break; 120 default: 121 return false; 122 } 123 124 *result = 0; 125 return true; 126 } 127 128 template <typename charT> 129 HGLOBAL CreateGlobalData(const std::basic_string<charT>& str) { 130 HGLOBAL data = 131 ::GlobalAlloc(GMEM_MOVEABLE, ((str.size() + 1) * sizeof(charT))); 132 if (data) { 133 charT* raw_data = static_cast<charT*>(::GlobalLock(data)); 134 memcpy(raw_data, str.data(), str.size() * sizeof(charT)); 135 raw_data[str.size()] = '\0'; 136 ::GlobalUnlock(data); 137 } 138 return data; 139 }; 140 141 bool BitmapHasInvalidPremultipliedColors(const SkBitmap& bitmap) { 142 for (int x = 0; x < bitmap.width(); ++x) { 143 for (int y = 0; y < bitmap.height(); ++y) { 144 uint32_t pixel = *bitmap.getAddr32(x, y); 145 if (SkColorGetR(pixel) > SkColorGetA(pixel) || 146 SkColorGetG(pixel) > SkColorGetA(pixel) || 147 SkColorGetB(pixel) > SkColorGetA(pixel)) 148 return true; 149 } 150 } 151 return false; 152 } 153 154 void MakeBitmapOpaque(const SkBitmap& bitmap) { 155 for (int x = 0; x < bitmap.width(); ++x) { 156 for (int y = 0; y < bitmap.height(); ++y) { 157 *bitmap.getAddr32(x, y) = SkColorSetA(*bitmap.getAddr32(x, y), 0xFF); 158 } 159 } 160 } 161 162 } // namespace 163 164 Clipboard::FormatType::FormatType() : data_() {} 165 166 Clipboard::FormatType::FormatType(UINT native_format) : data_() { 167 // There's no good way to actually initialize this in the constructor in 168 // C++03. 169 data_.cfFormat = native_format; 170 data_.dwAspect = DVASPECT_CONTENT; 171 data_.lindex = -1; 172 data_.tymed = TYMED_HGLOBAL; 173 } 174 175 Clipboard::FormatType::FormatType(UINT native_format, LONG index) : data_() { 176 // There's no good way to actually initialize this in the constructor in 177 // C++03. 178 data_.cfFormat = native_format; 179 data_.dwAspect = DVASPECT_CONTENT; 180 data_.lindex = index; 181 data_.tymed = TYMED_HGLOBAL; 182 } 183 184 Clipboard::FormatType::~FormatType() { 185 } 186 187 std::string Clipboard::FormatType::Serialize() const { 188 return base::IntToString(data_.cfFormat); 189 } 190 191 // static 192 Clipboard::FormatType Clipboard::FormatType::Deserialize( 193 const std::string& serialization) { 194 int clipboard_format = -1; 195 if (!base::StringToInt(serialization, &clipboard_format)) { 196 NOTREACHED(); 197 return FormatType(); 198 } 199 return FormatType(clipboard_format); 200 } 201 202 bool Clipboard::FormatType::operator<(const FormatType& other) const { 203 return ToUINT() < other.ToUINT(); 204 } 205 206 Clipboard::Clipboard() { 207 if (base::MessageLoop::current()->type() == base::MessageLoop::TYPE_UI) 208 clipboard_owner_.reset(new base::win::MessageWindow()); 209 } 210 211 Clipboard::~Clipboard() { 212 } 213 214 void Clipboard::WriteObjects(Buffer buffer, const ObjectMap& objects) { 215 DCHECK_EQ(buffer, BUFFER_STANDARD); 216 217 ScopedClipboard clipboard; 218 if (!clipboard.Acquire(GetClipboardWindow())) 219 return; 220 221 ::EmptyClipboard(); 222 223 for (ObjectMap::const_iterator iter = objects.begin(); 224 iter != objects.end(); ++iter) { 225 DispatchObject(static_cast<ObjectType>(iter->first), iter->second); 226 } 227 } 228 229 void Clipboard::WriteText(const char* text_data, size_t text_len) { 230 string16 text; 231 UTF8ToUTF16(text_data, text_len, &text); 232 HGLOBAL glob = CreateGlobalData(text); 233 234 WriteToClipboard(CF_UNICODETEXT, glob); 235 } 236 237 void Clipboard::WriteHTML(const char* markup_data, 238 size_t markup_len, 239 const char* url_data, 240 size_t url_len) { 241 std::string markup(markup_data, markup_len); 242 std::string url; 243 244 if (url_len > 0) 245 url.assign(url_data, url_len); 246 247 std::string html_fragment = ClipboardUtil::HtmlToCFHtml(markup, url); 248 HGLOBAL glob = CreateGlobalData(html_fragment); 249 250 WriteToClipboard(Clipboard::GetHtmlFormatType().ToUINT(), glob); 251 } 252 253 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) { 254 WriteData(GetRtfFormatType(), rtf_data, data_len); 255 } 256 257 void Clipboard::WriteBookmark(const char* title_data, 258 size_t title_len, 259 const char* url_data, 260 size_t url_len) { 261 std::string bookmark(title_data, title_len); 262 bookmark.append(1, L'\n'); 263 bookmark.append(url_data, url_len); 264 265 string16 wide_bookmark = UTF8ToWide(bookmark); 266 HGLOBAL glob = CreateGlobalData(wide_bookmark); 267 268 WriteToClipboard(GetUrlWFormatType().ToUINT(), glob); 269 } 270 271 void Clipboard::WriteWebSmartPaste() { 272 DCHECK(clipboard_owner_->hwnd() != NULL); 273 ::SetClipboardData(GetWebKitSmartPasteFormatType().ToUINT(), NULL); 274 } 275 276 void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) { 277 const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data); 278 HDC dc = ::GetDC(NULL); 279 280 // This doesn't actually cost us a memcpy when the bitmap comes from the 281 // renderer as we load it into the bitmap using setPixels which just sets a 282 // pointer. Someone has to memcpy it into GDI, it might as well be us here. 283 284 // TODO(darin): share data in gfx/bitmap_header.cc somehow 285 BITMAPINFO bm_info = {0}; 286 bm_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 287 bm_info.bmiHeader.biWidth = size->width(); 288 bm_info.bmiHeader.biHeight = -size->height(); // sets vertical orientation 289 bm_info.bmiHeader.biPlanes = 1; 290 bm_info.bmiHeader.biBitCount = 32; 291 bm_info.bmiHeader.biCompression = BI_RGB; 292 293 // ::CreateDIBSection allocates memory for us to copy our bitmap into. 294 // Unfortunately, we can't write the created bitmap to the clipboard, 295 // (see http://msdn2.microsoft.com/en-us/library/ms532292.aspx) 296 void *bits; 297 HBITMAP source_hbitmap = 298 ::CreateDIBSection(dc, &bm_info, DIB_RGB_COLORS, &bits, NULL, 0); 299 300 if (bits && source_hbitmap) { 301 // Copy the bitmap out of shared memory and into GDI 302 memcpy(bits, pixel_data, 4 * size->width() * size->height()); 303 304 // Now we have an HBITMAP, we can write it to the clipboard 305 WriteBitmapFromHandle(source_hbitmap, *size); 306 } 307 308 ::DeleteObject(source_hbitmap); 309 ::ReleaseDC(NULL, dc); 310 } 311 312 void Clipboard::WriteBitmapFromHandle(HBITMAP source_hbitmap, 313 const gfx::Size& size) { 314 // We would like to just call ::SetClipboardData on the source_hbitmap, 315 // but that bitmap might not be of a sort we can write to the clipboard. 316 // For this reason, we create a new bitmap, copy the bits over, and then 317 // write that to the clipboard. 318 319 HDC dc = ::GetDC(NULL); 320 HDC compatible_dc = ::CreateCompatibleDC(NULL); 321 HDC source_dc = ::CreateCompatibleDC(NULL); 322 323 // This is the HBITMAP we will eventually write to the clipboard 324 HBITMAP hbitmap = ::CreateCompatibleBitmap(dc, size.width(), size.height()); 325 if (!hbitmap) { 326 // Failed to create the bitmap 327 ::DeleteDC(compatible_dc); 328 ::DeleteDC(source_dc); 329 ::ReleaseDC(NULL, dc); 330 return; 331 } 332 333 HBITMAP old_hbitmap = (HBITMAP)SelectObject(compatible_dc, hbitmap); 334 HBITMAP old_source = (HBITMAP)SelectObject(source_dc, source_hbitmap); 335 336 // Now we need to blend it into an HBITMAP we can place on the clipboard 337 BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; 338 ::GdiAlphaBlend(compatible_dc, 0, 0, size.width(), size.height(), 339 source_dc, 0, 0, size.width(), size.height(), bf); 340 341 // Clean up all the handles we just opened 342 ::SelectObject(compatible_dc, old_hbitmap); 343 ::SelectObject(source_dc, old_source); 344 ::DeleteObject(old_hbitmap); 345 ::DeleteObject(old_source); 346 ::DeleteDC(compatible_dc); 347 ::DeleteDC(source_dc); 348 ::ReleaseDC(NULL, dc); 349 350 WriteToClipboard(CF_BITMAP, hbitmap); 351 } 352 353 void Clipboard::WriteData(const FormatType& format, 354 const char* data_data, 355 size_t data_len) { 356 HGLOBAL hdata = ::GlobalAlloc(GMEM_MOVEABLE, data_len); 357 if (!hdata) 358 return; 359 360 char* data = static_cast<char*>(::GlobalLock(hdata)); 361 memcpy(data, data_data, data_len); 362 ::GlobalUnlock(data); 363 WriteToClipboard(format.ToUINT(), hdata); 364 } 365 366 void Clipboard::WriteToClipboard(unsigned int format, HANDLE handle) { 367 DCHECK(clipboard_owner_->hwnd() != NULL); 368 if (handle && !::SetClipboardData(format, handle)) { 369 DCHECK(ERROR_CLIPBOARD_NOT_OPEN != GetLastError()); 370 FreeData(format, handle); 371 } 372 } 373 374 uint64 Clipboard::GetSequenceNumber(Buffer buffer) { 375 DCHECK_EQ(buffer, BUFFER_STANDARD); 376 return ::GetClipboardSequenceNumber(); 377 } 378 379 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, 380 Clipboard::Buffer buffer) const { 381 DCHECK_EQ(buffer, BUFFER_STANDARD); 382 return ::IsClipboardFormatAvailable(format.ToUINT()) != FALSE; 383 } 384 385 void Clipboard::Clear(Buffer buffer) { 386 DCHECK_EQ(buffer, BUFFER_STANDARD); 387 ScopedClipboard clipboard; 388 if (!clipboard.Acquire(GetClipboardWindow())) 389 return; 390 391 ::EmptyClipboard(); 392 } 393 394 void Clipboard::ReadAvailableTypes(Clipboard::Buffer buffer, 395 std::vector<string16>* types, 396 bool* contains_filenames) const { 397 if (!types || !contains_filenames) { 398 NOTREACHED(); 399 return; 400 } 401 402 types->clear(); 403 if (::IsClipboardFormatAvailable(GetPlainTextFormatType().ToUINT())) 404 types->push_back(UTF8ToUTF16(kMimeTypeText)); 405 if (::IsClipboardFormatAvailable(GetHtmlFormatType().ToUINT())) 406 types->push_back(UTF8ToUTF16(kMimeTypeHTML)); 407 if (::IsClipboardFormatAvailable(GetRtfFormatType().ToUINT())) 408 types->push_back(UTF8ToUTF16(kMimeTypeRTF)); 409 if (::IsClipboardFormatAvailable(CF_DIB)) 410 types->push_back(UTF8ToUTF16(kMimeTypePNG)); 411 *contains_filenames = false; 412 413 // Acquire the clipboard. 414 ScopedClipboard clipboard; 415 if (!clipboard.Acquire(GetClipboardWindow())) 416 return; 417 418 HANDLE hdata = ::GetClipboardData(GetWebCustomDataFormatType().ToUINT()); 419 if (!hdata) 420 return; 421 422 ReadCustomDataTypes(::GlobalLock(hdata), ::GlobalSize(hdata), types); 423 ::GlobalUnlock(hdata); 424 } 425 426 void Clipboard::ReadText(Clipboard::Buffer buffer, string16* result) const { 427 DCHECK_EQ(buffer, BUFFER_STANDARD); 428 if (!result) { 429 NOTREACHED(); 430 return; 431 } 432 433 result->clear(); 434 435 // Acquire the clipboard. 436 ScopedClipboard clipboard; 437 if (!clipboard.Acquire(GetClipboardWindow())) 438 return; 439 440 HANDLE data = ::GetClipboardData(CF_UNICODETEXT); 441 if (!data) 442 return; 443 444 result->assign(static_cast<const char16*>(::GlobalLock(data))); 445 ::GlobalUnlock(data); 446 } 447 448 void Clipboard::ReadAsciiText(Clipboard::Buffer buffer, 449 std::string* result) const { 450 DCHECK_EQ(buffer, BUFFER_STANDARD); 451 if (!result) { 452 NOTREACHED(); 453 return; 454 } 455 456 result->clear(); 457 458 // Acquire the clipboard. 459 ScopedClipboard clipboard; 460 if (!clipboard.Acquire(GetClipboardWindow())) 461 return; 462 463 HANDLE data = ::GetClipboardData(CF_TEXT); 464 if (!data) 465 return; 466 467 result->assign(static_cast<const char*>(::GlobalLock(data))); 468 ::GlobalUnlock(data); 469 } 470 471 void Clipboard::ReadHTML(Clipboard::Buffer buffer, string16* markup, 472 std::string* src_url, uint32* fragment_start, 473 uint32* fragment_end) const { 474 DCHECK_EQ(buffer, BUFFER_STANDARD); 475 476 markup->clear(); 477 // TODO(dcheng): Remove these checks, I don't think they should be optional. 478 DCHECK(src_url); 479 if (src_url) 480 src_url->clear(); 481 *fragment_start = 0; 482 *fragment_end = 0; 483 484 // Acquire the clipboard. 485 ScopedClipboard clipboard; 486 if (!clipboard.Acquire(GetClipboardWindow())) 487 return; 488 489 HANDLE data = ::GetClipboardData(GetHtmlFormatType().ToUINT()); 490 if (!data) 491 return; 492 493 std::string cf_html(static_cast<const char*>(::GlobalLock(data))); 494 ::GlobalUnlock(data); 495 496 size_t html_start = std::string::npos; 497 size_t start_index = std::string::npos; 498 size_t end_index = std::string::npos; 499 ClipboardUtil::CFHtmlExtractMetadata(cf_html, src_url, &html_start, 500 &start_index, &end_index); 501 502 // This might happen if the contents of the clipboard changed and CF_HTML is 503 // no longer available. 504 if (start_index == std::string::npos || 505 end_index == std::string::npos || 506 html_start == std::string::npos) 507 return; 508 509 if (start_index < html_start || end_index < start_index) 510 return; 511 512 std::vector<size_t> offsets; 513 offsets.push_back(start_index - html_start); 514 offsets.push_back(end_index - html_start); 515 markup->assign(base::UTF8ToUTF16AndAdjustOffsets(cf_html.data() + html_start, 516 &offsets)); 517 *fragment_start = base::checked_numeric_cast<uint32>(offsets[0]); 518 *fragment_end = base::checked_numeric_cast<uint32>(offsets[1]); 519 } 520 521 void Clipboard::ReadRTF(Buffer buffer, std::string* result) const { 522 DCHECK_EQ(buffer, BUFFER_STANDARD); 523 524 ReadData(GetRtfFormatType(), result); 525 } 526 527 SkBitmap Clipboard::ReadImage(Buffer buffer) const { 528 DCHECK_EQ(buffer, BUFFER_STANDARD); 529 530 // Acquire the clipboard. 531 ScopedClipboard clipboard; 532 if (!clipboard.Acquire(GetClipboardWindow())) 533 return SkBitmap(); 534 535 // We use a DIB rather than a DDB here since ::GetObject() with the 536 // HBITMAP returned from ::GetClipboardData(CF_BITMAP) always reports a color 537 // depth of 32bpp. 538 BITMAPINFO* bitmap = static_cast<BITMAPINFO*>(::GetClipboardData(CF_DIB)); 539 if (!bitmap) 540 return SkBitmap(); 541 int color_table_length = 0; 542 switch (bitmap->bmiHeader.biBitCount) { 543 case 1: 544 case 4: 545 case 8: 546 color_table_length = bitmap->bmiHeader.biClrUsed 547 ? bitmap->bmiHeader.biClrUsed 548 : 1 << bitmap->bmiHeader.biBitCount; 549 break; 550 case 16: 551 case 32: 552 if (bitmap->bmiHeader.biCompression == BI_BITFIELDS) 553 color_table_length = 3; 554 break; 555 case 24: 556 break; 557 default: 558 NOTREACHED(); 559 } 560 const void* bitmap_bits = reinterpret_cast<const char*>(bitmap) 561 + bitmap->bmiHeader.biSize + color_table_length * sizeof(RGBQUAD); 562 563 gfx::Canvas canvas(gfx::Size(bitmap->bmiHeader.biWidth, 564 bitmap->bmiHeader.biHeight), 565 ui::SCALE_FACTOR_100P, 566 false); 567 { 568 skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas()); 569 HDC dc = scoped_platform_paint.GetPlatformSurface(); 570 ::SetDIBitsToDevice(dc, 0, 0, bitmap->bmiHeader.biWidth, 571 bitmap->bmiHeader.biHeight, 0, 0, 0, 572 bitmap->bmiHeader.biHeight, bitmap_bits, bitmap, 573 DIB_RGB_COLORS); 574 } 575 // Windows doesn't really handle alpha channels well in many situations. When 576 // the source image is < 32 bpp, we force the bitmap to be opaque. When the 577 // source image is 32 bpp, the alpha channel might still contain garbage data. 578 // Since Windows uses premultiplied alpha, we scan for instances where 579 // (R, G, B) > A. If there are any invalid premultiplied colors in the image, 580 // we assume the alpha channel contains garbage and force the bitmap to be 581 // opaque as well. Note that this heuristic will fail on a transparent bitmap 582 // containing only black pixels... 583 const SkBitmap& device_bitmap = 584 canvas.sk_canvas()->getDevice()->accessBitmap(true); 585 { 586 SkAutoLockPixels lock(device_bitmap); 587 bool has_invalid_alpha_channel = bitmap->bmiHeader.biBitCount < 32 || 588 BitmapHasInvalidPremultipliedColors(device_bitmap); 589 if (has_invalid_alpha_channel) { 590 MakeBitmapOpaque(device_bitmap); 591 } 592 } 593 594 return canvas.ExtractImageRep().sk_bitmap(); 595 } 596 597 void Clipboard::ReadCustomData(Buffer buffer, 598 const string16& type, 599 string16* result) const { 600 DCHECK_EQ(buffer, BUFFER_STANDARD); 601 602 // Acquire the clipboard. 603 ScopedClipboard clipboard; 604 if (!clipboard.Acquire(GetClipboardWindow())) 605 return; 606 607 HANDLE hdata = ::GetClipboardData(GetWebCustomDataFormatType().ToUINT()); 608 if (!hdata) 609 return; 610 611 ReadCustomDataForType(::GlobalLock(hdata), ::GlobalSize(hdata), type, result); 612 ::GlobalUnlock(hdata); 613 } 614 615 void Clipboard::ReadBookmark(string16* title, std::string* url) const { 616 if (title) 617 title->clear(); 618 619 if (url) 620 url->clear(); 621 622 // Acquire the clipboard. 623 ScopedClipboard clipboard; 624 if (!clipboard.Acquire(GetClipboardWindow())) 625 return; 626 627 HANDLE data = ::GetClipboardData(GetUrlWFormatType().ToUINT()); 628 if (!data) 629 return; 630 631 string16 bookmark(static_cast<const char16*>(::GlobalLock(data))); 632 ::GlobalUnlock(data); 633 634 ParseBookmarkClipboardFormat(bookmark, title, url); 635 } 636 637 void Clipboard::ReadData(const FormatType& format, std::string* result) const { 638 if (!result) { 639 NOTREACHED(); 640 return; 641 } 642 643 ScopedClipboard clipboard; 644 if (!clipboard.Acquire(GetClipboardWindow())) 645 return; 646 647 HANDLE data = ::GetClipboardData(format.ToUINT()); 648 if (!data) 649 return; 650 651 result->assign(static_cast<const char*>(::GlobalLock(data)), 652 ::GlobalSize(data)); 653 ::GlobalUnlock(data); 654 } 655 656 // static 657 void Clipboard::ParseBookmarkClipboardFormat(const string16& bookmark, 658 string16* title, 659 std::string* url) { 660 const string16 kDelim = ASCIIToUTF16("\r\n"); 661 662 const size_t title_end = bookmark.find_first_of(kDelim); 663 if (title) 664 title->assign(bookmark.substr(0, title_end)); 665 666 if (url) { 667 const size_t url_start = bookmark.find_first_not_of(kDelim, title_end); 668 if (url_start != string16::npos) 669 *url = UTF16ToUTF8(bookmark.substr(url_start, string16::npos)); 670 } 671 } 672 673 // static 674 Clipboard::FormatType Clipboard::GetFormatType( 675 const std::string& format_string) { 676 return FormatType( 677 ::RegisterClipboardFormat(ASCIIToWide(format_string).c_str())); 678 } 679 680 // static 681 const Clipboard::FormatType& Clipboard::GetUrlFormatType() { 682 CR_DEFINE_STATIC_LOCAL( 683 FormatType, type, (::RegisterClipboardFormat(CFSTR_INETURLA))); 684 return type; 685 } 686 687 // static 688 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() { 689 CR_DEFINE_STATIC_LOCAL( 690 FormatType, type, (::RegisterClipboardFormat(CFSTR_INETURLW))); 691 return type; 692 } 693 694 // static 695 const Clipboard::FormatType& Clipboard::GetMozUrlFormatType() { 696 CR_DEFINE_STATIC_LOCAL( 697 FormatType, type, (::RegisterClipboardFormat(L"text/x-moz-url"))); 698 return type; 699 } 700 701 // static 702 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() { 703 CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_TEXT)); 704 return type; 705 } 706 707 // static 708 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() { 709 CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_UNICODETEXT)); 710 return type; 711 } 712 713 // static 714 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() { 715 CR_DEFINE_STATIC_LOCAL( 716 FormatType, type, (::RegisterClipboardFormat(CFSTR_FILENAMEA))); 717 return type; 718 } 719 720 // static 721 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() { 722 CR_DEFINE_STATIC_LOCAL( 723 FormatType, type, (::RegisterClipboardFormat(CFSTR_FILENAMEW))); 724 return type; 725 } 726 727 // MS HTML Format 728 // static 729 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() { 730 CR_DEFINE_STATIC_LOCAL( 731 FormatType, type, (::RegisterClipboardFormat(L"HTML Format"))); 732 return type; 733 } 734 735 // MS RTF Format 736 // static 737 const Clipboard::FormatType& Clipboard::GetRtfFormatType() { 738 CR_DEFINE_STATIC_LOCAL( 739 FormatType, type, (::RegisterClipboardFormat(L"Rich Text Format"))); 740 return type; 741 } 742 743 // static 744 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() { 745 CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_BITMAP)); 746 return type; 747 } 748 749 // Firefox text/html 750 // static 751 const Clipboard::FormatType& Clipboard::GetTextHtmlFormatType() { 752 CR_DEFINE_STATIC_LOCAL( 753 FormatType, type, (::RegisterClipboardFormat(L"text/html"))); 754 return type; 755 } 756 757 // static 758 const Clipboard::FormatType& Clipboard::GetCFHDropFormatType() { 759 CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_HDROP)); 760 return type; 761 } 762 763 // static 764 const Clipboard::FormatType& Clipboard::GetFileDescriptorFormatType() { 765 CR_DEFINE_STATIC_LOCAL( 766 FormatType, type, (::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR))); 767 return type; 768 } 769 770 // static 771 const Clipboard::FormatType& Clipboard::GetFileContentZeroFormatType() { 772 CR_DEFINE_STATIC_LOCAL( 773 FormatType, type, (::RegisterClipboardFormat(CFSTR_FILECONTENTS), 0)); 774 return type; 775 } 776 777 // static 778 const Clipboard::FormatType& Clipboard::GetIDListFormatType() { 779 CR_DEFINE_STATIC_LOCAL( 780 FormatType, type, (::RegisterClipboardFormat(CFSTR_SHELLIDLIST))); 781 return type; 782 } 783 784 // static 785 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() { 786 CR_DEFINE_STATIC_LOCAL( 787 FormatType, 788 type, 789 (::RegisterClipboardFormat(L"WebKit Smart Paste Format"))); 790 return type; 791 } 792 793 // static 794 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() { 795 // TODO(dcheng): This name is temporary. See http://crbug.com/106449. 796 CR_DEFINE_STATIC_LOCAL( 797 FormatType, 798 type, 799 (::RegisterClipboardFormat(L"Chromium Web Custom MIME Data Format"))); 800 return type; 801 } 802 803 // static 804 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() { 805 CR_DEFINE_STATIC_LOCAL( 806 FormatType, 807 type, 808 (::RegisterClipboardFormat(L"Chromium Pepper MIME Data Format"))); 809 return type; 810 } 811 812 // static 813 void Clipboard::FreeData(unsigned int format, HANDLE data) { 814 if (format == CF_BITMAP) 815 ::DeleteObject(static_cast<HBITMAP>(data)); 816 else 817 ::GlobalFree(data); 818 } 819 820 HWND Clipboard::GetClipboardWindow() const { 821 if (!clipboard_owner_) 822 return NULL; 823 824 if (clipboard_owner_->hwnd() == NULL) 825 clipboard_owner_->Create(base::Bind(&ClipboardOwnerWndProc)); 826 827 return clipboard_owner_->hwnd(); 828 } 829 830 } // namespace ui 831