OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2008 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 "base/clipboard.h" | |
9 | |
10 #include <shlobj.h> | |
11 #include <shellapi.h> | |
12 | |
13 #include "base/clipboard_util.h" | |
14 #include "base/file_path.h" | |
15 #include "base/gfx/size.h" | |
16 #include "base/lock.h" | |
17 #include "base/logging.h" | |
18 #include "base/message_loop.h" | |
19 #include "base/shared_memory.h" | |
20 #include "base/string_util.h" | |
21 | |
22 namespace { | |
23 | |
24 // A scoper to manage acquiring and automatically releasing the clipboard. | |
25 class ScopedClipboard { | |
26 public: | |
27 ScopedClipboard() : opened_(false) { } | |
28 | |
29 ~ScopedClipboard() { | |
30 if (opened_) | |
31 Release(); | |
32 } | |
33 | |
34 bool Acquire(HWND owner) { | |
35 const int kMaxAttemptsToOpenClipboard = 5; | |
36 | |
37 if (opened_) { | |
38 NOTREACHED(); | |
39 return false; | |
40 } | |
41 | |
42 // Attempt to open the clipboard, which will acquire the Windows clipboard | |
43 // lock. This may fail if another process currently holds this lock. | |
44 // We're willing to try a few times in the hopes of acquiring it. | |
45 // | |
46 // This turns out to be an issue when using remote desktop because the | |
47 // rdpclip.exe process likes to read what we've written to the clipboard and | |
48 // send it to the RDP client. If we open and close the clipboard in quick | |
49 // succession, we might be trying to open it while rdpclip.exe has it open, | |
50 // See Bug 815425. | |
51 // | |
52 // In fact, we believe we'll only spin this loop over remote desktop. In | |
53 // normal situations, the user is initiating clipboard operations and there | |
54 // shouldn't be contention. | |
55 | |
56 for (int attempts = 0; attempts < kMaxAttemptsToOpenClipboard; ++attempts) { | |
57 // If we didn't manage to open the clipboard, sleep a bit and be hopeful. | |
58 if (attempts != 0) | |
59 ::Sleep(5); | |
60 | |
61 if (::OpenClipboard(owner)) { | |
62 opened_ = true; | |
63 return true; | |
64 } | |
65 } | |
66 | |
67 // We failed to acquire the clipboard. | |
68 return false; | |
69 } | |
70 | |
71 void Release() { | |
72 if (opened_) { | |
73 ::CloseClipboard(); | |
74 opened_ = false; | |
75 } else { | |
76 NOTREACHED(); | |
77 } | |
78 } | |
79 | |
80 private: | |
81 bool opened_; | |
82 }; | |
83 | |
84 LRESULT CALLBACK ClipboardOwnerWndProc(HWND hwnd, | |
85 UINT message, | |
86 WPARAM wparam, | |
87 LPARAM lparam) { | |
88 LRESULT lresult = 0; | |
89 | |
90 switch (message) { | |
91 case WM_RENDERFORMAT: | |
92 // This message comes when SetClipboardData was sent a null data handle | |
93 // and now it's come time to put the data on the clipboard. | |
94 // We always set data, so there isn't a need to actually do anything here. | |
95 break; | |
96 case WM_RENDERALLFORMATS: | |
97 // This message comes when SetClipboardData was sent a null data handle | |
98 // and now this application is about to quit, so it must put data on | |
99 // the clipboard before it exits. | |
100 // We always set data, so there isn't a need to actually do anything here. | |
101 break; | |
102 case WM_DRAWCLIPBOARD: | |
103 break; | |
104 case WM_DESTROY: | |
105 break; | |
106 case WM_CHANGECBCHAIN: | |
107 break; | |
108 default: | |
109 lresult = DefWindowProc(hwnd, message, wparam, lparam); | |
110 break; | |
111 } | |
112 return lresult; | |
113 } | |
114 | |
115 template <typename charT> | |
116 HGLOBAL CreateGlobalData(const std::basic_string<charT>& str) { | |
117 HGLOBAL data = | |
118 ::GlobalAlloc(GMEM_MOVEABLE, ((str.size() + 1) * sizeof(charT))); | |
119 if (data) { | |
120 charT* raw_data = static_cast<charT*>(::GlobalLock(data)); | |
121 memcpy(raw_data, str.data(), str.size() * sizeof(charT)); | |
122 raw_data[str.size()] = '\0'; | |
123 ::GlobalUnlock(data); | |
124 } | |
125 return data; | |
126 }; | |
127 | |
128 } // namespace | |
129 | |
130 Clipboard::Clipboard() : create_window_(false) { | |
131 if (MessageLoop::current()->type() == MessageLoop::TYPE_UI) { | |
132 // Make a dummy HWND to be the clipboard's owner. | |
133 WNDCLASSEX wcex = {0}; | |
134 wcex.cbSize = sizeof(WNDCLASSEX); | |
135 wcex.lpfnWndProc = ClipboardOwnerWndProc; | |
136 wcex.hInstance = GetModuleHandle(NULL); | |
137 wcex.lpszClassName = L"ClipboardOwnerWindowClass"; | |
138 ::RegisterClassEx(&wcex); | |
139 create_window_ = true; | |
140 } | |
141 | |
142 clipboard_owner_ = NULL; | |
143 } | |
144 | |
145 Clipboard::~Clipboard() { | |
146 if (clipboard_owner_) | |
147 ::DestroyWindow(clipboard_owner_); | |
148 clipboard_owner_ = NULL; | |
149 } | |
150 | |
151 void Clipboard::WriteObjects(const ObjectMap& objects) { | |
152 WriteObjects(objects, NULL); | |
153 } | |
154 | |
155 void Clipboard::WriteObjects(const ObjectMap& objects, | |
156 base::ProcessHandle process) { | |
157 ScopedClipboard clipboard; | |
158 if (!clipboard.Acquire(GetClipboardWindow())) | |
159 return; | |
160 | |
161 ::EmptyClipboard(); | |
162 | |
163 for (ObjectMap::const_iterator iter = objects.begin(); | |
164 iter != objects.end(); ++iter) { | |
165 if (iter->first == CBF_SMBITMAP) | |
166 WriteBitmapFromSharedMemory(&(iter->second[0].front()), | |
167 &(iter->second[1].front()), | |
168 process); | |
169 else | |
170 DispatchObject(static_cast<ObjectType>(iter->first), iter->second); | |
171 } | |
172 } | |
173 | |
174 void Clipboard::WriteText(const char* text_data, size_t text_len) { | |
175 string16 text; | |
176 UTF8ToUTF16(text_data, text_len, &text); | |
177 HGLOBAL glob = CreateGlobalData(text); | |
178 | |
179 WriteToClipboard(CF_UNICODETEXT, glob); | |
180 } | |
181 | |
182 void Clipboard::WriteHTML(const char* markup_data, | |
183 size_t markup_len, | |
184 const char* url_data, | |
185 size_t url_len) { | |
186 std::string markup(markup_data, markup_len); | |
187 std::string url; | |
188 | |
189 if (url_len > 0) | |
190 url.assign(url_data, url_len); | |
191 | |
192 std::string html_fragment = ClipboardUtil::HtmlToCFHtml(markup, url); | |
193 HGLOBAL glob = CreateGlobalData(html_fragment); | |
194 | |
195 WriteToClipboard(StringToInt(GetHtmlFormatType()), glob); | |
196 } | |
197 | |
198 void Clipboard::WriteBookmark(const char* title_data, | |
199 size_t title_len, | |
200 const char* url_data, | |
201 size_t url_len) { | |
202 std::string bookmark(title_data, title_len); | |
203 bookmark.append(1, L'\n'); | |
204 bookmark.append(url_data, url_len); | |
205 | |
206 string16 wide_bookmark = UTF8ToWide(bookmark); | |
207 HGLOBAL glob = CreateGlobalData(wide_bookmark); | |
208 | |
209 WriteToClipboard(StringToInt(GetUrlWFormatType()), glob); | |
210 } | |
211 | |
212 void Clipboard::WriteWebSmartPaste() { | |
213 DCHECK(clipboard_owner_); | |
214 ::SetClipboardData(StringToInt(GetWebKitSmartPasteFormatType()), NULL); | |
215 } | |
216 | |
217 void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) { | |
218 const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data); | |
219 HDC dc = ::GetDC(NULL); | |
220 | |
221 // This doesn't actually cost us a memcpy when the bitmap comes from the | |
222 // renderer as we load it into the bitmap using setPixels which just sets a | |
223 // pointer. Someone has to memcpy it into GDI, it might as well be us here. | |
224 | |
225 // TODO(darin): share data in gfx/bitmap_header.cc somehow | |
226 BITMAPINFO bm_info = {0}; | |
227 bm_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); | |
228 bm_info.bmiHeader.biWidth = size->width(); | |
229 bm_info.bmiHeader.biHeight = -size->height(); // sets vertical orientation | |
230 bm_info.bmiHeader.biPlanes = 1; | |
231 bm_info.bmiHeader.biBitCount = 32; | |
232 bm_info.bmiHeader.biCompression = BI_RGB; | |
233 | |
234 // ::CreateDIBSection allocates memory for us to copy our bitmap into. | |
235 // Unfortunately, we can't write the created bitmap to the clipboard, | |
236 // (see http://msdn2.microsoft.com/en-us/library/ms532292.aspx) | |
237 void *bits; | |
238 HBITMAP source_hbitmap = | |
239 ::CreateDIBSection(dc, &bm_info, DIB_RGB_COLORS, &bits, NULL, 0); | |
240 | |
241 if (bits && source_hbitmap) { | |
242 // Copy the bitmap out of shared memory and into GDI | |
243 memcpy(bits, pixel_data, 4 * size->width() * size->height()); | |
244 | |
245 // Now we have an HBITMAP, we can write it to the clipboard | |
246 WriteBitmapFromHandle(source_hbitmap, *size); | |
247 } | |
248 | |
249 ::DeleteObject(source_hbitmap); | |
250 ::ReleaseDC(NULL, dc); | |
251 } | |
252 | |
253 void Clipboard::WriteBitmapFromSharedMemory(const char* bitmap_data, | |
254 const char* size_data, | |
255 base::ProcessHandle process) { | |
256 const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data); | |
257 | |
258 // bitmap_data has an encoded shared memory object. See | |
259 // DuplicateRemoteHandles(). | |
260 char* ptr = const_cast<char*>(bitmap_data); | |
261 scoped_ptr<const base::SharedMemory> bitmap(* | |
262 reinterpret_cast<const base::SharedMemory**>(ptr)); | |
263 | |
264 // TODO(darin): share data in gfx/bitmap_header.cc somehow. | |
265 BITMAPINFO bm_info = {0}; | |
266 bm_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); | |
267 bm_info.bmiHeader.biWidth = size->width(); | |
268 // Sets the vertical orientation. | |
269 bm_info.bmiHeader.biHeight = -size->height(); | |
270 bm_info.bmiHeader.biPlanes = 1; | |
271 bm_info.bmiHeader.biBitCount = 32; | |
272 bm_info.bmiHeader.biCompression = BI_RGB; | |
273 | |
274 HDC dc = ::GetDC(NULL); | |
275 | |
276 // We can create an HBITMAP directly using the shared memory handle, saving | |
277 // a memcpy. | |
278 HBITMAP source_hbitmap = | |
279 ::CreateDIBSection(dc, &bm_info, DIB_RGB_COLORS, NULL, | |
280 bitmap->handle(), 0); | |
281 | |
282 if (source_hbitmap) { | |
283 // Now we can write the HBITMAP to the clipboard | |
284 WriteBitmapFromHandle(source_hbitmap, *size); | |
285 } | |
286 | |
287 ::DeleteObject(source_hbitmap); | |
288 ::ReleaseDC(NULL, dc); | |
289 } | |
290 | |
291 void Clipboard::WriteBitmapFromHandle(HBITMAP source_hbitmap, | |
292 const gfx::Size& size) { | |
293 // We would like to just call ::SetClipboardData on the source_hbitmap, | |
294 // but that bitmap might not be of a sort we can write to the clipboard. | |
295 // For this reason, we create a new bitmap, copy the bits over, and then | |
296 // write that to the clipboard. | |
297 | |
298 HDC dc = ::GetDC(NULL); | |
299 HDC compatible_dc = ::CreateCompatibleDC(NULL); | |
300 HDC source_dc = ::CreateCompatibleDC(NULL); | |
301 | |
302 // This is the HBITMAP we will eventually write to the clipboard | |
303 HBITMAP hbitmap = ::CreateCompatibleBitmap(dc, size.width(), size.height()); | |
304 if (!hbitmap) { | |
305 // Failed to create the bitmap | |
306 ::DeleteDC(compatible_dc); | |
307 ::DeleteDC(source_dc); | |
308 ::ReleaseDC(NULL, dc); | |
309 return; | |
310 } | |
311 | |
312 HBITMAP old_hbitmap = (HBITMAP)SelectObject(compatible_dc, hbitmap); | |
313 HBITMAP old_source = (HBITMAP)SelectObject(source_dc, source_hbitmap); | |
314 | |
315 // Now we need to blend it into an HBITMAP we can place on the clipboard | |
316 BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; | |
317 ::GdiAlphaBlend(compatible_dc, 0, 0, size.width(), size.height(), | |
318 source_dc, 0, 0, size.width(), size.height(), bf); | |
319 | |
320 // Clean up all the handles we just opened | |
321 ::SelectObject(compatible_dc, old_hbitmap); | |
322 ::SelectObject(source_dc, old_source); | |
323 ::DeleteObject(old_hbitmap); | |
324 ::DeleteObject(old_source); | |
325 ::DeleteDC(compatible_dc); | |
326 ::DeleteDC(source_dc); | |
327 ::ReleaseDC(NULL, dc); | |
328 | |
329 WriteToClipboard(CF_BITMAP, hbitmap); | |
330 } | |
331 | |
332 // Write a file or set of files to the clipboard in HDROP format. When the user | |
333 // invokes a paste command (in a Windows explorer shell, for example), the files | |
334 // will be copied to the paste location. | |
335 void Clipboard::WriteFiles(const char* file_data, size_t file_len) { | |
336 // Calculate the amount of space we'll need store the strings and | |
337 // a DROPFILES struct. | |
338 size_t bytes = sizeof(DROPFILES) + file_len; | |
339 | |
340 HANDLE hdata = ::GlobalAlloc(GMEM_MOVEABLE, bytes); | |
341 if (!hdata) | |
342 return; | |
343 | |
344 char* data = static_cast<char*>(::GlobalLock(hdata)); | |
345 DROPFILES* drop_files = reinterpret_cast<DROPFILES*>(data); | |
346 drop_files->pFiles = sizeof(DROPFILES); | |
347 drop_files->fWide = TRUE; | |
348 | |
349 memcpy(data + sizeof(DROPFILES), file_data, file_len); | |
350 | |
351 ::GlobalUnlock(hdata); | |
352 WriteToClipboard(CF_HDROP, hdata); | |
353 } | |
354 | |
355 void Clipboard::WriteData(const char* format_name, size_t format_len, | |
356 const char* data_data, size_t data_len) { | |
357 std::string format(format_name, format_len); | |
358 CLIPFORMAT clip_format = | |
359 ::RegisterClipboardFormat(ASCIIToWide(format).c_str()); | |
360 | |
361 HGLOBAL hdata = ::GlobalAlloc(GMEM_MOVEABLE, data_len); | |
362 if (!hdata) | |
363 return; | |
364 | |
365 char* data = static_cast<char*>(::GlobalLock(hdata)); | |
366 memcpy(data, data_data, data_len); | |
367 ::GlobalUnlock(data); | |
368 WriteToClipboard(clip_format, hdata); | |
369 } | |
370 | |
371 void Clipboard::WriteToClipboard(unsigned int format, HANDLE handle) { | |
372 DCHECK(clipboard_owner_); | |
373 if (handle && !::SetClipboardData(format, handle)) { | |
374 DCHECK(ERROR_CLIPBOARD_NOT_OPEN != GetLastError()); | |
375 FreeData(format, handle); | |
376 } | |
377 } | |
378 | |
379 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, | |
380 Clipboard::Buffer buffer) const { | |
381 DCHECK_EQ(buffer, BUFFER_STANDARD); | |
382 return ::IsClipboardFormatAvailable(StringToInt(format)) != FALSE; | |
383 } | |
384 | |
385 bool Clipboard::IsFormatAvailableByString( | |
386 const std::string& ascii_format, Clipboard::Buffer buffer) const { | |
387 DCHECK_EQ(buffer, BUFFER_STANDARD); | |
388 std::wstring wide_format = ASCIIToWide(ascii_format); | |
389 CLIPFORMAT format = ::RegisterClipboardFormat(wide_format.c_str()); | |
390 return ::IsClipboardFormatAvailable(format) != FALSE; | |
391 } | |
392 | |
393 void Clipboard::ReadText(Clipboard::Buffer buffer, string16* result) const { | |
394 DCHECK_EQ(buffer, BUFFER_STANDARD); | |
395 if (!result) { | |
396 NOTREACHED(); | |
397 return; | |
398 } | |
399 | |
400 result->clear(); | |
401 | |
402 // Acquire the clipboard. | |
403 ScopedClipboard clipboard; | |
404 if (!clipboard.Acquire(GetClipboardWindow())) | |
405 return; | |
406 | |
407 HANDLE data = ::GetClipboardData(CF_UNICODETEXT); | |
408 if (!data) | |
409 return; | |
410 | |
411 result->assign(static_cast<const char16*>(::GlobalLock(data))); | |
412 ::GlobalUnlock(data); | |
413 } | |
414 | |
415 void Clipboard::ReadAsciiText(Clipboard::Buffer buffer, | |
416 std::string* result) const { | |
417 DCHECK_EQ(buffer, BUFFER_STANDARD); | |
418 if (!result) { | |
419 NOTREACHED(); | |
420 return; | |
421 } | |
422 | |
423 result->clear(); | |
424 | |
425 // Acquire the clipboard. | |
426 ScopedClipboard clipboard; | |
427 if (!clipboard.Acquire(GetClipboardWindow())) | |
428 return; | |
429 | |
430 HANDLE data = ::GetClipboardData(CF_TEXT); | |
431 if (!data) | |
432 return; | |
433 | |
434 result->assign(static_cast<const char*>(::GlobalLock(data))); | |
435 ::GlobalUnlock(data); | |
436 } | |
437 | |
438 void Clipboard::ReadHTML(Clipboard::Buffer buffer, string16* markup, | |
439 std::string* src_url) const { | |
440 DCHECK_EQ(buffer, BUFFER_STANDARD); | |
441 if (markup) | |
442 markup->clear(); | |
443 | |
444 if (src_url) | |
445 src_url->clear(); | |
446 | |
447 // Acquire the clipboard. | |
448 ScopedClipboard clipboard; | |
449 if (!clipboard.Acquire(GetClipboardWindow())) | |
450 return; | |
451 | |
452 HANDLE data = ::GetClipboardData(StringToInt(GetHtmlFormatType())); | |
453 if (!data) | |
454 return; | |
455 | |
456 std::string html_fragment(static_cast<const char*>(::GlobalLock(data))); | |
457 ::GlobalUnlock(data); | |
458 | |
459 std::string markup_utf8; | |
460 ClipboardUtil::CFHtmlToHtml(html_fragment, markup ? &markup_utf8 : NULL, | |
461 src_url); | |
462 if (markup) | |
463 markup->assign(UTF8ToWide(markup_utf8)); | |
464 } | |
465 | |
466 void Clipboard::ReadBookmark(string16* title, std::string* url) const { | |
467 if (title) | |
468 title->clear(); | |
469 | |
470 if (url) | |
471 url->clear(); | |
472 | |
473 // Acquire the clipboard. | |
474 ScopedClipboard clipboard; | |
475 if (!clipboard.Acquire(GetClipboardWindow())) | |
476 return; | |
477 | |
478 HANDLE data = ::GetClipboardData(StringToInt(GetUrlWFormatType())); | |
479 if (!data) | |
480 return; | |
481 | |
482 string16 bookmark(static_cast<const char16*>(::GlobalLock(data))); | |
483 ::GlobalUnlock(data); | |
484 | |
485 ParseBookmarkClipboardFormat(bookmark, title, url); | |
486 } | |
487 | |
488 // Read a file in HDROP format from the clipboard. | |
489 void Clipboard::ReadFile(FilePath* file) const { | |
490 if (!file) { | |
491 NOTREACHED(); | |
492 return; | |
493 } | |
494 | |
495 *file = FilePath(); | |
496 std::vector<FilePath> files; | |
497 ReadFiles(&files); | |
498 | |
499 // Take the first file, if available. | |
500 if (!files.empty()) | |
501 *file = files[0]; | |
502 } | |
503 | |
504 // Read a set of files in HDROP format from the clipboard. | |
505 void Clipboard::ReadFiles(std::vector<FilePath>* files) const { | |
506 if (!files) { | |
507 NOTREACHED(); | |
508 return; | |
509 } | |
510 | |
511 files->clear(); | |
512 | |
513 ScopedClipboard clipboard; | |
514 if (!clipboard.Acquire(GetClipboardWindow())) | |
515 return; | |
516 | |
517 HDROP drop = static_cast<HDROP>(::GetClipboardData(CF_HDROP)); | |
518 if (!drop) | |
519 return; | |
520 | |
521 // Count of files in the HDROP. | |
522 int count = ::DragQueryFile(drop, 0xffffffff, NULL, 0); | |
523 | |
524 if (count) { | |
525 for (int i = 0; i < count; ++i) { | |
526 int size = ::DragQueryFile(drop, i, NULL, 0) + 1; | |
527 std::wstring file; | |
528 ::DragQueryFile(drop, i, WriteInto(&file, size), size); | |
529 files->push_back(FilePath(file)); | |
530 } | |
531 } | |
532 } | |
533 | |
534 void Clipboard::ReadData(const std::string& format, std::string* result) { | |
535 if (!result) { | |
536 NOTREACHED(); | |
537 return; | |
538 } | |
539 | |
540 CLIPFORMAT clip_format = | |
541 ::RegisterClipboardFormat(ASCIIToWide(format).c_str()); | |
542 | |
543 ScopedClipboard clipboard; | |
544 if (!clipboard.Acquire(GetClipboardWindow())) | |
545 return; | |
546 | |
547 HANDLE data = ::GetClipboardData(clip_format); | |
548 if (!data) | |
549 return; | |
550 | |
551 result->assign(static_cast<const char*>(::GlobalLock(data)), | |
552 ::GlobalSize(data)); | |
553 ::GlobalUnlock(data); | |
554 } | |
555 | |
556 // static | |
557 void Clipboard::ParseBookmarkClipboardFormat(const string16& bookmark, | |
558 string16* title, | |
559 std::string* url) { | |
560 const string16 kDelim = ASCIIToUTF16("\r\n"); | |
561 | |
562 const size_t title_end = bookmark.find_first_of(kDelim); | |
563 if (title) | |
564 title->assign(bookmark.substr(0, title_end)); | |
565 | |
566 if (url) { | |
567 const size_t url_start = bookmark.find_first_not_of(kDelim, title_end); | |
568 if (url_start != string16::npos) | |
569 *url = UTF16ToUTF8(bookmark.substr(url_start, string16::npos)); | |
570 } | |
571 } | |
572 | |
573 // static | |
574 Clipboard::FormatType Clipboard::GetUrlFormatType() { | |
575 return IntToString(ClipboardUtil::GetUrlFormat()->cfFormat); | |
576 } | |
577 | |
578 // static | |
579 Clipboard::FormatType Clipboard::GetUrlWFormatType() { | |
580 return IntToString(ClipboardUtil::GetUrlWFormat()->cfFormat); | |
581 } | |
582 | |
583 // static | |
584 Clipboard::FormatType Clipboard::GetMozUrlFormatType() { | |
585 return IntToString(ClipboardUtil::GetMozUrlFormat()->cfFormat); | |
586 } | |
587 | |
588 // static | |
589 Clipboard::FormatType Clipboard::GetPlainTextFormatType() { | |
590 return IntToString(ClipboardUtil::GetPlainTextFormat()->cfFormat); | |
591 } | |
592 | |
593 // static | |
594 Clipboard::FormatType Clipboard::GetPlainTextWFormatType() { | |
595 return IntToString(ClipboardUtil::GetPlainTextWFormat()->cfFormat); | |
596 } | |
597 | |
598 // static | |
599 Clipboard::FormatType Clipboard::GetFilenameFormatType() { | |
600 return IntToString(ClipboardUtil::GetFilenameFormat()->cfFormat); | |
601 } | |
602 | |
603 // static | |
604 Clipboard::FormatType Clipboard::GetFilenameWFormatType() { | |
605 return IntToString(ClipboardUtil::GetFilenameWFormat()->cfFormat); | |
606 } | |
607 | |
608 // MS HTML Format | |
609 // static | |
610 Clipboard::FormatType Clipboard::GetHtmlFormatType() { | |
611 return IntToString(ClipboardUtil::GetHtmlFormat()->cfFormat); | |
612 } | |
613 | |
614 // static | |
615 Clipboard::FormatType Clipboard::GetBitmapFormatType() { | |
616 return IntToString(CF_BITMAP); | |
617 } | |
618 | |
619 // Firefox text/html | |
620 // static | |
621 Clipboard::FormatType Clipboard::GetTextHtmlFormatType() { | |
622 return IntToString(ClipboardUtil::GetTextHtmlFormat()->cfFormat); | |
623 } | |
624 | |
625 // static | |
626 Clipboard::FormatType Clipboard::GetCFHDropFormatType() { | |
627 return IntToString(ClipboardUtil::GetCFHDropFormat()->cfFormat); | |
628 } | |
629 | |
630 // static | |
631 Clipboard::FormatType Clipboard::GetFileDescriptorFormatType() { | |
632 return IntToString(ClipboardUtil::GetFileDescriptorFormat()->cfFormat); | |
633 } | |
634 | |
635 // static | |
636 Clipboard::FormatType Clipboard::GetFileContentFormatZeroType() { | |
637 return IntToString(ClipboardUtil::GetFileContentFormatZero()->cfFormat); | |
638 } | |
639 | |
640 // static | |
641 void Clipboard::DuplicateRemoteHandles(base::ProcessHandle process, | |
642 ObjectMap* objects) { | |
643 for (ObjectMap::iterator iter = objects->begin(); iter != objects->end(); | |
644 ++iter) { | |
645 if (iter->first == CBF_SMBITMAP) { | |
646 // There is a shared memory handle encoded on the first ObjectMapParam. | |
647 // Use it to open a local handle to the memory. | |
648 char* bitmap_data = &(iter->second[0].front()); | |
649 base::SharedMemoryHandle* remote_bitmap_handle = | |
650 reinterpret_cast<base::SharedMemoryHandle*>(bitmap_data); | |
651 | |
652 base::SharedMemory* bitmap = new base::SharedMemory(*remote_bitmap_handle, | |
653 false, process); | |
654 | |
655 // We store the object where the remote handle was located so it can | |
656 // be retrieved by the UI thread (see WriteBitmapFromSharedMemory()). | |
657 iter->second[0].clear(); | |
658 for (size_t i = 0; i < sizeof(bitmap); i++) | |
659 iter->second[0].push_back(reinterpret_cast<char*>(&bitmap)[i]); | |
660 } | |
661 } | |
662 } | |
663 | |
664 // static | |
665 Clipboard::FormatType Clipboard::GetWebKitSmartPasteFormatType() { | |
666 return IntToString(ClipboardUtil::GetWebKitSmartPasteFormat()->cfFormat); | |
667 } | |
668 | |
669 // static | |
670 void Clipboard::FreeData(unsigned int format, HANDLE data) { | |
671 if (format == CF_BITMAP) | |
672 ::DeleteObject(static_cast<HBITMAP>(data)); | |
673 else | |
674 ::GlobalFree(data); | |
675 } | |
676 | |
677 HWND Clipboard::GetClipboardWindow() const { | |
678 if (!clipboard_owner_ && create_window_) { | |
679 clipboard_owner_ = ::CreateWindow(L"ClipboardOwnerWindowClass", | |
680 L"ClipboardOwnerWindow", | |
681 0, 0, 0, 0, 0, | |
682 HWND_MESSAGE, | |
683 0, 0, 0); | |
684 } | |
685 return clipboard_owner_; | |
686 } | |
OLD | NEW |