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