Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(252)

Side by Side Diff: ui/base/clipboard/clipboard_win.cc

Issue 851853002: It is time. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Trying to reup because the last upload failed. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/base/clipboard/clipboard_win.h ('k') | ui/base/clipboard/custom_data_helper.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 // Many of these functions are based on those found in
6 // webkit/port/platform/PasteboardWin.cpp
7
8 #include "ui/base/clipboard/clipboard_win.h"
9
10 #include <shellapi.h>
11 #include <shlobj.h>
12
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"
33
34 namespace ui {
35
36 namespace {
37
38 // A scoper to manage acquiring and automatically releasing the clipboard.
39 class ScopedClipboard {
40 public:
41 ScopedClipboard() : opened_(false) { }
42
43 ~ScopedClipboard() {
44 if (opened_)
45 Release();
46 }
47
48 bool Acquire(HWND owner) {
49 const int kMaxAttemptsToOpenClipboard = 5;
50
51 if (opened_) {
52 NOTREACHED();
53 return false;
54 }
55
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.
59 //
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,
64 // See Bug 815425.
65 //
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.
69
70 for (int attempts = 0; attempts < kMaxAttemptsToOpenClipboard; ++attempts) {
71 // If we didn't manage to open the clipboard, sleep a bit and be hopeful.
72 if (attempts != 0)
73 ::Sleep(5);
74
75 if (::OpenClipboard(owner)) {
76 opened_ = true;
77 return true;
78 }
79 }
80
81 // We failed to acquire the clipboard.
82 return false;
83 }
84
85 void Release() {
86 if (opened_) {
87 ::CloseClipboard();
88 opened_ = false;
89 } else {
90 NOTREACHED();
91 }
92 }
93
94 private:
95 bool opened_;
96 };
97
98 bool ClipboardOwnerWndProc(UINT message,
99 WPARAM wparam,
100 LPARAM lparam,
101 LRESULT* result) {
102 switch (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.
107 break;
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.
113 break;
114 case WM_DRAWCLIPBOARD:
115 break;
116 case WM_DESTROY:
117 break;
118 case WM_CHANGECBCHAIN:
119 break;
120 default:
121 return false;
122 }
123
124 *result = 0;
125 return true;
126 }
127
128 template <typename charT>
129 HGLOBAL CreateGlobalData(const std::basic_string<charT>& str) {
130 HGLOBAL data =
131 ::GlobalAlloc(GMEM_MOVEABLE, ((str.size() + 1) * sizeof(charT)));
132 if (data) {
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);
137 }
138 return data;
139 };
140
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))
148 return true;
149 }
150 }
151 return false;
152 }
153
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);
158 }
159 }
160 }
161
162 void ParseBookmarkClipboardFormat(const base::string16& bookmark,
163 base::string16* title,
164 std::string* url) {
165 const base::string16 kDelim = base::ASCIIToUTF16("\r\n");
166
167 const size_t title_end = bookmark.find_first_of(kDelim);
168 if (title)
169 title->assign(bookmark.substr(0, title_end));
170
171 if (url) {
172 const size_t url_start = bookmark.find_first_not_of(kDelim, title_end);
173 if (url_start != base::string16::npos) {
174 *url =
175 base::UTF16ToUTF8(bookmark.substr(url_start, base::string16::npos));
176 }
177 }
178 }
179
180 void FreeData(unsigned int format, HANDLE data) {
181 if (format == CF_BITMAP)
182 ::DeleteObject(static_cast<HBITMAP>(data));
183 else
184 ::GlobalFree(data);
185 }
186
187 } // namespace
188
189 // Clipboard::FormatType implementation.
190 Clipboard::FormatType::FormatType() : data_() {}
191
192 Clipboard::FormatType::FormatType(UINT native_format) : data_() {
193 // There's no good way to actually initialize this in the constructor in
194 // C++03.
195 data_.cfFormat = static_cast<CLIPFORMAT>(native_format);
196 data_.dwAspect = DVASPECT_CONTENT;
197 data_.lindex = -1;
198 data_.tymed = TYMED_HGLOBAL;
199 }
200
201 Clipboard::FormatType::FormatType(UINT native_format, LONG index) : data_() {
202 // There's no good way to actually initialize this in the constructor in
203 // C++03.
204 data_.cfFormat = static_cast<CLIPFORMAT>(native_format);
205 data_.dwAspect = DVASPECT_CONTENT;
206 data_.lindex = index;
207 data_.tymed = TYMED_HGLOBAL;
208 }
209
210 Clipboard::FormatType::~FormatType() {
211 }
212
213 std::string Clipboard::FormatType::Serialize() const {
214 return base::IntToString(data_.cfFormat);
215 }
216
217 // static
218 Clipboard::FormatType Clipboard::FormatType::Deserialize(
219 const std::string& serialization) {
220 int clipboard_format = -1;
221 if (!base::StringToInt(serialization, &clipboard_format)) {
222 NOTREACHED();
223 return FormatType();
224 }
225 return FormatType(clipboard_format);
226 }
227
228 bool Clipboard::FormatType::operator<(const FormatType& other) const {
229 return data_.cfFormat < other.data_.cfFormat;
230 }
231
232 bool Clipboard::FormatType::Equals(const FormatType& other) const {
233 return data_.cfFormat == other.data_.cfFormat;
234 }
235
236 // Various predefined FormatTypes.
237 // static
238 Clipboard::FormatType Clipboard::GetFormatType(
239 const std::string& format_string) {
240 return FormatType(
241 ::RegisterClipboardFormat(base::ASCIIToWide(format_string).c_str()));
242 }
243
244 // static
245 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
246 CR_DEFINE_STATIC_LOCAL(
247 FormatType, type, (::RegisterClipboardFormat(CFSTR_INETURLA)));
248 return type;
249 }
250
251 // static
252 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
253 CR_DEFINE_STATIC_LOCAL(
254 FormatType, type, (::RegisterClipboardFormat(CFSTR_INETURLW)));
255 return type;
256 }
257
258 // static
259 const Clipboard::FormatType& Clipboard::GetMozUrlFormatType() {
260 CR_DEFINE_STATIC_LOCAL(
261 FormatType, type, (::RegisterClipboardFormat(L"text/x-moz-url")));
262 return type;
263 }
264
265 // static
266 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
267 CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_TEXT));
268 return type;
269 }
270
271 // static
272 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
273 CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_UNICODETEXT));
274 return type;
275 }
276
277 // static
278 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
279 CR_DEFINE_STATIC_LOCAL(
280 FormatType, type, (::RegisterClipboardFormat(CFSTR_FILENAMEA)));
281 return type;
282 }
283
284 // static
285 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
286 CR_DEFINE_STATIC_LOCAL(
287 FormatType, type, (::RegisterClipboardFormat(CFSTR_FILENAMEW)));
288 return type;
289 }
290
291 // MS HTML Format
292 // static
293 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
294 CR_DEFINE_STATIC_LOCAL(
295 FormatType, type, (::RegisterClipboardFormat(L"HTML Format")));
296 return type;
297 }
298
299 // MS RTF Format
300 // static
301 const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
302 CR_DEFINE_STATIC_LOCAL(
303 FormatType, type, (::RegisterClipboardFormat(L"Rich Text Format")));
304 return type;
305 }
306
307 // static
308 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
309 CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_BITMAP));
310 return type;
311 }
312
313 // Firefox text/html
314 // static
315 const Clipboard::FormatType& Clipboard::GetTextHtmlFormatType() {
316 CR_DEFINE_STATIC_LOCAL(
317 FormatType, type, (::RegisterClipboardFormat(L"text/html")));
318 return type;
319 }
320
321 // static
322 const Clipboard::FormatType& Clipboard::GetCFHDropFormatType() {
323 CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_HDROP));
324 return type;
325 }
326
327 // static
328 const Clipboard::FormatType& Clipboard::GetFileDescriptorFormatType() {
329 CR_DEFINE_STATIC_LOCAL(
330 FormatType, type, (::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR)));
331 return type;
332 }
333
334 // static
335 const Clipboard::FormatType& Clipboard::GetFileContentZeroFormatType() {
336 CR_DEFINE_STATIC_LOCAL(
337 FormatType, type, (::RegisterClipboardFormat(CFSTR_FILECONTENTS), 0));
338 return type;
339 }
340
341 // static
342 const Clipboard::FormatType& Clipboard::GetIDListFormatType() {
343 CR_DEFINE_STATIC_LOCAL(
344 FormatType, type, (::RegisterClipboardFormat(CFSTR_SHELLIDLIST)));
345 return type;
346 }
347
348 // static
349 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
350 CR_DEFINE_STATIC_LOCAL(
351 FormatType,
352 type,
353 (::RegisterClipboardFormat(L"WebKit Smart Paste Format")));
354 return type;
355 }
356
357 // static
358 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
359 // TODO(dcheng): This name is temporary. See http://crbug.com/106449.
360 CR_DEFINE_STATIC_LOCAL(
361 FormatType,
362 type,
363 (::RegisterClipboardFormat(L"Chromium Web Custom MIME Data Format")));
364 return type;
365 }
366
367 // static
368 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
369 CR_DEFINE_STATIC_LOCAL(
370 FormatType,
371 type,
372 (::RegisterClipboardFormat(L"Chromium Pepper MIME Data Format")));
373 return type;
374 }
375
376 // Clipboard factory method.
377 // static
378 Clipboard* Clipboard::Create() {
379 return new ClipboardWin;
380 }
381
382 // ClipboardWin implementation.
383 ClipboardWin::ClipboardWin() {
384 if (base::MessageLoopForUI::IsCurrent())
385 clipboard_owner_.reset(new base::win::MessageWindow());
386 }
387
388 ClipboardWin::~ClipboardWin() {
389 }
390
391 uint64 ClipboardWin::GetSequenceNumber(ClipboardType type) {
392 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
393 return ::GetClipboardSequenceNumber();
394 }
395
396 bool ClipboardWin::IsFormatAvailable(const Clipboard::FormatType& format,
397 ClipboardType type) const {
398 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
399 return ::IsClipboardFormatAvailable(format.ToFormatEtc().cfFormat) != FALSE;
400 }
401
402 void ClipboardWin::Clear(ClipboardType type) {
403 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
404 ScopedClipboard clipboard;
405 if (!clipboard.Acquire(GetClipboardWindow()))
406 return;
407
408 ::EmptyClipboard();
409 }
410
411 void ClipboardWin::ReadAvailableTypes(ClipboardType type,
412 std::vector<base::string16>* types,
413 bool* contains_filenames) const {
414 if (!types || !contains_filenames) {
415 NOTREACHED();
416 return;
417 }
418
419 types->clear();
420 if (::IsClipboardFormatAvailable(
421 GetPlainTextFormatType().ToFormatEtc().cfFormat))
422 types->push_back(base::UTF8ToUTF16(kMimeTypeText));
423 if (::IsClipboardFormatAvailable(GetHtmlFormatType().ToFormatEtc().cfFormat))
424 types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
425 if (::IsClipboardFormatAvailable(GetRtfFormatType().ToFormatEtc().cfFormat))
426 types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
427 if (::IsClipboardFormatAvailable(CF_DIB))
428 types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
429 *contains_filenames = false;
430
431 // Acquire the clipboard.
432 ScopedClipboard clipboard;
433 if (!clipboard.Acquire(GetClipboardWindow()))
434 return;
435
436 HANDLE hdata =
437 ::GetClipboardData(GetWebCustomDataFormatType().ToFormatEtc().cfFormat);
438 if (!hdata)
439 return;
440
441 ReadCustomDataTypes(::GlobalLock(hdata), ::GlobalSize(hdata), types);
442 ::GlobalUnlock(hdata);
443 }
444
445 void ClipboardWin::ReadText(ClipboardType type, base::string16* result) const {
446 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
447 if (!result) {
448 NOTREACHED();
449 return;
450 }
451
452 result->clear();
453
454 // Acquire the clipboard.
455 ScopedClipboard clipboard;
456 if (!clipboard.Acquire(GetClipboardWindow()))
457 return;
458
459 HANDLE data = ::GetClipboardData(CF_UNICODETEXT);
460 if (!data)
461 return;
462
463 result->assign(static_cast<const base::char16*>(::GlobalLock(data)));
464 ::GlobalUnlock(data);
465 }
466
467 void ClipboardWin::ReadAsciiText(ClipboardType type,
468 std::string* result) const {
469 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
470 if (!result) {
471 NOTREACHED();
472 return;
473 }
474
475 result->clear();
476
477 // Acquire the clipboard.
478 ScopedClipboard clipboard;
479 if (!clipboard.Acquire(GetClipboardWindow()))
480 return;
481
482 HANDLE data = ::GetClipboardData(CF_TEXT);
483 if (!data)
484 return;
485
486 result->assign(static_cast<const char*>(::GlobalLock(data)));
487 ::GlobalUnlock(data);
488 }
489
490 void ClipboardWin::ReadHTML(ClipboardType type,
491 base::string16* markup,
492 std::string* src_url,
493 uint32* fragment_start,
494 uint32* fragment_end) const {
495 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
496
497 markup->clear();
498 // TODO(dcheng): Remove these checks, I don't think they should be optional.
499 DCHECK(src_url);
500 if (src_url)
501 src_url->clear();
502 *fragment_start = 0;
503 *fragment_end = 0;
504
505 // Acquire the clipboard.
506 ScopedClipboard clipboard;
507 if (!clipboard.Acquire(GetClipboardWindow()))
508 return;
509
510 HANDLE data = ::GetClipboardData(GetHtmlFormatType().ToFormatEtc().cfFormat);
511 if (!data)
512 return;
513
514 std::string cf_html(static_cast<const char*>(::GlobalLock(data)));
515 ::GlobalUnlock(data);
516
517 size_t html_start = std::string::npos;
518 size_t start_index = std::string::npos;
519 size_t end_index = std::string::npos;
520 ClipboardUtil::CFHtmlExtractMetadata(cf_html, src_url, &html_start,
521 &start_index, &end_index);
522
523 // This might happen if the contents of the clipboard changed and CF_HTML is
524 // no longer available.
525 if (start_index == std::string::npos ||
526 end_index == std::string::npos ||
527 html_start == std::string::npos)
528 return;
529
530 if (start_index < html_start || end_index < start_index)
531 return;
532
533 std::vector<size_t> offsets;
534 offsets.push_back(start_index - html_start);
535 offsets.push_back(end_index - html_start);
536 markup->assign(base::UTF8ToUTF16AndAdjustOffsets(cf_html.data() + html_start,
537 &offsets));
538 *fragment_start = base::checked_cast<uint32>(offsets[0]);
539 *fragment_end = base::checked_cast<uint32>(offsets[1]);
540 }
541
542 void ClipboardWin::ReadRTF(ClipboardType type, std::string* result) const {
543 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
544
545 ReadData(GetRtfFormatType(), result);
546 }
547
548 SkBitmap ClipboardWin::ReadImage(ClipboardType type) const {
549 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
550
551 // Acquire the clipboard.
552 ScopedClipboard clipboard;
553 if (!clipboard.Acquire(GetClipboardWindow()))
554 return SkBitmap();
555
556 // We use a DIB rather than a DDB here since ::GetObject() with the
557 // HBITMAP returned from ::GetClipboardData(CF_BITMAP) always reports a color
558 // depth of 32bpp.
559 BITMAPINFO* bitmap = static_cast<BITMAPINFO*>(::GetClipboardData(CF_DIB));
560 if (!bitmap)
561 return SkBitmap();
562 int color_table_length = 0;
563 switch (bitmap->bmiHeader.biBitCount) {
564 case 1:
565 case 4:
566 case 8:
567 color_table_length = bitmap->bmiHeader.biClrUsed
568 ? bitmap->bmiHeader.biClrUsed
569 : 1 << bitmap->bmiHeader.biBitCount;
570 break;
571 case 16:
572 case 32:
573 if (bitmap->bmiHeader.biCompression == BI_BITFIELDS)
574 color_table_length = 3;
575 break;
576 case 24:
577 break;
578 default:
579 NOTREACHED();
580 }
581 const void* bitmap_bits = reinterpret_cast<const char*>(bitmap)
582 + bitmap->bmiHeader.biSize + color_table_length * sizeof(RGBQUAD);
583
584 gfx::Canvas canvas(gfx::Size(bitmap->bmiHeader.biWidth,
585 bitmap->bmiHeader.biHeight),
586 1.0f,
587 false);
588 {
589 skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas());
590 HDC dc = scoped_platform_paint.GetPlatformSurface();
591 ::SetDIBitsToDevice(dc, 0, 0, bitmap->bmiHeader.biWidth,
592 bitmap->bmiHeader.biHeight, 0, 0, 0,
593 bitmap->bmiHeader.biHeight, bitmap_bits, bitmap,
594 DIB_RGB_COLORS);
595 }
596 // Windows doesn't really handle alpha channels well in many situations. When
597 // the source image is < 32 bpp, we force the bitmap to be opaque. When the
598 // source image is 32 bpp, the alpha channel might still contain garbage data.
599 // Since Windows uses premultiplied alpha, we scan for instances where
600 // (R, G, B) > A. If there are any invalid premultiplied colors in the image,
601 // we assume the alpha channel contains garbage and force the bitmap to be
602 // opaque as well. Note that this heuristic will fail on a transparent bitmap
603 // containing only black pixels...
604 const SkBitmap& device_bitmap =
605 canvas.sk_canvas()->getDevice()->accessBitmap(true);
606 {
607 SkAutoLockPixels lock(device_bitmap);
608 bool has_invalid_alpha_channel = bitmap->bmiHeader.biBitCount < 32 ||
609 BitmapHasInvalidPremultipliedColors(device_bitmap);
610 if (has_invalid_alpha_channel) {
611 MakeBitmapOpaque(device_bitmap);
612 }
613 }
614
615 return canvas.ExtractImageRep().sk_bitmap();
616 }
617
618 void ClipboardWin::ReadCustomData(ClipboardType clipboard_type,
619 const base::string16& type,
620 base::string16* result) const {
621 DCHECK_EQ(clipboard_type, CLIPBOARD_TYPE_COPY_PASTE);
622
623 // Acquire the clipboard.
624 ScopedClipboard clipboard;
625 if (!clipboard.Acquire(GetClipboardWindow()))
626 return;
627
628 HANDLE hdata =
629 ::GetClipboardData(GetWebCustomDataFormatType().ToFormatEtc().cfFormat);
630 if (!hdata)
631 return;
632
633 ReadCustomDataForType(::GlobalLock(hdata), ::GlobalSize(hdata), type, result);
634 ::GlobalUnlock(hdata);
635 }
636
637 void ClipboardWin::ReadBookmark(base::string16* title, std::string* url) const {
638 if (title)
639 title->clear();
640
641 if (url)
642 url->clear();
643
644 // Acquire the clipboard.
645 ScopedClipboard clipboard;
646 if (!clipboard.Acquire(GetClipboardWindow()))
647 return;
648
649 HANDLE data = ::GetClipboardData(GetUrlWFormatType().ToFormatEtc().cfFormat);
650 if (!data)
651 return;
652
653 base::string16 bookmark(static_cast<const base::char16*>(::GlobalLock(data)));
654 ::GlobalUnlock(data);
655
656 ParseBookmarkClipboardFormat(bookmark, title, url);
657 }
658
659 void ClipboardWin::ReadData(const FormatType& format,
660 std::string* result) const {
661 if (!result) {
662 NOTREACHED();
663 return;
664 }
665
666 ScopedClipboard clipboard;
667 if (!clipboard.Acquire(GetClipboardWindow()))
668 return;
669
670 HANDLE data = ::GetClipboardData(format.ToFormatEtc().cfFormat);
671 if (!data)
672 return;
673
674 result->assign(static_cast<const char*>(::GlobalLock(data)),
675 ::GlobalSize(data));
676 ::GlobalUnlock(data);
677 }
678
679 void ClipboardWin::WriteObjects(ClipboardType type, const ObjectMap& objects) {
680 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
681
682 ScopedClipboard clipboard;
683 if (!clipboard.Acquire(GetClipboardWindow()))
684 return;
685
686 ::EmptyClipboard();
687
688 for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end();
689 ++iter) {
690 DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
691 }
692 }
693
694 void ClipboardWin::WriteText(const char* text_data, size_t text_len) {
695 base::string16 text;
696 base::UTF8ToUTF16(text_data, text_len, &text);
697 HGLOBAL glob = CreateGlobalData(text);
698
699 WriteToClipboard(CF_UNICODETEXT, glob);
700 }
701
702 void ClipboardWin::WriteHTML(const char* markup_data,
703 size_t markup_len,
704 const char* url_data,
705 size_t url_len) {
706 std::string markup(markup_data, markup_len);
707 std::string url;
708
709 if (url_len > 0)
710 url.assign(url_data, url_len);
711
712 std::string html_fragment = ClipboardUtil::HtmlToCFHtml(markup, url);
713 HGLOBAL glob = CreateGlobalData(html_fragment);
714
715 WriteToClipboard(Clipboard::GetHtmlFormatType().ToFormatEtc().cfFormat, glob);
716 }
717
718 void ClipboardWin::WriteRTF(const char* rtf_data, size_t data_len) {
719 WriteData(GetRtfFormatType(), rtf_data, data_len);
720 }
721
722 void ClipboardWin::WriteBookmark(const char* title_data,
723 size_t title_len,
724 const char* url_data,
725 size_t url_len) {
726 std::string bookmark(title_data, title_len);
727 bookmark.append(1, L'\n');
728 bookmark.append(url_data, url_len);
729
730 base::string16 wide_bookmark = base::UTF8ToWide(bookmark);
731 HGLOBAL glob = CreateGlobalData(wide_bookmark);
732
733 WriteToClipboard(GetUrlWFormatType().ToFormatEtc().cfFormat, glob);
734 }
735
736 void ClipboardWin::WriteWebSmartPaste() {
737 DCHECK(clipboard_owner_->hwnd() != NULL);
738 ::SetClipboardData(GetWebKitSmartPasteFormatType().ToFormatEtc().cfFormat,
739 NULL);
740 }
741
742 void ClipboardWin::WriteBitmap(const SkBitmap& bitmap) {
743 HDC dc = ::GetDC(NULL);
744
745 // This doesn't actually cost us a memcpy when the bitmap comes from the
746 // renderer as we load it into the bitmap using setPixels which just sets a
747 // pointer. Someone has to memcpy it into GDI, it might as well be us here.
748
749 // TODO(darin): share data in gfx/bitmap_header.cc somehow
750 BITMAPINFO bm_info = {0};
751 bm_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
752 bm_info.bmiHeader.biWidth = bitmap.width();
753 bm_info.bmiHeader.biHeight = -bitmap.height(); // sets vertical orientation
754 bm_info.bmiHeader.biPlanes = 1;
755 bm_info.bmiHeader.biBitCount = 32;
756 bm_info.bmiHeader.biCompression = BI_RGB;
757
758 // ::CreateDIBSection allocates memory for us to copy our bitmap into.
759 // Unfortunately, we can't write the created bitmap to the clipboard,
760 // (see http://msdn2.microsoft.com/en-us/library/ms532292.aspx)
761 void* bits;
762 HBITMAP source_hbitmap =
763 ::CreateDIBSection(dc, &bm_info, DIB_RGB_COLORS, &bits, NULL, 0);
764
765 if (bits && source_hbitmap) {
766 {
767 SkAutoLockPixels bitmap_lock(bitmap);
768 // Copy the bitmap out of shared memory and into GDI
769 memcpy(bits, bitmap.getPixels(), bitmap.getSize());
770 }
771
772 // Now we have an HBITMAP, we can write it to the clipboard
773 WriteBitmapFromHandle(source_hbitmap,
774 gfx::Size(bitmap.width(), bitmap.height()));
775 }
776
777 ::DeleteObject(source_hbitmap);
778 ::ReleaseDC(NULL, dc);
779 }
780
781 void ClipboardWin::WriteData(const FormatType& format,
782 const char* data_data,
783 size_t data_len) {
784 HGLOBAL hdata = ::GlobalAlloc(GMEM_MOVEABLE, data_len);
785 if (!hdata)
786 return;
787
788 char* data = static_cast<char*>(::GlobalLock(hdata));
789 memcpy(data, data_data, data_len);
790 ::GlobalUnlock(data);
791 WriteToClipboard(format.ToFormatEtc().cfFormat, hdata);
792 }
793
794 void ClipboardWin::WriteBitmapFromHandle(HBITMAP source_hbitmap,
795 const gfx::Size& size) {
796 // We would like to just call ::SetClipboardData on the source_hbitmap,
797 // but that bitmap might not be of a sort we can write to the clipboard.
798 // For this reason, we create a new bitmap, copy the bits over, and then
799 // write that to the clipboard.
800
801 HDC dc = ::GetDC(NULL);
802 HDC compatible_dc = ::CreateCompatibleDC(NULL);
803 HDC source_dc = ::CreateCompatibleDC(NULL);
804
805 // This is the HBITMAP we will eventually write to the clipboard
806 HBITMAP hbitmap = ::CreateCompatibleBitmap(dc, size.width(), size.height());
807 if (!hbitmap) {
808 // Failed to create the bitmap
809 ::DeleteDC(compatible_dc);
810 ::DeleteDC(source_dc);
811 ::ReleaseDC(NULL, dc);
812 return;
813 }
814
815 HBITMAP old_hbitmap = (HBITMAP)SelectObject(compatible_dc, hbitmap);
816 HBITMAP old_source = (HBITMAP)SelectObject(source_dc, source_hbitmap);
817
818 // Now we need to blend it into an HBITMAP we can place on the clipboard
819 BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
820 ::GdiAlphaBlend(compatible_dc,
821 0,
822 0,
823 size.width(),
824 size.height(),
825 source_dc,
826 0,
827 0,
828 size.width(),
829 size.height(),
830 bf);
831
832 // Clean up all the handles we just opened
833 ::SelectObject(compatible_dc, old_hbitmap);
834 ::SelectObject(source_dc, old_source);
835 ::DeleteObject(old_hbitmap);
836 ::DeleteObject(old_source);
837 ::DeleteDC(compatible_dc);
838 ::DeleteDC(source_dc);
839 ::ReleaseDC(NULL, dc);
840
841 WriteToClipboard(CF_BITMAP, hbitmap);
842 }
843
844 void ClipboardWin::WriteToClipboard(unsigned int format, HANDLE handle) {
845 DCHECK(clipboard_owner_->hwnd() != NULL);
846 if (handle && !::SetClipboardData(format, handle)) {
847 DCHECK(ERROR_CLIPBOARD_NOT_OPEN != GetLastError());
848 FreeData(format, handle);
849 }
850 }
851
852 HWND ClipboardWin::GetClipboardWindow() const {
853 if (!clipboard_owner_)
854 return NULL;
855
856 if (clipboard_owner_->hwnd() == NULL)
857 clipboard_owner_->Create(base::Bind(&ClipboardOwnerWndProc));
858
859 return clipboard_owner_->hwnd();
860 }
861
862 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/clipboard/clipboard_win.h ('k') | ui/base/clipboard/custom_data_helper.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698