diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-03 04:25:37 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-03 04:25:37 +0000 |
commit | 90f399075f9082bf7031512d6579ec1196dc060a (patch) | |
tree | 8d47273615d98732a60d0e77a0787d1623204a4b /base/clipboard_win.cc | |
parent | f0f400cb2e0a3c545d723524e8bbaf136caacf81 (diff) | |
download | chromium_src-90f399075f9082bf7031512d6579ec1196dc060a.zip chromium_src-90f399075f9082bf7031512d6579ec1196dc060a.tar.gz chromium_src-90f399075f9082bf7031512d6579ec1196dc060a.tar.bz2 |
Move the clipboard stuff out of base and into app/clipboard. I renamed
clipboard_util to clipboard_util_win since it's Windows-only. This patch makes
test_shell depend on app as well. There should be no logic change.
TEST=none
BUG=none
Review URL: http://codereview.chromium.org/260003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27937 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/clipboard_win.cc')
-rw-r--r-- | base/clipboard_win.cc | 686 |
1 files changed, 0 insertions, 686 deletions
diff --git a/base/clipboard_win.cc b/base/clipboard_win.cc deleted file mode 100644 index a8048e0..0000000 --- a/base/clipboard_win.cc +++ /dev/null @@ -1,686 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Many of these functions are based on those found in -// webkit/port/platform/PasteboardWin.cpp - -#include "base/clipboard.h" - -#include <shlobj.h> -#include <shellapi.h> - -#include "base/clipboard_util.h" -#include "base/file_path.h" -#include "base/gfx/size.h" -#include "base/lock.h" -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/shared_memory.h" -#include "base/string_util.h" - -namespace { - -// A scoper to manage acquiring and automatically releasing the clipboard. -class ScopedClipboard { - public: - ScopedClipboard() : opened_(false) { } - - ~ScopedClipboard() { - if (opened_) - Release(); - } - - bool Acquire(HWND owner) { - const int kMaxAttemptsToOpenClipboard = 5; - - if (opened_) { - NOTREACHED(); - return false; - } - - // Attempt to open the clipboard, which will acquire the Windows clipboard - // lock. This may fail if another process currently holds this lock. - // We're willing to try a few times in the hopes of acquiring it. - // - // This turns out to be an issue when using remote desktop because the - // rdpclip.exe process likes to read what we've written to the clipboard and - // send it to the RDP client. If we open and close the clipboard in quick - // succession, we might be trying to open it while rdpclip.exe has it open, - // See Bug 815425. - // - // In fact, we believe we'll only spin this loop over remote desktop. In - // normal situations, the user is initiating clipboard operations and there - // shouldn't be contention. - - for (int attempts = 0; attempts < kMaxAttemptsToOpenClipboard; ++attempts) { - // If we didn't manage to open the clipboard, sleep a bit and be hopeful. - if (attempts != 0) - ::Sleep(5); - - if (::OpenClipboard(owner)) { - opened_ = true; - return true; - } - } - - // We failed to acquire the clipboard. - return false; - } - - void Release() { - if (opened_) { - ::CloseClipboard(); - opened_ = false; - } else { - NOTREACHED(); - } - } - - private: - bool opened_; -}; - -LRESULT CALLBACK ClipboardOwnerWndProc(HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam) { - LRESULT lresult = 0; - - switch (message) { - case WM_RENDERFORMAT: - // This message comes when SetClipboardData was sent a null data handle - // and now it's come time to put the data on the clipboard. - // We always set data, so there isn't a need to actually do anything here. - break; - case WM_RENDERALLFORMATS: - // This message comes when SetClipboardData was sent a null data handle - // and now this application is about to quit, so it must put data on - // the clipboard before it exits. - // We always set data, so there isn't a need to actually do anything here. - break; - case WM_DRAWCLIPBOARD: - break; - case WM_DESTROY: - break; - case WM_CHANGECBCHAIN: - break; - default: - lresult = DefWindowProc(hwnd, message, wparam, lparam); - break; - } - return lresult; -} - -template <typename charT> -HGLOBAL CreateGlobalData(const std::basic_string<charT>& str) { - HGLOBAL data = - ::GlobalAlloc(GMEM_MOVEABLE, ((str.size() + 1) * sizeof(charT))); - if (data) { - charT* raw_data = static_cast<charT*>(::GlobalLock(data)); - memcpy(raw_data, str.data(), str.size() * sizeof(charT)); - raw_data[str.size()] = '\0'; - ::GlobalUnlock(data); - } - return data; -}; - -} // namespace - -Clipboard::Clipboard() : create_window_(false) { - if (MessageLoop::current()->type() == MessageLoop::TYPE_UI) { - // Make a dummy HWND to be the clipboard's owner. - WNDCLASSEX wcex = {0}; - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.lpfnWndProc = ClipboardOwnerWndProc; - wcex.hInstance = GetModuleHandle(NULL); - wcex.lpszClassName = L"ClipboardOwnerWindowClass"; - ::RegisterClassEx(&wcex); - create_window_ = true; - } - - clipboard_owner_ = NULL; -} - -Clipboard::~Clipboard() { - if (clipboard_owner_) - ::DestroyWindow(clipboard_owner_); - clipboard_owner_ = NULL; -} - -void Clipboard::WriteObjects(const ObjectMap& objects) { - WriteObjects(objects, NULL); -} - -void Clipboard::WriteObjects(const ObjectMap& objects, - base::ProcessHandle process) { - ScopedClipboard clipboard; - if (!clipboard.Acquire(GetClipboardWindow())) - return; - - ::EmptyClipboard(); - - for (ObjectMap::const_iterator iter = objects.begin(); - iter != objects.end(); ++iter) { - if (iter->first == CBF_SMBITMAP) - WriteBitmapFromSharedMemory(&(iter->second[0].front()), - &(iter->second[1].front()), - process); - else - DispatchObject(static_cast<ObjectType>(iter->first), iter->second); - } -} - -void Clipboard::WriteText(const char* text_data, size_t text_len) { - string16 text; - UTF8ToUTF16(text_data, text_len, &text); - HGLOBAL glob = CreateGlobalData(text); - - WriteToClipboard(CF_UNICODETEXT, glob); -} - -void Clipboard::WriteHTML(const char* markup_data, - size_t markup_len, - const char* url_data, - size_t url_len) { - std::string markup(markup_data, markup_len); - std::string url; - - if (url_len > 0) - url.assign(url_data, url_len); - - std::string html_fragment = ClipboardUtil::HtmlToCFHtml(markup, url); - HGLOBAL glob = CreateGlobalData(html_fragment); - - WriteToClipboard(StringToInt(GetHtmlFormatType()), glob); -} - -void Clipboard::WriteBookmark(const char* title_data, - size_t title_len, - const char* url_data, - size_t url_len) { - std::string bookmark(title_data, title_len); - bookmark.append(1, L'\n'); - bookmark.append(url_data, url_len); - - string16 wide_bookmark = UTF8ToWide(bookmark); - HGLOBAL glob = CreateGlobalData(wide_bookmark); - - WriteToClipboard(StringToInt(GetUrlWFormatType()), glob); -} - -void Clipboard::WriteWebSmartPaste() { - DCHECK(clipboard_owner_); - ::SetClipboardData(StringToInt(GetWebKitSmartPasteFormatType()), NULL); -} - -void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) { - const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data); - HDC dc = ::GetDC(NULL); - - // This doesn't actually cost us a memcpy when the bitmap comes from the - // renderer as we load it into the bitmap using setPixels which just sets a - // pointer. Someone has to memcpy it into GDI, it might as well be us here. - - // TODO(darin): share data in gfx/bitmap_header.cc somehow - BITMAPINFO bm_info = {0}; - bm_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bm_info.bmiHeader.biWidth = size->width(); - bm_info.bmiHeader.biHeight = -size->height(); // sets vertical orientation - bm_info.bmiHeader.biPlanes = 1; - bm_info.bmiHeader.biBitCount = 32; - bm_info.bmiHeader.biCompression = BI_RGB; - - // ::CreateDIBSection allocates memory for us to copy our bitmap into. - // Unfortunately, we can't write the created bitmap to the clipboard, - // (see http://msdn2.microsoft.com/en-us/library/ms532292.aspx) - void *bits; - HBITMAP source_hbitmap = - ::CreateDIBSection(dc, &bm_info, DIB_RGB_COLORS, &bits, NULL, 0); - - if (bits && source_hbitmap) { - // Copy the bitmap out of shared memory and into GDI - memcpy(bits, pixel_data, 4 * size->width() * size->height()); - - // Now we have an HBITMAP, we can write it to the clipboard - WriteBitmapFromHandle(source_hbitmap, *size); - } - - ::DeleteObject(source_hbitmap); - ::ReleaseDC(NULL, dc); -} - -void Clipboard::WriteBitmapFromSharedMemory(const char* bitmap_data, - const char* size_data, - base::ProcessHandle process) { - const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data); - - // bitmap_data has an encoded shared memory object. See - // DuplicateRemoteHandles(). - char* ptr = const_cast<char*>(bitmap_data); - scoped_ptr<const base::SharedMemory> bitmap(* - reinterpret_cast<const base::SharedMemory**>(ptr)); - - // TODO(darin): share data in gfx/bitmap_header.cc somehow. - BITMAPINFO bm_info = {0}; - bm_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bm_info.bmiHeader.biWidth = size->width(); - // Sets the vertical orientation. - bm_info.bmiHeader.biHeight = -size->height(); - bm_info.bmiHeader.biPlanes = 1; - bm_info.bmiHeader.biBitCount = 32; - bm_info.bmiHeader.biCompression = BI_RGB; - - HDC dc = ::GetDC(NULL); - - // We can create an HBITMAP directly using the shared memory handle, saving - // a memcpy. - HBITMAP source_hbitmap = - ::CreateDIBSection(dc, &bm_info, DIB_RGB_COLORS, NULL, - bitmap->handle(), 0); - - if (source_hbitmap) { - // Now we can write the HBITMAP to the clipboard - WriteBitmapFromHandle(source_hbitmap, *size); - } - - ::DeleteObject(source_hbitmap); - ::ReleaseDC(NULL, dc); -} - -void Clipboard::WriteBitmapFromHandle(HBITMAP source_hbitmap, - const gfx::Size& size) { - // We would like to just call ::SetClipboardData on the source_hbitmap, - // but that bitmap might not be of a sort we can write to the clipboard. - // For this reason, we create a new bitmap, copy the bits over, and then - // write that to the clipboard. - - HDC dc = ::GetDC(NULL); - HDC compatible_dc = ::CreateCompatibleDC(NULL); - HDC source_dc = ::CreateCompatibleDC(NULL); - - // This is the HBITMAP we will eventually write to the clipboard - HBITMAP hbitmap = ::CreateCompatibleBitmap(dc, size.width(), size.height()); - if (!hbitmap) { - // Failed to create the bitmap - ::DeleteDC(compatible_dc); - ::DeleteDC(source_dc); - ::ReleaseDC(NULL, dc); - return; - } - - HBITMAP old_hbitmap = (HBITMAP)SelectObject(compatible_dc, hbitmap); - HBITMAP old_source = (HBITMAP)SelectObject(source_dc, source_hbitmap); - - // Now we need to blend it into an HBITMAP we can place on the clipboard - BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; - ::GdiAlphaBlend(compatible_dc, 0, 0, size.width(), size.height(), - source_dc, 0, 0, size.width(), size.height(), bf); - - // Clean up all the handles we just opened - ::SelectObject(compatible_dc, old_hbitmap); - ::SelectObject(source_dc, old_source); - ::DeleteObject(old_hbitmap); - ::DeleteObject(old_source); - ::DeleteDC(compatible_dc); - ::DeleteDC(source_dc); - ::ReleaseDC(NULL, dc); - - WriteToClipboard(CF_BITMAP, hbitmap); -} - -// Write a file or set of files to the clipboard in HDROP format. When the user -// invokes a paste command (in a Windows explorer shell, for example), the files -// will be copied to the paste location. -void Clipboard::WriteFiles(const char* file_data, size_t file_len) { - // Calculate the amount of space we'll need store the strings and - // a DROPFILES struct. - size_t bytes = sizeof(DROPFILES) + file_len; - - HANDLE hdata = ::GlobalAlloc(GMEM_MOVEABLE, bytes); - if (!hdata) - return; - - char* data = static_cast<char*>(::GlobalLock(hdata)); - DROPFILES* drop_files = reinterpret_cast<DROPFILES*>(data); - drop_files->pFiles = sizeof(DROPFILES); - drop_files->fWide = TRUE; - - memcpy(data + sizeof(DROPFILES), file_data, file_len); - - ::GlobalUnlock(hdata); - WriteToClipboard(CF_HDROP, hdata); -} - -void Clipboard::WriteData(const char* format_name, size_t format_len, - const char* data_data, size_t data_len) { - std::string format(format_name, format_len); - CLIPFORMAT clip_format = - ::RegisterClipboardFormat(ASCIIToWide(format).c_str()); - - HGLOBAL hdata = ::GlobalAlloc(GMEM_MOVEABLE, data_len); - if (!hdata) - return; - - char* data = static_cast<char*>(::GlobalLock(hdata)); - memcpy(data, data_data, data_len); - ::GlobalUnlock(data); - WriteToClipboard(clip_format, hdata); -} - -void Clipboard::WriteToClipboard(unsigned int format, HANDLE handle) { - DCHECK(clipboard_owner_); - if (handle && !::SetClipboardData(format, handle)) { - DCHECK(ERROR_CLIPBOARD_NOT_OPEN != GetLastError()); - FreeData(format, handle); - } -} - -bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, - Clipboard::Buffer buffer) const { - DCHECK_EQ(buffer, BUFFER_STANDARD); - return ::IsClipboardFormatAvailable(StringToInt(format)) != FALSE; -} - -bool Clipboard::IsFormatAvailableByString( - const std::string& ascii_format, Clipboard::Buffer buffer) const { - DCHECK_EQ(buffer, BUFFER_STANDARD); - std::wstring wide_format = ASCIIToWide(ascii_format); - CLIPFORMAT format = ::RegisterClipboardFormat(wide_format.c_str()); - return ::IsClipboardFormatAvailable(format) != FALSE; -} - -void Clipboard::ReadText(Clipboard::Buffer buffer, string16* result) const { - DCHECK_EQ(buffer, BUFFER_STANDARD); - if (!result) { - NOTREACHED(); - return; - } - - result->clear(); - - // Acquire the clipboard. - ScopedClipboard clipboard; - if (!clipboard.Acquire(GetClipboardWindow())) - return; - - HANDLE data = ::GetClipboardData(CF_UNICODETEXT); - if (!data) - return; - - result->assign(static_cast<const char16*>(::GlobalLock(data))); - ::GlobalUnlock(data); -} - -void Clipboard::ReadAsciiText(Clipboard::Buffer buffer, - std::string* result) const { - DCHECK_EQ(buffer, BUFFER_STANDARD); - if (!result) { - NOTREACHED(); - return; - } - - result->clear(); - - // Acquire the clipboard. - ScopedClipboard clipboard; - if (!clipboard.Acquire(GetClipboardWindow())) - return; - - HANDLE data = ::GetClipboardData(CF_TEXT); - if (!data) - return; - - result->assign(static_cast<const char*>(::GlobalLock(data))); - ::GlobalUnlock(data); -} - -void Clipboard::ReadHTML(Clipboard::Buffer buffer, string16* markup, - std::string* src_url) const { - DCHECK_EQ(buffer, BUFFER_STANDARD); - if (markup) - markup->clear(); - - if (src_url) - src_url->clear(); - - // Acquire the clipboard. - ScopedClipboard clipboard; - if (!clipboard.Acquire(GetClipboardWindow())) - return; - - HANDLE data = ::GetClipboardData(StringToInt(GetHtmlFormatType())); - if (!data) - return; - - std::string html_fragment(static_cast<const char*>(::GlobalLock(data))); - ::GlobalUnlock(data); - - std::string markup_utf8; - ClipboardUtil::CFHtmlToHtml(html_fragment, markup ? &markup_utf8 : NULL, - src_url); - if (markup) - markup->assign(UTF8ToWide(markup_utf8)); -} - -void Clipboard::ReadBookmark(string16* title, std::string* url) const { - if (title) - title->clear(); - - if (url) - url->clear(); - - // Acquire the clipboard. - ScopedClipboard clipboard; - if (!clipboard.Acquire(GetClipboardWindow())) - return; - - HANDLE data = ::GetClipboardData(StringToInt(GetUrlWFormatType())); - if (!data) - return; - - string16 bookmark(static_cast<const char16*>(::GlobalLock(data))); - ::GlobalUnlock(data); - - ParseBookmarkClipboardFormat(bookmark, title, url); -} - -// Read a file in HDROP format from the clipboard. -void Clipboard::ReadFile(FilePath* file) const { - if (!file) { - NOTREACHED(); - return; - } - - *file = FilePath(); - std::vector<FilePath> files; - ReadFiles(&files); - - // Take the first file, if available. - if (!files.empty()) - *file = files[0]; -} - -// Read a set of files in HDROP format from the clipboard. -void Clipboard::ReadFiles(std::vector<FilePath>* files) const { - if (!files) { - NOTREACHED(); - return; - } - - files->clear(); - - ScopedClipboard clipboard; - if (!clipboard.Acquire(GetClipboardWindow())) - return; - - HDROP drop = static_cast<HDROP>(::GetClipboardData(CF_HDROP)); - if (!drop) - return; - - // Count of files in the HDROP. - int count = ::DragQueryFile(drop, 0xffffffff, NULL, 0); - - if (count) { - for (int i = 0; i < count; ++i) { - int size = ::DragQueryFile(drop, i, NULL, 0) + 1; - std::wstring file; - ::DragQueryFile(drop, i, WriteInto(&file, size), size); - files->push_back(FilePath(file)); - } - } -} - -void Clipboard::ReadData(const std::string& format, std::string* result) { - if (!result) { - NOTREACHED(); - return; - } - - CLIPFORMAT clip_format = - ::RegisterClipboardFormat(ASCIIToWide(format).c_str()); - - ScopedClipboard clipboard; - if (!clipboard.Acquire(GetClipboardWindow())) - return; - - HANDLE data = ::GetClipboardData(clip_format); - if (!data) - return; - - result->assign(static_cast<const char*>(::GlobalLock(data)), - ::GlobalSize(data)); - ::GlobalUnlock(data); -} - -// static -void Clipboard::ParseBookmarkClipboardFormat(const string16& bookmark, - string16* title, - std::string* url) { - const string16 kDelim = ASCIIToUTF16("\r\n"); - - const size_t title_end = bookmark.find_first_of(kDelim); - if (title) - title->assign(bookmark.substr(0, title_end)); - - if (url) { - const size_t url_start = bookmark.find_first_not_of(kDelim, title_end); - if (url_start != string16::npos) - *url = UTF16ToUTF8(bookmark.substr(url_start, string16::npos)); - } -} - -// static -Clipboard::FormatType Clipboard::GetUrlFormatType() { - return IntToString(ClipboardUtil::GetUrlFormat()->cfFormat); -} - -// static -Clipboard::FormatType Clipboard::GetUrlWFormatType() { - return IntToString(ClipboardUtil::GetUrlWFormat()->cfFormat); -} - -// static -Clipboard::FormatType Clipboard::GetMozUrlFormatType() { - return IntToString(ClipboardUtil::GetMozUrlFormat()->cfFormat); -} - -// static -Clipboard::FormatType Clipboard::GetPlainTextFormatType() { - return IntToString(ClipboardUtil::GetPlainTextFormat()->cfFormat); -} - -// static -Clipboard::FormatType Clipboard::GetPlainTextWFormatType() { - return IntToString(ClipboardUtil::GetPlainTextWFormat()->cfFormat); -} - -// static -Clipboard::FormatType Clipboard::GetFilenameFormatType() { - return IntToString(ClipboardUtil::GetFilenameFormat()->cfFormat); -} - -// static -Clipboard::FormatType Clipboard::GetFilenameWFormatType() { - return IntToString(ClipboardUtil::GetFilenameWFormat()->cfFormat); -} - -// MS HTML Format -// static -Clipboard::FormatType Clipboard::GetHtmlFormatType() { - return IntToString(ClipboardUtil::GetHtmlFormat()->cfFormat); -} - -// static -Clipboard::FormatType Clipboard::GetBitmapFormatType() { - return IntToString(CF_BITMAP); -} - -// Firefox text/html -// static -Clipboard::FormatType Clipboard::GetTextHtmlFormatType() { - return IntToString(ClipboardUtil::GetTextHtmlFormat()->cfFormat); -} - -// static -Clipboard::FormatType Clipboard::GetCFHDropFormatType() { - return IntToString(ClipboardUtil::GetCFHDropFormat()->cfFormat); -} - -// static -Clipboard::FormatType Clipboard::GetFileDescriptorFormatType() { - return IntToString(ClipboardUtil::GetFileDescriptorFormat()->cfFormat); -} - -// static -Clipboard::FormatType Clipboard::GetFileContentFormatZeroType() { - return IntToString(ClipboardUtil::GetFileContentFormatZero()->cfFormat); -} - -// static -void Clipboard::DuplicateRemoteHandles(base::ProcessHandle process, - ObjectMap* objects) { - for (ObjectMap::iterator iter = objects->begin(); iter != objects->end(); - ++iter) { - if (iter->first == CBF_SMBITMAP) { - // There is a shared memory handle encoded on the first ObjectMapParam. - // Use it to open a local handle to the memory. - char* bitmap_data = &(iter->second[0].front()); - base::SharedMemoryHandle* remote_bitmap_handle = - reinterpret_cast<base::SharedMemoryHandle*>(bitmap_data); - - base::SharedMemory* bitmap = new base::SharedMemory(*remote_bitmap_handle, - false, process); - - // We store the object where the remote handle was located so it can - // be retrieved by the UI thread (see WriteBitmapFromSharedMemory()). - iter->second[0].clear(); - for (size_t i = 0; i < sizeof(bitmap); i++) - iter->second[0].push_back(reinterpret_cast<char*>(&bitmap)[i]); - } - } -} - -// static -Clipboard::FormatType Clipboard::GetWebKitSmartPasteFormatType() { - return IntToString(ClipboardUtil::GetWebKitSmartPasteFormat()->cfFormat); -} - -// static -void Clipboard::FreeData(unsigned int format, HANDLE data) { - if (format == CF_BITMAP) - ::DeleteObject(static_cast<HBITMAP>(data)); - else - ::GlobalFree(data); -} - -HWND Clipboard::GetClipboardWindow() const { - if (!clipboard_owner_ && create_window_) { - clipboard_owner_ = ::CreateWindow(L"ClipboardOwnerWindowClass", - L"ClipboardOwnerWindow", - 0, 0, 0, 0, 0, - HWND_MESSAGE, - 0, 0, 0); - } - return clipboard_owner_; -} |