Home | History | Annotate | Download | only in clipboard
      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:
     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 }  // namespace
    163 
    164 Clipboard::FormatType::FormatType() : data_() {}
    165 
    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 
    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 
    184 Clipboard::FormatType::~FormatType() {
    185 }
    186 
    187 std::string Clipboard::FormatType::Serialize() const {
    188   return base::IntToString(data_.cfFormat);
    189 }
    190 
    191 // static
    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 
    202 bool Clipboard::FormatType::operator<(const FormatType& other) const {
    203   return ToUINT() < other.ToUINT();
    204 }
    205 
    206 bool Clipboard::FormatType::Equals(const FormatType& other) const {
    207   return ToUINT() == other.ToUINT();
    208 }
    209 
    210 Clipboard::Clipboard() {
    211   if (base::MessageLoopForUI::IsCurrent())
    212     clipboard_owner_.reset(new base::win::MessageWindow());
    213 }
    214 
    215 Clipboard::~Clipboard() {
    216 }
    217 
    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 
    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 
    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 
    257 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) {
    258   WriteData(GetRtfFormatType(), rtf_data, data_len);
    259 }
    260 
    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 
    275 void Clipboard::WriteWebSmartPaste() {
    276   DCHECK(clipboard_owner_->hwnd() != NULL);
    277   ::SetClipboardData(GetWebKitSmartPasteFormatType().ToUINT(), NULL);
    278 }
    279 
    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 
    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 
    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 
    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 
    381 uint64 Clipboard::GetSequenceNumber(ClipboardType type) {
    382   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
    383   return ::GetClipboardSequenceNumber();
    384 }
    385 
    386 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 
    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 
    401 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 
    433 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 
    455 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 
    477 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 
    529 void Clipboard::ReadRTF(ClipboardType type, std::string* result) const {
    530   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
    531 
    532   ReadData(GetRtfFormatType(), result);
    533 }
    534 
    535 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 
    605 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 
    623 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 
    645 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
    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
    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
    691 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
    692   CR_DEFINE_STATIC_LOCAL(
    693       FormatType, type, (::RegisterClipboardFormat(CFSTR_INETURLA)));
    694   return type;
    695 }
    696 
    697 // static
    698 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
    699   CR_DEFINE_STATIC_LOCAL(
    700       FormatType, type, (::RegisterClipboardFormat(CFSTR_INETURLW)));
    701   return type;
    702 }
    703 
    704 // static
    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
    712 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
    713   CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_TEXT));
    714   return type;
    715 }
    716 
    717 // static
    718 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
    719   CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_UNICODETEXT));
    720   return type;
    721 }
    722 
    723 // static
    724 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
    725   CR_DEFINE_STATIC_LOCAL(
    726       FormatType, type, (::RegisterClipboardFormat(CFSTR_FILENAMEA)));
    727   return type;
    728 }
    729 
    730 // static
    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
    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
    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
    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
    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
    768 const Clipboard::FormatType& Clipboard::GetCFHDropFormatType() {
    769   CR_DEFINE_STATIC_LOCAL(FormatType, type, (CF_HDROP));
    770   return type;
    771 }
    772 
    773 // static
    774 const Clipboard::FormatType& Clipboard::GetFileDescriptorFormatType() {
    775   CR_DEFINE_STATIC_LOCAL(
    776       FormatType, type, (::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR)));
    777   return type;
    778 }
    779 
    780 // static
    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
    788 const Clipboard::FormatType& Clipboard::GetIDListFormatType() {
    789   CR_DEFINE_STATIC_LOCAL(
    790       FormatType, type, (::RegisterClipboardFormat(CFSTR_SHELLIDLIST)));
    791   return type;
    792 }
    793 
    794 // static
    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
    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
    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
    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 
    830 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