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/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/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()));
267 const Clipboard::FormatType
& Clipboard::GetUrlFormatType() {
268 CR_DEFINE_STATIC_LOCAL(
269 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_INETURLA
)));
274 const Clipboard::FormatType
& Clipboard::GetUrlWFormatType() {
275 CR_DEFINE_STATIC_LOCAL(
276 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_INETURLW
)));
281 const Clipboard::FormatType
& Clipboard::GetMozUrlFormatType() {
282 CR_DEFINE_STATIC_LOCAL(
283 FormatType
, type
, (::RegisterClipboardFormat(L
"text/x-moz-url")));
288 const Clipboard::FormatType
& Clipboard::GetPlainTextFormatType() {
289 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (CF_TEXT
));
294 const Clipboard::FormatType
& Clipboard::GetPlainTextWFormatType() {
295 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (CF_UNICODETEXT
));
300 const Clipboard::FormatType
& Clipboard::GetFilenameFormatType() {
301 CR_DEFINE_STATIC_LOCAL(
302 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_FILENAMEA
)));
307 const Clipboard::FormatType
& Clipboard::GetFilenameWFormatType() {
308 CR_DEFINE_STATIC_LOCAL(
309 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_FILENAMEW
)));
315 const Clipboard::FormatType
& Clipboard::GetHtmlFormatType() {
316 CR_DEFINE_STATIC_LOCAL(
317 FormatType
, type
, (::RegisterClipboardFormat(L
"HTML Format")));
323 const Clipboard::FormatType
& Clipboard::GetRtfFormatType() {
324 CR_DEFINE_STATIC_LOCAL(
325 FormatType
, type
, (::RegisterClipboardFormat(L
"Rich Text Format")));
330 const Clipboard::FormatType
& Clipboard::GetBitmapFormatType() {
331 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (CF_BITMAP
));
337 const Clipboard::FormatType
& Clipboard::GetTextHtmlFormatType() {
338 CR_DEFINE_STATIC_LOCAL(
339 FormatType
, type
, (::RegisterClipboardFormat(L
"text/html")));
344 const Clipboard::FormatType
& Clipboard::GetCFHDropFormatType() {
345 CR_DEFINE_STATIC_LOCAL(FormatType
, type
, (CF_HDROP
));
350 const Clipboard::FormatType
& Clipboard::GetFileDescriptorFormatType() {
351 CR_DEFINE_STATIC_LOCAL(
352 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR
)));
357 const Clipboard::FormatType
& Clipboard::GetFileContentZeroFormatType() {
358 CR_DEFINE_STATIC_LOCAL(
359 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_FILECONTENTS
), 0));
364 const Clipboard::FormatType
& Clipboard::GetIDListFormatType() {
365 CR_DEFINE_STATIC_LOCAL(
366 FormatType
, type
, (::RegisterClipboardFormat(CFSTR_SHELLIDLIST
)));
371 const Clipboard::FormatType
& Clipboard::GetWebKitSmartPasteFormatType() {
372 CR_DEFINE_STATIC_LOCAL(
375 (::RegisterClipboardFormat(L
"WebKit Smart Paste Format")));
380 const Clipboard::FormatType
& Clipboard::GetWebCustomDataFormatType() {
381 // TODO(dcheng): This name is temporary. See http://crbug.com/106449.
382 CR_DEFINE_STATIC_LOCAL(
385 (::RegisterClipboardFormat(L
"Chromium Web Custom MIME Data Format")));
390 const Clipboard::FormatType
& Clipboard::GetPepperCustomDataFormatType() {
391 CR_DEFINE_STATIC_LOCAL(
394 (::RegisterClipboardFormat(L
"Chromium Pepper MIME Data Format")));
398 // Clipboard factory method.
400 Clipboard
* Clipboard::Create() {
401 return new ClipboardWin
;
404 // ClipboardWin implementation.
405 ClipboardWin::ClipboardWin() {
406 if (base::MessageLoopForUI::IsCurrent())
407 clipboard_owner_
.reset(new base::win::MessageWindow());
410 ClipboardWin::~ClipboardWin() {
413 uint64
ClipboardWin::GetSequenceNumber(ClipboardType type
) const {
414 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
415 return ::GetClipboardSequenceNumber();
418 bool ClipboardWin::IsFormatAvailable(const Clipboard::FormatType
& format
,
419 ClipboardType type
) const {
420 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
421 return ::IsClipboardFormatAvailable(format
.ToFormatEtc().cfFormat
) != FALSE
;
424 void ClipboardWin::Clear(ClipboardType type
) {
425 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
426 ScopedClipboard clipboard
;
427 if (!clipboard
.Acquire(GetClipboardWindow()))
433 void ClipboardWin::ReadAvailableTypes(ClipboardType type
,
434 std::vector
<base::string16
>* types
,
435 bool* contains_filenames
) const {
436 if (!types
|| !contains_filenames
) {
442 if (::IsClipboardFormatAvailable(
443 GetPlainTextFormatType().ToFormatEtc().cfFormat
))
444 types
->push_back(base::UTF8ToUTF16(kMimeTypeText
));
445 if (::IsClipboardFormatAvailable(GetHtmlFormatType().ToFormatEtc().cfFormat
))
446 types
->push_back(base::UTF8ToUTF16(kMimeTypeHTML
));
447 if (::IsClipboardFormatAvailable(GetRtfFormatType().ToFormatEtc().cfFormat
))
448 types
->push_back(base::UTF8ToUTF16(kMimeTypeRTF
));
449 if (::IsClipboardFormatAvailable(CF_DIB
))
450 types
->push_back(base::UTF8ToUTF16(kMimeTypePNG
));
451 *contains_filenames
= false;
453 // Acquire the clipboard.
454 ScopedClipboard clipboard
;
455 if (!clipboard
.Acquire(GetClipboardWindow()))
459 ::GetClipboardData(GetWebCustomDataFormatType().ToFormatEtc().cfFormat
);
463 ReadCustomDataTypes(::GlobalLock(hdata
), ::GlobalSize(hdata
), types
);
464 ::GlobalUnlock(hdata
);
467 void ClipboardWin::ReadText(ClipboardType type
, base::string16
* result
) const {
468 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
476 // Acquire the clipboard.
477 ScopedClipboard clipboard
;
478 if (!clipboard
.Acquire(GetClipboardWindow()))
481 HANDLE data
= ::GetClipboardData(CF_UNICODETEXT
);
485 result
->assign(static_cast<const base::char16
*>(::GlobalLock(data
)));
486 ::GlobalUnlock(data
);
489 void ClipboardWin::ReadAsciiText(ClipboardType type
,
490 std::string
* result
) const {
491 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
499 // Acquire the clipboard.
500 ScopedClipboard clipboard
;
501 if (!clipboard
.Acquire(GetClipboardWindow()))
504 HANDLE data
= ::GetClipboardData(CF_TEXT
);
508 result
->assign(static_cast<const char*>(::GlobalLock(data
)));
509 ::GlobalUnlock(data
);
512 void ClipboardWin::ReadHTML(ClipboardType type
,
513 base::string16
* markup
,
514 std::string
* src_url
,
515 uint32
* fragment_start
,
516 uint32
* fragment_end
) const {
517 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
520 // TODO(dcheng): Remove these checks, I don't think they should be optional.
527 // Acquire the clipboard.
528 ScopedClipboard clipboard
;
529 if (!clipboard
.Acquire(GetClipboardWindow()))
532 HANDLE data
= ::GetClipboardData(GetHtmlFormatType().ToFormatEtc().cfFormat
);
536 std::string
cf_html(static_cast<const char*>(::GlobalLock(data
)));
537 ::GlobalUnlock(data
);
539 size_t html_start
= std::string::npos
;
540 size_t start_index
= std::string::npos
;
541 size_t end_index
= std::string::npos
;
542 ClipboardUtil::CFHtmlExtractMetadata(cf_html
, src_url
, &html_start
,
543 &start_index
, &end_index
);
545 // This might happen if the contents of the clipboard changed and CF_HTML is
546 // no longer available.
547 if (start_index
== std::string::npos
||
548 end_index
== std::string::npos
||
549 html_start
== std::string::npos
)
552 if (start_index
< html_start
|| end_index
< start_index
)
555 std::vector
<size_t> offsets
;
556 offsets
.push_back(start_index
- html_start
);
557 offsets
.push_back(end_index
- html_start
);
558 markup
->assign(base::UTF8ToUTF16AndAdjustOffsets(cf_html
.data() + html_start
,
560 *fragment_start
= base::checked_cast
<uint32
>(offsets
[0]);
561 *fragment_end
= base::checked_cast
<uint32
>(offsets
[1]);
564 void ClipboardWin::ReadRTF(ClipboardType type
, std::string
* result
) const {
565 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
567 ReadData(GetRtfFormatType(), result
);
570 SkBitmap
ClipboardWin::ReadImage(ClipboardType type
) const {
571 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
573 // Acquire the clipboard.
574 ScopedClipboard clipboard
;
575 if (!clipboard
.Acquire(GetClipboardWindow()))
578 // We use a DIB rather than a DDB here since ::GetObject() with the
579 // HBITMAP returned from ::GetClipboardData(CF_BITMAP) always reports a color
581 BITMAPINFO
* bitmap
= static_cast<BITMAPINFO
*>(::GetClipboardData(CF_DIB
));
584 int color_table_length
= 0;
585 switch (bitmap
->bmiHeader
.biBitCount
) {
589 color_table_length
= bitmap
->bmiHeader
.biClrUsed
590 ? bitmap
->bmiHeader
.biClrUsed
591 : 1 << bitmap
->bmiHeader
.biBitCount
;
595 if (bitmap
->bmiHeader
.biCompression
== BI_BITFIELDS
)
596 color_table_length
= 3;
603 const void* bitmap_bits
= reinterpret_cast<const char*>(bitmap
)
604 + bitmap
->bmiHeader
.biSize
+ color_table_length
* sizeof(RGBQUAD
);
606 gfx::Canvas
canvas(gfx::Size(bitmap
->bmiHeader
.biWidth
,
607 bitmap
->bmiHeader
.biHeight
),
611 skia::ScopedPlatformPaint
scoped_platform_paint(canvas
.sk_canvas());
612 HDC dc
= scoped_platform_paint
.GetPlatformSurface();
613 ::SetDIBitsToDevice(dc
, 0, 0, bitmap
->bmiHeader
.biWidth
,
614 bitmap
->bmiHeader
.biHeight
, 0, 0, 0,
615 bitmap
->bmiHeader
.biHeight
, bitmap_bits
, bitmap
,
618 // Windows doesn't really handle alpha channels well in many situations. When
619 // the source image is < 32 bpp, we force the bitmap to be opaque. When the
620 // source image is 32 bpp, the alpha channel might still contain garbage data.
621 // Since Windows uses premultiplied alpha, we scan for instances where
622 // (R, G, B) > A. If there are any invalid premultiplied colors in the image,
623 // we assume the alpha channel contains garbage and force the bitmap to be
624 // opaque as well. Note that this heuristic will fail on a transparent bitmap
625 // containing only black pixels...
626 const SkBitmap
& device_bitmap
=
627 canvas
.sk_canvas()->getDevice()->accessBitmap(true);
629 SkAutoLockPixels
lock(device_bitmap
);
630 bool has_invalid_alpha_channel
= bitmap
->bmiHeader
.biBitCount
< 32 ||
631 BitmapHasInvalidPremultipliedColors(device_bitmap
);
632 if (has_invalid_alpha_channel
) {
633 MakeBitmapOpaque(device_bitmap
);
637 return canvas
.ExtractImageRep().sk_bitmap();
640 void ClipboardWin::ReadCustomData(ClipboardType clipboard_type
,
641 const base::string16
& type
,
642 base::string16
* result
) const {
643 DCHECK_EQ(clipboard_type
, CLIPBOARD_TYPE_COPY_PASTE
);
645 // Acquire the clipboard.
646 ScopedClipboard clipboard
;
647 if (!clipboard
.Acquire(GetClipboardWindow()))
651 ::GetClipboardData(GetWebCustomDataFormatType().ToFormatEtc().cfFormat
);
655 ReadCustomDataForType(::GlobalLock(hdata
), ::GlobalSize(hdata
), type
, result
);
656 ::GlobalUnlock(hdata
);
659 void ClipboardWin::ReadBookmark(base::string16
* title
, std::string
* url
) const {
666 // Acquire the clipboard.
667 ScopedClipboard clipboard
;
668 if (!clipboard
.Acquire(GetClipboardWindow()))
671 HANDLE data
= ::GetClipboardData(GetUrlWFormatType().ToFormatEtc().cfFormat
);
675 base::string16
bookmark(static_cast<const base::char16
*>(::GlobalLock(data
)));
676 ::GlobalUnlock(data
);
678 ParseBookmarkClipboardFormat(bookmark
, title
, url
);
681 void ClipboardWin::ReadData(const FormatType
& format
,
682 std::string
* result
) const {
688 ScopedClipboard clipboard
;
689 if (!clipboard
.Acquire(GetClipboardWindow()))
692 HANDLE data
= ::GetClipboardData(format
.ToFormatEtc().cfFormat
);
696 result
->assign(static_cast<const char*>(::GlobalLock(data
)),
698 ::GlobalUnlock(data
);
701 void ClipboardWin::WriteObjects(ClipboardType type
, const ObjectMap
& objects
) {
702 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
704 ScopedClipboard clipboard
;
705 if (!clipboard
.Acquire(GetClipboardWindow()))
710 for (ObjectMap::const_iterator iter
= objects
.begin(); iter
!= objects
.end();
712 DispatchObject(static_cast<ObjectType
>(iter
->first
), iter
->second
);
716 void ClipboardWin::WriteText(const char* text_data
, size_t text_len
) {
718 base::UTF8ToUTF16(text_data
, text_len
, &text
);
719 HGLOBAL glob
= CreateGlobalData(text
);
721 WriteToClipboard(CF_UNICODETEXT
, glob
);
724 void ClipboardWin::WriteHTML(const char* markup_data
,
726 const char* url_data
,
728 std::string
markup(markup_data
, markup_len
);
732 url
.assign(url_data
, url_len
);
734 std::string html_fragment
= ClipboardUtil::HtmlToCFHtml(markup
, url
);
735 HGLOBAL glob
= CreateGlobalData(html_fragment
);
737 WriteToClipboard(Clipboard::GetHtmlFormatType().ToFormatEtc().cfFormat
, glob
);
740 void ClipboardWin::WriteRTF(const char* rtf_data
, size_t data_len
) {
741 WriteData(GetRtfFormatType(), rtf_data
, data_len
);
744 void ClipboardWin::WriteBookmark(const char* title_data
,
746 const char* url_data
,
748 std::string
bookmark(title_data
, title_len
);
749 bookmark
.append(1, L
'\n');
750 bookmark
.append(url_data
, url_len
);
752 base::string16 wide_bookmark
= base::UTF8ToUTF16(bookmark
);
753 HGLOBAL glob
= CreateGlobalData(wide_bookmark
);
755 WriteToClipboard(GetUrlWFormatType().ToFormatEtc().cfFormat
, glob
);
758 void ClipboardWin::WriteWebSmartPaste() {
759 DCHECK(clipboard_owner_
->hwnd() != NULL
);
760 ::SetClipboardData(GetWebKitSmartPasteFormatType().ToFormatEtc().cfFormat
,
764 void ClipboardWin::WriteBitmap(const SkBitmap
& bitmap
) {
765 HDC dc
= ::GetDC(NULL
);
767 // This doesn't actually cost us a memcpy when the bitmap comes from the
768 // renderer as we load it into the bitmap using setPixels which just sets a
769 // pointer. Someone has to memcpy it into GDI, it might as well be us here.
771 // TODO(darin): share data in gfx/bitmap_header.cc somehow
772 BITMAPINFO bm_info
= {0};
773 bm_info
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
774 bm_info
.bmiHeader
.biWidth
= bitmap
.width();
775 bm_info
.bmiHeader
.biHeight
= -bitmap
.height(); // sets vertical orientation
776 bm_info
.bmiHeader
.biPlanes
= 1;
777 bm_info
.bmiHeader
.biBitCount
= 32;
778 bm_info
.bmiHeader
.biCompression
= BI_RGB
;
780 // ::CreateDIBSection allocates memory for us to copy our bitmap into.
781 // Unfortunately, we can't write the created bitmap to the clipboard,
782 // (see http://msdn2.microsoft.com/en-us/library/ms532292.aspx)
784 HBITMAP source_hbitmap
=
785 ::CreateDIBSection(dc
, &bm_info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
787 if (bits
&& source_hbitmap
) {
789 SkAutoLockPixels
bitmap_lock(bitmap
);
790 // Copy the bitmap out of shared memory and into GDI
791 memcpy(bits
, bitmap
.getPixels(), bitmap
.getSize());
794 // Now we have an HBITMAP, we can write it to the clipboard
795 WriteBitmapFromHandle(source_hbitmap
,
796 gfx::Size(bitmap
.width(), bitmap
.height()));
799 ::DeleteObject(source_hbitmap
);
800 ::ReleaseDC(NULL
, dc
);
803 void ClipboardWin::WriteData(const FormatType
& format
,
804 const char* data_data
,
806 HGLOBAL hdata
= ::GlobalAlloc(GMEM_MOVEABLE
, data_len
);
810 char* data
= static_cast<char*>(::GlobalLock(hdata
));
811 memcpy(data
, data_data
, data_len
);
812 ::GlobalUnlock(data
);
813 WriteToClipboard(format
.ToFormatEtc().cfFormat
, hdata
);
816 void ClipboardWin::WriteBitmapFromHandle(HBITMAP source_hbitmap
,
817 const gfx::Size
& size
) {
818 // We would like to just call ::SetClipboardData on the source_hbitmap,
819 // but that bitmap might not be of a sort we can write to the clipboard.
820 // For this reason, we create a new bitmap, copy the bits over, and then
821 // write that to the clipboard.
823 HDC dc
= ::GetDC(NULL
);
824 HDC compatible_dc
= ::CreateCompatibleDC(NULL
);
825 HDC source_dc
= ::CreateCompatibleDC(NULL
);
827 // This is the HBITMAP we will eventually write to the clipboard
828 HBITMAP hbitmap
= ::CreateCompatibleBitmap(dc
, size
.width(), size
.height());
830 // Failed to create the bitmap
831 ::DeleteDC(compatible_dc
);
832 ::DeleteDC(source_dc
);
833 ::ReleaseDC(NULL
, dc
);
837 HBITMAP old_hbitmap
= (HBITMAP
)SelectObject(compatible_dc
, hbitmap
);
838 HBITMAP old_source
= (HBITMAP
)SelectObject(source_dc
, source_hbitmap
);
840 // Now we need to blend it into an HBITMAP we can place on the clipboard
841 BLENDFUNCTION bf
= {AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
842 ::GdiAlphaBlend(compatible_dc
,
854 // Clean up all the handles we just opened
855 ::SelectObject(compatible_dc
, old_hbitmap
);
856 ::SelectObject(source_dc
, old_source
);
857 ::DeleteObject(old_hbitmap
);
858 ::DeleteObject(old_source
);
859 ::DeleteDC(compatible_dc
);
860 ::DeleteDC(source_dc
);
861 ::ReleaseDC(NULL
, dc
);
863 WriteToClipboard(CF_BITMAP
, hbitmap
);
866 void ClipboardWin::WriteToClipboard(unsigned int format
, HANDLE handle
) {
867 DCHECK(clipboard_owner_
->hwnd() != NULL
);
868 if (handle
&& !::SetClipboardData(format
, handle
)) {
869 DCHECK(ERROR_CLIPBOARD_NOT_OPEN
!= GetLastError());
870 FreeData(format
, handle
);
874 HWND
ClipboardWin::GetClipboardWindow() const {
875 if (!clipboard_owner_
)
878 if (clipboard_owner_
->hwnd() == NULL
)
879 clipboard_owner_
->Create(base::Bind(&ClipboardOwnerWndProc
));
881 return clipboard_owner_
->hwnd();