summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/clipboard_linux.cc67
-rwxr-xr-xbase/gfx/gtk_util.cc31
-rwxr-xr-xbase/gfx/gtk_util.h9
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