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_win.h"
13 #include "base/basictypes.h"
14 #include "base/bind.h"
15 #include "base/files/file_path.h"
16 #include "base/lazy_instance.h"
17 #include "base/logging.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/geometry/size.h"
38 // A scoper to impersonate the anonymous token and revert when leaving scope
39 class AnonymousImpersonator
{
41 AnonymousImpersonator() {
42 must_revert_
= ::ImpersonateAnonymousToken(::GetCurrentThread());
45 ~AnonymousImpersonator() {
52 DISALLOW_COPY_AND_ASSIGN(AnonymousImpersonator
);
55 // A scoper to manage acquiring and automatically releasing the clipboard.
56 class ScopedClipboard
{
58 ScopedClipboard() : opened_(false) { }
65 bool Acquire(HWND owner
) {
66 const int kMaxAttemptsToOpenClipboard
= 5;
73 // Attempt to open the clipboard, which will acquire the Windows clipboard
74 // lock. This may fail if another process currently holds this lock.
75 // We're willing to try a few times in the hopes of acquiring it.
77 // This turns out to be an issue when using remote desktop because the
78 // rdpclip.exe process likes to read what we've written to the clipboard and
79 // send it to the RDP client. If we open and close the clipboard in quick
80 // succession, we might be trying to open it while rdpclip.exe has it open,
83 // In fact, we believe we'll only spin this loop over remote desktop. In
84 // normal situations, the user is initiating clipboard operations and there
85 // shouldn't be contention.
87 for (int attempts
= 0; attempts
< kMaxAttemptsToOpenClipboard
; ++attempts
) {
88 // If we didn't manage to open the clipboard, sleep a bit and be hopeful.
92 if (::OpenClipboard(owner
)) {
98 // We failed to acquire the clipboard.
104 // Impersonate the anonymous token during the call to CloseClipboard
105 // This prevents Windows 8+ capturing the broker's access token which
106 // could be accessed by lower-privileges chrome processes leading to
108 AnonymousImpersonator impersonator
;
120 bool ClipboardOwnerWndProc(UINT message
,
125 case WM_RENDERFORMAT
:
126 // This message comes when SetClipboardData was sent a null data handle
127 // and now it's come time to put the data on the clipboard.
128 // We always set data, so there isn't a need to actually do anything here.
130 case WM_RENDERALLFORMATS
:
131 // This message comes when SetClipboardData was sent a null data handle
132 // and now this application is about to quit, so it must put data on
133 // the clipboard before it exits.
134 // We always set data, so there isn't a need to actually do anything here.
136 case WM_DRAWCLIPBOARD
:
140 case WM_CHANGECBCHAIN
:
150 template <typename charT
>
151 HGLOBAL
CreateGlobalData(const std::basic_string
<charT
>& str
) {
153 ::GlobalAlloc(GMEM_MOVEABLE
, ((str
.size() + 1) * sizeof(charT
)));
155 charT
* raw_data
= static_cast<charT
*>(::GlobalLock(data
));
156 memcpy(raw_data
, str
.data(), str
.size() * sizeof(charT
));
157 raw_data
[str
.size()] = '\0';
158 ::GlobalUnlock(data
);
163 bool BitmapHasInvalidPremultipliedColors(const SkBitmap
& bitmap
) {
164 for (int x
= 0; x
< bitmap
.width(); ++x
) {
165 for (int y
= 0; y
< bitmap
.height(); ++y
) {
166 uint32_t pixel
= *bitmap
.getAddr32(x
, y
);
167 if (SkColorGetR(pixel
) > SkColorGetA(pixel
) ||
168 SkColorGetG(pixel
) > SkColorGetA(pixel
) ||
169 SkColorGetB(pixel
) > SkColorGetA(pixel
))
176 void MakeBitmapOpaque(const SkBitmap
& bitmap
) {
177 for (int x
= 0; x
< bitmap
.width(); ++x
) {
178 for (int y
= 0; y
< bitmap
.height(); ++y
) {
179 *bitmap
.getAddr32(x
, y
) = SkColorSetA(*bitmap
.getAddr32(x
, y
), 0xFF);
184 void ParseBookmarkClipboardFormat(const base::string16
& bookmark
,
185 base::string16
* title
,
187 const base::string16 kDelim
= base::ASCIIToUTF16("\r\n");
189 const size_t title_end
= bookmark
.find_first_of(kDelim
);
191 title
->assign(bookmark
.substr(0, title_end
));
194 const size_t url_start
= bookmark
.find_first_not_of(kDelim
, title_end
);
195 if (url_start
!= base::string16::npos
) {
197 base::UTF16ToUTF8(bookmark
.substr(url_start
, base::string16::npos
));
202 void FreeData(unsigned int format
, HANDLE data
) {
203 if (format
== CF_BITMAP
)
204 ::DeleteObject(static_cast<HBITMAP
>(data
));
211 // Clipboard::FormatType implementation.
212 Clipboard::FormatType::FormatType() : data_() {}
214 Clipboard::FormatType::FormatType(UINT native_format
) : data_() {
215 // There's no good way to actually initialize this in the constructor in
217 data_
.cfFormat
= static_cast<CLIPFORMAT
>(native_format
);
218 data_
.dwAspect
= DVASPECT_CONTENT
;
220 data_
.tymed
= TYMED_HGLOBAL
;
223 Clipboard::FormatType::FormatType(UINT native_format
, LONG index
) : data_() {
224 // There's no good way to actually initialize this in the constructor in
226 data_
.cfFormat
= static_cast<CLIPFORMAT
>(native_format
);
227 data_
.dwAspect
= DVASPECT_CONTENT
;
228 data_
.lindex
= index
;
229 data_
.tymed
= TYMED_HGLOBAL
;
232 Clipboard::FormatType::~FormatType() {
235 std::string
Clipboard::FormatType::Serialize() const {
236 return base::IntToString(data_
.cfFormat
);
240 Clipboard::FormatType
Clipboard::FormatType::Deserialize(
241 const std::string
& serialization
) {
242 int clipboard_format
= -1;
243 if (!base::StringToInt(serialization
, &clipboard_format
)) {
247 return FormatType(clipboard_format
);
250 bool Clipboard::FormatType::operator<(const FormatType
& other
) const {
251 return data_
.cfFormat
< other
.data_
.cfFormat
;
254 bool Clipboard::FormatType::Equals(const FormatType
& other
) const {
255 return data_
.cfFormat
== other
.data_
.cfFormat
;
258 // Various predefined FormatTypes.
260 Clipboard::FormatType
Clipboard::GetFormatType(
261 const std::string
& format_string
) {
263 ::RegisterClipboardFormat(base::ASCIIToUTF16(format_string
).c_str()));
266 // The following formats can be referenced by ClipboardUtilWin::GetPlainText.
267 // For reasons (COM), they must be initialized in a thread-safe manner.
268 // TODO(dcheng): We probably need to make static initialization of "known"
269 // FormatTypes thread-safe on all platforms.
270 #define CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(name, ...) \
271 struct FormatTypeArgumentForwarder : public FormatType { \
272 FormatTypeArgumentForwarder() : FormatType(__VA_ARGS__) { } \
274 static base::LazyInstance<FormatTypeArgumentForwarder>::Leaky name = \
275 LAZY_INSTANCE_INITIALIZER
277 const Clipboard::FormatType
& Clipboard::GetUrlFormatType() {
278 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
279 type
, ::RegisterClipboardFormat(CFSTR_INETURLA
));
284 const Clipboard::FormatType
& Clipboard::GetUrlWFormatType() {
285 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
286 type
, ::RegisterClipboardFormat(CFSTR_INETURLW
));
291 const Clipboard::FormatType
& Clipboard::GetMozUrlFormatType() {
292 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
293 type
, ::RegisterClipboardFormat(L
"text/x-moz-url"));
298 const Clipboard::FormatType
& Clipboard::GetPlainTextFormatType() {
299 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type
, CF_TEXT
);
304 const Clipboard::FormatType
& Clipboard::GetPlainTextWFormatType() {
305 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type
, CF_UNICODETEXT
);
310 const Clipboard::FormatType
& Clipboard::GetFilenameFormatType() {
311 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
312 type
, ::RegisterClipboardFormat(CFSTR_FILENAMEA
));
317 const Clipboard::FormatType
& Clipboard::GetFilenameWFormatType() {
318 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
319 type
, ::RegisterClipboardFormat(CFSTR_FILENAMEW
));
325 const Clipboard::FormatType
& Clipboard::GetHtmlFormatType() {
326 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
327 type
, ::RegisterClipboardFormat(L
"HTML Format"));
333 const Clipboard::FormatType
& Clipboard::GetRtfFormatType() {
334 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
335 type
, ::RegisterClipboardFormat(L
"Rich Text Format"));
340 const Clipboard::FormatType
& Clipboard::GetBitmapFormatType() {
341 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type
, CF_BITMAP
);
347 const Clipboard::FormatType
& Clipboard::GetTextHtmlFormatType() {
348 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
349 type
, ::RegisterClipboardFormat(L
"text/html"));
354 const Clipboard::FormatType
& Clipboard::GetCFHDropFormatType() {
355 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type
, CF_HDROP
);
360 const Clipboard::FormatType
& Clipboard::GetFileDescriptorFormatType() {
361 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
362 type
, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR
));
367 const Clipboard::FormatType
& Clipboard::GetFileContentZeroFormatType() {
368 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
369 type
, ::RegisterClipboardFormat(CFSTR_FILECONTENTS
), 0);
374 const Clipboard::FormatType
& Clipboard::GetIDListFormatType() {
375 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
376 type
, ::RegisterClipboardFormat(CFSTR_SHELLIDLIST
));
381 const Clipboard::FormatType
& Clipboard::GetWebKitSmartPasteFormatType() {
382 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
384 ::RegisterClipboardFormat(L
"WebKit Smart Paste Format"));
389 const Clipboard::FormatType
& Clipboard::GetWebCustomDataFormatType() {
390 // TODO(dcheng): This name is temporary. See http://crbug.com/106449.
391 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
393 ::RegisterClipboardFormat(L
"Chromium Web Custom MIME Data Format"));
398 const Clipboard::FormatType
& Clipboard::GetPepperCustomDataFormatType() {
399 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
401 ::RegisterClipboardFormat(L
"Chromium Pepper MIME Data Format"));
404 #undef CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE
406 // Clipboard factory method.
408 Clipboard
* Clipboard::Create() {
409 return new ClipboardWin
;
412 // ClipboardWin implementation.
413 ClipboardWin::ClipboardWin() {
414 if (base::MessageLoopForUI::IsCurrent())
415 clipboard_owner_
.reset(new base::win::MessageWindow());
418 ClipboardWin::~ClipboardWin() {
421 uint64
ClipboardWin::GetSequenceNumber(ClipboardType type
) const {
422 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
423 return ::GetClipboardSequenceNumber();
426 bool ClipboardWin::IsFormatAvailable(const Clipboard::FormatType
& format
,
427 ClipboardType type
) const {
428 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
429 return ::IsClipboardFormatAvailable(format
.ToFormatEtc().cfFormat
) != FALSE
;
432 void ClipboardWin::Clear(ClipboardType type
) {
433 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
434 ScopedClipboard clipboard
;
435 if (!clipboard
.Acquire(GetClipboardWindow()))
441 void ClipboardWin::ReadAvailableTypes(ClipboardType type
,
442 std::vector
<base::string16
>* types
,
443 bool* contains_filenames
) const {
444 if (!types
|| !contains_filenames
) {
450 if (::IsClipboardFormatAvailable(
451 GetPlainTextFormatType().ToFormatEtc().cfFormat
))
452 types
->push_back(base::UTF8ToUTF16(kMimeTypeText
));
453 if (::IsClipboardFormatAvailable(GetHtmlFormatType().ToFormatEtc().cfFormat
))
454 types
->push_back(base::UTF8ToUTF16(kMimeTypeHTML
));
455 if (::IsClipboardFormatAvailable(GetRtfFormatType().ToFormatEtc().cfFormat
))
456 types
->push_back(base::UTF8ToUTF16(kMimeTypeRTF
));
457 if (::IsClipboardFormatAvailable(CF_DIB
))
458 types
->push_back(base::UTF8ToUTF16(kMimeTypePNG
));
459 *contains_filenames
= false;
461 // Acquire the clipboard.
462 ScopedClipboard clipboard
;
463 if (!clipboard
.Acquire(GetClipboardWindow()))
467 ::GetClipboardData(GetWebCustomDataFormatType().ToFormatEtc().cfFormat
);
471 ReadCustomDataTypes(::GlobalLock(hdata
), ::GlobalSize(hdata
), types
);
472 ::GlobalUnlock(hdata
);
475 void ClipboardWin::ReadText(ClipboardType type
, base::string16
* result
) const {
476 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
484 // Acquire the clipboard.
485 ScopedClipboard clipboard
;
486 if (!clipboard
.Acquire(GetClipboardWindow()))
489 HANDLE data
= ::GetClipboardData(CF_UNICODETEXT
);
493 result
->assign(static_cast<const base::char16
*>(::GlobalLock(data
)));
494 ::GlobalUnlock(data
);
497 void ClipboardWin::ReadAsciiText(ClipboardType type
,
498 std::string
* result
) const {
499 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
507 // Acquire the clipboard.
508 ScopedClipboard clipboard
;
509 if (!clipboard
.Acquire(GetClipboardWindow()))
512 HANDLE data
= ::GetClipboardData(CF_TEXT
);
516 result
->assign(static_cast<const char*>(::GlobalLock(data
)));
517 ::GlobalUnlock(data
);
520 void ClipboardWin::ReadHTML(ClipboardType type
,
521 base::string16
* markup
,
522 std::string
* src_url
,
523 uint32
* fragment_start
,
524 uint32
* fragment_end
) const {
525 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
528 // TODO(dcheng): Remove these checks, I don't think they should be optional.
535 // Acquire the clipboard.
536 ScopedClipboard clipboard
;
537 if (!clipboard
.Acquire(GetClipboardWindow()))
540 HANDLE data
= ::GetClipboardData(GetHtmlFormatType().ToFormatEtc().cfFormat
);
544 std::string
cf_html(static_cast<const char*>(::GlobalLock(data
)));
545 ::GlobalUnlock(data
);
547 size_t html_start
= std::string::npos
;
548 size_t start_index
= std::string::npos
;
549 size_t end_index
= std::string::npos
;
550 ClipboardUtil::CFHtmlExtractMetadata(cf_html
, src_url
, &html_start
,
551 &start_index
, &end_index
);
553 // This might happen if the contents of the clipboard changed and CF_HTML is
554 // no longer available.
555 if (start_index
== std::string::npos
||
556 end_index
== std::string::npos
||
557 html_start
== std::string::npos
)
560 if (start_index
< html_start
|| end_index
< start_index
)
563 std::vector
<size_t> offsets
;
564 offsets
.push_back(start_index
- html_start
);
565 offsets
.push_back(end_index
- html_start
);
566 markup
->assign(base::UTF8ToUTF16AndAdjustOffsets(cf_html
.data() + html_start
,
568 *fragment_start
= base::checked_cast
<uint32
>(offsets
[0]);
569 *fragment_end
= base::checked_cast
<uint32
>(offsets
[1]);
572 void ClipboardWin::ReadRTF(ClipboardType type
, std::string
* result
) const {
573 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
575 ReadData(GetRtfFormatType(), result
);
578 SkBitmap
ClipboardWin::ReadImage(ClipboardType type
) const {
579 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
581 // Acquire the clipboard.
582 ScopedClipboard clipboard
;
583 if (!clipboard
.Acquire(GetClipboardWindow()))
586 // We use a DIB rather than a DDB here since ::GetObject() with the
587 // HBITMAP returned from ::GetClipboardData(CF_BITMAP) always reports a color
589 BITMAPINFO
* bitmap
= static_cast<BITMAPINFO
*>(::GetClipboardData(CF_DIB
));
592 int color_table_length
= 0;
593 switch (bitmap
->bmiHeader
.biBitCount
) {
597 color_table_length
= bitmap
->bmiHeader
.biClrUsed
598 ? bitmap
->bmiHeader
.biClrUsed
599 : 1 << bitmap
->bmiHeader
.biBitCount
;
603 if (bitmap
->bmiHeader
.biCompression
== BI_BITFIELDS
)
604 color_table_length
= 3;
611 const void* bitmap_bits
= reinterpret_cast<const char*>(bitmap
)
612 + bitmap
->bmiHeader
.biSize
+ color_table_length
* sizeof(RGBQUAD
);
614 gfx::Canvas
canvas(gfx::Size(bitmap
->bmiHeader
.biWidth
,
615 bitmap
->bmiHeader
.biHeight
),
619 skia::ScopedPlatformPaint
scoped_platform_paint(canvas
.sk_canvas());
620 HDC dc
= scoped_platform_paint
.GetPlatformSurface();
621 ::SetDIBitsToDevice(dc
, 0, 0, bitmap
->bmiHeader
.biWidth
,
622 bitmap
->bmiHeader
.biHeight
, 0, 0, 0,
623 bitmap
->bmiHeader
.biHeight
, bitmap_bits
, bitmap
,
626 // Windows doesn't really handle alpha channels well in many situations. When
627 // the source image is < 32 bpp, we force the bitmap to be opaque. When the
628 // source image is 32 bpp, the alpha channel might still contain garbage data.
629 // Since Windows uses premultiplied alpha, we scan for instances where
630 // (R, G, B) > A. If there are any invalid premultiplied colors in the image,
631 // we assume the alpha channel contains garbage and force the bitmap to be
632 // opaque as well. Note that this heuristic will fail on a transparent bitmap
633 // containing only black pixels...
634 const SkBitmap
& device_bitmap
=
635 canvas
.sk_canvas()->getDevice()->accessBitmap(true);
637 SkAutoLockPixels
lock(device_bitmap
);
638 bool has_invalid_alpha_channel
= bitmap
->bmiHeader
.biBitCount
< 32 ||
639 BitmapHasInvalidPremultipliedColors(device_bitmap
);
640 if (has_invalid_alpha_channel
) {
641 MakeBitmapOpaque(device_bitmap
);
645 return canvas
.ExtractImageRep().sk_bitmap();
648 void ClipboardWin::ReadCustomData(ClipboardType clipboard_type
,
649 const base::string16
& type
,
650 base::string16
* result
) const {
651 DCHECK_EQ(clipboard_type
, CLIPBOARD_TYPE_COPY_PASTE
);
653 // Acquire the clipboard.
654 ScopedClipboard clipboard
;
655 if (!clipboard
.Acquire(GetClipboardWindow()))
659 ::GetClipboardData(GetWebCustomDataFormatType().ToFormatEtc().cfFormat
);
663 ReadCustomDataForType(::GlobalLock(hdata
), ::GlobalSize(hdata
), type
, result
);
664 ::GlobalUnlock(hdata
);
667 void ClipboardWin::ReadBookmark(base::string16
* title
, std::string
* url
) const {
674 // Acquire the clipboard.
675 ScopedClipboard clipboard
;
676 if (!clipboard
.Acquire(GetClipboardWindow()))
679 HANDLE data
= ::GetClipboardData(GetUrlWFormatType().ToFormatEtc().cfFormat
);
683 base::string16
bookmark(static_cast<const base::char16
*>(::GlobalLock(data
)));
684 ::GlobalUnlock(data
);
686 ParseBookmarkClipboardFormat(bookmark
, title
, url
);
689 void ClipboardWin::ReadData(const FormatType
& format
,
690 std::string
* result
) const {
696 ScopedClipboard clipboard
;
697 if (!clipboard
.Acquire(GetClipboardWindow()))
700 HANDLE data
= ::GetClipboardData(format
.ToFormatEtc().cfFormat
);
704 result
->assign(static_cast<const char*>(::GlobalLock(data
)),
706 ::GlobalUnlock(data
);
709 void ClipboardWin::WriteObjects(ClipboardType type
, const ObjectMap
& objects
) {
710 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
712 ScopedClipboard clipboard
;
713 if (!clipboard
.Acquire(GetClipboardWindow()))
718 for (ObjectMap::const_iterator iter
= objects
.begin(); iter
!= objects
.end();
720 DispatchObject(static_cast<ObjectType
>(iter
->first
), iter
->second
);
724 void ClipboardWin::WriteText(const char* text_data
, size_t text_len
) {
726 base::UTF8ToUTF16(text_data
, text_len
, &text
);
727 HGLOBAL glob
= CreateGlobalData(text
);
729 WriteToClipboard(CF_UNICODETEXT
, glob
);
732 void ClipboardWin::WriteHTML(const char* markup_data
,
734 const char* url_data
,
736 std::string
markup(markup_data
, markup_len
);
740 url
.assign(url_data
, url_len
);
742 std::string html_fragment
= ClipboardUtil::HtmlToCFHtml(markup
, url
);
743 HGLOBAL glob
= CreateGlobalData(html_fragment
);
745 WriteToClipboard(Clipboard::GetHtmlFormatType().ToFormatEtc().cfFormat
, glob
);
748 void ClipboardWin::WriteRTF(const char* rtf_data
, size_t data_len
) {
749 WriteData(GetRtfFormatType(), rtf_data
, data_len
);
752 void ClipboardWin::WriteBookmark(const char* title_data
,
754 const char* url_data
,
756 std::string
bookmark(title_data
, title_len
);
757 bookmark
.append(1, L
'\n');
758 bookmark
.append(url_data
, url_len
);
760 base::string16 wide_bookmark
= base::UTF8ToUTF16(bookmark
);
761 HGLOBAL glob
= CreateGlobalData(wide_bookmark
);
763 WriteToClipboard(GetUrlWFormatType().ToFormatEtc().cfFormat
, glob
);
766 void ClipboardWin::WriteWebSmartPaste() {
767 DCHECK(clipboard_owner_
->hwnd() != NULL
);
768 ::SetClipboardData(GetWebKitSmartPasteFormatType().ToFormatEtc().cfFormat
,
772 void ClipboardWin::WriteBitmap(const SkBitmap
& bitmap
) {
773 HDC dc
= ::GetDC(NULL
);
775 // This doesn't actually cost us a memcpy when the bitmap comes from the
776 // renderer as we load it into the bitmap using setPixels which just sets a
777 // pointer. Someone has to memcpy it into GDI, it might as well be us here.
779 // TODO(darin): share data in gfx/bitmap_header.cc somehow
780 BITMAPINFO bm_info
= {};
781 bm_info
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
782 bm_info
.bmiHeader
.biWidth
= bitmap
.width();
783 bm_info
.bmiHeader
.biHeight
= -bitmap
.height(); // sets vertical orientation
784 bm_info
.bmiHeader
.biPlanes
= 1;
785 bm_info
.bmiHeader
.biBitCount
= 32;
786 bm_info
.bmiHeader
.biCompression
= BI_RGB
;
788 // ::CreateDIBSection allocates memory for us to copy our bitmap into.
789 // Unfortunately, we can't write the created bitmap to the clipboard,
790 // (see http://msdn2.microsoft.com/en-us/library/ms532292.aspx)
792 HBITMAP source_hbitmap
=
793 ::CreateDIBSection(dc
, &bm_info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
795 if (bits
&& source_hbitmap
) {
797 SkAutoLockPixels
bitmap_lock(bitmap
);
798 // Copy the bitmap out of shared memory and into GDI
799 memcpy(bits
, bitmap
.getPixels(), bitmap
.getSize());
802 // Now we have an HBITMAP, we can write it to the clipboard
803 WriteBitmapFromHandle(source_hbitmap
,
804 gfx::Size(bitmap
.width(), bitmap
.height()));
807 ::DeleteObject(source_hbitmap
);
808 ::ReleaseDC(NULL
, dc
);
811 void ClipboardWin::WriteData(const FormatType
& format
,
812 const char* data_data
,
814 HGLOBAL hdata
= ::GlobalAlloc(GMEM_MOVEABLE
, data_len
);
818 char* data
= static_cast<char*>(::GlobalLock(hdata
));
819 memcpy(data
, data_data
, data_len
);
820 ::GlobalUnlock(data
);
821 WriteToClipboard(format
.ToFormatEtc().cfFormat
, hdata
);
824 void ClipboardWin::WriteBitmapFromHandle(HBITMAP source_hbitmap
,
825 const gfx::Size
& size
) {
826 // We would like to just call ::SetClipboardData on the source_hbitmap,
827 // but that bitmap might not be of a sort we can write to the clipboard.
828 // For this reason, we create a new bitmap, copy the bits over, and then
829 // write that to the clipboard.
831 HDC dc
= ::GetDC(NULL
);
832 HDC compatible_dc
= ::CreateCompatibleDC(NULL
);
833 HDC source_dc
= ::CreateCompatibleDC(NULL
);
835 // This is the HBITMAP we will eventually write to the clipboard
836 HBITMAP hbitmap
= ::CreateCompatibleBitmap(dc
, size
.width(), size
.height());
838 // Failed to create the bitmap
839 ::DeleteDC(compatible_dc
);
840 ::DeleteDC(source_dc
);
841 ::ReleaseDC(NULL
, dc
);
845 HBITMAP old_hbitmap
= (HBITMAP
)SelectObject(compatible_dc
, hbitmap
);
846 HBITMAP old_source
= (HBITMAP
)SelectObject(source_dc
, source_hbitmap
);
848 // Now we need to blend it into an HBITMAP we can place on the clipboard
849 BLENDFUNCTION bf
= {AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
850 ::GdiAlphaBlend(compatible_dc
,
862 // Clean up all the handles we just opened
863 ::SelectObject(compatible_dc
, old_hbitmap
);
864 ::SelectObject(source_dc
, old_source
);
865 ::DeleteObject(old_hbitmap
);
866 ::DeleteObject(old_source
);
867 ::DeleteDC(compatible_dc
);
868 ::DeleteDC(source_dc
);
869 ::ReleaseDC(NULL
, dc
);
871 WriteToClipboard(CF_BITMAP
, hbitmap
);
874 void ClipboardWin::WriteToClipboard(unsigned int format
, HANDLE handle
) {
875 DCHECK(clipboard_owner_
->hwnd() != NULL
);
876 if (handle
&& !::SetClipboardData(format
, handle
)) {
877 DCHECK(ERROR_CLIPBOARD_NOT_OPEN
!= GetLastError());
878 FreeData(format
, handle
);
882 HWND
ClipboardWin::GetClipboardWindow() const {
883 if (!clipboard_owner_
)
886 if (clipboard_owner_
->hwnd() == NULL
)
887 clipboard_owner_
->Create(base::Bind(&ClipboardOwnerWndProc
));
889 return clipboard_owner_
->hwnd();