| 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 |