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 <shellapi.h> 11 #include <shlobj.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/numerics/safe_conversions.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 bool Clipboard::FormatType::Equals(const FormatType& other) const { 207 return ToUINT() == other.ToUINT(); 208 } 209 210 Clipboard::Clipboard() { 211 if (base::MessageLoopForUI::IsCurrent()) 212 clipboard_owner_.reset(new base::win::MessageWindow()); 213 } 214 215 Clipboard::~Clipboard() { 216 } 217 218 void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) { 219 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 220 221 ScopedClipboard clipboard; 222 if (!clipboard.Acquire(GetClipboardWindow())) 223 return; 224 225 ::EmptyClipboard(); 226 227 for (ObjectMap::const_iterator iter = objects.begin(); 228 iter != objects.end(); ++iter) { 229 DispatchObject(static_cast<ObjectType>(iter->first), iter->second); 230 } 231 } 232 233 void Clipboard::WriteText(const char* text_data, size_t text_len) { 234 base::string16 text; 235 base::UTF8ToUTF16(text_data, text_len, &text); 236 HGLOBAL glob = CreateGlobalData(text); 237 238 WriteToClipboard(CF_UNICODETEXT, glob); 239 } 240 241 void Clipboard::WriteHTML(const char* markup_data, 242 size_t markup_len, 243 const char* url_data, 244 size_t url_len) { 245 std::string markup(markup_data, markup_len); 246 std::string url; 247 248 if (url_len > 0) 249 url.assign(url_data, url_len); 250 251 std::string html_fragment = ClipboardUtil::HtmlToCFHtml(markup, url); 252 HGLOBAL glob = CreateGlobalData(html_fragment); 253 254 WriteToClipboard(Clipboard::GetHtmlFormatType().ToUINT(), glob); 255 } 256 257 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) { 258 WriteData(GetRtfFormatType(), rtf_data, data_len); 259 } 260 261 void Clipboard::WriteBookmark(const char* title_data, 262 size_t title_len, 263 const char* url_data, 264 size_t url_len) { 265 std::string bookmark(title_data, title_len); 266 bookmark.append(1, L'\n'); 267 bookmark.append(url_data, url_len); 268 269 base::string16 wide_bookmark = base::UTF8ToWide(bookmark); 270 HGLOBAL glob = CreateGlobalData(wide_bookmark); 271 272 WriteToClipboard(GetUrlWFormatType().ToUINT(), glob); 273 } 274 275 void Clipboard::WriteWebSmartPaste() { 276 DCHECK(clipboard_owner_->hwnd() != NULL); 277 ::SetClipboardData(GetWebKitSmartPasteFormatType().ToUINT(), NULL); 278 } 279 280 void Clipboard::WriteBitmap(const SkBitmap& bitmap) { 281 HDC dc = ::GetDC(NULL); 282 283 // This doesn't actually cost us a memcpy when the bitmap comes from the 284 // renderer as we load it into the bitmap using setPixels which just sets a 285 // pointer. Someone has to memcpy it into GDI, it might as well be us here. 286 287 // TODO(darin): share data in gfx/bitmap_header.cc somehow 288 BITMAPINFO bm_info = {0}; 289 bm_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 290 bm_info.bmiHeader.biWidth = bitmap.width(); 291 bm_info.bmiHeader.biHeight = -bitmap.height(); // sets vertical orientation 292 bm_info.bmiHeader.biPlanes = 1; 293 bm_info.bmiHeader.biBitCount = 32; 294 bm_info.bmiHeader.biCompression = BI_RGB; 295 296 // ::CreateDIBSection allocates memory for us to copy our bitmap into. 297 // Unfortunately, we can't write the created bitmap to the clipboard, 298 // (see http://msdn2.microsoft.com/en-us/library/ms532292.aspx) 299 void *bits; 300 HBITMAP source_hbitmap = 301 ::CreateDIBSection(dc, &bm_info, DIB_RGB_COLORS, &bits, NULL, 0); 302 303 if (bits && source_hbitmap) { 304 { 305 SkAutoLockPixels bitmap_lock(bitmap); 306 // Copy the bitmap out of shared memory and into GDI 307 memcpy(bits, bitmap.getPixels(), bitmap.getSize()); 308 } 309 310 // Now we have an HBITMAP, we can write it to the clipboard 311 WriteBitmapFromHandle(source_hbitmap, 312 gfx::Size(bitmap.width(), bitmap.height())); 313 } 314 315 ::DeleteObject(source_hbitmap); 316 ::ReleaseDC(NULL, dc); 317 } 318 319 void Clipboard::WriteBitmapFromHandle(HBITMAP source_hbitmap, 320 const gfx::Size& size) { 321 // We would like to just call ::SetClipboardData on the source_hbitmap, 322 // but that bitmap might not be of a sort we can write to the clipboard. 323 // For this reason, we create a new bitmap, copy the bits over, and then 324 // write that to the clipboard. 325 326 HDC dc = ::GetDC(NULL); 327 HDC compatible_dc = ::CreateCompatibleDC(NULL); 328 HDC source_dc = ::CreateCompatibleDC(NULL); 329 330 // This is the HBITMAP we will eventually write to the clipboard 331 HBITMAP hbitmap = ::CreateCompatibleBitmap(dc, size.width(), size.height()); 332 if (!hbitmap) { 333 // Failed to create the bitmap 334 ::DeleteDC(compatible_dc); 335 ::DeleteDC(source_dc); 336 ::ReleaseDC(NULL, dc); 337 return; 338 } 339 340 HBITMAP old_hbitmap = (HBITMAP)SelectObject(compatible_dc, hbitmap); 341 HBITMAP old_source = (HBITMAP)SelectObject(source_dc, source_hbitmap); 342 343 // Now we need to blend it into an HBITMAP we can place on the clipboard 344 BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; 345 ::GdiAlphaBlend(compatible_dc, 0, 0, size.width(), size.height(), 346 source_dc, 0, 0, size.width(), size.height(), bf); 347 348 // Clean up all the handles we just opened 349 ::SelectObject(compatible_dc, old_hbitmap); 350 ::SelectObject(source_dc, old_source); 351 ::DeleteObject(old_hbitmap); 352 ::DeleteObject(old_source); 353 ::DeleteDC(compatible_dc); 354 ::DeleteDC(source_dc); 355 ::ReleaseDC(NULL, dc); 356 357 WriteToClipboard(CF_BITMAP, hbitmap); 358 } 359 360 void Clipboard::WriteData(const FormatType& format, 361 const char* data_data, 362 size_t data_len) { 363 HGLOBAL hdata = ::GlobalAlloc(GMEM_MOVEABLE, data_len); 364 if (!hdata) 365 return; 366 367 char* data = static_cast<char*>(::GlobalLock(hdata)); 368 memcpy(data, data_data, data_len); 369 ::GlobalUnlock(data); 370 WriteToClipboard(format.ToUINT(), hdata); 371 } 372 373 void Clipboard::WriteToClipboard(unsigned int format, HANDLE handle) { 374 DCHECK(clipboard_owner_->hwnd() != NULL); 375 if (handle && !::SetClipboardData(format, handle)) { 376 DCHECK(ERROR_CLIPBOARD_NOT_OPEN != GetLastError()); 377 FreeData(format, handle); 378 } 379 } 380 381 uint64 Clipboard::GetSequenceNumber(ClipboardType type) { 382 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 383 return ::GetClipboardSequenceNumber(); 384 } 385 386 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, 387 ClipboardType type) const { 388 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 389 return ::IsClipboardFormatAvailable(format.ToUINT()) != FALSE; 390 } 391 392 void Clipboard::Clear(ClipboardType type) { 393 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 394 ScopedClipboard clipboard; 395 if (!clipboard.Acquire(GetClipboardWindow())) 396 return; 397 398 ::EmptyClipboard(); 399 } 400 401 void Clipboard::ReadAvailableTypes(ClipboardType type, 402 std::vector<base::string16>* types, 403 bool* contains_filenames) const { 404 if (!types || !contains_filenames) { 405 NOTREACHED(); 406 return; 407 } 408 409 types->clear(); 410 if (::IsClipboardFormatAvailable(GetPlainTextFormatType().ToUINT())) 411 types->push_back(base::UTF8ToUTF16(kMimeTypeText)); 412 if (::IsClipboardFormatAvailable(GetHtmlFormatType().ToUINT())) 413 types->push_back(base::UTF8ToUTF16(kMimeTypeHTML)); 414 if (::IsClipboardFormatAvailable(GetRtfFormatType().ToUINT())) 415 types->push_back(base::UTF8ToUTF16(kMimeTypeRTF)); 416 if (::IsClipboardFormatAvailable(CF_DIB)) 417 types->push_back(base::UTF8ToUTF16(kMimeTypePNG)); 418 *contains_filenames = false; 419 420 // Acquire the clipboard. 421 ScopedClipboard clipboard; 422 if (!clipboard.Acquire(GetClipboardWindow())) 423 return; 424 425 HANDLE hdata = ::GetClipboardData(GetWebCustomDataFormatType().ToUINT()); 426 if (!hdata) 427 return; 428 429 ReadCustomDataTypes(::GlobalLock(hdata), ::GlobalSize(hdata), types); 430 ::GlobalUnlock(hdata); 431 } 432 433 void Clipboard::ReadText(ClipboardType type, base::string16* result) const { 434 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 435 if (!result) { 436 NOTREACHED(); 437 return; 438 } 439 440 result->clear(); 441 442 // Acquire the clipboard. 443 ScopedClipboard clipboard; 444 if (!clipboard.Acquire(GetClipboardWindow())) 445 return; 446 447 HANDLE data = ::GetClipboardData(CF_UNICODETEXT); 448 if (!data) 449 return; 450 451 result->assign(static_cast<const base::char16*>(::GlobalLock(data))); 452 ::GlobalUnlock(data); 453 } 454 455 void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const { 456 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 457 if (!result) { 458 NOTREACHED(); 459 return; 460 } 461 462 result->clear(); 463 464 // Acquire the clipboard. 465 ScopedClipboard clipboard; 466 if (!clipboard.Acquire(GetClipboardWindow())) 467 return; 468 469 HANDLE data = ::GetClipboardData(CF_TEXT); 470 if (!data) 471 return; 472 473 result->assign(static_cast<const char*>(::GlobalLock(data))); 474 ::GlobalUnlock(data); 475 } 476 477 void Clipboard::ReadHTML(ClipboardType type, 478 base::string16* markup, 479 std::string* src_url, 480 uint32* fragment_start, 481 uint32* fragment_end) const { 482 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 483 484 markup->clear(); 485 // TODO(dcheng): Remove these checks, I don't think they should be optional. 486 DCHECK(src_url); 487 if (src_url) 488 src_url->clear(); 489 *fragment_start = 0; 490 *fragment_end = 0; 491 492 // Acquire the clipboard. 493 ScopedClipboard clipboard; 494 if (!clipboard.Acquire(GetClipboardWindow())) 495 return; 496 497 HANDLE data = ::GetClipboardData(GetHtmlFormatType().ToUINT()); 498 if (!data) 499 return; 500 501 std::string cf_html(static_cast<const char*>(::GlobalLock(data))); 502 ::GlobalUnlock(data); 503 504 size_t html_start = std::string::npos; 505 size_t start_index = std::string::npos; 506 size_t end_index = std::string::npos; 507 ClipboardUtil::CFHtmlExtractMetadata(cf_html, src_url, &html_start, 508 &start_index, &end_index); 509 510 // This might happen if the contents of the clipboard changed and CF_HTML is 511 // no longer available. 512 if (start_index == std::string::npos || 513 end_index == std::string::npos || 514 html_start == std::string::npos) 515 return; 516 517 if (start_index < html_start || end_index < start_index) 518 return; 519 520 std::vector<size_t> offsets; 521 offsets.push_back(start_index - html_start); 522 offsets.push_back(end_index - html_start); 523 markup->assign(base::UTF8ToUTF16AndAdjustOffsets(cf_html.data() + html_start, 524 &offsets)); 525 *fragment_start = base::checked_cast<uint32>(offsets[0]); 526 *fragment_end = base::checked_cast<uint32>(offsets[1]); 527 } 528 529 void Clipboard::ReadRTF(ClipboardType type, std::string* result) const { 530 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 531 532 ReadData(GetRtfFormatType(), result); 533 } 534 535 SkBitmap Clipboard::ReadImage(ClipboardType type) const { 536 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 537 538 // Acquire the clipboard. 539 ScopedClipboard clipboard; 540 if (!clipboard.Acquire(GetClipboardWindow())) 541 return SkBitmap(); 542 543 // We use a DIB rather than a DDB here since ::GetObject() with the 544 // HBITMAP returned from ::GetClipboardData(CF_BITMAP) always reports a color 545 // depth of 32bpp. 546 BITMAPINFO* bitmap = static_cast<BITMAPINFO*>(::GetClipboardData(CF_DIB)); 547 if (!bitmap) 548 return SkBitmap(); 549 int color_table_length = 0; 550 switch (bitmap->bmiHeader.biBitCount) { 551 case 1: 552 case 4: 553 case 8: 554 color_table_length = bitmap->bmiHeader.biClrUsed 555 ? bitmap->bmiHeader.biClrUsed 556 : 1 << bitmap->bmiHeader.biBitCount; 557 break; 558 case 16: 559 case 32: 560 if (bitmap->bmiHeader.biCompression == BI_BITFIELDS) 561 color_table_length = 3; 562 break; 563 case 24: 564 break; 565 default: 566 NOTREACHED(); 567 } 568 const void* bitmap_bits = reinterpret_cast<const char*>(bitmap) 569 + bitmap->bmiHeader.biSize + color_table_length * sizeof(RGBQUAD); 570 571 gfx::Canvas canvas(gfx::Size(bitmap->bmiHeader.biWidth, 572 bitmap->bmiHeader.biHeight), 573 1.0f, 574 false); 575 { 576 skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas()); 577 HDC dc = scoped_platform_paint.GetPlatformSurface(); 578 ::SetDIBitsToDevice(dc, 0, 0, bitmap->bmiHeader.biWidth, 579 bitmap->bmiHeader.biHeight, 0, 0, 0, 580 bitmap->bmiHeader.biHeight, bitmap_bits, bitmap, 581 DIB_RGB_COLORS); 582 } 583 // Windows doesn't really handle alpha channels well in many situations. When 584 // the source image is < 32 bpp, we force the bitmap to be opaque. When the 585 // source image is 32 bpp, the alpha channel might still contain garbage data. 586 // Since Windows uses premultiplied alpha, we scan for instances where 587 // (R, G, B) > A. If there are any invalid premultiplied colors in the image, 588 // we assume the alpha channel contains garbage and force the bitmap to be 589 // opaque as well. Note that this heuristic will fail on a transparent bitmap 590 // containing only black pixels... 591 const SkBitmap& device_bitmap = 592 canvas.sk_canvas()->getDevice()->accessBitmap(true); 593 { 594 SkAutoLockPixels lock(device_bitmap); 595 bool has_invalid_alpha_channel = bitmap->bmiHeader.biBitCount < 32 || 596 BitmapHasInvalidPremultipliedColors(device_bitmap); 597 if (has_invalid_alpha_channel) { 598 MakeBitmapOpaque(device_bitmap); 599 } 600 } 601 602 return canvas.ExtractImageRep().sk_bitmap(); 603 } 604 605 void Clipboard::ReadCustomData(ClipboardType clipboard_type, 606 const base::string16& type, 607 base::string16* result) const { 608 DCHECK_EQ(clipboard_type, CLIPBOARD_TYPE_COPY_PASTE); 609 610 // Acquire the clipboard. 611 ScopedClipboard clipboard; 612 if (!clipboard.Acquire(GetClipboardWindow())) 613 return; 614 615 HANDLE hdata = ::GetClipboardData(GetWebCustomDataFormatType().ToUINT()); 616 if (!hdata) 617 return; 618 619 ReadCustomDataForType(::GlobalLock(hdata), ::GlobalSize(hdata), type, result); 620 ::GlobalUnlock(hdata); 621 } 622 623 void Clipboard::ReadBookmark(base::string16* title, std::string* url) const { 624 if (title) 625 title->clear(); 626 627 if (url) 628 url->clear(); 629 630 // Acquire the clipboard. 631 ScopedClipboard clipboard; 632 if (!clipboard.Acquire(GetClipboardWindow())) 633 return; 634 635 HANDLE data = ::GetClipboardData(GetUrlWFormatType().ToUINT()); 636 if (!data) 637 return; 638 639 base::string16 bookmark(static_cast<const base::char16*>(::GlobalLock(data))); 640 ::GlobalUnlock(data); 641 642 ParseBookmarkClipboardFormat(bookmark, title, url); 643 } 644 645 void Clipboard::ReadData(const FormatType& format, std::string* result) const { 646 if (!result) { 647 NOTREACHED(); 648 return; 649 } 650 651 ScopedClipboard clipboard; 652 if (!clipboard.Acquire(GetClipboardWindow())) 653 return; 654 655 HANDLE data = ::GetClipboardData(format.ToUINT()); 656 if (!data) 657 return; 658 659 result->assign(static_cast<const char*>(::GlobalLock(data)), 660 ::GlobalSize(data)); 661 ::GlobalUnlock(data); 662 } 663 664 // static 665 void Clipboard::ParseBookmarkClipboardFormat(const base::string16& bookmark, 666 base::string16* title, 667 std::string* url) { 668 const base::string16 kDelim = base::ASCIIToUTF16("\r\n"); 669 670 const size_t title_end = bookmark.find_first_of(kDelim); 671 if (title) 672 title->assign(bookmark.substr(0, title_end)); 673 674 if (url) { 675 const size_t url_start = bookmark.find_first_not_of(kDelim, title_end); 676 if (url_start != base::string16::npos) { 677 *url = base::UTF16ToUTF8( 678 bookmark.substr(url_start, base::string16::npos)); 679 } 680 } 681 } 682 683 // static 684 Clipboard::FormatType Clipboard::GetFormatType( 685 const std::string& format_string) { 686 return FormatType( 687 ::RegisterClipboardFormat(base::ASCIIToWide(format_string).c_str())); 688 } 689 690 // static 691 const Clipboard::FormatType& Clipboard::GetUrlFormatType() { 692 CR_DEFINE_STATIC_LOCAL( 693 FormatType, type, (::RegisterClipboardFormat(CFSTR_INETURLA))); 694 return type; 695 } 696 697 // static 698 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() { 699 CR_DEFINE_STATIC_LOCAL( 700 FormatType, type, (::RegisterClipboardFormat(CFSTR_INETURLW))); 701 return type; 702 } 703 704 // static 705 const Clipboard::FormatType& Clipboard::GetMozUrlFormatType() { 706 CR_DEFINE_STATIC_LOCAL( 707 FormatType, type, (::RegisterClipboardFormat(L"text/x-moz-url"))); 708 return type; 709 } 710 711 // static 712 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() { 713 CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_TEXT)); 714 return type; 715 } 716 717 // static 718 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() { 719 CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_UNICODETEXT)); 720 return type; 721 } 722 723 // static 724 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() { 725 CR_DEFINE_STATIC_LOCAL( 726 FormatType, type, (::RegisterClipboardFormat(CFSTR_FILENAMEA))); 727 return type; 728 } 729 730 // static 731 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() { 732 CR_DEFINE_STATIC_LOCAL( 733 FormatType, type, (::RegisterClipboardFormat(CFSTR_FILENAMEW))); 734 return type; 735 } 736 737 // MS HTML Format 738 // static 739 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() { 740 CR_DEFINE_STATIC_LOCAL( 741 FormatType, type, (::RegisterClipboardFormat(L"HTML Format"))); 742 return type; 743 } 744 745 // MS RTF Format 746 // static 747 const Clipboard::FormatType& Clipboard::GetRtfFormatType() { 748 CR_DEFINE_STATIC_LOCAL( 749 FormatType, type, (::RegisterClipboardFormat(L"Rich Text Format"))); 750 return type; 751 } 752 753 // static 754 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() { 755 CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_BITMAP)); 756 return type; 757 } 758 759 // Firefox text/html 760 // static 761 const Clipboard::FormatType& Clipboard::GetTextHtmlFormatType() { 762 CR_DEFINE_STATIC_LOCAL( 763 FormatType, type, (::RegisterClipboardFormat(L"text/html"))); 764 return type; 765 } 766 767 // static 768 const Clipboard::FormatType& Clipboard::GetCFHDropFormatType() { 769 CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_HDROP)); 770 return type; 771 } 772 773 // static 774 const Clipboard::FormatType& Clipboard::GetFileDescriptorFormatType() { 775 CR_DEFINE_STATIC_LOCAL( 776 FormatType, type, (::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR))); 777 return type; 778 } 779 780 // static 781 const Clipboard::FormatType& Clipboard::GetFileContentZeroFormatType() { 782 CR_DEFINE_STATIC_LOCAL( 783 FormatType, type, (::RegisterClipboardFormat(CFSTR_FILECONTENTS), 0)); 784 return type; 785 } 786 787 // static 788 const Clipboard::FormatType& Clipboard::GetIDListFormatType() { 789 CR_DEFINE_STATIC_LOCAL( 790 FormatType, type, (::RegisterClipboardFormat(CFSTR_SHELLIDLIST))); 791 return type; 792 } 793 794 // static 795 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() { 796 CR_DEFINE_STATIC_LOCAL( 797 FormatType, 798 type, 799 (::RegisterClipboardFormat(L"WebKit Smart Paste Format"))); 800 return type; 801 } 802 803 // static 804 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() { 805 // TODO(dcheng): This name is temporary. See http://crbug.com/106449. 806 CR_DEFINE_STATIC_LOCAL( 807 FormatType, 808 type, 809 (::RegisterClipboardFormat(L"Chromium Web Custom MIME Data Format"))); 810 return type; 811 } 812 813 // static 814 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() { 815 CR_DEFINE_STATIC_LOCAL( 816 FormatType, 817 type, 818 (::RegisterClipboardFormat(L"Chromium Pepper MIME Data Format"))); 819 return type; 820 } 821 822 // static 823 void Clipboard::FreeData(unsigned int format, HANDLE data) { 824 if (format == CF_BITMAP) 825 ::DeleteObject(static_cast<HBITMAP>(data)); 826 else 827 ::GlobalFree(data); 828 } 829 830 HWND Clipboard::GetClipboardWindow() const { 831 if (!clipboard_owner_) 832 return NULL; 833 834 if (clipboard_owner_->hwnd() == NULL) 835 clipboard_owner_->Create(base::Bind(&ClipboardOwnerWndProc)); 836 837 return clipboard_owner_->hwnd(); 838 } 839 840 } // namespace ui 841