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