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