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/memory/shared_memory.h"
19 #include "base/message_loop/message_loop.h"
20 #include "base/numerics/safe_conversions.h"
21 #include "base/stl_util.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/utf_offset_string_conversions.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "base/win/message_window.h"
27 #include "base/win/scoped_gdi_object.h"
28 #include "base/win/scoped_hdc.h"
29 #include "third_party/skia/include/core/SkBitmap.h"
30 #include "ui/base/clipboard/clipboard_util_win.h"
31 #include "ui/base/clipboard/custom_data_helper.h"
32 #include "ui/gfx/canvas.h"
33 #include "ui/gfx/geometry/size.h"
39 // A scoper to impersonate the anonymous token and revert when leaving scope
40 class AnonymousImpersonator
{
42 AnonymousImpersonator() {
43 must_revert_
= ::ImpersonateAnonymousToken(::GetCurrentThread());
46 ~AnonymousImpersonator() {
53 DISALLOW_COPY_AND_ASSIGN(AnonymousImpersonator
);
56 // A scoper to manage acquiring and automatically releasing the clipboard.
57 class ScopedClipboard
{
59 ScopedClipboard() : opened_(false) { }
66 bool Acquire(HWND owner
) {
67 const int kMaxAttemptsToOpenClipboard
= 5;
74 // Attempt to open the clipboard, which will acquire the Windows clipboard
75 // lock. This may fail if another process currently holds this lock.
76 // We're willing to try a few times in the hopes of acquiring it.
78 // This turns out to be an issue when using remote desktop because the
79 // rdpclip.exe process likes to read what we've written to the clipboard and
80 // send it to the RDP client. If we open and close the clipboard in quick
81 // succession, we might be trying to open it while rdpclip.exe has it open,
84 // In fact, we believe we'll only spin this loop over remote desktop. In
85 // normal situations, the user is initiating clipboard operations and there
86 // shouldn't be contention.
88 for (int attempts
= 0; attempts
< kMaxAttemptsToOpenClipboard
; ++attempts
) {
89 // If we didn't manage to open the clipboard, sleep a bit and be hopeful.
93 if (::OpenClipboard(owner
)) {
99 // We failed to acquire the clipboard.
105 // Impersonate the anonymous token during the call to CloseClipboard
106 // This prevents Windows 8+ capturing the broker's access token which
107 // could be accessed by lower-privileges chrome processes leading to
109 AnonymousImpersonator impersonator
;
121 bool ClipboardOwnerWndProc(UINT message
,
126 case WM_RENDERFORMAT
:
127 // This message comes when SetClipboardData was sent a null data handle
128 // and now it's come time to put the data on the clipboard.
129 // We always set data, so there isn't a need to actually do anything here.
131 case WM_RENDERALLFORMATS
:
132 // This message comes when SetClipboardData was sent a null data handle
133 // and now this application is about to quit, so it must put data on
134 // the clipboard before it exits.
135 // We always set data, so there isn't a need to actually do anything here.
137 case WM_DRAWCLIPBOARD
:
141 case WM_CHANGECBCHAIN
:
151 template <typename charT
>
152 HGLOBAL
CreateGlobalData(const std::basic_string
<charT
>& str
) {
154 ::GlobalAlloc(GMEM_MOVEABLE
, ((str
.size() + 1) * sizeof(charT
)));
156 charT
* raw_data
= static_cast<charT
*>(::GlobalLock(data
));
157 memcpy(raw_data
, str
.data(), str
.size() * sizeof(charT
));
158 raw_data
[str
.size()] = '\0';
159 ::GlobalUnlock(data
);
164 bool BitmapHasInvalidPremultipliedColors(const SkBitmap
& bitmap
) {
165 for (int x
= 0; x
< bitmap
.width(); ++x
) {
166 for (int y
= 0; y
< bitmap
.height(); ++y
) {
167 uint32_t pixel
= *bitmap
.getAddr32(x
, y
);
168 if (SkColorGetR(pixel
) > SkColorGetA(pixel
) ||
169 SkColorGetG(pixel
) > SkColorGetA(pixel
) ||
170 SkColorGetB(pixel
) > SkColorGetA(pixel
))
177 void MakeBitmapOpaque(const SkBitmap
& bitmap
) {
178 for (int x
= 0; x
< bitmap
.width(); ++x
) {
179 for (int y
= 0; y
< bitmap
.height(); ++y
) {
180 *bitmap
.getAddr32(x
, y
) = SkColorSetA(*bitmap
.getAddr32(x
, y
), 0xFF);
185 void ParseBookmarkClipboardFormat(const base::string16
& bookmark
,
186 base::string16
* title
,
188 const base::string16 kDelim
= base::ASCIIToUTF16("\r\n");
190 const size_t title_end
= bookmark
.find_first_of(kDelim
);
192 title
->assign(bookmark
.substr(0, title_end
));
195 const size_t url_start
= bookmark
.find_first_not_of(kDelim
, title_end
);
196 if (url_start
!= base::string16::npos
) {
198 base::UTF16ToUTF8(bookmark
.substr(url_start
, base::string16::npos
));
203 void FreeData(unsigned int format
, HANDLE data
) {
204 if (format
== CF_BITMAP
)
205 ::DeleteObject(static_cast<HBITMAP
>(data
));
212 // Clipboard::FormatType implementation.
213 Clipboard::FormatType::FormatType() : data_() {}
215 Clipboard::FormatType::FormatType(UINT native_format
) : data_() {
216 // There's no good way to actually initialize this in the constructor in
218 data_
.cfFormat
= static_cast<CLIPFORMAT
>(native_format
);
219 data_
.dwAspect
= DVASPECT_CONTENT
;
221 data_
.tymed
= TYMED_HGLOBAL
;
224 Clipboard::FormatType::FormatType(UINT native_format
, LONG index
) : data_() {
225 // There's no good way to actually initialize this in the constructor in
227 data_
.cfFormat
= static_cast<CLIPFORMAT
>(native_format
);
228 data_
.dwAspect
= DVASPECT_CONTENT
;
229 data_
.lindex
= index
;
230 data_
.tymed
= TYMED_HGLOBAL
;
233 Clipboard::FormatType::~FormatType() {
236 std::string
Clipboard::FormatType::Serialize() const {
237 return base::IntToString(data_
.cfFormat
);
241 Clipboard::FormatType
Clipboard::FormatType::Deserialize(
242 const std::string
& serialization
) {
243 int clipboard_format
= -1;
244 if (!base::StringToInt(serialization
, &clipboard_format
)) {
248 return FormatType(clipboard_format
);
251 bool Clipboard::FormatType::operator<(const FormatType
& other
) const {
252 return data_
.cfFormat
< other
.data_
.cfFormat
;
255 bool Clipboard::FormatType::Equals(const FormatType
& other
) const {
256 return data_
.cfFormat
== other
.data_
.cfFormat
;
259 // Various predefined FormatTypes.
261 Clipboard::FormatType
Clipboard::GetFormatType(
262 const std::string
& format_string
) {
264 ::RegisterClipboardFormat(base::ASCIIToUTF16(format_string
).c_str()));
267 // The following formats can be referenced by ClipboardUtilWin::GetPlainText.
268 // For reasons (COM), they must be initialized in a thread-safe manner.
269 // TODO(dcheng): We probably need to make static initialization of "known"
270 // FormatTypes thread-safe on all platforms.
271 #define CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(name, ...) \
272 struct FormatTypeArgumentForwarder : public FormatType { \
273 FormatTypeArgumentForwarder() : FormatType(__VA_ARGS__) { } \
275 static base::LazyInstance<FormatTypeArgumentForwarder>::Leaky name = \
276 LAZY_INSTANCE_INITIALIZER
278 const Clipboard::FormatType
& Clipboard::GetUrlFormatType() {
279 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
280 type
, ::RegisterClipboardFormat(CFSTR_INETURLA
));
285 const Clipboard::FormatType
& Clipboard::GetUrlWFormatType() {
286 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
287 type
, ::RegisterClipboardFormat(CFSTR_INETURLW
));
292 const Clipboard::FormatType
& Clipboard::GetMozUrlFormatType() {
293 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
294 type
, ::RegisterClipboardFormat(L
"text/x-moz-url"));
299 const Clipboard::FormatType
& Clipboard::GetPlainTextFormatType() {
300 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type
, CF_TEXT
);
305 const Clipboard::FormatType
& Clipboard::GetPlainTextWFormatType() {
306 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type
, CF_UNICODETEXT
);
311 const Clipboard::FormatType
& Clipboard::GetFilenameFormatType() {
312 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
313 type
, ::RegisterClipboardFormat(CFSTR_FILENAMEA
));
318 const Clipboard::FormatType
& Clipboard::GetFilenameWFormatType() {
319 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
320 type
, ::RegisterClipboardFormat(CFSTR_FILENAMEW
));
326 const Clipboard::FormatType
& Clipboard::GetHtmlFormatType() {
327 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
328 type
, ::RegisterClipboardFormat(L
"HTML Format"));
334 const Clipboard::FormatType
& Clipboard::GetRtfFormatType() {
335 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
336 type
, ::RegisterClipboardFormat(L
"Rich Text Format"));
341 const Clipboard::FormatType
& Clipboard::GetBitmapFormatType() {
342 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type
, CF_BITMAP
);
348 const Clipboard::FormatType
& Clipboard::GetTextHtmlFormatType() {
349 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
350 type
, ::RegisterClipboardFormat(L
"text/html"));
355 const Clipboard::FormatType
& Clipboard::GetCFHDropFormatType() {
356 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(type
, CF_HDROP
);
361 const Clipboard::FormatType
& Clipboard::GetFileDescriptorFormatType() {
362 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
363 type
, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR
));
368 const Clipboard::FormatType
& Clipboard::GetFileContentZeroFormatType() {
369 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
370 type
, ::RegisterClipboardFormat(CFSTR_FILECONTENTS
), 0);
375 const Clipboard::FormatType
& Clipboard::GetIDListFormatType() {
376 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
377 type
, ::RegisterClipboardFormat(CFSTR_SHELLIDLIST
));
382 const Clipboard::FormatType
& Clipboard::GetWebKitSmartPasteFormatType() {
383 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
385 ::RegisterClipboardFormat(L
"WebKit Smart Paste Format"));
390 const Clipboard::FormatType
& Clipboard::GetWebCustomDataFormatType() {
391 // TODO(dcheng): This name is temporary. See http://crbug.com/106449.
392 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
394 ::RegisterClipboardFormat(L
"Chromium Web Custom MIME Data Format"));
399 const Clipboard::FormatType
& Clipboard::GetPepperCustomDataFormatType() {
400 CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE(
402 ::RegisterClipboardFormat(L
"Chromium Pepper MIME Data Format"));
405 #undef CR_STATIC_UI_CLIPBOARD_FORMAT_TYPE
407 // Clipboard factory method.
409 Clipboard
* Clipboard::Create() {
410 return new ClipboardWin
;
413 // ClipboardWin implementation.
414 ClipboardWin::ClipboardWin() {
415 if (base::MessageLoopForUI::IsCurrent())
416 clipboard_owner_
.reset(new base::win::MessageWindow());
419 ClipboardWin::~ClipboardWin() {
422 uint64
ClipboardWin::GetSequenceNumber(ClipboardType type
) const {
423 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
424 return ::GetClipboardSequenceNumber();
427 bool ClipboardWin::IsFormatAvailable(const Clipboard::FormatType
& format
,
428 ClipboardType type
) const {
429 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
430 return ::IsClipboardFormatAvailable(format
.ToFormatEtc().cfFormat
) != FALSE
;
433 void ClipboardWin::Clear(ClipboardType type
) {
434 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
435 ScopedClipboard clipboard
;
436 if (!clipboard
.Acquire(GetClipboardWindow()))
442 void ClipboardWin::ReadAvailableTypes(ClipboardType type
,
443 std::vector
<base::string16
>* types
,
444 bool* contains_filenames
) const {
445 if (!types
|| !contains_filenames
) {
451 if (::IsClipboardFormatAvailable(
452 GetPlainTextFormatType().ToFormatEtc().cfFormat
))
453 types
->push_back(base::UTF8ToUTF16(kMimeTypeText
));
454 if (::IsClipboardFormatAvailable(GetHtmlFormatType().ToFormatEtc().cfFormat
))
455 types
->push_back(base::UTF8ToUTF16(kMimeTypeHTML
));
456 if (::IsClipboardFormatAvailable(GetRtfFormatType().ToFormatEtc().cfFormat
))
457 types
->push_back(base::UTF8ToUTF16(kMimeTypeRTF
));
458 if (::IsClipboardFormatAvailable(CF_DIB
))
459 types
->push_back(base::UTF8ToUTF16(kMimeTypePNG
));
460 *contains_filenames
= false;
462 // Acquire the clipboard.
463 ScopedClipboard clipboard
;
464 if (!clipboard
.Acquire(GetClipboardWindow()))
468 ::GetClipboardData(GetWebCustomDataFormatType().ToFormatEtc().cfFormat
);
472 ReadCustomDataTypes(::GlobalLock(hdata
), ::GlobalSize(hdata
), types
);
473 ::GlobalUnlock(hdata
);
476 void ClipboardWin::ReadText(ClipboardType type
, base::string16
* result
) const {
477 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
485 // Acquire the clipboard.
486 ScopedClipboard clipboard
;
487 if (!clipboard
.Acquire(GetClipboardWindow()))
490 HANDLE data
= ::GetClipboardData(CF_UNICODETEXT
);
494 result
->assign(static_cast<const base::char16
*>(::GlobalLock(data
)));
495 ::GlobalUnlock(data
);
498 void ClipboardWin::ReadAsciiText(ClipboardType type
,
499 std::string
* result
) const {
500 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
508 // Acquire the clipboard.
509 ScopedClipboard clipboard
;
510 if (!clipboard
.Acquire(GetClipboardWindow()))
513 HANDLE data
= ::GetClipboardData(CF_TEXT
);
517 result
->assign(static_cast<const char*>(::GlobalLock(data
)));
518 ::GlobalUnlock(data
);
521 void ClipboardWin::ReadHTML(ClipboardType type
,
522 base::string16
* markup
,
523 std::string
* src_url
,
524 uint32
* fragment_start
,
525 uint32
* fragment_end
) const {
526 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
529 // TODO(dcheng): Remove these checks, I don't think they should be optional.
536 // Acquire the clipboard.
537 ScopedClipboard clipboard
;
538 if (!clipboard
.Acquire(GetClipboardWindow()))
541 HANDLE data
= ::GetClipboardData(GetHtmlFormatType().ToFormatEtc().cfFormat
);
545 std::string
cf_html(static_cast<const char*>(::GlobalLock(data
)));
546 ::GlobalUnlock(data
);
548 size_t html_start
= std::string::npos
;
549 size_t start_index
= std::string::npos
;
550 size_t end_index
= std::string::npos
;
551 ClipboardUtil::CFHtmlExtractMetadata(cf_html
, src_url
, &html_start
,
552 &start_index
, &end_index
);
554 // This might happen if the contents of the clipboard changed and CF_HTML is
555 // no longer available.
556 if (start_index
== std::string::npos
||
557 end_index
== std::string::npos
||
558 html_start
== std::string::npos
)
561 if (start_index
< html_start
|| end_index
< start_index
)
564 std::vector
<size_t> offsets
;
565 offsets
.push_back(start_index
- html_start
);
566 offsets
.push_back(end_index
- html_start
);
567 markup
->assign(base::UTF8ToUTF16AndAdjustOffsets(cf_html
.data() + html_start
,
569 *fragment_start
= base::checked_cast
<uint32
>(offsets
[0]);
570 *fragment_end
= base::checked_cast
<uint32
>(offsets
[1]);
573 void ClipboardWin::ReadRTF(ClipboardType type
, std::string
* result
) const {
574 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
576 ReadData(GetRtfFormatType(), result
);
579 SkBitmap
ClipboardWin::ReadImage(ClipboardType type
) const {
580 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
582 // Acquire the clipboard.
583 ScopedClipboard clipboard
;
584 if (!clipboard
.Acquire(GetClipboardWindow()))
587 // We use a DIB rather than a DDB here since ::GetObject() with the
588 // HBITMAP returned from ::GetClipboardData(CF_BITMAP) always reports a color
590 BITMAPINFO
* bitmap
= static_cast<BITMAPINFO
*>(::GetClipboardData(CF_DIB
));
593 int color_table_length
= 0;
594 switch (bitmap
->bmiHeader
.biBitCount
) {
598 color_table_length
= bitmap
->bmiHeader
.biClrUsed
599 ? bitmap
->bmiHeader
.biClrUsed
600 : 1 << bitmap
->bmiHeader
.biBitCount
;
604 if (bitmap
->bmiHeader
.biCompression
== BI_BITFIELDS
)
605 color_table_length
= 3;
612 const void* bitmap_bits
= reinterpret_cast<const char*>(bitmap
)
613 + bitmap
->bmiHeader
.biSize
+ color_table_length
* sizeof(RGBQUAD
);
615 gfx::Canvas
canvas(gfx::Size(bitmap
->bmiHeader
.biWidth
,
616 bitmap
->bmiHeader
.biHeight
),
620 skia::ScopedPlatformPaint
scoped_platform_paint(canvas
.sk_canvas());
621 HDC dc
= scoped_platform_paint
.GetPlatformSurface();
622 ::SetDIBitsToDevice(dc
, 0, 0, bitmap
->bmiHeader
.biWidth
,
623 bitmap
->bmiHeader
.biHeight
, 0, 0, 0,
624 bitmap
->bmiHeader
.biHeight
, bitmap_bits
, bitmap
,
627 // Windows doesn't really handle alpha channels well in many situations. When
628 // the source image is < 32 bpp, we force the bitmap to be opaque. When the
629 // source image is 32 bpp, the alpha channel might still contain garbage data.
630 // Since Windows uses premultiplied alpha, we scan for instances where
631 // (R, G, B) > A. If there are any invalid premultiplied colors in the image,
632 // we assume the alpha channel contains garbage and force the bitmap to be
633 // opaque as well. Note that this heuristic will fail on a transparent bitmap
634 // containing only black pixels...
635 const SkBitmap
& device_bitmap
=
636 canvas
.sk_canvas()->getDevice()->accessBitmap(true);
638 SkAutoLockPixels
lock(device_bitmap
);
639 bool has_invalid_alpha_channel
= bitmap
->bmiHeader
.biBitCount
< 32 ||
640 BitmapHasInvalidPremultipliedColors(device_bitmap
);
641 if (has_invalid_alpha_channel
) {
642 MakeBitmapOpaque(device_bitmap
);
646 return canvas
.ExtractImageRep().sk_bitmap();
649 void ClipboardWin::ReadCustomData(ClipboardType clipboard_type
,
650 const base::string16
& type
,
651 base::string16
* result
) const {
652 DCHECK_EQ(clipboard_type
, CLIPBOARD_TYPE_COPY_PASTE
);
654 // Acquire the clipboard.
655 ScopedClipboard clipboard
;
656 if (!clipboard
.Acquire(GetClipboardWindow()))
660 ::GetClipboardData(GetWebCustomDataFormatType().ToFormatEtc().cfFormat
);
664 ReadCustomDataForType(::GlobalLock(hdata
), ::GlobalSize(hdata
), type
, result
);
665 ::GlobalUnlock(hdata
);
668 void ClipboardWin::ReadBookmark(base::string16
* title
, std::string
* url
) const {
675 // Acquire the clipboard.
676 ScopedClipboard clipboard
;
677 if (!clipboard
.Acquire(GetClipboardWindow()))
680 HANDLE data
= ::GetClipboardData(GetUrlWFormatType().ToFormatEtc().cfFormat
);
684 base::string16
bookmark(static_cast<const base::char16
*>(::GlobalLock(data
)));
685 ::GlobalUnlock(data
);
687 ParseBookmarkClipboardFormat(bookmark
, title
, url
);
690 void ClipboardWin::ReadData(const FormatType
& format
,
691 std::string
* result
) const {
697 ScopedClipboard clipboard
;
698 if (!clipboard
.Acquire(GetClipboardWindow()))
701 HANDLE data
= ::GetClipboardData(format
.ToFormatEtc().cfFormat
);
705 result
->assign(static_cast<const char*>(::GlobalLock(data
)),
707 ::GlobalUnlock(data
);
710 void ClipboardWin::WriteObjects(ClipboardType type
, const ObjectMap
& objects
) {
711 DCHECK_EQ(type
, CLIPBOARD_TYPE_COPY_PASTE
);
713 ScopedClipboard clipboard
;
714 if (!clipboard
.Acquire(GetClipboardWindow()))
719 for (ObjectMap::const_iterator iter
= objects
.begin(); iter
!= objects
.end();
721 DispatchObject(static_cast<ObjectType
>(iter
->first
), iter
->second
);
725 void ClipboardWin::WriteText(const char* text_data
, size_t text_len
) {
727 base::UTF8ToUTF16(text_data
, text_len
, &text
);
728 HGLOBAL glob
= CreateGlobalData(text
);
730 WriteToClipboard(CF_UNICODETEXT
, glob
);
733 void ClipboardWin::WriteHTML(const char* markup_data
,
735 const char* url_data
,
737 std::string
markup(markup_data
, markup_len
);
741 url
.assign(url_data
, url_len
);
743 std::string html_fragment
= ClipboardUtil::HtmlToCFHtml(markup
, url
);
744 HGLOBAL glob
= CreateGlobalData(html_fragment
);
746 WriteToClipboard(Clipboard::GetHtmlFormatType().ToFormatEtc().cfFormat
, glob
);
749 void ClipboardWin::WriteRTF(const char* rtf_data
, size_t data_len
) {
750 WriteData(GetRtfFormatType(), rtf_data
, data_len
);
753 void ClipboardWin::WriteBookmark(const char* title_data
,
755 const char* url_data
,
757 std::string
bookmark(title_data
, title_len
);
758 bookmark
.append(1, L
'\n');
759 bookmark
.append(url_data
, url_len
);
761 base::string16 wide_bookmark
= base::UTF8ToUTF16(bookmark
);
762 HGLOBAL glob
= CreateGlobalData(wide_bookmark
);
764 WriteToClipboard(GetUrlWFormatType().ToFormatEtc().cfFormat
, glob
);
767 void ClipboardWin::WriteWebSmartPaste() {
768 DCHECK(clipboard_owner_
->hwnd() != NULL
);
769 ::SetClipboardData(GetWebKitSmartPasteFormatType().ToFormatEtc().cfFormat
,
773 void ClipboardWin::WriteBitmap(const SkBitmap
& bitmap
) {
774 HDC dc
= ::GetDC(NULL
);
776 // This doesn't actually cost us a memcpy when the bitmap comes from the
777 // renderer as we load it into the bitmap using setPixels which just sets a
778 // pointer. Someone has to memcpy it into GDI, it might as well be us here.
780 // TODO(darin): share data in gfx/bitmap_header.cc somehow
781 BITMAPINFO bm_info
= {};
782 bm_info
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
783 bm_info
.bmiHeader
.biWidth
= bitmap
.width();
784 bm_info
.bmiHeader
.biHeight
= -bitmap
.height(); // sets vertical orientation
785 bm_info
.bmiHeader
.biPlanes
= 1;
786 bm_info
.bmiHeader
.biBitCount
= 32;
787 bm_info
.bmiHeader
.biCompression
= BI_RGB
;
789 // ::CreateDIBSection allocates memory for us to copy our bitmap into.
790 // Unfortunately, we can't write the created bitmap to the clipboard,
791 // (see http://msdn2.microsoft.com/en-us/library/ms532292.aspx)
793 HBITMAP source_hbitmap
=
794 ::CreateDIBSection(dc
, &bm_info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
796 if (bits
&& source_hbitmap
) {
798 SkAutoLockPixels
bitmap_lock(bitmap
);
799 // Copy the bitmap out of shared memory and into GDI
800 memcpy(bits
, bitmap
.getPixels(), bitmap
.getSize());
803 // Now we have an HBITMAP, we can write it to the clipboard
804 WriteBitmapFromHandle(source_hbitmap
,
805 gfx::Size(bitmap
.width(), bitmap
.height()));
808 ::DeleteObject(source_hbitmap
);
809 ::ReleaseDC(NULL
, dc
);
812 void ClipboardWin::WriteData(const FormatType
& format
,
813 const char* data_data
,
815 HGLOBAL hdata
= ::GlobalAlloc(GMEM_MOVEABLE
, data_len
);
819 char* data
= static_cast<char*>(::GlobalLock(hdata
));
820 memcpy(data
, data_data
, data_len
);
821 ::GlobalUnlock(data
);
822 WriteToClipboard(format
.ToFormatEtc().cfFormat
, hdata
);
825 void ClipboardWin::WriteBitmapFromHandle(HBITMAP source_hbitmap
,
826 const gfx::Size
& size
) {
827 // We would like to just call ::SetClipboardData on the source_hbitmap,
828 // but that bitmap might not be of a sort we can write to the clipboard.
829 // For this reason, we create a new bitmap, copy the bits over, and then
830 // write that to the clipboard.
832 HDC dc
= ::GetDC(NULL
);
833 HDC compatible_dc
= ::CreateCompatibleDC(NULL
);
834 HDC source_dc
= ::CreateCompatibleDC(NULL
);
836 // This is the HBITMAP we will eventually write to the clipboard
837 HBITMAP hbitmap
= ::CreateCompatibleBitmap(dc
, size
.width(), size
.height());
839 // Failed to create the bitmap
840 ::DeleteDC(compatible_dc
);
841 ::DeleteDC(source_dc
);
842 ::ReleaseDC(NULL
, dc
);
846 HBITMAP old_hbitmap
= (HBITMAP
)SelectObject(compatible_dc
, hbitmap
);
847 HBITMAP old_source
= (HBITMAP
)SelectObject(source_dc
, source_hbitmap
);
849 // Now we need to blend it into an HBITMAP we can place on the clipboard
850 BLENDFUNCTION bf
= {AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
851 ::GdiAlphaBlend(compatible_dc
,
863 // Clean up all the handles we just opened
864 ::SelectObject(compatible_dc
, old_hbitmap
);
865 ::SelectObject(source_dc
, old_source
);
866 ::DeleteObject(old_hbitmap
);
867 ::DeleteObject(old_source
);
868 ::DeleteDC(compatible_dc
);
869 ::DeleteDC(source_dc
);
870 ::ReleaseDC(NULL
, dc
);
872 WriteToClipboard(CF_BITMAP
, hbitmap
);
875 void ClipboardWin::WriteToClipboard(unsigned int format
, HANDLE handle
) {
876 DCHECK(clipboard_owner_
->hwnd() != NULL
);
877 if (handle
&& !::SetClipboardData(format
, handle
)) {
878 DCHECK(ERROR_CLIPBOARD_NOT_OPEN
!= GetLastError());
879 FreeData(format
, handle
);
883 HWND
ClipboardWin::GetClipboardWindow() const {
884 if (!clipboard_owner_
)
887 if (clipboard_owner_
->hwnd() == NULL
)
888 clipboard_owner_
->Create(base::Bind(&ClipboardOwnerWndProc
));
890 return clipboard_owner_
->hwnd();