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.
5 // Many of these functions are based on those found in
6 // webkit/port/platform/PasteboardWin.cpp
8 #include "ui/base/clipboard/clipboard.h"
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"
38 // A scoper to manage acquiring and automatically releasing the clipboard.
39 class ScopedClipboard
{
41 ScopedClipboard() : opened_(false) { }
48 bool Acquire(HWND owner
) {
49 const int kMaxAttemptsToOpenClipboard
= 5;
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.
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,
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.
70 for (int attempts
= 0; attempts
< kMaxAttemptsToOpenClipboard
; ++attempts
) {
71 // If we didn't manage to open the clipboard, sleep a bit and be hopeful.
75 if (::OpenClipboard(owner
)) {
81 // We failed to acquire the clipboard.
98 bool ClipboardOwnerWndProc(UINT 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.
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.
114 case WM_DRAWCLIPBOARD
:
118 case WM_CHANGECBCHAIN
:
128 template <typename charT
>
129 HGLOBAL
CreateGlobalData(const std::basic_string
<charT
>& str
) {
131 ::GlobalAlloc(GMEM_MOVEABLE
, ((str
.size() + 1) * sizeof(charT
)));
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
);
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
))
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);
164 Clipboard::FormatType::FormatType() : data_() {}
166 Clipboard::FormatType::FormatType(UINT native_format
) : data_() {
167 // There's no good way to actually initialize this in the constructor in
169 data_
.cfFormat
= native_format
;
170 data_
.dwAspect
= DVASPECT_CONTENT
;
172 data_
.tymed
= TYMED_HGLOBAL
;
175 Clipboard::FormatType::FormatType(UINT native_format
, LONG index
) : data_() {
176 // There's no good way to actually initialize this in the constructor in
178 data_
.cfFormat
= native_format
;
179 data_
.dwAspect
= DVASPECT_CONTENT
;
180 data_
.lindex
= index
;
181 data_
.tymed
= TYMED_HGLOBAL
;
184 Clipboard::FormatType::~FormatType() {
187 std::string
Clipboard::FormatType::Serialize() const {
188 return base::IntToString(data_
.cfFormat
);
192 Clipboard::FormatType
Clipboard::FormatType::Deserialize(
193 const std::string
& serialization
) {
194 int clipboard_format
= -1;
195 if (!base::StringToInt(serialization
, &clipboard_format
)) {
199 return FormatType(clipboard_format
);
202 bool Clipboard::FormatType::operator<(const FormatType
& other
) const {
203 return ToUINT() < other
.ToUINT();
206 Clipboard::Clipboard() {
207 if (base::MessageLoop::current()->type() == base::MessageLoop::TYPE_UI
)
208 clipboard_owner_
.reset(new base::win::MessageWindow());
211 Clipboard::~Clipboard() {
214 void Clipboard::WriteObjects(ClipboardType type
, const ObjectMap
& objects
) {
215 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
217 ScopedClipboard clipboard
;
218 if (!clipboard
.Acquire(GetClipboardWindow()))
223 for (ObjectMap::const_iterator iter
= objects
.begin();
224 iter
!= objects
.end(); ++iter
) {
225 DispatchObject(static_cast<ObjectType
>(iter
->first
), iter
->second
);
229 void Clipboard::WriteText(const char* text_data
, size_t text_len
) {
231 base::UTF8ToUTF16(text_data
, text_len
, &text
);
232 HGLOBAL glob
= CreateGlobalData(text
);
234 WriteToClipboard(CF_UNICODETEXT
, glob
);
237 void Clipboard::WriteHTML(const char* markup_data
,
239 const char* url_data
,
241 std::string
markup(markup_data
, markup_len
);
245 url
.assign(url_data
, url_len
);
247 std::string html_fragment
= ClipboardUtil::HtmlToCFHtml(markup
, url
);
248 HGLOBAL glob
= CreateGlobalData(html_fragment
);
250 WriteToClipboard(Clipboard::GetHtmlFormatType().ToUINT(), glob
);
253 void Clipboard::WriteRTF(const char* rtf_data
, size_t data_len
) {
254 WriteData(GetRtfFormatType(), rtf_data
, data_len
);
257 void Clipboard::WriteBookmark(const char* title_data
,
259 const char* url_data
,
261 std::string
bookmark(title_data
, title_len
);
262 bookmark
.append(1, L
'\n');
263 bookmark
.append(url_data
, url_len
);
265 base::string16 wide_bookmark
= base::UTF8ToWide(bookmark
);
266 HGLOBAL glob
= CreateGlobalData(wide_bookmark
);
268 WriteToClipboard(GetUrlWFormatType().ToUINT(), glob
);
271 void Clipboard::WriteWebSmartPaste() {
272 DCHECK(clipboard_owner_
->hwnd() != NULL
);
273 ::SetClipboardData(GetWebKitSmartPasteFormatType().ToUINT(), NULL
);
276 void Clipboard::WriteBitmap(const SkBitmap
& bitmap
) {
277 HDC dc
= ::GetDC(NULL
);
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.
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
;
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)
296 HBITMAP source_hbitmap
=
297 ::CreateDIBSection(dc
, &bm_info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
299 if (bits
&& source_hbitmap
) {
301 SkAutoLockPixels
bitmap_lock(bitmap
);
302 // Copy the bitmap out of shared memory and into GDI
303 memcpy(bits
, bitmap
.getPixels(), bitmap
.getSize());
306 // Now we have an HBITMAP, we can write it to the clipboard
307 WriteBitmapFromHandle(source_hbitmap
,
308 gfx::Size(bitmap
.width(), bitmap
.height()));
311 ::DeleteObject(source_hbitmap
);
312 ::ReleaseDC(NULL
, dc
);
315 void 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.
322 HDC dc
= ::GetDC(NULL
);
323 HDC compatible_dc
= ::CreateCompatibleDC(NULL
);
324 HDC source_dc
= ::CreateCompatibleDC(NULL
);
326 // This is the HBITMAP we will eventually write to the clipboard
327 HBITMAP hbitmap
= ::CreateCompatibleBitmap(dc
, size
.width(), size
.height());
329 // Failed to create the bitmap
330 ::DeleteDC(compatible_dc
);
331 ::DeleteDC(source_dc
);
332 ::ReleaseDC(NULL
, dc
);
336 HBITMAP old_hbitmap
= (HBITMAP
)SelectObject(compatible_dc
, hbitmap
);
337 HBITMAP old_source
= (HBITMAP
)SelectObject(source_dc
, source_hbitmap
);
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
);
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
);
353 WriteToClipboard(CF_BITMAP
, hbitmap
);
356 void Clipboard::WriteData(const FormatType
& format
,
357 const char* data_data
,
359 HGLOBAL hdata
= ::GlobalAlloc(GMEM_MOVEABLE
, data_len
);
363 char* data
= static_cast<char*>(::GlobalLock(hdata
));
364 memcpy(data
, data_data
, data_len
);
365 ::GlobalUnlock(data
);
366 WriteToClipboard(format
.ToUINT(), hdata
);
369 void 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
);
377 uint64
Clipboard::GetSequenceNumber(ClipboardType type
) {
378 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
379 return ::GetClipboardSequenceNumber();
382 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType
& format
,
383 ClipboardType type
) const {
384 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
385 return ::IsClipboardFormatAvailable(format
.ToUINT()) != FALSE
;
388 void Clipboard::Clear(ClipboardType type
) {
389 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
390 ScopedClipboard clipboard
;
391 if (!clipboard
.Acquire(GetClipboardWindow()))
397 void Clipboard::ReadAvailableTypes(ClipboardType type
,
398 std::vector
<base::string16
>* types
,
399 bool* contains_filenames
) const {
400 if (!types
|| !contains_filenames
) {
406 if (::IsClipboardFormatAvailable(GetPlainTextFormatType().ToUINT()))
407 types
->push_back(base::UTF8ToUTF16(kMimeTypeText
));
408 if (::IsClipboardFormatAvailable(GetHtmlFormatType().ToUINT()))
409 types
->push_back(base::UTF8ToUTF16(kMimeTypeHTML
));
410 if (::IsClipboardFormatAvailable(GetRtfFormatType().ToUINT()))
411 types
->push_back(base::UTF8ToUTF16(kMimeTypeRTF
));
412 if (::IsClipboardFormatAvailable(CF_DIB
))
413 types
->push_back(base::UTF8ToUTF16(kMimeTypePNG
));
414 *contains_filenames
= false;
416 // Acquire the clipboard.
417 ScopedClipboard clipboard
;
418 if (!clipboard
.Acquire(GetClipboardWindow()))
421 HANDLE hdata
= ::GetClipboardData(GetWebCustomDataFormatType().ToUINT());
425 ReadCustomDataTypes(::GlobalLock(hdata
), ::GlobalSize(hdata
), types
);
426 ::GlobalUnlock(hdata
);
429 void Clipboard::ReadText(ClipboardType type
, base::string16
* result
) const {
430 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
438 // Acquire the clipboard.
439 ScopedClipboard clipboard
;
440 if (!clipboard
.Acquire(GetClipboardWindow()))
443 HANDLE data
= ::GetClipboardData(CF_UNICODETEXT
);
447 result
->assign(static_cast<const base::char16
*>(::GlobalLock(data
)));
448 ::GlobalUnlock(data
);
451 void Clipboard::ReadAsciiText(ClipboardType type
, std::string
* result
) const {
452 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
460 // Acquire the clipboard.
461 ScopedClipboard clipboard
;
462 if (!clipboard
.Acquire(GetClipboardWindow()))
465 HANDLE data
= ::GetClipboardData(CF_TEXT
);
469 result
->assign(static_cast<const char*>(::GlobalLock(data
)));
470 ::GlobalUnlock(data
);
473 void Clipboard::ReadHTML(ClipboardType type
,
474 base::string16
* markup
,
475 std::string
* src_url
,
476 uint32
* fragment_start
,
477 uint32
* fragment_end
) const {
478 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
481 // TODO(dcheng): Remove these checks, I don't think they should be optional.
488 // Acquire the clipboard.
489 ScopedClipboard clipboard
;
490 if (!clipboard
.Acquire(GetClipboardWindow()))
493 HANDLE data
= ::GetClipboardData(GetHtmlFormatType().ToUINT());
497 std::string
cf_html(static_cast<const char*>(::GlobalLock(data
)));
498 ::GlobalUnlock(data
);
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
);
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
)
513 if (start_index
< html_start
|| end_index
< start_index
)
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
,
521 *fragment_start
= base::checked_numeric_cast
<uint32
>(offsets
[0]);
522 *fragment_end
= base::checked_numeric_cast
<uint32
>(offsets
[1]);
525 void Clipboard::ReadRTF(ClipboardType type
, std::string
* result
) const {
526 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
528 ReadData(GetRtfFormatType(), result
);
531 SkBitmap
Clipboard::ReadImage(ClipboardType type
) const {
532 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
534 // Acquire the clipboard.
535 ScopedClipboard clipboard
;
536 if (!clipboard
.Acquire(GetClipboardWindow()))
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
542 BITMAPINFO
* bitmap
= static_cast<BITMAPINFO
*>(::GetClipboardData(CF_DIB
));
545 int color_table_length
= 0;
546 switch (bitmap
->bmiHeader
.biBitCount
) {
550 color_table_length
= bitmap
->bmiHeader
.biClrUsed
551 ? bitmap
->bmiHeader
.biClrUsed
552 : 1 << bitmap
->bmiHeader
.biBitCount
;
556 if (bitmap
->bmiHeader
.biCompression
== BI_BITFIELDS
)
557 color_table_length
= 3;
564 const void* bitmap_bits
= reinterpret_cast<const char*>(bitmap
)
565 + bitmap
->bmiHeader
.biSize
+ color_table_length
* sizeof(RGBQUAD
);
567 gfx::Canvas
canvas(gfx::Size(bitmap
->bmiHeader
.biWidth
,
568 bitmap
->bmiHeader
.biHeight
),
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
,
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);
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
);
598 return canvas
.ExtractImageRep().sk_bitmap();
601 void Clipboard::ReadCustomData(ClipboardType clipboard_type
,
602 const base::string16
& type
,
603 base::string16
* result
) const {
604 DCHECK_EQ(clipboard_type
, CLIPBOARD_TYPE_COPY_PASTE
);
606 // Acquire the clipboard.
607 ScopedClipboard clipboard
;
608 if (!clipboard
.Acquire(GetClipboardWindow()))
611 HANDLE hdata
= ::GetClipboardData(GetWebCustomDataFormatType().ToUINT());
615 ReadCustomDataForType(::GlobalLock(hdata
), ::GlobalSize(hdata
), type
, result
);
616 ::GlobalUnlock(hdata
);
619 void Clipboard::ReadBookmark(base::string16
* title
, std::string
* url
) const {
626 // Acquire the clipboard.
627 ScopedClipboard clipboard
;
628 if (!clipboard
.Acquire(GetClipboardWindow()))
631 HANDLE data
= ::GetClipboardData(GetUrlWFormatType().ToUINT());
635 base::string16
bookmark(static_cast<const base::char16
*>(::GlobalLock(data
)));
636 ::GlobalUnlock(data
);
638 ParseBookmarkClipboardFormat(bookmark
, title
, url
);
641 void Clipboard::ReadData(const FormatType
& format
, std::string
* result
) const {
647 ScopedClipboard clipboard
;
648 if (!clipboard
.Acquire(GetClipboardWindow()))
651 HANDLE data
= ::GetClipboardData(format
.ToUINT());
655 result
->assign(static_cast<const char*>(::GlobalLock(data
)),
657 ::GlobalUnlock(data
);
661 void Clipboard::ParseBookmarkClipboardFormat(const base::string16
& bookmark
,
662 base::string16
* title
,
664 const base::string16 kDelim
= base::ASCIIToUTF16("\r\n");
666 const size_t title_end
= bookmark
.find_first_of(kDelim
);
668 title
->assign(bookmark
.substr(0, title_end
));
671 const size_t url_start
= bookmark
.find_first_not_of(kDelim
, title_end
);
672 if (url_start
!= base::string16::npos
) {
673 *url
= base::UTF16ToUTF8(
674 bookmark
.substr(url_start
, base::string16::npos
));
680 Clipboard::FormatType
Clipboard::GetFormatType(
681 const std::string
& format_string
) {
683 ::RegisterClipboardFormat(base::ASCIIToWide(format_string
).c_str()));
687 const Clipboard::FormatType
& Clipboard::GetUrlFormatType() {
688 CR_DEFINE_STATIC_LOCAL(
689 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_INETURLA
)));
694 const Clipboard::FormatType
& Clipboard::GetUrlWFormatType() {
695 CR_DEFINE_STATIC_LOCAL(
696 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_INETURLW
)));
701 const Clipboard::FormatType
& Clipboard::GetMozUrlFormatType() {
702 CR_DEFINE_STATIC_LOCAL(
703 FormatType
, type
, (::RegisterClipboardFormat(L
"text/x-moz-url")));
708 const Clipboard::FormatType
& Clipboard::GetPlainTextFormatType() {
709 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (CF_TEXT
));
714 const Clipboard::FormatType
& Clipboard::GetPlainTextWFormatType() {
715 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (CF_UNICODETEXT
));
720 const Clipboard::FormatType
& Clipboard::GetFilenameFormatType() {
721 CR_DEFINE_STATIC_LOCAL(
722 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_FILENAMEA
)));
727 const Clipboard::FormatType
& Clipboard::GetFilenameWFormatType() {
728 CR_DEFINE_STATIC_LOCAL(
729 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_FILENAMEW
)));
735 const Clipboard::FormatType
& Clipboard::GetHtmlFormatType() {
736 CR_DEFINE_STATIC_LOCAL(
737 FormatType
, type
, (::RegisterClipboardFormat(L
"HTML Format")));
743 const Clipboard::FormatType
& Clipboard::GetRtfFormatType() {
744 CR_DEFINE_STATIC_LOCAL(
745 FormatType
, type
, (::RegisterClipboardFormat(L
"Rich Text Format")));
750 const Clipboard::FormatType
& Clipboard::GetBitmapFormatType() {
751 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (CF_BITMAP
));
757 const Clipboard::FormatType
& Clipboard::GetTextHtmlFormatType() {
758 CR_DEFINE_STATIC_LOCAL(
759 FormatType
, type
, (::RegisterClipboardFormat(L
"text/html")));
764 const Clipboard::FormatType
& Clipboard::GetCFHDropFormatType() {
765 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (CF_HDROP
));
770 const Clipboard::FormatType
& Clipboard::GetFileDescriptorFormatType() {
771 CR_DEFINE_STATIC_LOCAL(
772 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR
)));
777 const Clipboard::FormatType
& Clipboard::GetFileContentZeroFormatType() {
778 CR_DEFINE_STATIC_LOCAL(
779 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_FILECONTENTS
), 0));
784 const Clipboard::FormatType
& Clipboard::GetIDListFormatType() {
785 CR_DEFINE_STATIC_LOCAL(
786 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_SHELLIDLIST
)));
791 const Clipboard::FormatType
& Clipboard::GetWebKitSmartPasteFormatType() {
792 CR_DEFINE_STATIC_LOCAL(
795 (::RegisterClipboardFormat(L
"WebKit Smart Paste Format")));
800 const Clipboard::FormatType
& Clipboard::GetWebCustomDataFormatType() {
801 // TODO(dcheng): This name is temporary. See http://crbug.com/106449.
802 CR_DEFINE_STATIC_LOCAL(
805 (::RegisterClipboardFormat(L
"Chromium Web Custom MIME Data Format")));
810 const Clipboard::FormatType
& Clipboard::GetPepperCustomDataFormatType() {
811 CR_DEFINE_STATIC_LOCAL(
814 (::RegisterClipboardFormat(L
"Chromium Pepper MIME Data Format")));
819 void Clipboard::FreeData(unsigned int format
, HANDLE data
) {
820 if (format
== CF_BITMAP
)
821 ::DeleteObject(static_cast<HBITMAP
>(data
));
826 HWND
Clipboard::GetClipboardWindow() const {
827 if (!clipboard_owner_
)
830 if (clipboard_owner_
->hwnd() == NULL
)
831 clipboard_owner_
->Create(base::Bind(&ClipboardOwnerWndProc
));
833 return clipboard_owner_
->hwnd();