diff options
-rw-r--r-- | base/clipboard_linux.cc | 67 | ||||
-rwxr-xr-x | base/gfx/gtk_util.cc | 31 | ||||
-rwxr-xr-x | base/gfx/gtk_util.h | 9 |
3 files changed, 68 insertions, 39 deletions
diff --git a/base/clipboard_linux.cc b/base/clipboard_linux.cc index 26228ad..4d52038 100644 --- a/base/clipboard_linux.cc +++ b/base/clipboard_linux.cc @@ -10,12 +10,12 @@ #include <string> #include <utility> -#include "base/gfx/png_encoder.h" +#include "base/gfx/gtk_util.h" #include "base/string_util.h" namespace { -const char* kMimePng = "image/png"; +const char* kMimeBmp = "image/bmp"; const char* kMimeHtml = "text/html"; const char* kMimeText = "text/plain"; const char* kMimeWebkitSmartPaste = "chromium-internal/webkit-paste"; @@ -40,15 +40,20 @@ void GetData(GtkClipboard* clipboard, Clipboard::TargetMap* data_map = reinterpret_cast<Clipboard::TargetMap*>(user_data); - Clipboard::TargetMap::iterator iter = - data_map->find(GdkAtomToString(selection_data->target)); + std::string target_string = GdkAtomToString(selection_data->target); + Clipboard::TargetMap::iterator iter = data_map->find(target_string); if (iter == data_map->end()) return; - gtk_selection_data_set(selection_data, selection_data->target, 8, - reinterpret_cast<guchar*>(iter->second.first), - iter->second.second); + if (target_string == kMimeBmp) { + gtk_selection_data_set_pixbuf(selection_data, + reinterpret_cast<GdkPixbuf*>(iter->second.first)); + } else { + gtk_selection_data_set(selection_data, selection_data->target, 8, + reinterpret_cast<guchar*>(iter->second.first), + iter->second.second); + } } // GtkClipboardClearFunc callback. @@ -61,8 +66,12 @@ void ClearData(GtkClipboard* clipboard, std::set<char*> ptrs; for (Clipboard::TargetMap::iterator iter = map->begin(); - iter != map->end(); ++iter) - ptrs.insert(iter->second.first); + iter != map->end(); ++iter) { + if (iter->first == kMimeBmp) + g_object_unref(reinterpret_cast<GdkPixbuf*>(iter->second.first)); + else + ptrs.insert(iter->second.first); + } for (std::set<char*>::iterator iter = ptrs.begin(); iter != ptrs.end(); ++iter) @@ -87,6 +96,11 @@ void FreeTargetMap(Clipboard::TargetMap map) { map.clear(); } +// Called on GdkPixbuf destruction; see WriteBitmap(). +void GdkPixbufFree(guchar* pixels, gpointer data) { + free(pixels); +} + } // namespace Clipboard::Clipboard() { @@ -161,24 +175,21 @@ void Clipboard::WriteWebSmartPaste() { InsertMapping(kMimeWebkitSmartPaste, NULL, 0); } -// We have to convert the image to a PNG because gtk_clipboard_request_image() -// only works with PNGs. Warning: this is an internal implementation detail of -// gtk_clipboard_request_image() and might change in the future. void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) { const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data); - std::vector<unsigned char> png_data; - if (!PNGEncoder::Encode( - reinterpret_cast<const unsigned char*>(pixel_data), - PNGEncoder::FORMAT_BGRA, size->width(), size->height(), - size->width() * 4, false, &png_data)) { - DLOG(ERROR) << "Failed to encode bitmap for clipboard."; - return; - } - char* data = new char[png_data.size()]; - memcpy(data, png_data.data(), png_data.size()); - - InsertMapping(kMimePng, data, png_data.size()); + int length = size->width() * size->height() * 4; + guchar* data = gfx::BGRAToRGBA(reinterpret_cast<const uint8_t*>(pixel_data), + size->width(), size->height(), 0); + + GdkPixbuf* pixbuf = + gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, TRUE, + 8, size->width(), size->height(), + size->width() * 4, GdkPixbufFree, NULL); + // We store the GdkPixbuf*, and the size_t half of the pair is meaningless. + // Note that this contrasts with the vast majority of entries in our target + // map, which directly store the data and its length. + InsertMapping(kMimeBmp, reinterpret_cast<char*>(pixbuf), 0); } void Clipboard::WriteBookmark(const char* title_data, size_t title_len, @@ -305,8 +316,12 @@ void Clipboard::InsertMapping(const char* key, size_t data_len) { TargetMap::iterator iter = clipboard_data_->find(key); - if (iter != clipboard_data_->end()) - delete[] iter->second.first; + if (iter != clipboard_data_->end()) { + if (strcmp(kMimeBmp, key) == 0) + g_object_unref(reinterpret_cast<GdkPixbuf*>(iter->second.first)); + else + delete[] iter->second.first; + } (*clipboard_data_)[key] = std::make_pair(data, data_len); } diff --git a/base/gfx/gtk_util.cc b/base/gfx/gtk_util.cc index ba93c34..0d2eee0 100755 --- a/base/gfx/gtk_util.cc +++ b/base/gfx/gtk_util.cc @@ -40,25 +40,34 @@ static void FreePixels(guchar* pixels, gpointer data) { free(data); } -GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap* bitmap) { - bitmap->lockPixels(); - int width = bitmap->width(); - int height = bitmap->height(); - int stride = bitmap->rowBytes(); - const guchar* orig_data = static_cast<guchar*>(bitmap->getPixels()); - guchar* data = static_cast<guchar*>(malloc(height * stride)); +uint8_t* BGRAToRGBA(const uint8_t* pixels, int width, int height, int stride) { + if (stride == 0) + stride = width * 4; + + guchar* new_pixels = static_cast<guchar*>(malloc(height * stride)); // We have to copy the pixels and swap from BGRA to RGBA. for (int i = 0; i < height; ++i) { for (int j = 0; j < width; ++j) { int idx = i * stride + j * 4; - data[idx] = orig_data[idx + 2]; - data[idx + 1] = orig_data[idx + 1]; - data[idx + 2] = orig_data[idx]; - data[idx + 3] = orig_data[idx + 3]; + new_pixels[idx] = pixels[idx + 2]; + new_pixels[idx + 1] = pixels[idx + 1]; + new_pixels[idx + 2] = pixels[idx]; + new_pixels[idx + 3] = pixels[idx + 3]; } } + return new_pixels; +} + +GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap* bitmap) { + bitmap->lockPixels(); + int width = bitmap->width(); + int height = bitmap->height(); + int stride = bitmap->rowBytes(); + const guchar* orig_data = static_cast<guchar*>(bitmap->getPixels()); + guchar* data = BGRAToRGBA(orig_data, width, height, stride); + // This pixbuf takes ownership of our malloc()ed data and will // free it for us when it is destroyed. GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( diff --git a/base/gfx/gtk_util.h b/base/gfx/gtk_util.h index 6a6cdd6..1b70ae0 100755 --- a/base/gfx/gtk_util.h +++ b/base/gfx/gtk_util.h @@ -30,8 +30,13 @@ extern const GdkColor kGdkGreen; void SubtractRectanglesFromRegion(GdkRegion* region, const std::vector<Rect>& cutouts); -// Convert and copy a SkBitmap to a GdkPixbuf. NOTE: This is an expensive -// operation, all of the pixels must be copied and their order swapped. +// Makes a copy of |pixels| with the ordering changed from BGRA to RGBA. +// The caller is responsible for free()ing the data. If |stride| is 0, +// it's assumed to be 4 * |width|. +uint8_t* BGRAToRGBA(const uint8_t* pixels, int width, int height, int stride); + +// Convert and copy a SkBitmap to a GdkPixbuf. NOTE: this uses BGRAToRGBA, so +// it is an expensive operation. GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap* bitmap); // Create a GtkBin with |child| as its child widget. This bin will paint a |