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