diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-05 01:34:30 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-05 01:34:30 +0000 |
commit | 3ee3ffd1d79a0c1544f3bfd70c7de7606df9482f (patch) | |
tree | 0943a0925f5974478463e5d00886be29109858e6 | |
parent | 38733063b7e1cf0b6e67c0b590773ff4f1aaa18d (diff) | |
download | chromium_src-3ee3ffd1d79a0c1544f3bfd70c7de7606df9482f.zip chromium_src-3ee3ffd1d79a0c1544f3bfd70c7de7606df9482f.tar.gz chromium_src-3ee3ffd1d79a0c1544f3bfd70c7de7606df9482f.tar.bz2 |
Rewrote the clipboard API to be more concurrent. Added a helper class to make it more foolproof. Updated all clients and unittests. Mac port by jeremy@chromium.org
Review URL: http://codereview.chromium.org/9154
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4719 0039d316-1c4b-4281-b951-d872f2087c98
27 files changed, 873 insertions, 550 deletions
diff --git a/base/base.xcodeproj/project.pbxproj b/base/base.xcodeproj/project.pbxproj index 1031f02..ccb0001 100644 --- a/base/base.xcodeproj/project.pbxproj +++ b/base/base.xcodeproj/project.pbxproj @@ -170,7 +170,9 @@ B52C916C0E9428F500208D01 /* clipboard_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B52C916B0E9428F500208D01 /* clipboard_unittest.cc */; }; B53C85280E9C298C000F70AB /* idle_timer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 820EB4EB0E3A60FE009668FC /* idle_timer.cc */; }; B57E4D780E9C26340090055D /* idletimer_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B57E4D770E9C26340090055D /* idletimer_unittest.cc */; }; + B5A8618E0EC1257900B332C2 /* clipboard.cc in Sources */ = {isa = PBXBuildFile; fileRef = B5A8618D0EC1257900B332C2 /* clipboard.cc */; }; B5D544AB0EAFB7E000272A1C /* sys_string_conversions_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B5D544AA0EAFB7E000272A1C /* sys_string_conversions_unittest.cc */; }; + B5E8F6CC0EBFB38E008DD1E9 /* scoped_clipboard_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = B5E8F6CB0EBFB38E008DD1E9 /* scoped_clipboard_writer.cc */; }; B5EF235C0E89ABF500E1E114 /* platform_canvas_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = ABE1BA0C0E756EC4009041DA /* platform_canvas_unittest.cc */; }; BA0F69870E79D7980079A8A1 /* thread_local_storage_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA0F69860E79D7980079A8A1 /* thread_local_storage_unittest.cc */; }; BA5CC5840E788093004EDD45 /* shared_memory_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA5CC5830E788093004EDD45 /* shared_memory_unittest.cc */; }; @@ -630,7 +632,10 @@ ABF68B280EB0F93100E72835 /* field_trial.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = field_trial.cc; sourceTree = "<group>"; }; B52C916B0E9428F500208D01 /* clipboard_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = clipboard_unittest.cc; sourceTree = "<group>"; }; B57E4D770E9C26340090055D /* idletimer_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idletimer_unittest.cc; sourceTree = "<group>"; }; + B5A8618D0EC1257900B332C2 /* clipboard.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = clipboard.cc; sourceTree = "<group>"; }; B5D544AA0EAFB7E000272A1C /* sys_string_conversions_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sys_string_conversions_unittest.cc; sourceTree = "<group>"; }; + B5E8F6CA0EBFB38E008DD1E9 /* scoped_clipboard_writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scoped_clipboard_writer.h; sourceTree = "<group>"; }; + B5E8F6CB0EBFB38E008DD1E9 /* scoped_clipboard_writer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scoped_clipboard_writer.cc; sourceTree = "<group>"; }; BA0F69860E79D7980079A8A1 /* thread_local_storage_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thread_local_storage_unittest.cc; sourceTree = "<group>"; }; BA5CC5830E788093004EDD45 /* shared_memory_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shared_memory_unittest.cc; sourceTree = "<group>"; }; BA739A000E5E3242009842A7 /* tracked_objects_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tracked_objects_unittest.cc; sourceTree = "<group>"; }; @@ -838,6 +843,7 @@ 825402D80D92D15E0006B936 /* blapit.h */, A5A0276B0E4BA33700498DA9 /* build_config.h */, 7BD8F6D20E65DB0200034DE9 /* bzip2_error_handler.cc */, + B5A8618D0EC1257900B332C2 /* clipboard.cc */, 825402DB0D92D1730006B936 /* clipboard.h */, ABF4B99D0DC2BB6000A6E319 /* clipboard_mac.mm */, B52C916B0E9428F500208D01 /* clipboard_unittest.cc */, @@ -968,6 +974,8 @@ 8254035F0D92D27C0006B936 /* revocable_store.h */, E49F1A5D0E4CD6E200386AEC /* run_all_unittests.cc */, 7B5AD60D0D9DD8050012BCF1 /* scoped_cftyperef.h */, + B5E8F6CB0EBFB38E008DD1E9 /* scoped_clipboard_writer.cc */, + B5E8F6CA0EBFB38E008DD1E9 /* scoped_clipboard_writer.h */, 7BA35DD10E8C0D5F0023C8B9 /* scoped_nsautorelease_pool.h */, 7BA35DD20E8C0D5F0023C8B9 /* scoped_nsautorelease_pool.mm */, 825403610D92D27C0006B936 /* scoped_ptr.h */, @@ -1358,6 +1366,7 @@ ABF4B98F0DC2BA6900A6E319 /* base_paths_mac.mm in Sources */, E45062A60E40A9BE0025A81A /* base_switches.cc in Sources */, 7BD8F6D30E65DB0200034DE9 /* bzip2_error_handler.cc in Sources */, + B5A8618E0EC1257900B332C2 /* clipboard.cc in Sources */, ABF4B99E0DC2BB6000A6E319 /* clipboard_mac.mm in Sources */, E48A05F70E3F61B300172919 /* command_line.cc in Sources */, 824653680DC12CEC007C2BAA /* condition_variable_posix.cc in Sources */, @@ -1397,6 +1406,7 @@ 4D11B59B0E91730200EF7617 /* rand_util_posix.cc in Sources */, 7B836C050E55BBB800F6AD31 /* ref_counted.cc in Sources */, 8246548C0DC259DB007C2BAA /* revocable_store.cc in Sources */, + B5E8F6CC0EBFB38E008DD1E9 /* scoped_clipboard_writer.cc in Sources */, 7BA35DD30E8C0D5F0023C8B9 /* scoped_nsautorelease_pool.mm in Sources */, ABF4B9BC0DC2BD1000A6E319 /* sha2.cc in Sources */, ABF4B9BE0DC2BD1500A6E319 /* sha512.cc in Sources */, diff --git a/base/base_lib.scons b/base/base_lib.scons index 0ef9cf4..70572c2 100644 --- a/base/base_lib.scons +++ b/base/base_lib.scons @@ -35,6 +35,7 @@ input_files = [ 'base_paths.cc', 'base_switches.cc', 'bzip2_error_handler.cc', + 'clipboard.cc', 'clipboard_util.cc', 'command_line.cc', 'debug_util.cc', @@ -63,6 +64,7 @@ input_files = [ 'ref_counted.cc', 'resource_util.cc', 'revocable_store.cc', + 'scoped_clipboard_writer.cc', 'sha2.cc', 'simple_thread.cc', 'stats_table.cc', diff --git a/base/build/base.vcproj b/base/build/base.vcproj index f031e75..cd69ae1 100644 --- a/base/build/base.vcproj +++ b/base/build/base.vcproj @@ -206,6 +206,10 @@ > </File> <File + RelativePath="..\clipboard.cc" + > + </File> + <File RelativePath="..\clipboard.h" > </File> @@ -638,6 +642,14 @@ > </File> <File + RelativePath="..\scoped_clipboard_writer.cc" + > + </File> + <File + RelativePath="..\scoped_clipboard_writer.h" + > + </File> + <File RelativePath="..\scoped_handle.h" > </File> diff --git a/base/clipboard.cc b/base/clipboard.cc new file mode 100644 index 0000000..d3ec589 --- /dev/null +++ b/base/clipboard.cc @@ -0,0 +1,55 @@ +// 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 "base/logging.h" + +void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) { + switch (type) { + case CBF_TEXT: + WriteText(&(params[0].front()), params[0].size()); + break; + + case CBF_HTML: + if (params.size() == 2) + WriteHTML(&(params[0].front()), params[0].size(), + &(params[1].front()), params[1].size()); + else + WriteHTML(&(params[0].front()), params[0].size(), NULL, 0); + break; + +#if defined(OS_WIN) || defined(OS_MACOSX) + case CBF_BOOKMARK: + WriteBookmark(&(params[0].front()), params[0].size(), + &(params[1].front()), params[1].size()); + break; + + case CBF_LINK: + WriteHyperlink(&(params[0].front()), params[0].size(), + &(params[1].front()), params[1].size()); + break; + + case CBF_FILES: + WriteFiles(&(params[0].front()), params[0].size()); + break; +#endif // defined(OS_WIN) || defined(OS_MACOSX) + +#if defined(OS_WIN) + case CBF_WEBKIT: + WriteWebSmartPaste(); + break; + + case CBF_BITMAP: + WriteBitmap(&(params[0].front()), &(params[1].front())); + break; +#endif // defined(OS_WIN) + + default: + NOTREACHED(); + } +} diff --git a/base/clipboard.h b/base/clipboard.h index f6d2531..a91d6cb 100644 --- a/base/clipboard.h +++ b/base/clipboard.h @@ -31,58 +31,66 @@ class Clipboard { #elif defined(OS_LINUX) typedef struct _GdkAtom* FormatType; typedef struct _GtkClipboard GtkClipboard; - // A mapping from target (format) string to the relevant data (usually a - // string, but potentially arbitrary data). - typedef std::map<std::string, std::pair<uint8*, size_t> > TargetMap; + typedef std::map<std::string, std::pair<char*, size_t> > TargetMap; #endif + // ObjectType designates the type of data to be stored in the clipboard. This + // designation is shared across all OSes. The system-specific designation + // is defined by FormatType. A single ObjectType might be represented by + // several system-specific FormatTypes. For example, on Linux the CBF_TEXT + // ObjectType maps to "text/plain", "STRING", and several other formats. On + // windows it maps to CF_UNICODETEXT. + enum ObjectType { + CBF_TEXT, + CBF_HTML, + CBF_BOOKMARK, + CBF_LINK, + CBF_FILES, + CBF_WEBKIT, + CBF_BITMAP, + CBF_SMBITMAP // bitmap from shared memory + }; + + // ObjectMap is a map from ObjectType to associated data. + // The data is organized differently for each ObjectType. The following + // table summarizes what kind of data is stored for each key. + // * indicates an optional argument. + // + // Key Arguments Type + // ------------------------------------- + // CBF_TEXT text char array + // CBF_HTML html char array + // url* char array + // CBF_BOOKMARK html char array + // url char array + // CBF_LINK html char array + // url char array + // CBF_FILES files char array representing multiple files. + // Filenames are separated by null characters and + // the final filename is double null terminated. + // CBF_WEBKIT none empty vector + // CBF_BITMAP pixels byte array + // size gfx::Size struct + // CBF_SMBITMAP shared_mem shared memory handle + // size gfx::Size struct + typedef std::vector<char> ObjectMapParam; + typedef std::vector<ObjectMapParam> ObjectMapParams; + typedef std::map<int /* ObjectType */, ObjectMapParams> ObjectMap; + Clipboard(); ~Clipboard(); - // Clears the clipboard. It is usually a good idea to clear the clipboard - // before writing content to the clipboard. - void Clear(); - - // Adds UNICODE and ASCII text to the clipboard. - void WriteText(const std::wstring& text); - - // Adds HTML to the clipboard. The url parameter is optional, but especially - // useful if the HTML fragment contains relative links - void WriteHTML(const std::wstring& markup, const std::string& src_url); - - // Adds a bookmark to the clipboard - void WriteBookmark(const std::wstring& title, const std::string& url); - - // Adds both a bookmark and an HTML hyperlink to the clipboard. It is a - // convenience wrapper around WriteBookmark and WriteHTML. - void WriteHyperlink(const std::wstring& title, const std::string& url); - -#if defined(OS_WIN) - // Adds a bitmap to the clipboard - // This is the slowest way to copy a bitmap to the clipboard as we must first - // memcpy the pixels into GDI and the blit the bitmap to the clipboard. - // Pixel format is assumed to be 32-bit BI_RGB. - void WriteBitmap(const void* pixels, const gfx::Size& size); - - // Adds a bitmap to the clipboard - // This function requires read and write access to the bitmap, but does not - // actually modify the shared memory region. - // Pixel format is assumed to be 32-bit BI_RGB. - void WriteBitmapFromSharedMemory(const SharedMemory& bitmap, - const gfx::Size& size); - - // Adds a bitmap to the clipboard - // This is the fastest way to copy a bitmap to the clipboard. The HBITMAP - // may either be device-dependent or device-independent. - void WriteBitmapFromHandle(HBITMAP hbitmap, const gfx::Size& size); - - // Used by WebKit to determine whether WebKit wrote the clipboard last - void WriteWebSmartPaste(); -#endif + // Write a bunch of objects to the system clipboard. Copies are made of the + // contents of |objects|. On Windows they are copied to the system clipboard. + // On linux they are copied into a structure owned by the Clipboard object and + // kept until the system clipboard is set again. + void WriteObjects(const ObjectMap& objects); - // Adds a file or group of files to the clipboard. - void WriteFile(const std::wstring& file); - void WriteFiles(const std::vector<std::wstring>& files); + // Behaves as above. If there is some shared memory handle passed as one of + // the objects, it came from the process designated by |process|. This will + // assist in turning it into a shared memory region that the current process + // can use. + void WriteObjects(const ObjectMap& objects, ProcessHandle process); // Tests whether the clipboard contains a certain format bool IsFormatAvailable(FormatType format) const; @@ -125,8 +133,42 @@ class Clipboard { #endif private: + void WriteText(const char* text_data, size_t text_len); + + void WriteHTML(const char* markup_data, + size_t markup_len, + const char* url_data, + size_t url_len); + + void WriteBookmark(const char* title_data, + size_t title_len, + const char* url_data, + size_t url_len); + + void WriteHyperlink(const char* title_data, + size_t title_len, + const char* url_data, + size_t url_len); + + void WriteWebSmartPaste(); + + void WriteFiles(const char* file_data, size_t file_len); + + void DispatchObject(ObjectType type, const ObjectMapParams& params); #if defined(OS_WIN) - static void MarkupToHTMLClipboardFormat(const std::wstring& markup, + void WriteBitmap(const char* pixel_data, const char* size_data); + + void WriteBitmapFromSharedMemory(const char* bitmap_data, + const char* size_data, + ProcessHandle handle); + + void WriteBitmapFromHandle(HBITMAP source_hbitmap, + const gfx::Size& size); + + // Safely write to system clipboard. Free |handle| on failure. + void WriteToClipboard(FormatType format, HANDLE handle); + + static void MarkupToHTMLClipboardFormat(const std::string& markup, const std::string& src_url, std::string* html_fragment); @@ -138,25 +180,26 @@ class Clipboard { std::wstring* title, std::string* url); + // Free a handle depending on its type (as intuited from format) + static void FreeData(FormatType format, HANDLE data); + HWND clipboard_owner_; #elif defined(OS_LINUX) + // Data is stored in the |clipboard_data_| map until it is saved to the system + // clipboard. The Store* functions save data to the |clipboard_data_| map. The + // SetGtkClipboard function replaces whatever is on the system clipboard with + // the contents of |clipboard_data_|. + // The Write* functions make a deep copy of the data passed to them an store + // it in |clipboard_data_|. + // Write changes to gtk clipboard. void SetGtkClipboard(); // Free pointers in clipboard_data_ and clear() the map. void FreeTargetMap(); - // Insert a mapping into clipboard_data_, or change an existing mapping. - uint8* InsertOrOverwrite(std::string target, uint8* data, size_t data_len); - - // We have to be able to store multiple formats on the clipboard - // simultaneously. The Chrome Clipboard class accomplishes this by - // expecting that consecutive calls to Write* (WriteHTML, WriteText, etc.) - // The GTK clipboard interface does not naturally support consecutive calls - // building on one another. So we keep all data in a map, and always pass the - // map when we are setting the gtk clipboard. Consecutive calls to Write* - // will write to the map and set the GTK clipboard, then add to the same - // map and set the GTK clipboard again. GTK thinks it is wiping out the - // clipboard but we are actually keeping the previous data. - TargetMap clipboard_data_; + // Insert a mapping into clipboard_data_. + void InsertMapping(const char* key, char* data, size_t data_len); + + TargetMap* clipboard_data_; GtkClipboard* clipboard_; #endif diff --git a/base/clipboard_linux.cc b/base/clipboard_linux.cc index 1e4686a..427ec13 100644 --- a/base/clipboard_linux.cc +++ b/base/clipboard_linux.cc @@ -32,18 +32,44 @@ void GetData(GtkClipboard* clipboard, return; gtk_selection_data_set(selection_data, selection_data->target, 8, - iter->second.first, + reinterpret_cast<guchar*>(iter->second.first), iter->second.second); } // GtkClipboardClearFunc callback. -// GTK will call this when new data is set on the clipboard (whether or not we -// retain ownership) or when gtk_clipboard_clear() is called. We don't do -// anything because we don't want to clear the clipboard_data_ map if we call -// set data several times in a row. Instead we manually clear the -// clipboard_data_ map on Clear() and on Clipboard destruction. +// We are guaranteed this will be called exactly once for each call to +// gtk_clipboard_set_with_data void ClearData(GtkClipboard* clipboard, gpointer user_data) { + Clipboard::TargetMap* map = + reinterpret_cast<Clipboard::TargetMap*>(user_data); + std::set<char*> ptrs; + + for (Clipboard::TargetMap::iterator iter = map->begin(); + iter != map->end(); ++iter) + ptrs.insert(iter->second.first); + + for (std::set<char*>::iterator iter = ptrs.begin(); + iter != ptrs.end(); ++iter) + delete[] *iter; + + delete map; +} + +// Frees the pointers in the given map and clears the map. +// Does not double-free any pointers. +void FreeTargetMap(Clipboard::TargetMap map) { + std::set<char*> ptrs; + + for (Clipboard::TargetMap::iterator iter = map.begin(); + iter != map.end(); ++iter) + ptrs.insert(iter->second.first); + + for (std::set<char*>::iterator iter = ptrs.begin(); + iter != ptrs.end(); ++iter) + delete[] *iter; + + map.clear(); } } // namespace @@ -56,46 +82,62 @@ Clipboard::~Clipboard() { // TODO(estade): do we want to save clipboard data after we exit? // gtk_clipboard_set_can_store and gtk_clipboard_store work // but have strangely awful performance. - Clear(); } -void Clipboard::Clear() { - gtk_clipboard_clear(clipboard_); - FreeTargetMap(); +void Clipboard::WriteObjects(const ObjectMap& objects) { + clipboard_data_ = new TargetMap(); + + for (ObjectMap::const_iterator iter = objects.begin(); + iter != objects.end(); ++iter) { + DispatchObject(static_cast<ObjectType>(iter->first), iter->second); + } + + SetGtkClipboard(); } -void Clipboard::WriteText(const std::wstring& text) { - std::string utf8_text = WideToUTF8(text); - size_t text_len = utf8_text.size() + 1; - uint8* text_data = new uint8[text_len]; - memcpy(text_data, utf8_text.c_str(), text_len); +// Take ownership of the GTK clipboard and inform it of the targets we support. +void Clipboard::SetGtkClipboard() { + GtkTargetEntry targets[clipboard_data_->size()]; - uint8* old_data = InsertOrOverwrite(kMimeText, text_data, text_len); - InsertOrOverwrite("TEXT", text_data, text_len); - InsertOrOverwrite("STRING", text_data, text_len); - InsertOrOverwrite("UTF8_STRING", text_data, text_len); - InsertOrOverwrite("COMPOUND_TEXT", text_data, text_len); + int i = 0; + for (Clipboard::TargetMap::iterator iter = clipboard_data_->begin(); + iter != clipboard_data_->end(); ++iter, ++i) { + char* target_string = new char[iter->first.size() + 1]; + strcpy(target_string, iter->first.c_str()); + targets[i].target = target_string; + targets[i].flags = 0; + targets[i].info = i; + } - if (old_data) - delete[] old_data; - - SetGtkClipboard(); + gtk_clipboard_set_with_data(clipboard_, targets, + clipboard_data_->size(), + GetData, ClearData, + clipboard_data_); + + for (size_t i = 0; i < clipboard_data_->size(); i++) + delete[] targets[i].target; } -void Clipboard::WriteHTML(const std::wstring& markup, - const std::string& src_url) { - // TODO(estade): might not want to ignore src_url - std::string html = WideToUTF8(markup); - size_t data_len = html.size() + 1; - uint8* html_data = new uint8[data_len]; - memcpy(html_data, html.c_str(), data_len); +void Clipboard::WriteText(const char* text_data, size_t text_len) { + char* data = new char[text_len]; + memcpy(data, text_data, text_len); - uint8* old_data = InsertOrOverwrite(kMimeHtml, html_data, data_len); + InsertMapping(kMimeText, data, text_len); + InsertMapping("TEXT", data, text_len); + InsertMapping("STRING", data, text_len); + InsertMapping("UTF8_STRING", data, text_len); + InsertMapping("COMPOUND_TEXT", data, text_len); +} - if (old_data) - delete[] old_data; +void Clipboard::WriteHTML(const char* markup_data, + size_t markup_len, + const char* url_data, + size_t url_len) { + // TODO(estade): might not want to ignore |url_data| + char* data = new char[markup_len]; + memcpy(data, markup_data, markup_len); - SetGtkClipboard(); + InsertMapping(kMimeHtml, data, markup_len); } // We do not use gtk_clipboard_wait_is_target_available because of @@ -185,62 +227,18 @@ Clipboard::FormatType Clipboard::GetHtmlFormatType() { return gdk_atom_intern(kMimeHtml, false); } -// Take ownership of the GTK clipboard and inform it of the targets we support. -void Clipboard::SetGtkClipboard() { - GtkTargetEntry targets[clipboard_data_.size()]; - - int i = 0; - for (Clipboard::TargetMap::iterator iter = clipboard_data_.begin(); - iter != clipboard_data_.end(); iter++, i++) { - char* target_string = new char[iter->first.size() + 1]; - strcpy(target_string, iter->first.c_str()); - targets[i].target = target_string; - targets[i].flags = 0; - targets[i].info = i; - } - - gtk_clipboard_set_with_data(clipboard_, targets, - clipboard_data_.size(), - GetData, ClearData, - &clipboard_data_); - - for (size_t i = 0; i < clipboard_data_.size(); i++) - delete[] targets[i].target; -} - -// Free the pointers in the clipboard_data_ map and reset the map. -void Clipboard::FreeTargetMap() { - std::set<uint8*> ptrs; +// Insert the key/value pair in the clipboard_data structure. If +// the mapping already exists, it frees the associated data. Don't worry +// about double freeing because if the same key is inserted into the +// map twice, it must have come from different Write* functions and the +// data pointer cannot be the same. +void Clipboard::InsertMapping(const char* key, + char* data, + size_t data_len) { + TargetMap::iterator iter = clipboard_data_->find(key); - for (Clipboard::TargetMap::iterator iter = clipboard_data_.begin(); - iter != clipboard_data_.end(); iter++) - ptrs.insert(iter->second.first); - - for (std::set<uint8*>::iterator iter = ptrs.begin(); - iter != ptrs.end(); iter++) - delete[] *iter; + if (iter != clipboard_data_->end()) + delete[] iter->second.first; - clipboard_data_.clear(); + (*clipboard_data_)[key] = std::make_pair(data, data_len); } - -// Insert the key/value pair in the clipboard_data structure. Overwrite -// and any old value that might have had that key. If we overwrote something, -// return the pointer to that something. Otherwise return null. -uint8* Clipboard::InsertOrOverwrite(std::string key, - uint8* data, size_t data_len) { - std::pair<std::string, std::pair<uint8*, size_t> > mapping = - std::make_pair(key, std::make_pair(data, data_len)); - - Clipboard::TargetMap::iterator iter = clipboard_data_.find(key); - uint8* retval = NULL; - - if (iter == clipboard_data_.end()) { - clipboard_data_.insert(mapping); - } else { - retval = iter->second.first; - iter->second = mapping.second; - } - - return retval; -} - diff --git a/base/clipboard_mac.mm b/base/clipboard_mac.mm index 7213859..10fd91a 100644 --- a/base/clipboard_mac.mm +++ b/base/clipboard_mac.mm @@ -32,39 +32,59 @@ Clipboard::Clipboard() { Clipboard::~Clipboard() { } -void Clipboard::Clear() { +void Clipboard::WriteObjects(const ObjectMap& objects) { NSPasteboard* pb = GetPasteboard(); [pb declareTypes:[NSArray array] owner:nil]; + + for (ObjectMap::const_iterator iter = objects.begin(); + iter != objects.end(); ++iter) { + DispatchObject(static_cast<ObjectType>(iter->first), iter->second); + } + } -void Clipboard::WriteText(const std::wstring& text) { +void Clipboard::WriteText(const char* text_data, size_t text_len) { + std::string text_str(text_data, text_len); + NSString *text = base::SysUTF8ToNSString(text_str); NSPasteboard* pb = GetPasteboard(); [pb addTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; - [pb setString:base::SysWideToNSString(text) forType:NSStringPboardType]; + [pb setString:text forType:NSStringPboardType]; } -void Clipboard::WriteHTML(const std::wstring& markup, - const std::string& src_url) { - // TODO(avi): src_url? +void Clipboard::WriteHTML(const char* markup_data, + size_t markup_len, + const char* url_data, + size_t url_len) { + std::string html_fragment_str(markup_data, markup_len); + NSString *html_fragment = base::SysUTF8ToNSString(html_fragment_str); + + // TODO(avi): url_data? NSPasteboard* pb = GetPasteboard(); [pb addTypes:[NSArray arrayWithObject:NSHTMLPboardType] owner:nil]; - [pb setString:base::SysWideToNSString(markup) forType:NSHTMLPboardType]; + [pb setString:html_fragment forType:NSHTMLPboardType]; } -void Clipboard::WriteBookmark(const std::wstring& title, - const std::string& url) { - WriteHyperlink(title, url); +void Clipboard::WriteBookmark(const char* title_data, + size_t title_len, + const char* url_data, + size_t url_len) { + WriteHyperlink(title_data, title_len, url_data, url_len); } -void Clipboard::WriteHyperlink(const std::wstring& title, - const std::string& url) { +void Clipboard::WriteHyperlink(const char* title_data, + size_t title_len, + const char* url_data, + size_t url_len) { + std::string title_str(title_data, title_len); + NSString *title = base::SysUTF8ToNSString(title_str); + std::string url_str(url_data, url_len); + NSString *url = base::SysUTF8ToNSString(url_str); + // TODO(playmobil): In the Windows version of this function, an HTML // representation of the bookmark is also added to the clipboard, to support // drag and drop of web shortcuts. I don't think we need to do this on the // Mac, but we should double check later on. - NSURL* nsurl = [NSURL URLWithString: - [NSString stringWithUTF8String:url.c_str()]]; - NSString* nstitle = base::SysWideToNSString(title); + NSURL* nsurl = [NSURL URLWithString:url]; NSPasteboard* pb = GetPasteboard(); // passing UTIs into the pasteboard methods is valid >= 10.5 @@ -73,19 +93,27 @@ void Clipboard::WriteHyperlink(const std::wstring& title, nil] owner:nil]; [nsurl writeToPasteboard:pb]; - [pb setString:nstitle forType:kUTTypeURLName]; + [pb setString:title forType:kUTTypeURLName]; } -void Clipboard::WriteFile(const std::wstring& file) { - std::vector<std::wstring> files; - files.push_back(file); - WriteFiles(files); -} +void Clipboard::WriteFiles(const char* file_data, size_t file_len) { + NSMutableArray* fileList = [NSMutableArray arrayWithCapacity:1]; + + // Offset of current filename from start of file_data array. + size_t current_filename_offset = 0; + + // file_data is double null terminated (see table at top of clipboard.h). + // So this loop can ignore the second null terminator, thus file_len - 1. + // TODO(playmobil): If we need a loop like this on other platforms then split + // this out into a common function that outputs a std::vector<const char*>. + for (size_t i = 0; i < file_len - 1; ++i) { + if (file_data[i] == '\0') { + const char* filename = &file_data[current_filename_offset]; + [fileList addObject:[NSString stringWithUTF8String:filename]]; -void Clipboard::WriteFiles(const std::vector<std::wstring>& files) { - NSMutableArray* fileList = [NSMutableArray arrayWithCapacity:files.size()]; - for (size_t i = 0; i < files.size(); ++i) { - [fileList addObject:base::SysWideToNSString(files[i])]; + current_filename_offset = i + 1; + continue; + } } NSPasteboard* pb = GetPasteboard(); diff --git a/base/clipboard_unittest.cc b/base/clipboard_unittest.cc index 066bd3e..fb48b49 100644 --- a/base/clipboard_unittest.cc +++ b/base/clipboard_unittest.cc @@ -7,6 +7,7 @@ #include "base/basictypes.h" #include "base/clipboard.h" #include "base/platform_test.h" +#include "base/scoped_clipboard_writer.h" #include "base/string_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -15,13 +16,20 @@ typedef PlatformTest ClipboardTest; TEST_F(ClipboardTest, ClearTest) { Clipboard clipboard; - clipboard.Clear(); - clipboard.WriteText(L"erase me"); - clipboard.Clear(); - EXPECT_EQ(false, clipboard.IsFormatAvailable( + { + ScopedClipboardWriter scw(&clipboard); + scw.WriteText(std::wstring(L"clear me")); + } + + { + ScopedClipboardWriter scw(&clipboard); + scw.WriteHTML(std::wstring(L"<b>broom</b>"), ""); + } + + EXPECT_FALSE(clipboard.IsFormatAvailable( + Clipboard::GetPlainTextWFormatType())); + EXPECT_FALSE(clipboard.IsFormatAvailable( Clipboard::GetPlainTextFormatType())); - EXPECT_EQ(false, clipboard.IsFormatAvailable( - Clipboard::GetHtmlFormatType())); } TEST_F(ClipboardTest, TextTest) { @@ -30,11 +38,14 @@ TEST_F(ClipboardTest, TextTest) { std::wstring text(L"This is a wstring!#$"), text_result; std::string ascii_text; - clipboard.Clear(); - clipboard.WriteText(text); - EXPECT_EQ(true, clipboard.IsFormatAvailable( + { + ScopedClipboardWriter scw(&clipboard); + scw.WriteText(text); + } + + EXPECT_TRUE(clipboard.IsFormatAvailable( Clipboard::GetPlainTextWFormatType())); - EXPECT_EQ(true, clipboard.IsFormatAvailable( + EXPECT_TRUE(clipboard.IsFormatAvailable( Clipboard::GetPlainTextFormatType())); clipboard.ReadText(&text_result); EXPECT_EQ(text, text_result); @@ -42,29 +53,17 @@ TEST_F(ClipboardTest, TextTest) { EXPECT_EQ(WideToUTF8(text), ascii_text); } -TEST_F(ClipboardTest, OverwriteTest) { - Clipboard clipboard; - - std::wstring text1(L"first string"), text2(L"second string"), text_result; - - clipboard.Clear(); - clipboard.WriteText(text1); - clipboard.WriteText(text2); - - EXPECT_TRUE(clipboard.IsFormatAvailable( - Clipboard::GetPlainTextWFormatType())); - clipboard.ReadText(&text_result); - EXPECT_EQ(text2, text_result); -} - TEST_F(ClipboardTest, HTMLTest) { Clipboard clipboard; - std::wstring markup(L"<strong>Hi!</string>"), markup_result; + std::wstring markup(L"<string>Hi!</string>"), markup_result; std::string url("http://www.example.com/"), url_result; - clipboard.Clear(); - clipboard.WriteHTML(markup, url); + { + ScopedClipboardWriter scw(&clipboard); + scw.WriteHTML(markup, url); + } + EXPECT_EQ(true, clipboard.IsFormatAvailable( Clipboard::GetHtmlFormatType())); clipboard.ReadHTML(&markup_result, &url_result); @@ -82,8 +81,11 @@ TEST_F(ClipboardTest, TrickyHTMLTest) { std::wstring markup(L"<em>Bye!<!--EndFragment --></em>"), markup_result; std::string url, url_result; - clipboard.Clear(); - clipboard.WriteHTML(markup, url); + { + ScopedClipboardWriter scw(&clipboard); + scw.WriteHTML(markup, url); + } + EXPECT_EQ(true, clipboard.IsFormatAvailable( Clipboard::GetHtmlFormatType())); clipboard.ReadHTML(&markup_result, &url_result); @@ -103,8 +105,11 @@ TEST_F(ClipboardTest, BookmarkTest) { std::wstring title(L"The Example Company"), title_result; std::string url("http://www.example.com/"), url_result; - clipboard.Clear(); - clipboard.WriteBookmark(title, url); + { + ScopedClipboardWriter scw(&clipboard); + scw.WriteBookmark(title, url); + } + EXPECT_EQ(true, clipboard.IsFormatAvailable(Clipboard::GetUrlWFormatType())); clipboard.ReadBookmark(&title_result, &url_result); @@ -121,9 +126,12 @@ TEST_F(ClipboardTest, MultiFormatTest) { std::string url("http://www.example.com/"), url_result; std::string ascii_text; - clipboard.Clear(); - clipboard.WriteHTML(markup, url); - clipboard.WriteText(text); + { + ScopedClipboardWriter scw(&clipboard); + scw.WriteHTML(markup, url); + scw.WriteText(text); + } + EXPECT_EQ(true, clipboard.IsFormatAvailable(Clipboard::GetHtmlFormatType())); EXPECT_EQ(true, clipboard.IsFormatAvailable( @@ -149,7 +157,6 @@ TEST_F(ClipboardTest, MultiFormatTest) { // don't try to use a non-existent file you've retrieved from the clipboard. TEST_F(ClipboardTest, FileTest) { Clipboard clipboard; - clipboard.Clear(); #if defined(OS_WIN) std::wstring file = L"C:\\Downloads\\My Downloads\\A Special File.txt"; #else @@ -157,7 +164,12 @@ TEST_F(ClipboardTest, FileTest) { // clipboard. std::wstring file = L"/usr/bin/make"; #endif - clipboard.WriteFile(file); + + { + ScopedClipboardWriter scw(&clipboard); + scw.WriteFile(file); + } + std::wstring out_file; clipboard.ReadFile(&out_file); EXPECT_EQ(file, out_file); @@ -165,8 +177,7 @@ TEST_F(ClipboardTest, FileTest) { TEST_F(ClipboardTest, MultipleFilesTest) { Clipboard clipboard; - clipboard.Clear(); - + #if defined(OS_WIN) std::wstring file1 = L"C:\\Downloads\\My Downloads\\File 1.exe"; std::wstring file2 = L"C:\\Downloads\\My Downloads\\File 2.pdf"; @@ -182,7 +193,11 @@ TEST_F(ClipboardTest, MultipleFilesTest) { files.push_back(file1); files.push_back(file2); files.push_back(file3); - clipboard.WriteFiles(files); + + { + ScopedClipboardWriter scw(&clipboard); + scw.WriteFiles(files); + } std::vector<std::wstring> out_files; clipboard.ReadFiles(&out_files); @@ -196,14 +211,17 @@ TEST_F(ClipboardTest, MultipleFilesTest) { #if defined(OS_WIN) // Windows only tests. TEST_F(ClipboardTest, HyperlinkTest) { Clipboard clipboard; - + std::wstring title(L"The Example Company"), title_result; std::string url("http://www.example.com/"), url_result; std::wstring html(L"<a href=\"http://www.example.com/\">" L"The Example Company</a>"), html_result; - - clipboard.Clear(); - clipboard.WriteHyperlink(title, url); + + { + ScopedClipboardWriter scw(&clipboard); + scw.WriteHyperlink(title, url); + } + EXPECT_EQ(true, clipboard.IsFormatAvailable(Clipboard::GetUrlWFormatType())); EXPECT_EQ(true, @@ -219,8 +237,11 @@ TEST_F(ClipboardTest, HyperlinkTest) { TEST_F(ClipboardTest, WebSmartPasteTest) { Clipboard clipboard; - clipboard.Clear(); - clipboard.WriteWebSmartPaste(); + { + ScopedClipboardWriter scw(&clipboard); + scw.WriteWebSmartPaste(); + } + EXPECT_EQ(true, clipboard.IsFormatAvailable( Clipboard::GetWebKitSmartPasteFormatType())); } @@ -234,8 +255,11 @@ TEST_F(ClipboardTest, BitmapTest) { Clipboard clipboard; - clipboard.Clear(); - clipboard.WriteBitmap(fake_bitmap, gfx::Size(3, 4)); + { + ScopedClipboardWriter scw(&clipboard); + scw.WriteBitmapFromPixels(fake_bitmap, gfx::Size(3, 4)); + } + EXPECT_EQ(true, clipboard.IsFormatAvailable( Clipboard::GetBitmapFormatType())); } diff --git a/base/clipboard_win.cc b/base/clipboard_win.cc index c22f2a0..d8581cc 100644 --- a/base/clipboard_win.cc +++ b/base/clipboard_win.cc @@ -149,82 +149,94 @@ Clipboard::~Clipboard() { clipboard_owner_ = NULL; } -void Clipboard::Clear() { - // Acquire the clipboard. +void Clipboard::WriteObjects(const ObjectMap& objects) { + WriteObjects(objects, NULL); +} + +void Clipboard::WriteObjects(const ObjectMap& objects, ProcessHandle process) { ClipboardLock lock; if (!lock.Acquire(clipboard_owner_)) return; ::EmptyClipboard(); -} -void Clipboard::WriteText(const std::wstring& text) { - ClipboardLock lock; - if (!lock.Acquire(clipboard_owner_)) - return; + 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) { + std::wstring text; + UTF8ToWide(text_data, text_len, &text); HGLOBAL glob = CreateGlobalData(text); - if (glob && !::SetClipboardData(CF_UNICODETEXT, glob)) - ::GlobalFree(glob); + + WriteToClipboard(CF_UNICODETEXT, glob); } -void Clipboard::WriteHTML(const std::wstring& markup, - const std::string& url) { - // Acquire the clipboard. - ClipboardLock lock; - if (!lock.Acquire(clipboard_owner_)) - return; +void Clipboard::WriteHTML(const char* markup_data, + size_t markup_len, + const char* url_data, + size_t url_len) { + std::string html_fragment, + markup(markup_data, markup_len), + url; + + if (url_len > 0) + url.assign(url_data, url_len); - std::string html_fragment; MarkupToHTMLClipboardFormat(markup, url, &html_fragment); HGLOBAL glob = CreateGlobalData(html_fragment); - if (glob && !::SetClipboardData(GetHtmlFormatType(), glob)) { - ::GlobalFree(glob); - } -} -void Clipboard::WriteBookmark(const std::wstring& title, - const std::string& url) { - // Acquire the clipboard. - ClipboardLock lock; - if (!lock.Acquire(clipboard_owner_)) - return; + WriteToClipboard(GetHtmlFormatType(), glob); +} - std::wstring bookmark(title); +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(UTF8ToWide(url)); - HGLOBAL glob = CreateGlobalData(bookmark); - if (glob && !::SetClipboardData(GetUrlWFormatType(), glob)) { - ::GlobalFree(glob); - } + bookmark.append(url_data, url_len); + + std::wstring wide_bookmark = UTF8ToWide(bookmark); + HGLOBAL glob = CreateGlobalData(wide_bookmark); + + WriteToClipboard(GetUrlWFormatType(), glob); } -void Clipboard::WriteHyperlink(const std::wstring& title, - const std::string& url) { - // Write as a bookmark. - WriteBookmark(title, url); +void Clipboard::WriteHyperlink(const char* title_data, + size_t title_len, + const char* url_data, + size_t url_len) { + // Store as a bookmark. + WriteBookmark(title_data, title_len, url_data, url_len); + + std::string title(title_data, title_len), + url(url_data, url_len), + link("<a href=\""); - // Build the HTML link. - std::wstring link(L"<a href=\""); - link.append(UTF8ToWide(url)); - link.append(L"\">"); + // Construct the hyperlink. + link.append(url); + link.append("\">"); link.append(title); - link.append(L"</a>"); + link.append("</a>"); - // Write as an HTML link. - WriteHTML(link, std::string()); + // Store hyperlink as html. + WriteHTML(link.c_str(), link.size(), NULL, 0); } void Clipboard::WriteWebSmartPaste() { - // Acquire the clipboard. - ClipboardLock lock; - if (!lock.Acquire(clipboard_owner_)) - return; - - SetClipboardData(GetWebKitSmartPasteFormatType(), NULL); + ::SetClipboardData(GetWebKitSmartPasteFormatType(), NULL); } -void Clipboard::WriteBitmap(const void* pixels, const gfx::Size& size) { +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 @@ -234,8 +246,8 @@ void Clipboard::WriteBitmap(const void* pixels, const gfx::Size& size) { // 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.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; @@ -249,23 +261,30 @@ void Clipboard::WriteBitmap(const void* pixels, const gfx::Size& size) { if (bits && source_hbitmap) { // Copy the bitmap out of shared memory and into GDI - memcpy(bits, pixels, 4 * size.width() * size.height()); + 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); + WriteBitmapFromHandle(source_hbitmap, *size); } ::DeleteObject(source_hbitmap); ::ReleaseDC(NULL, dc); } -void Clipboard::WriteBitmapFromSharedMemory(const SharedMemory& bitmap, - const gfx::Size& size) { +void Clipboard::WriteBitmapFromSharedMemory(const char* bitmap_data, + const char* size_data, + ProcessHandle process) { + const SharedMemoryHandle* remote_bitmap_handle = + reinterpret_cast<const SharedMemoryHandle*>(bitmap_data); + const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data); + + SharedMemory bitmap(*remote_bitmap_handle, false, process); + // 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 the vertical orientation + bm_info.bmiHeader.biWidth = size->width(); + bm_info.bmiHeader.biHeight = -size->height(); // Sets the vertical orientation bm_info.bmiHeader.biPlanes = 1; bm_info.bmiHeader.biBitCount = 32; bm_info.bmiHeader.biCompression = BI_RGB; @@ -275,11 +294,12 @@ void Clipboard::WriteBitmapFromSharedMemory(const SharedMemory& bitmap, // 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); + ::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); + WriteBitmapFromHandle(source_hbitmap, *size); } ::DeleteObject(source_hbitmap); @@ -288,11 +308,6 @@ void Clipboard::WriteBitmapFromSharedMemory(const SharedMemory& bitmap, void Clipboard::WriteBitmapFromHandle(HBITMAP source_hbitmap, const gfx::Size& size) { - // Acquire the clipboard. - ClipboardLock lock; - if (!lock.Acquire(clipboard_owner_)) - return; - // 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 @@ -329,52 +344,37 @@ void Clipboard::WriteBitmapFromHandle(HBITMAP source_hbitmap, ::DeleteDC(source_dc); ::ReleaseDC(NULL, dc); - // Actually write the bitmap to the clipboard - ::SetClipboardData(CF_BITMAP, hbitmap); + 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::WriteFile(const std::wstring& file) { - std::vector<std::wstring> files; - files.push_back(file); - WriteFiles(files); -} - -void Clipboard::WriteFiles(const std::vector<std::wstring>& files) { - ClipboardLock lock; - if (!lock.Acquire(clipboard_owner_)) - return; - - // Calculate the amount of space we'll need store the strings: require - // NULL terminator between strings, and double null terminator at the end. - size_t bytes = sizeof(DROPFILES); - for (size_t i = 0; i < files.size(); ++i) - bytes += (files[i].length() + 1) * sizeof(wchar_t); - bytes += sizeof(wchar_t); +void Clipboard::WriteFiles(const char* file_data, size_t file_len) { + std::wstring filenames(UTF8ToWide(std::string(file_data, file_len))); + // Calculate the amount of space we'll need store the strings and + // a DROPFILES struct. + size_t bytes = sizeof(DROPFILES) + filenames.length() * sizeof(wchar_t); HANDLE hdata = ::GlobalAlloc(GMEM_MOVEABLE, bytes); if (!hdata) return; - DROPFILES* drop_files = static_cast<DROPFILES*>(::GlobalLock(hdata)); + char* data = static_cast<char*>(::GlobalLock(hdata)); + DROPFILES* drop_files = reinterpret_cast<DROPFILES*>(data); drop_files->pFiles = sizeof(DROPFILES); drop_files->fWide = TRUE; - BYTE* data = reinterpret_cast<BYTE*>(drop_files) + sizeof(DROPFILES); - - // Copy the strings stored in 'files' with proper NULL separation. - wchar_t* data_pos = reinterpret_cast<wchar_t*>(data); - for (size_t i = 0; i < files.size(); ++i) { - size_t offset = files[i].length() + 1; - memcpy(data_pos, files[i].c_str(), offset * sizeof(wchar_t)); - data_pos += offset; - } - data_pos[0] = L'\0'; // Double NULL termination after the last string. + + memcpy(data + sizeof DROPFILES, filenames.c_str(), + filenames.length() * sizeof(wchar_t)); ::GlobalUnlock(hdata); - if (!::SetClipboardData(CF_HDROP, hdata)) - ::GlobalFree(hdata); + WriteToClipboard(CF_HDROP, hdata); +} + +void Clipboard::WriteToClipboard(FormatType format, HANDLE handle) { + if (handle && !::SetClipboardData(format, handle)) + FreeData(format, handle); } bool Clipboard::IsFormatAvailable(unsigned int format) const { @@ -514,7 +514,7 @@ void Clipboard::ReadFiles(std::vector<std::wstring>* files) const { } // static -void Clipboard::MarkupToHTMLClipboardFormat(const std::wstring& markup, +void Clipboard::MarkupToHTMLClipboardFormat(const std::string& markup, const std::string& src_url, std::string* html_fragment) { DCHECK(html_fragment); @@ -526,8 +526,6 @@ void Clipboard::MarkupToHTMLClipboardFormat(const std::wstring& markup, return; } - std::string markup_utf8 = WideToUTF8(markup); - html_fragment->assign("Version:0.9"); std::string start_html("\nStartHTML:"); @@ -557,7 +555,7 @@ void Clipboard::MarkupToHTMLClipboardFormat(const std::wstring& markup, (4*kMaxDigits); start_fragment_offset = start_html_offset + start_markup.length(); - end_fragment_offset = start_fragment_offset + markup_utf8.length(); + end_fragment_offset = start_fragment_offset + markup.length(); end_html_offset = end_fragment_offset + end_markup.length(); // fill in needed data @@ -565,7 +563,7 @@ void Clipboard::MarkupToHTMLClipboardFormat(const std::wstring& markup, end_html.append(StringPrintf("%010u", end_html_offset)); start_fragment.append(StringPrintf("%010u", start_fragment_offset)); end_fragment.append(StringPrintf("%010u", end_fragment_offset)); - start_markup.append(markup_utf8); + start_markup.append(markup); // create full html_fragment string from the fragments html_fragment->append(start_html); @@ -702,3 +700,10 @@ Clipboard::FormatType Clipboard::GetWebKitSmartPasteFormatType() { return ClipboardUtil::GetWebKitSmartPasteFormat()->cfFormat; } +// static +void Clipboard::FreeData(FormatType format, HANDLE data) { + if (format == CF_BITMAP) + ::DeleteObject(static_cast<HBITMAP>(data)); + else + ::GlobalFree(data); +} diff --git a/base/scoped_clipboard_writer.cc b/base/scoped_clipboard_writer.cc new file mode 100644 index 0000000..a570981 --- /dev/null +++ b/base/scoped_clipboard_writer.cc @@ -0,0 +1,130 @@ +// 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. + +#include "base/scoped_clipboard_writer.h" + +#include "base/clipboard.h" +#include "base/string_util.h" + +ScopedClipboardWriter::ScopedClipboardWriter(Clipboard* clipboard) + : clipboard_(clipboard) { +} + +ScopedClipboardWriter::~ScopedClipboardWriter() { + if (!objects_.empty() && clipboard_) + clipboard_->WriteObjects(objects_); +} + +void ScopedClipboardWriter::WriteText(const std::wstring& text) { + if (text.empty()) + return; + + std::string utf8_text = WideToUTF8(text); + + Clipboard::ObjectMapParams params; + params.push_back(Clipboard::ObjectMapParam(utf8_text.begin(), + utf8_text.end())); + objects_[Clipboard::CBF_TEXT] = params; +} + +void ScopedClipboardWriter::WriteHTML(const std::wstring& markup, + const std::string& src_url) { + if (markup.empty()) + return; + + std::string utf8_markup = WideToUTF8(markup); + + Clipboard::ObjectMapParams params; + params.push_back( + Clipboard::ObjectMapParam(utf8_markup.begin(), + utf8_markup.end())); + if (!src_url.empty()) { + params.push_back(Clipboard::ObjectMapParam(src_url.begin(), + src_url.end())); + } + + objects_[Clipboard::CBF_HTML] = params; +} + +void ScopedClipboardWriter::WriteBookmark(const std::wstring& title, + const std::string& url) { + if (title.empty() || url.empty()) + return; + + std::string utf8_markup = WideToUTF8(title); + + Clipboard::ObjectMapParams params; + params.push_back(Clipboard::ObjectMapParam(utf8_markup.begin(), + utf8_markup.end())); + params.push_back(Clipboard::ObjectMapParam(url.begin(), url.end())); + objects_[Clipboard::CBF_BOOKMARK] = params; +} + +void ScopedClipboardWriter::WriteHyperlink(const std::wstring& title, + const std::string& url) { + if (title.empty() || url.empty()) + return; + + std::string utf8_markup = WideToUTF8(title); + + Clipboard::ObjectMapParams params; + params.push_back(Clipboard::ObjectMapParam(utf8_markup.begin(), + utf8_markup.end())); + params.push_back(Clipboard::ObjectMapParam(url.begin(), url.end())); + objects_[Clipboard::CBF_LINK] = params; +} + +void ScopedClipboardWriter::WriteFile(const std::wstring& file) { + WriteFiles(std::vector<std::wstring>(1, file)); +} + +// Save the filenames as a string separated by nulls and terminated with an +// extra null. +void ScopedClipboardWriter::WriteFiles(const std::vector<std::wstring>& files) { + if (files.empty()) + return; + + Clipboard::ObjectMapParam param; + + for (std::vector<std::wstring>::const_iterator iter = files.begin(); + iter != files.end(); ++iter) { + std::string filename = WideToUTF8(*iter); + for (std::string::const_iterator filename_iter = filename.begin(); + filename_iter != filename.end(); ++filename_iter) { + param.push_back(*filename_iter); + } + param.push_back('\0'); + } + + param.push_back('\0'); + + Clipboard::ObjectMapParams params; + params.push_back(param); + objects_[Clipboard::CBF_FILES] = params; +} + +#if defined(OS_WIN) +void ScopedClipboardWriter::WriteWebSmartPaste() { + objects_[Clipboard::CBF_WEBKIT] = Clipboard::ObjectMapParams(); +} + +void ScopedClipboardWriter::WriteBitmapFromPixels(const void* pixels, + const gfx::Size& size) { + Clipboard::ObjectMapParam param1, param2; + const char* pixels_data = reinterpret_cast<const char*>(pixels); + size_t pixels_len = 4 * size.width() * size.height(); + for (size_t i = 0; i < pixels_len; i++) + param1.push_back(pixels_data[i]); + + const char* size_data = reinterpret_cast<const char*>(&size); + size_t size_len = sizeof(gfx::Size); + for (size_t i = 0; i < size_len; i++) + param2.push_back(size_data[i]); + + Clipboard::ObjectMapParams params; + params.push_back(param1); + params.push_back(param2); + objects_[Clipboard::CBF_BITMAP] = params; +} +#endif // defined(OS_WIN) diff --git a/base/scoped_clipboard_writer.h b/base/scoped_clipboard_writer.h new file mode 100644 index 0000000..08a36fd --- /dev/null +++ b/base/scoped_clipboard_writer.h @@ -0,0 +1,62 @@ +// 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. + +#ifndef SCOPED_CLIPBOARD_WRITER_H_ +#define SCOPED_CLIPBOARD_WRITER_H_ + +#include "base/clipboard.h" + +#if defined(OS_WIN) +class SkBitmap; +#endif + +// This class is a wrapper for |Clipboard| that handles packing data +// into a Clipboard::ObjectMap. +// NB: You should probably NOT be using this class if you include +// webkit_glue.h. Use ScopedClipboardWriterGlue instead. +class ScopedClipboardWriter { + public: + // Create an instance that is a simple wrapper around clipboard. + ScopedClipboardWriter(Clipboard* clipboard); + + ~ScopedClipboardWriter(); + + // Adds UNICODE and ASCII text to the clipboard. + void WriteText(const std::wstring& text); + + // Adds HTML to the clipboard. The url parameter is optional, but especially + // useful if the HTML fragment contains relative links + void WriteHTML(const std::wstring& markup, const std::string& src_url); + + // Adds a bookmark to the clipboard + void WriteBookmark(const std::wstring& title, const std::string& url); + + // Adds both a bookmark and an HTML hyperlink to the clipboard. It is a + // convenience wrapper around WriteBookmark and WriteHTML. + void WriteHyperlink(const std::wstring& title, const std::string& url); + + // Adds a file or group of files to the clipboard. + void WriteFile(const std::wstring& file); + void WriteFiles(const std::vector<std::wstring>& files); + +#if defined(OS_WIN) + // Used by WebKit to determine whether WebKit wrote the clipboard last + void WriteWebSmartPaste(); + + // Adds a bitmap to the clipboard + // This is the slowest way to copy a bitmap to the clipboard as we must first + // memcpy the pixels into GDI and the blit the bitmap to the clipboard. + // Pixel format is assumed to be 32-bit BI_RGB. + void WriteBitmapFromPixels(const void* pixels, const gfx::Size& size); +#endif + + protected: + Clipboard::ObjectMap objects_; + Clipboard* clipboard_; + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedClipboardWriter); +}; + +#endif // SCOPED_CLIPBOARD_WRITER_H_ diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc index 5974b81..fa60973 100644 --- a/chrome/browser/autocomplete/autocomplete_edit.cc +++ b/chrome/browser/autocomplete/autocomplete_edit.cc @@ -11,6 +11,7 @@ #include "base/gfx/skia_utils.h" #include "base/iat_patch.h" #include "base/ref_counted.h" +#include "base/scoped_clipboard_writer.h" #include "base/string_util.h" #include "chrome/app/chrome_dll_resource.h" #include "chrome/browser/autocomplete/autocomplete_popup.h" @@ -1405,9 +1406,8 @@ void AutocompleteEditView::OnCopy() { if (text.empty()) return; - ClipboardService* clipboard = g_browser_process->clipboard_service(); - clipboard->Clear(); - clipboard->WriteText(text); + ScopedClipboardWriter scw(g_browser_process->clipboard_service()); + scw.WriteText(text); // Check if the user is copying the whole address bar. If they are, we // assume they are trying to copy a URL and write this to the clipboard as a @@ -1421,7 +1421,7 @@ void AutocompleteEditView::OnCopy() { // which will screw up our calculation of the desired_tld. GURL url; if (model_->GetURLForText(text, &url)) - clipboard->WriteHyperlink(text, url.spec()); + scw.WriteHyperlink(text, url.spec()); } void AutocompleteEditView::OnCut() { diff --git a/chrome/browser/download/download_util.cc b/chrome/browser/download/download_util.cc index f9040b3..262c507 100644 --- a/chrome/browser/download/download_util.cc +++ b/chrome/browser/download/download_util.cc @@ -10,6 +10,7 @@ #include "base/base_drag_source.h" #include "base/file_util.h" +#include "base/scoped_clipboard_writer.h" #include "base/gfx/image_operations.h" #include "base/string_util.h" #include "chrome/app/locales/locale_settings.h" @@ -105,24 +106,20 @@ bool BaseContextMenu::IsCommandEnabled(int id) const { } void BaseContextMenu::ExecuteCommand(int id) { - ClipboardService* clipboard = g_browser_process->clipboard_service(); - DCHECK(clipboard); + ScopedClipboardWriter scw(g_browser_process->clipboard_service()); switch (id) { case SHOW_IN_FOLDER: download_->manager()->ShowDownloadInShell(download_); break; case COPY_LINK: - clipboard->Clear(); - clipboard->WriteText(download_->url()); + scw.WriteText(download_->url()); break; case COPY_PATH: - clipboard->Clear(); - clipboard->WriteText(download_->full_path()); + scw.WriteText(download_->full_path()); break; case COPY_FILE: // TODO(paulg): Move to OSExchangeData when implementing drag and drop? - clipboard->Clear(); - clipboard->WriteFile(download_->full_path()); + scw.WriteFile(download_->full_path()); break; case OPEN_WHEN_COMPLETE: OpenDownload(download_); diff --git a/chrome/browser/render_view_context_menu_controller.cc b/chrome/browser/render_view_context_menu_controller.cc index f639b19..0e1b8f0 100644 --- a/chrome/browser/render_view_context_menu_controller.cc +++ b/chrome/browser/render_view_context_menu_controller.cc @@ -6,6 +6,7 @@ #include "base/command_line.h" #include "base/path_service.h" +#include "base/scoped_clipboard_writer.h" #include "base/string_util.h" #include "chrome/app/chrome_dll_resource.h" #include "chrome/common/chrome_paths.h" @@ -65,8 +66,8 @@ void RenderViewContextMenuController::WriteTextToClipboard( if (!clipboard) return; - clipboard->Clear(); - clipboard->WriteText(text); + ScopedClipboardWriter scw(clipboard); + scw.WriteText(text); } void RenderViewContextMenuController::WriteURLToClipboard(const GURL& url) { diff --git a/chrome/browser/resource_message_filter.cc b/chrome/browser/resource_message_filter.cc index 17c266b..2e25e92 100644 --- a/chrome/browser/resource_message_filter.cc +++ b/chrome/browser/resource_message_filter.cc @@ -4,6 +4,7 @@ #include "chrome/browser/resource_message_filter.h" +#include "base/clipboard.h" #include "base/histogram.h" #include "base/thread.h" #include "chrome/browser/chrome_plugin_browsing_context.h" @@ -125,22 +126,10 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ViewHostMsg_DnsPrefetch, OnDnsPrefetch) IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_PaintRect, render_widget_helper_->DidReceivePaintMsg(message)) - IPC_MESSAGE_FORWARD(ViewHostMsg_ClipboardClear, - static_cast<Clipboard*>(GetClipboardService()), - Clipboard::Clear) - IPC_MESSAGE_FORWARD(ViewHostMsg_ClipboardWriteText, - static_cast<Clipboard*>(GetClipboardService()), - Clipboard::WriteText) - IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteHTML, - OnClipboardWriteHTML) - IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteBookmark, - OnClipboardWriteBookmark) - // We need to do more work to marshall around bitmaps - IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteBitmap, - OnClipboardWriteBitmap) - IPC_MESSAGE_FORWARD(ViewHostMsg_ClipboardWriteWebSmartPaste, - static_cast<Clipboard*>(GetClipboardService()), - Clipboard::WriteWebSmartPaste) + IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsAsync, + OnClipboardWriteObjects) + IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsSync, + OnClipboardWriteObjects) IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardIsFormatAvailable, OnClipboardIsFormatAvailable) IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardReadText, OnClipboardReadText) @@ -431,26 +420,12 @@ void ResourceMessageFilter::OnDownloadUrl(const IPC::Message& message, request_context_); } -void ResourceMessageFilter::OnClipboardWriteHTML(const std::wstring& markup, - const GURL& src_url) { - GetClipboardService()->WriteHTML(markup, src_url.spec()); -} - -void ResourceMessageFilter::OnClipboardWriteBookmark(const std::wstring& title, - const GURL& url) { - GetClipboardService()->WriteBookmark(title, url.spec()); -} - -void ResourceMessageFilter::OnClipboardWriteBitmap( - SharedMemoryHandle bitmap_buf, gfx::Size size) { - // hbitmap here is only valid in the context of the renderer. We need to - // import it into our process using SharedMemory in order to get a handle - // that is valid. - // - // We need to ask for write permission to the shared memory in order to - // call WriteBitmapFromSharedMemory - SharedMemory shared_mem(bitmap_buf, false, render_handle_); - GetClipboardService()->WriteBitmapFromSharedMemory(shared_mem, size); +void ResourceMessageFilter::OnClipboardWriteObjects( + const Clipboard::ObjectMap& objects) { + // We pass the render_handle_ to assist the clipboard with using shared + // memory objects. render_handle_ is a handle to the process that would + // own any shared memory that might be in the object list. + GetClipboardService()->WriteObjects(objects, render_handle_); } void ResourceMessageFilter::OnClipboardIsFormatAvailable(unsigned int format, diff --git a/chrome/browser/resource_message_filter.h b/chrome/browser/resource_message_filter.h index 1ac4c15..7dd3513 100644 --- a/chrome/browser/resource_message_filter.h +++ b/chrome/browser/resource_message_filter.h @@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_RENDERER_RESOURCE_MSG_FILTER_H__ #define CHROME_BROWSER_RENDERER_RESOURCE_MSG_FILTER_H__ +#include "base/clipboard.h" #include "base/gfx/rect.h" #include "base/gfx/native_widget_types.h" #include "base/ref_counted.h" @@ -121,9 +122,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, void OnDnsPrefetch(const std::vector<std::string>& hostnames); void OnReceiveContextMenuMsg(const IPC::Message& msg); // Clipboard messages - void OnClipboardWriteHTML(const std::wstring& markup, const GURL& src_url); - void OnClipboardWriteBookmark(const std::wstring& title, const GURL& url); - void OnClipboardWriteBitmap(SharedMemoryHandle bitmap, gfx::Size size); + void OnClipboardWriteObjects(const Clipboard::ObjectMap& objects); void OnClipboardIsFormatAvailable(unsigned int format, bool* result); void OnClipboardReadText(std::wstring* result); void OnClipboardReadAsciiText(std::string* result); diff --git a/chrome/common/clipboard_service.cc b/chrome/common/clipboard_service.cc deleted file mode 100644 index a666c0c..0000000 --- a/chrome/common/clipboard_service.cc +++ /dev/null @@ -1,20 +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 "chrome/common/clipboard_service.h" - -#include "SkBitmap.h" - -ClipboardService::ClipboardService() { -} - -void ClipboardService::WriteBitmap(const SkBitmap& bitmap) { - SkAutoLockPixels bitmap_lock(bitmap); - Clipboard::WriteBitmap(bitmap.getPixels(), - gfx::Size(bitmap.width(), bitmap.height())); -} - diff --git a/chrome/common/clipboard_service.h b/chrome/common/clipboard_service.h index 7da0e0a..ed34afd 100644 --- a/chrome/common/clipboard_service.h +++ b/chrome/common/clipboard_service.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_COMMON_CLIPBOARD_SERIVCE_H__ -#define CHROME_COMMON_CLIPBOARD_SERIVCE_H__ +#ifndef CHROME_COMMON_CLIPBOARD_SERVICE_H__ +#define CHROME_COMMON_CLIPBOARD_SERVICE_H__ #include <string> #include <vector> @@ -14,17 +14,11 @@ class SkBitmap; class ClipboardService : public Clipboard { public: - ClipboardService(); - - // Adds a bitmap to the clipboard - // This is the slowest way to copy a bitmap to the clipboard as we must fist - // memcpy the bits into GDI and the blit the bitmap to the clipboard. - void WriteBitmap(const SkBitmap& bitmap); + ClipboardService() {} private: DISALLOW_EVIL_CONSTRUCTORS(ClipboardService); }; -#endif // CHROME_COMMON_CLIPBOARD_SERIVCE_H__ - +#endif // CHROME_COMMON_CLIPBOARD_SERVICE_H__ diff --git a/chrome/common/common.vcproj b/chrome/common/common.vcproj index 8bcb3ff..5359cfbd 100644 --- a/chrome/common/common.vcproj +++ b/chrome/common/common.vcproj @@ -390,10 +390,6 @@ > </File> <File - RelativePath=".\clipboard_service.cc" - > - </File> - <File RelativePath=".\clipboard_service.h" > </File> diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 61da8e7..ea97bc7 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/clipboard.h" #include "base/gfx/rect.h" #include "base/shared_memory.h" #include "chrome/common/ipc_message_macros.h" @@ -783,21 +784,15 @@ IPC_BEGIN_MESSAGES(ViewHost, 2) std::wstring /* plugin_path */) // Clipboard IPC messages - IPC_MESSAGE_CONTROL0(ViewHostMsg_ClipboardClear) - IPC_MESSAGE_CONTROL1(ViewHostMsg_ClipboardWriteText, - std::wstring /* text */) - IPC_MESSAGE_CONTROL2(ViewHostMsg_ClipboardWriteHTML, - std::wstring /* html */, - GURL /* url */) - IPC_MESSAGE_CONTROL2(ViewHostMsg_ClipboardWriteBookmark, - std::wstring /* title */, - GURL /* url */) - // This message is synchronized so that the renderer known when it is safe to + + // This message is used when the object list does not contain a bitmap. + IPC_MESSAGE_CONTROL1(ViewHostMsg_ClipboardWriteObjectsAsync, + Clipboard::ObjectMap /* objects */) + // This message is used when the object list contains a bitmap. + // It is synchronized so that the renderer knows when it is safe to // free the shared memory used to transfer the bitmap. - IPC_SYNC_MESSAGE_CONTROL2_0(ViewHostMsg_ClipboardWriteBitmap, - SharedMemoryHandle /* bitmap */, - gfx::Size /* size */) - IPC_MESSAGE_CONTROL0(ViewHostMsg_ClipboardWriteWebSmartPaste) + IPC_SYNC_MESSAGE_CONTROL1_0(ViewHostMsg_ClipboardWriteObjectsSync, + Clipboard::ObjectMap /* objects */) IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_ClipboardIsFormatAvailable, int /* format */, bool /* result */) diff --git a/chrome/renderer/renderer_glue.cc b/chrome/renderer/renderer_glue.cc index 83e5b95..297e5ac 100644 --- a/chrome/renderer/renderer_glue.cc +++ b/chrome/renderer/renderer_glue.cc @@ -7,6 +7,8 @@ #include <windows.h> #include <wininet.h> +#include "base/clipboard.h" +#include "base/scoped_clipboard_writer.h" #include "chrome/renderer/net/render_dns_master.h" #include "chrome/common/resource_bundle.h" #include "chrome/plugin/npobject_util.h" @@ -14,9 +16,12 @@ #include "chrome/renderer/visitedlink_slave.h" #include "googleurl/src/url_util.h" #include "net/base/mime_util.h" +#include "webkit/glue/scoped_clipboard_writer_glue.h" #include "webkit/glue/webframe.h" #include "webkit/glue/webkit_glue.h" +#include <vector> + #include "SkBitmap.h" #include <strsafe.h> // note: per msdn docs, this must *follow* other includes @@ -66,6 +71,66 @@ class ResizableStackArray { size_t cur_capacity_; }; +#if defined(OS_WIN) +// This definition of WriteBitmap uses shared memory to communicate across +// processes. +void ScopedClipboardWriterGlue::WriteBitmap(const SkBitmap& bitmap) { + // do not try to write a bitmap more than once + if (shared_buf_) + return; + + size_t buf_size = bitmap.getSize(); + gfx::Size size(bitmap.width(), bitmap.height()); + + // Allocate a shared memory buffer to hold the bitmap bits + shared_buf_ = RenderProcess::AllocSharedMemory(buf_size); + if (!shared_buf_ || !shared_buf_->Map(buf_size)) { + NOTREACHED(); + return; + } + + // Copy the bits into shared memory + SkAutoLockPixels bitmap_lock(bitmap); + memcpy(shared_buf_->memory(), bitmap.getPixels(), buf_size); + shared_buf_->Unmap(); + + Clipboard::ObjectMapParam param1, param2; + SharedMemoryHandle smh = shared_buf_->handle(); + + const char* shared_handle = reinterpret_cast<const char*>(&smh); + for (size_t i = 0; i < sizeof SharedMemoryHandle; i++) + param1.push_back(shared_handle[i]); + + const char* size_data = reinterpret_cast<const char*>(&size); + for (size_t i = 0; i < sizeof gfx::Size; i++) + param2.push_back(size_data[i]); + + Clipboard::ObjectMapParams params; + params.push_back(param1); + params.push_back(param2); + objects_[Clipboard::CBF_SMBITMAP] = params; +} +#endif + +// Define a destructor that makes IPCs to flush the contents to the +// system clipboard. +ScopedClipboardWriterGlue::~ScopedClipboardWriterGlue() { + if (objects_.empty()) + return; + +#if defined(OS_WIN) + if (shared_buf_) { + RenderThread::current()->Send( + new ViewHostMsg_ClipboardWriteObjectsSync(objects_)); + RenderProcess::FreeSharedMemory(shared_buf_); + return; + } +#endif + + RenderThread::current()->Send( + new ViewHostMsg_ClipboardWriteObjectsAsync(objects_)); +} + namespace webkit_glue { void PrefetchDns(const std::string& hostname) { @@ -141,58 +206,8 @@ HCURSOR webkit_glue::LoadCursor(int cursor_id) { // Clipboard glue -void webkit_glue::ClipboardClear() { - RenderThread::current()->Send(new ViewHostMsg_ClipboardClear()); -} - -void webkit_glue::ClipboardWriteText(const std::wstring& text) { - RenderThread::current()->Send(new ViewHostMsg_ClipboardWriteText(text)); -} - -void webkit_glue::ClipboardWriteHTML(const std::wstring& html, - const GURL& url) { - RenderThread::current()->Send(new ViewHostMsg_ClipboardWriteHTML(html, url)); -} - -void webkit_glue::ClipboardWriteBookmark(const std::wstring& title, - const GURL& url) { - RenderThread::current()->Send( - new ViewHostMsg_ClipboardWriteBookmark(title, url)); -} - -// Here we need to do some work to marshal the bitmap through shared memory -void webkit_glue::ClipboardWriteBitmap(const SkBitmap& bitmap) { - size_t buf_size = bitmap.getSize(); - gfx::Size size(bitmap.width(), bitmap.height()); - - // Allocate a shared memory buffer to hold the bitmap bits - SharedMemory* shared_buf = - RenderProcess::AllocSharedMemory(buf_size); - if (!shared_buf) { - NOTREACHED(); - return; - } - if (!shared_buf->Map(buf_size)) { - NOTREACHED(); - return; - } - - // Copy the bits into shared memory - SkAutoLockPixels bitmap_lock(bitmap); - memcpy(shared_buf->memory(), bitmap.getPixels(), buf_size); - shared_buf->Unmap(); - - // Send the handle over synchronous IPC - RenderThread::current()->Send( - new ViewHostMsg_ClipboardWriteBitmap(shared_buf->handle(), size)); - - // The browser should be done with the bitmap now. It's our job to free - // the shared memory. - RenderProcess::FreeSharedMemory(shared_buf); -} - -void webkit_glue::ClipboardWriteWebSmartPaste() { - RenderThread::current()->Send(new ViewHostMsg_ClipboardWriteWebSmartPaste()); +Clipboard* webkit_glue::ClipboardGetClipboard(){ + return NULL; } bool webkit_glue::ClipboardIsFormatAvailable(unsigned int format) { diff --git a/chrome/views/text_field.cc b/chrome/views/text_field.cc index baa70a1..c36fdbb 100644 --- a/chrome/views/text_field.cc +++ b/chrome/views/text_field.cc @@ -12,6 +12,7 @@ #include <vsstyle.h> #include "base/gfx/native_theme.h" +#include "base/scoped_clipboard_writer.h" #include "base/string_util.h" #include "base/win_util.h" #include "chrome/browser/browser_process.h" @@ -371,10 +372,8 @@ void TextField::Edit::OnCopy() { const std::wstring text(GetSelectedText()); if (!text.empty()) { - ClipboardService* clipboard = g_browser_process->clipboard_service(); - - clipboard->Clear(); - clipboard->WriteText(text); + ScopedClipboardWriter scw(g_browser_process->clipboard_service()); + scw.WriteText(text); } } diff --git a/webkit/build/glue/glue.vcproj b/webkit/build/glue/glue.vcproj index 784de66..28fe820 100644 --- a/webkit/build/glue/glue.vcproj +++ b/webkit/build/glue/glue.vcproj @@ -481,6 +481,10 @@ > </File> <File + RelativePath="..\..\glue\scoped_clipboard_writer_glue.h" + > + </File> + <File RelativePath="..\..\glue\searchable_form_data.cc" > </File> diff --git a/webkit/glue/scoped_clipboard_writer_glue.h b/webkit/glue/scoped_clipboard_writer_glue.h new file mode 100644 index 0000000..5a3ecb5 --- /dev/null +++ b/webkit/glue/scoped_clipboard_writer_glue.h @@ -0,0 +1,29 @@ +// 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. + +#ifndef SCOPED_CLIPBOARD_WRITER_GLUE_H__ +#define SCOPED_CLIPBOARD_WRITER_GLUE_H__ + +#include "base/clipboard.h" +#include "base/scoped_clipboard_writer.h" + +class ScopedClipboardWriterGlue : public ScopedClipboardWriter { + public: + ScopedClipboardWriterGlue(Clipboard* clipboard) + : ScopedClipboardWriter(clipboard), + shared_buf_(NULL) { + } + + ~ScopedClipboardWriterGlue(); + +#if defined(OS_WIN) + void ScopedClipboardWriterGlue::WriteBitmap(const SkBitmap& bitmap); +#endif + + private: + SharedMemory* shared_buf_; + DISALLOW_COPY_AND_ASSIGN(ScopedClipboardWriterGlue); +}; + +#endif // SCOPED_CLIPBOARD_WRITER_GLUE_H__ diff --git a/webkit/glue/simple_clipboard_impl.cc b/webkit/glue/simple_clipboard_impl.cc index e332a47..b60a36808 100644 --- a/webkit/glue/simple_clipboard_impl.cc +++ b/webkit/glue/simple_clipboard_impl.cc @@ -7,46 +7,32 @@ #include <string> #include "base/clipboard.h" +#include "webkit/glue/scoped_clipboard_writer_glue.h" #include "googleurl/src/gurl.h" #include "SkBitmap.h" // Clipboard glue -// Basically just proxy the calls off to the clipboard -namespace webkit_glue { - -Clipboard clipboard; - -void ClipboardClear() { - clipboard.Clear(); -} - -void ClipboardWriteText(const std::wstring& text) { - clipboard.WriteText(text); +#if defined(OS_WIN) +// The call is being made within the current process. +void ScopedClipboardWriterGlue::WriteBitmap(const SkBitmap& bitmap) { + SkAutoLockPixels bitmap_lock(bitmap); + WriteBitmapFromPixels(bitmap.getPixels(), gfx::Size(bitmap.width(), + bitmap.height())); } +#endif // defined(OS_WIN) -void ClipboardWriteHTML(const std::wstring& html, - const GURL& url) { - clipboard.WriteHTML(html, url.spec()); +ScopedClipboardWriterGlue::~ScopedClipboardWriterGlue() { } -void ClipboardWriteBookmark(const std::wstring& title, - const GURL& url) { - clipboard.WriteBookmark(title, url.spec()); -} +namespace webkit_glue { -#if defined(OS_WIN) -void ClipboardWriteBitmap(const SkBitmap& bitmap) { - SkAutoLockPixels bitmap_lock(bitmap); - clipboard.WriteBitmap(bitmap.getPixels(), - gfx::Size(bitmap.width(), bitmap.height())); -} +Clipboard clipboard; -void ClipboardWriteWebSmartPaste() { - clipboard.WriteWebSmartPaste(); +Clipboard* ClipboardGetClipboard() { + return &clipboard; } -#endif bool ClipboardIsFormatAvailable(Clipboard::FormatType format) { return clipboard.IsFormatAvailable(format); @@ -68,4 +54,3 @@ void ClipboardReadHTML(std::wstring* markup, GURL* url) { } } // namespace webkit_glue - diff --git a/webkit/glue/webkit_glue.h b/webkit/glue/webkit_glue.h index b8b2156..2691b25 100644 --- a/webkit/glue/webkit_glue.h +++ b/webkit/glue/webkit_glue.h @@ -42,6 +42,7 @@ class Frame; } class SkBitmap; +class Clipboard; #if defined(OS_MACOSX) typedef struct CGImage* CGImageRef; @@ -194,25 +195,8 @@ HCURSOR LoadCursor(int cursor_id); // Glue to access the clipboard. -// Clear the clipboard. It is usually a good idea to clear the clipboard -// before writing content to the clipboard. -void ClipboardClear(); - -// Adds UNICODE and ASCII text to the clipboard. -void ClipboardWriteText(const std::wstring& text); - -// Adds HTML to the clipboard. The url parameter is optional, but especially -// useful if the HTML fragment contains relative links -void ClipboardWriteHTML(const std::wstring& html, const GURL& url); - -// Adds a bookmark to the clipboard -void ClipboardWriteBookmark(const std::wstring& title, const GURL& url); - -// Adds a bitmap to the clipboard -void ClipboardWriteBitmap(const SkBitmap& bitmap); - -// Used by WebKit to determine whether WebKit wrote the clipboard last -void ClipboardWriteWebSmartPaste(); +// Get a clipboard that can be used to construct a ScopedClipboardWriterGlue. +Clipboard* ClipboardGetClipboard(); // Tests whether the clipboard contains a certain format bool ClipboardIsFormatAvailable(unsigned int format); diff --git a/webkit/port/platform/win/PasteboardWin.cpp b/webkit/port/platform/win/PasteboardWin.cpp index f22b85f..3063dc9 100644 --- a/webkit/port/platform/win/PasteboardWin.cpp +++ b/webkit/port/platform/win/PasteboardWin.cpp @@ -45,6 +45,7 @@ #include "base/clipboard_util.h" #include "webkit/glue/glue_util.h" +#include "webkit/glue/scoped_clipboard_writer_glue.h" #include "webkit/glue/webkit_glue.h" namespace WebCore { @@ -70,36 +71,35 @@ Pasteboard::Pasteboard() void Pasteboard::clear() { - webkit_glue::ClipboardClear(); + // The ScopedClipboardWriter class takes care of clearing the clipboard's + // previous contents. } void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) { - clear(); + ScopedClipboardWriterGlue scw(webkit_glue::ClipboardGetClipboard()); ExceptionCode ec = 0; - webkit_glue::ClipboardWriteHTML( + scw.WriteHTML( webkit_glue::StringToStdWString( createMarkup(selectedRange, 0, AnnotateForInterchange)), GURL(webkit_glue::StringToStdWString( - selectedRange->startContainer(ec)->document()->url()))); + selectedRange->startContainer(ec)->document()->url())).spec()); // Put plain string on the pasteboard. CF_UNICODETEXT covers CF_TEXT as well String str = frame->selectedText(); replaceNewlinesWithWindowsStyleNewlines(str); replaceNBSPWithSpace(str); - webkit_glue::ClipboardWriteText(webkit_glue::StringToStdWString(str)); + scw.WriteText(webkit_glue::StringToStdWString(str)); if (canSmartCopyOrDelete) - webkit_glue::ClipboardWriteWebSmartPaste(); + scw.WriteWebSmartPaste(); } void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame) { ASSERT(!url.isEmpty()); - clear(); - String title(titleStr); if (title.isEmpty()) { title = url.lastPathComponent(); @@ -107,17 +107,19 @@ void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame) title = url.host(); } + ScopedClipboardWriterGlue scw(webkit_glue::ClipboardGetClipboard()); + // write to clipboard in format com.apple.safari.bookmarkdata to be able to paste into the bookmarks view with appropriate title - webkit_glue::ClipboardWriteBookmark(webkit_glue::StringToStdWString(titleStr), - webkit_glue::KURLToGURL(url)); + scw.WriteBookmark(webkit_glue::StringToStdWString(titleStr), + webkit_glue::KURLToGURL(url).spec()); // write to clipboard in format CF_HTML to be able to paste into contenteditable areas as a link std::wstring link(webkit_glue::StringToStdWString(urlToMarkup(url, title))); - webkit_glue::ClipboardWriteHTML(link, GURL()); + scw.WriteHTML(link, GURL().spec()); // bare-bones CF_UNICODETEXT support std::wstring spec(webkit_glue::StringToStdWString(url)); - webkit_glue::ClipboardWriteText(spec); + scw.WriteText(spec); } void Pasteboard::writeImage(Node* node, const KURL& url, const String& title) @@ -129,24 +131,23 @@ void Pasteboard::writeImage(Node* node, const KURL& url, const String& title) Image* image = cachedImage->image(); ASSERT(image); - clear(); NativeImageSkia* bitmap = image->nativeImageForCurrentFrame(); + ScopedClipboardWriterGlue scw(webkit_glue::ClipboardGetClipboard()); + if (bitmap) - webkit_glue::ClipboardWriteBitmap(*bitmap); + scw.WriteBitmap(*bitmap); if (!url.isEmpty()) { - webkit_glue::ClipboardWriteBookmark(webkit_glue::StringToStdWString(title), - webkit_glue::KURLToGURL(url)); // write to clipboard in format com.apple.safari.bookmarkdata to be able to paste into the bookmarks view with appropriate title - webkit_glue::ClipboardWriteBookmark(webkit_glue::StringToStdWString(title), - webkit_glue::KURLToGURL(url)); + scw.WriteBookmark(webkit_glue::StringToStdWString(title), + webkit_glue::KURLToGURL(url).spec()); // write to clipboard in format CF_HTML to be able to paste into contenteditable areas as a an image std::wstring markup(webkit_glue::StringToStdWString(urlToImageMarkup(url, title))); - webkit_glue::ClipboardWriteHTML(markup, GURL()); + scw.WriteHTML(markup, GURL().spec()); // bare-bones CF_UNICODETEXT support std::wstring spec(webkit_glue::StringToStdWString(url.string())); - webkit_glue::ClipboardWriteText(spec); + scw.WriteText(spec); } } |