OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Many of these functions are based on those found in | 5 // Many of these functions are based on those found in |
6 // webkit/port/platform/PasteboardWin.cpp | 6 // webkit/port/platform/PasteboardWin.cpp |
7 | 7 |
8 #include <shlobj.h> | 8 #include <shlobj.h> |
9 #include <shellapi.h> | 9 #include <shellapi.h> |
10 | 10 |
11 #include "base/clipboard.h" | 11 #include "base/clipboard.h" |
12 | 12 |
13 #include "base/clipboard_util.h" | 13 #include "base/clipboard_util.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/message_loop.h" |
15 #include "base/string_util.h" | 16 #include "base/string_util.h" |
16 | 17 |
17 namespace { | 18 namespace { |
18 | 19 |
19 // A scoper to manage acquiring and automatically releasing the clipboard. | 20 // A scoper to manage acquiring and automatically releasing the clipboard. |
20 class ScopedClipboard { | 21 class ScopedClipboard { |
21 public: | 22 public: |
22 ScopedClipboard() : opened_(false) { } | 23 ScopedClipboard() : opened_(false) { } |
23 | 24 |
24 ~ScopedClipboard() { | 25 ~ScopedClipboard() { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 private: | 76 private: |
76 bool opened_; | 77 bool opened_; |
77 }; | 78 }; |
78 | 79 |
79 LRESULT CALLBACK ClipboardOwnerWndProc(HWND hwnd, | 80 LRESULT CALLBACK ClipboardOwnerWndProc(HWND hwnd, |
80 UINT message, | 81 UINT message, |
81 WPARAM wparam, | 82 WPARAM wparam, |
82 LPARAM lparam) { | 83 LPARAM lparam) { |
83 LRESULT lresult = 0; | 84 LRESULT lresult = 0; |
84 | 85 |
85 switch(message) { | 86 switch (message) { |
86 case WM_RENDERFORMAT: | 87 case WM_RENDERFORMAT: |
87 // This message comes when SetClipboardData was sent a null data handle | 88 // This message comes when SetClipboardData was sent a null data handle |
88 // and now it's come time to put the data on the clipboard. | 89 // and now it's come time to put the data on the clipboard. |
89 // We always set data, so there isn't a need to actually do anything here. | 90 // We always set data, so there isn't a need to actually do anything here. |
90 break; | 91 break; |
91 case WM_RENDERALLFORMATS: | 92 case WM_RENDERALLFORMATS: |
92 // This message comes when SetClipboardData was sent a null data handle | 93 // This message comes when SetClipboardData was sent a null data handle |
93 // and now this application is about to quit, so it must put data on | 94 // and now this application is about to quit, so it must put data on |
94 // the clipboard before it exits. | 95 // the clipboard before it exits. |
95 // We always set data, so there isn't a need to actually do anything here. | 96 // We always set data, so there isn't a need to actually do anything here. |
(...skipping 19 matching lines...) Expand all Loading... |
115 charT* raw_data = static_cast<charT*>(::GlobalLock(data)); | 116 charT* raw_data = static_cast<charT*>(::GlobalLock(data)); |
116 memcpy(raw_data, str.data(), str.size() * sizeof(charT)); | 117 memcpy(raw_data, str.data(), str.size() * sizeof(charT)); |
117 raw_data[str.size()] = '\0'; | 118 raw_data[str.size()] = '\0'; |
118 ::GlobalUnlock(data); | 119 ::GlobalUnlock(data); |
119 } | 120 } |
120 return data; | 121 return data; |
121 }; | 122 }; |
122 | 123 |
123 } // namespace | 124 } // namespace |
124 | 125 |
125 Clipboard::Clipboard() { | 126 Clipboard::Clipboard() : create_window_(false) { |
126 // make a dummy HWND to be the clipboard's owner | 127 if (MessageLoop::current()->type() == MessageLoop::TYPE_UI) { |
127 WNDCLASSEX wcex = {0}; | 128 // Make a dummy HWND to be the clipboard's owner. |
128 wcex.cbSize = sizeof(WNDCLASSEX); | 129 WNDCLASSEX wcex = {0}; |
129 wcex.lpfnWndProc = ClipboardOwnerWndProc; | 130 wcex.cbSize = sizeof(WNDCLASSEX); |
130 wcex.hInstance = GetModuleHandle(NULL); | 131 wcex.lpfnWndProc = ClipboardOwnerWndProc; |
131 wcex.lpszClassName = L"ClipboardOwnerWindowClass"; | 132 wcex.hInstance = GetModuleHandle(NULL); |
132 ::RegisterClassEx(&wcex); | 133 wcex.lpszClassName = L"ClipboardOwnerWindowClass"; |
| 134 ::RegisterClassEx(&wcex); |
| 135 create_window_ = true; |
| 136 } |
133 | 137 |
134 clipboard_owner_ = NULL; | 138 clipboard_owner_ = NULL; |
135 } | 139 } |
136 | 140 |
137 Clipboard::~Clipboard() { | 141 Clipboard::~Clipboard() { |
138 if (clipboard_owner_) | 142 if (clipboard_owner_) |
139 ::DestroyWindow(clipboard_owner_); | 143 ::DestroyWindow(clipboard_owner_); |
140 clipboard_owner_ = NULL; | 144 clipboard_owner_ = NULL; |
141 } | 145 } |
142 | 146 |
143 void Clipboard::WriteObjects(const ObjectMap& objects) { | 147 void Clipboard::WriteObjects(const ObjectMap& objects) { |
144 WriteObjects(objects, NULL); | 148 WriteObjects(objects, NULL); |
145 } | 149 } |
146 | 150 |
147 void Clipboard::WriteObjects(const ObjectMap& objects, | 151 void Clipboard::WriteObjects(const ObjectMap& objects, |
148 base::ProcessHandle process) { | 152 base::ProcessHandle process) { |
149 ScopedClipboard clipboard; | 153 ScopedClipboard clipboard; |
150 if (!clipboard.Acquire(GetClipboardWindow())) | 154 if (!clipboard.Acquire(GetClipboardWindow())) |
151 return; | 155 return; |
152 | 156 |
153 ::EmptyClipboard(); | 157 ::EmptyClipboard(); |
154 | 158 |
155 for (ObjectMap::const_iterator iter = objects.begin(); | 159 for (ObjectMap::const_iterator iter = objects.begin(); |
156 iter != objects.end(); ++iter) { | 160 iter != objects.end(); ++iter) { |
157 if (iter->first == CBF_SMBITMAP) | 161 if (iter->first == CBF_SMBITMAP) |
158 WriteBitmapFromSharedMemory(&(iter->second[0].front()), | 162 WriteBitmapFromSharedMemory(&(iter->second[0].front()), |
159 &(iter->second[1].front()), | 163 &(iter->second[1].front()), |
160 process); | 164 process); |
161 else | 165 else |
162 DispatchObject(static_cast<ObjectType>(iter->first), iter->second); | 166 DispatchObject(static_cast<ObjectType>(iter->first), iter->second); |
163 } | 167 } |
164 } | 168 } |
165 | 169 |
166 void Clipboard::WriteText(const char* text_data, size_t text_len) { | 170 void Clipboard::WriteText(const char* text_data, size_t text_len) { |
167 std::wstring text; | 171 std::wstring text; |
168 UTF8ToWide(text_data, text_len, &text); | 172 UTF8ToWide(text_data, text_len, &text); |
169 HGLOBAL glob = CreateGlobalData(text); | 173 HGLOBAL glob = CreateGlobalData(text); |
170 | 174 |
171 WriteToClipboard(CF_UNICODETEXT, glob); | 175 WriteToClipboard(CF_UNICODETEXT, glob); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 link.append(url); | 220 link.append(url); |
217 link.append("\">"); | 221 link.append("\">"); |
218 link.append(title); | 222 link.append(title); |
219 link.append("</a>"); | 223 link.append("</a>"); |
220 | 224 |
221 // Store hyperlink as html. | 225 // Store hyperlink as html. |
222 WriteHTML(link.c_str(), link.size(), NULL, 0); | 226 WriteHTML(link.c_str(), link.size(), NULL, 0); |
223 } | 227 } |
224 | 228 |
225 void Clipboard::WriteWebSmartPaste() { | 229 void Clipboard::WriteWebSmartPaste() { |
| 230 DCHECK(clipboard_owner_); |
226 ::SetClipboardData(GetWebKitSmartPasteFormatType(), NULL); | 231 ::SetClipboardData(GetWebKitSmartPasteFormatType(), NULL); |
227 } | 232 } |
228 | 233 |
229 void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) { | 234 void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) { |
230 const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data); | 235 const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data); |
231 HDC dc = ::GetDC(NULL); | 236 HDC dc = ::GetDC(NULL); |
232 | 237 |
233 // This doesn't actually cost us a memcpy when the bitmap comes from the | 238 // This doesn't actually cost us a memcpy when the bitmap comes from the |
234 // renderer as we load it into the bitmap using setPixels which just sets a | 239 // renderer as we load it into the bitmap using setPixels which just sets a |
235 // pointer. Someone has to memcpy it into GDI, it might as well be us here. | 240 // pointer. Someone has to memcpy it into GDI, it might as well be us here. |
(...skipping 22 matching lines...) Expand all Loading... |
258 WriteBitmapFromHandle(source_hbitmap, *size); | 263 WriteBitmapFromHandle(source_hbitmap, *size); |
259 } | 264 } |
260 | 265 |
261 ::DeleteObject(source_hbitmap); | 266 ::DeleteObject(source_hbitmap); |
262 ::ReleaseDC(NULL, dc); | 267 ::ReleaseDC(NULL, dc); |
263 } | 268 } |
264 | 269 |
265 void Clipboard::WriteBitmapFromSharedMemory(const char* bitmap_data, | 270 void Clipboard::WriteBitmapFromSharedMemory(const char* bitmap_data, |
266 const char* size_data, | 271 const char* size_data, |
267 base::ProcessHandle process) { | 272 base::ProcessHandle process) { |
268 const base::SharedMemoryHandle* remote_bitmap_handle = | |
269 reinterpret_cast<const base::SharedMemoryHandle*>(bitmap_data); | |
270 const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data); | 273 const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data); |
271 | 274 |
272 base::SharedMemory bitmap(*remote_bitmap_handle, false, process); | 275 // bitmap_data has an encoded shared memory object. See |
| 276 // DuplicateRemoteHandles(). |
| 277 char* ptr = const_cast<char*>(bitmap_data); |
| 278 scoped_ptr<const base::SharedMemory> bitmap(* |
| 279 reinterpret_cast<const base::SharedMemory**>(ptr)); |
273 | 280 |
274 // TODO(darin): share data in gfx/bitmap_header.cc somehow | 281 // TODO(darin): share data in gfx/bitmap_header.cc somehow. |
275 BITMAPINFO bm_info = {0}; | 282 BITMAPINFO bm_info = {0}; |
276 bm_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); | 283 bm_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); |
277 bm_info.bmiHeader.biWidth = size->width(); | 284 bm_info.bmiHeader.biWidth = size->width(); |
278 bm_info.bmiHeader.biHeight = -size->height(); // Sets the vertical orientatio
n | 285 bm_info.bmiHeader.biHeight = -size->height(); // Sets the vertical orientatio
n |
279 bm_info.bmiHeader.biPlanes = 1; | 286 bm_info.bmiHeader.biPlanes = 1; |
280 bm_info.bmiHeader.biBitCount = 32; | 287 bm_info.bmiHeader.biBitCount = 32; |
281 bm_info.bmiHeader.biCompression = BI_RGB; | 288 bm_info.bmiHeader.biCompression = BI_RGB; |
282 | 289 |
283 HDC dc = ::GetDC(NULL); | 290 HDC dc = ::GetDC(NULL); |
284 | 291 |
285 // We can create an HBITMAP directly using the shared memory handle, saving | 292 // We can create an HBITMAP directly using the shared memory handle, saving |
286 // a memcpy. | 293 // a memcpy. |
287 HBITMAP source_hbitmap = | 294 HBITMAP source_hbitmap = |
288 ::CreateDIBSection(dc, &bm_info, DIB_RGB_COLORS, NULL, | 295 ::CreateDIBSection(dc, &bm_info, DIB_RGB_COLORS, NULL, |
289 bitmap.handle(), 0); | 296 bitmap->handle(), 0); |
290 | 297 |
291 if (source_hbitmap) { | 298 if (source_hbitmap) { |
292 // Now we can write the HBITMAP to the clipboard | 299 // Now we can write the HBITMAP to the clipboard |
293 WriteBitmapFromHandle(source_hbitmap, *size); | 300 WriteBitmapFromHandle(source_hbitmap, *size); |
294 } | 301 } |
295 | 302 |
296 ::DeleteObject(source_hbitmap); | 303 ::DeleteObject(source_hbitmap); |
297 ::ReleaseDC(NULL, dc); | 304 ::ReleaseDC(NULL, dc); |
298 } | 305 } |
299 | 306 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
357 drop_files->fWide = TRUE; | 364 drop_files->fWide = TRUE; |
358 | 365 |
359 memcpy(data + sizeof DROPFILES, filenames.c_str(), | 366 memcpy(data + sizeof DROPFILES, filenames.c_str(), |
360 filenames.length() * sizeof(wchar_t)); | 367 filenames.length() * sizeof(wchar_t)); |
361 | 368 |
362 ::GlobalUnlock(hdata); | 369 ::GlobalUnlock(hdata); |
363 WriteToClipboard(CF_HDROP, hdata); | 370 WriteToClipboard(CF_HDROP, hdata); |
364 } | 371 } |
365 | 372 |
366 void Clipboard::WriteToClipboard(FormatType format, HANDLE handle) { | 373 void Clipboard::WriteToClipboard(FormatType format, HANDLE handle) { |
367 if (handle && !::SetClipboardData(format, handle)) | 374 DCHECK(clipboard_owner_); |
| 375 if (handle && !::SetClipboardData(format, handle)) { |
| 376 DCHECK(ERROR_CLIPBOARD_NOT_OPEN != GetLastError()); |
368 FreeData(format, handle); | 377 FreeData(format, handle); |
| 378 } |
369 } | 379 } |
370 | 380 |
371 bool Clipboard::IsFormatAvailable(unsigned int format) const { | 381 bool Clipboard::IsFormatAvailable(unsigned int format) const { |
372 return ::IsClipboardFormatAvailable(format) != FALSE; | 382 return ::IsClipboardFormatAvailable(format) != FALSE; |
373 } | 383 } |
374 | 384 |
375 void Clipboard::ReadText(std::wstring* result) const { | 385 void Clipboard::ReadText(std::wstring* result) const { |
376 if (!result) { | 386 if (!result) { |
377 NOTREACHED(); | 387 NOTREACHED(); |
378 return; | 388 return; |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
584 Clipboard::FormatType Clipboard::GetFileDescriptorFormatType() { | 594 Clipboard::FormatType Clipboard::GetFileDescriptorFormatType() { |
585 return ClipboardUtil::GetFileDescriptorFormat()->cfFormat; | 595 return ClipboardUtil::GetFileDescriptorFormat()->cfFormat; |
586 } | 596 } |
587 | 597 |
588 // static | 598 // static |
589 Clipboard::FormatType Clipboard::GetFileContentFormatZeroType() { | 599 Clipboard::FormatType Clipboard::GetFileContentFormatZeroType() { |
590 return ClipboardUtil::GetFileContentFormatZero()->cfFormat; | 600 return ClipboardUtil::GetFileContentFormatZero()->cfFormat; |
591 } | 601 } |
592 | 602 |
593 // static | 603 // static |
| 604 void Clipboard::DuplicateRemoteHandles(base::ProcessHandle process, |
| 605 ObjectMap* objects) { |
| 606 for (ObjectMap::iterator iter = objects->begin(); iter != objects->end(); |
| 607 ++iter) { |
| 608 if (iter->first == CBF_SMBITMAP) { |
| 609 // There is a shared memory handle encoded on the first ObjectMapParam. |
| 610 // Use it to open a local handle to the memory. |
| 611 char* bitmap_data = &(iter->second[0].front()); |
| 612 base::SharedMemoryHandle* remote_bitmap_handle = |
| 613 reinterpret_cast<base::SharedMemoryHandle*>(bitmap_data); |
| 614 |
| 615 base::SharedMemory* bitmap = new base::SharedMemory(*remote_bitmap_handle, |
| 616 false, process); |
| 617 |
| 618 // We store the object where the remote handle was located so it can |
| 619 // be retrieved by the UI thread (see WriteBitmapFromSharedMemory()). |
| 620 iter->second[0].clear(); |
| 621 for (size_t i = 0; i < sizeof(bitmap); i++) |
| 622 iter->second[0].push_back(reinterpret_cast<char*>(&bitmap)[i]); |
| 623 } |
| 624 } |
| 625 } |
| 626 |
| 627 // static |
594 Clipboard::FormatType Clipboard::GetWebKitSmartPasteFormatType() { | 628 Clipboard::FormatType Clipboard::GetWebKitSmartPasteFormatType() { |
595 return ClipboardUtil::GetWebKitSmartPasteFormat()->cfFormat; | 629 return ClipboardUtil::GetWebKitSmartPasteFormat()->cfFormat; |
596 } | 630 } |
597 | 631 |
598 // static | 632 // static |
599 void Clipboard::FreeData(FormatType format, HANDLE data) { | 633 void Clipboard::FreeData(FormatType format, HANDLE data) { |
600 if (format == CF_BITMAP) | 634 if (format == CF_BITMAP) |
601 ::DeleteObject(static_cast<HBITMAP>(data)); | 635 ::DeleteObject(static_cast<HBITMAP>(data)); |
602 else | 636 else |
603 ::GlobalFree(data); | 637 ::GlobalFree(data); |
604 } | 638 } |
605 | 639 |
606 HWND Clipboard::GetClipboardWindow() const { | 640 HWND Clipboard::GetClipboardWindow() const { |
607 if (!clipboard_owner_) { | 641 if (!clipboard_owner_ && create_window_) { |
608 clipboard_owner_ = ::CreateWindow(L"ClipboardOwnerWindowClass", | 642 clipboard_owner_ = ::CreateWindow(L"ClipboardOwnerWindowClass", |
609 L"ClipboardOwnerWindow", | 643 L"ClipboardOwnerWindow", |
610 0, 0, 0, 0, 0, | 644 0, 0, 0, 0, 0, |
611 HWND_MESSAGE, | 645 HWND_MESSAGE, |
612 0, 0, 0); | 646 0, 0, 0); |
613 } | 647 } |
614 return clipboard_owner_; | 648 return clipboard_owner_; |
615 } | 649 } |
OLD | NEW |