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/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"
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 bool Clipboard::FormatType::Equals(const FormatType
& other
) const {
207 return ToUINT() == other
.ToUINT();
210 Clipboard::Clipboard() {
211 if (base::MessageLoopForUI::IsCurrent())
212 clipboard_owner_
.reset(new base::win::MessageWindow());
215 Clipboard::~Clipboard() {
218 void Clipboard::WriteObjects(ClipboardType type
, const ObjectMap
& objects
) {
219 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
221 ScopedClipboard clipboard
;
222 if (!clipboard
.Acquire(GetClipboardWindow()))
227 for (ObjectMap::const_iterator iter
= objects
.begin();
228 iter
!= objects
.end(); ++iter
) {
229 DispatchObject(static_cast<ObjectType
>(iter
->first
), iter
->second
);
233 void Clipboard::WriteText(const char* text_data
, size_t text_len
) {
235 base::UTF8ToUTF16(text_data
, text_len
, &text
);
236 HGLOBAL glob
= CreateGlobalData(text
);
238 WriteToClipboard(CF_UNICODETEXT
, glob
);
241 void Clipboard::WriteHTML(const char* markup_data
,
243 const char* url_data
,
245 std::string
markup(markup_data
, markup_len
);
249 url
.assign(url_data
, url_len
);
251 std::string html_fragment
= ClipboardUtil::HtmlToCFHtml(markup
, url
);
252 HGLOBAL glob
= CreateGlobalData(html_fragment
);
254 WriteToClipboard(Clipboard::GetHtmlFormatType().ToUINT(), glob
);
257 void Clipboard::WriteRTF(const char* rtf_data
, size_t data_len
) {
258 WriteData(GetRtfFormatType(), rtf_data
, data_len
);
261 void Clipboard::WriteBookmark(const char* title_data
,
263 const char* url_data
,
265 std::string
bookmark(title_data
, title_len
);
266 bookmark
.append(1, L
'\n');
267 bookmark
.append(url_data
, url_len
);
269 base::string16 wide_bookmark
= base::UTF8ToWide(bookmark
);
270 HGLOBAL glob
= CreateGlobalData(wide_bookmark
);
272 WriteToClipboard(GetUrlWFormatType().ToUINT(), glob
);
275 void Clipboard::WriteWebSmartPaste() {
276 DCHECK(clipboard_owner_
->hwnd() != NULL
);
277 ::SetClipboardData(GetWebKitSmartPasteFormatType().ToUINT(), NULL
);
280 void Clipboard::WriteBitmap(const SkBitmap
& bitmap
) {
281 HDC dc
= ::GetDC(NULL
);
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.
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
;
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)
300 HBITMAP source_hbitmap
=
301 ::CreateDIBSection(dc
, &bm_info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
303 if (bits
&& source_hbitmap
) {
305 SkAutoLockPixels
bitmap_lock(bitmap
);
306 // Copy the bitmap out of shared memory and into GDI
307 memcpy(bits
, bitmap
.getPixels(), bitmap
.getSize());
310 // Now we have an HBITMAP, we can write it to the clipboard
311 WriteBitmapFromHandle(source_hbitmap
,
312 gfx::Size(bitmap
.width(), bitmap
.height()));
315 ::DeleteObject(source_hbitmap
);
316 ::ReleaseDC(NULL
, dc
);
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.
326 HDC dc
= ::GetDC(NULL
);
327 HDC compatible_dc
= ::CreateCompatibleDC(NULL
);
328 HDC source_dc
= ::CreateCompatibleDC(NULL
);
330 // This is the HBITMAP we will eventually write to the clipboard
331 HBITMAP hbitmap
= ::CreateCompatibleBitmap(dc
, size
.width(), size
.height());
333 // Failed to create the bitmap
334 ::DeleteDC(compatible_dc
);
335 ::DeleteDC(source_dc
);
336 ::ReleaseDC(NULL
, dc
);
340 HBITMAP old_hbitmap
= (HBITMAP
)SelectObject(compatible_dc
, hbitmap
);
341 HBITMAP old_source
= (HBITMAP
)SelectObject(source_dc
, source_hbitmap
);
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
);
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
);
357 WriteToClipboard(CF_BITMAP
, hbitmap
);
360 void Clipboard::WriteData(const FormatType
& format
,
361 const char* data_data
,
363 HGLOBAL hdata
= ::GlobalAlloc(GMEM_MOVEABLE
, data_len
);
367 char* data
= static_cast<char*>(::GlobalLock(hdata
));
368 memcpy(data
, data_data
, data_len
);
369 ::GlobalUnlock(data
);
370 WriteToClipboard(format
.ToUINT(), hdata
);
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
);
381 uint64
Clipboard::GetSequenceNumber(ClipboardType type
) {
382 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
383 return ::GetClipboardSequenceNumber();
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
;
392 void Clipboard::Clear(ClipboardType type
) {
393 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
394 ScopedClipboard clipboard
;
395 if (!clipboard
.Acquire(GetClipboardWindow()))
401 void Clipboard::ReadAvailableTypes(ClipboardType type
,
402 std::vector
<base::string16
>* types
,
403 bool* contains_filenames
) const {
404 if (!types
|| !contains_filenames
) {
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;
420 // Acquire the clipboard.
421 ScopedClipboard clipboard
;
422 if (!clipboard
.Acquire(GetClipboardWindow()))
425 HANDLE hdata
= ::GetClipboardData(GetWebCustomDataFormatType().ToUINT());
429 ReadCustomDataTypes(::GlobalLock(hdata
), ::GlobalSize(hdata
), types
);
430 ::GlobalUnlock(hdata
);
433 void Clipboard::ReadText(ClipboardType type
, base::string16
* result
) const {
434 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
442 // Acquire the clipboard.
443 ScopedClipboard clipboard
;
444 if (!clipboard
.Acquire(GetClipboardWindow()))
447 HANDLE data
= ::GetClipboardData(CF_UNICODETEXT
);
451 result
->assign(static_cast<const base::char16
*>(::GlobalLock(data
)));
452 ::GlobalUnlock(data
);
455 void Clipboard::ReadAsciiText(ClipboardType type
, std::string
* result
) const {
456 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
464 // Acquire the clipboard.
465 ScopedClipboard clipboard
;
466 if (!clipboard
.Acquire(GetClipboardWindow()))
469 HANDLE data
= ::GetClipboardData(CF_TEXT
);
473 result
->assign(static_cast<const char*>(::GlobalLock(data
)));
474 ::GlobalUnlock(data
);
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
);
485 // TODO(dcheng): Remove these checks, I don't think they should be optional.
492 // Acquire the clipboard.
493 ScopedClipboard clipboard
;
494 if (!clipboard
.Acquire(GetClipboardWindow()))
497 HANDLE data
= ::GetClipboardData(GetHtmlFormatType().ToUINT());
501 std::string
cf_html(static_cast<const char*>(::GlobalLock(data
)));
502 ::GlobalUnlock(data
);
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
);
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
)
517 if (start_index
< html_start
|| end_index
< start_index
)
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
,
525 *fragment_start
= base::checked_cast
<uint32
>(offsets
[0]);
526 *fragment_end
= base::checked_cast
<uint32
>(offsets
[1]);
529 void Clipboard::ReadRTF(ClipboardType type
, std::string
* result
) const {
530 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
532 ReadData(GetRtfFormatType(), result
);
535 SkBitmap
Clipboard::ReadImage(ClipboardType type
) const {
536 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
538 // Acquire the clipboard.
539 ScopedClipboard clipboard
;
540 if (!clipboard
.Acquire(GetClipboardWindow()))
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
546 BITMAPINFO
* bitmap
= static_cast<BITMAPINFO
*>(::GetClipboardData(CF_DIB
));
549 int color_table_length
= 0;
550 switch (bitmap
->bmiHeader
.biBitCount
) {
554 color_table_length
= bitmap
->bmiHeader
.biClrUsed
555 ? bitmap
->bmiHeader
.biClrUsed
556 : 1 << bitmap
->bmiHeader
.biBitCount
;
560 if (bitmap
->bmiHeader
.biCompression
== BI_BITFIELDS
)
561 color_table_length
= 3;
568 const void* bitmap_bits
= reinterpret_cast<const char*>(bitmap
)
569 + bitmap
->bmiHeader
.biSize
+ color_table_length
* sizeof(RGBQUAD
);
571 gfx::Canvas
canvas(gfx::Size(bitmap
->bmiHeader
.biWidth
,
572 bitmap
->bmiHeader
.biHeight
),
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
,
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);
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
);
602 return canvas
.ExtractImageRep().sk_bitmap();
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
);
610 // Acquire the clipboard.
611 ScopedClipboard clipboard
;
612 if (!clipboard
.Acquire(GetClipboardWindow()))
615 HANDLE hdata
= ::GetClipboardData(GetWebCustomDataFormatType().ToUINT());
619 ReadCustomDataForType(::GlobalLock(hdata
), ::GlobalSize(hdata
), type
, result
);
620 ::GlobalUnlock(hdata
);
623 void Clipboard::ReadBookmark(base::string16
* title
, std::string
* url
) const {
630 // Acquire the clipboard.
631 ScopedClipboard clipboard
;
632 if (!clipboard
.Acquire(GetClipboardWindow()))
635 HANDLE data
= ::GetClipboardData(GetUrlWFormatType().ToUINT());
639 base::string16
bookmark(static_cast<const base::char16
*>(::GlobalLock(data
)));
640 ::GlobalUnlock(data
);
642 ParseBookmarkClipboardFormat(bookmark
, title
, url
);
645 void Clipboard::ReadData(const FormatType
& format
, std::string
* result
) const {
651 ScopedClipboard clipboard
;
652 if (!clipboard
.Acquire(GetClipboardWindow()))
655 HANDLE data
= ::GetClipboardData(format
.ToUINT());
659 result
->assign(static_cast<const char*>(::GlobalLock(data
)),
661 ::GlobalUnlock(data
);
665 void Clipboard::ParseBookmarkClipboardFormat(const base::string16
& bookmark
,
666 base::string16
* title
,
668 const base::string16 kDelim
= base::ASCIIToUTF16("\r\n");
670 const size_t title_end
= bookmark
.find_first_of(kDelim
);
672 title
->assign(bookmark
.substr(0, title_end
));
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
));
684 Clipboard::FormatType
Clipboard::GetFormatType(
685 const std::string
& format_string
) {
687 ::RegisterClipboardFormat(base::ASCIIToWide(format_string
).c_str()));
691 const Clipboard::FormatType
& Clipboard::GetUrlFormatType() {
692 CR_DEFINE_STATIC_LOCAL(
693 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_INETURLA
)));
698 const Clipboard::FormatType
& Clipboard::GetUrlWFormatType() {
699 CR_DEFINE_STATIC_LOCAL(
700 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_INETURLW
)));
705 const Clipboard::FormatType
& Clipboard::GetMozUrlFormatType() {
706 CR_DEFINE_STATIC_LOCAL(
707 FormatType
, type
, (::RegisterClipboardFormat(L
"text/x-moz-url")));
712 const Clipboard::FormatType
& Clipboard::GetPlainTextFormatType() {
713 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (CF_TEXT
));
718 const Clipboard::FormatType
& Clipboard::GetPlainTextWFormatType() {
719 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (CF_UNICODETEXT
));
724 const Clipboard::FormatType
& Clipboard::GetFilenameFormatType() {
725 CR_DEFINE_STATIC_LOCAL(
726 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_FILENAMEA
)));
731 const Clipboard::FormatType
& Clipboard::GetFilenameWFormatType() {
732 CR_DEFINE_STATIC_LOCAL(
733 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_FILENAMEW
)));
739 const Clipboard::FormatType
& Clipboard::GetHtmlFormatType() {
740 CR_DEFINE_STATIC_LOCAL(
741 FormatType
, type
, (::RegisterClipboardFormat(L
"HTML Format")));
747 const Clipboard::FormatType
& Clipboard::GetRtfFormatType() {
748 CR_DEFINE_STATIC_LOCAL(
749 FormatType
, type
, (::RegisterClipboardFormat(L
"Rich Text Format")));
754 const Clipboard::FormatType
& Clipboard::GetBitmapFormatType() {
755 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (CF_BITMAP
));
761 const Clipboard::FormatType
& Clipboard::GetTextHtmlFormatType() {
762 CR_DEFINE_STATIC_LOCAL(
763 FormatType
, type
, (::RegisterClipboardFormat(L
"text/html")));
768 const Clipboard::FormatType
& Clipboard::GetCFHDropFormatType() {
769 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (CF_HDROP
));
774 const Clipboard::FormatType
& Clipboard::GetFileDescriptorFormatType() {
775 CR_DEFINE_STATIC_LOCAL(
776 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR
)));
781 const Clipboard::FormatType
& Clipboard::GetFileContentZeroFormatType() {
782 CR_DEFINE_STATIC_LOCAL(
783 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_FILECONTENTS
), 0));
788 const Clipboard::FormatType
& Clipboard::GetIDListFormatType() {
789 CR_DEFINE_STATIC_LOCAL(
790 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_SHELLIDLIST
)));
795 const Clipboard::FormatType
& Clipboard::GetWebKitSmartPasteFormatType() {
796 CR_DEFINE_STATIC_LOCAL(
799 (::RegisterClipboardFormat(L
"WebKit Smart Paste Format")));
804 const Clipboard::FormatType
& Clipboard::GetWebCustomDataFormatType() {
805 // TODO(dcheng): This name is temporary. See http://crbug.com/106449.
806 CR_DEFINE_STATIC_LOCAL(
809 (::RegisterClipboardFormat(L
"Chromium Web Custom MIME Data Format")));
814 const Clipboard::FormatType
& Clipboard::GetPepperCustomDataFormatType() {
815 CR_DEFINE_STATIC_LOCAL(
818 (::RegisterClipboardFormat(L
"Chromium Pepper MIME Data Format")));
823 void Clipboard::FreeData(unsigned int format
, HANDLE data
) {
824 if (format
== CF_BITMAP
)
825 ::DeleteObject(static_cast<HBITMAP
>(data
));
830 HWND
Clipboard::GetClipboardWindow() const {
831 if (!clipboard_owner_
)
834 if (clipboard_owner_
->hwnd() == NULL
)
835 clipboard_owner_
->Create(base::Bind(&ClipboardOwnerWndProc
));
837 return clipboard_owner_
->hwnd();