| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "gfx/gtk_util.h" | |
| 6 | |
| 7 #include <gdk/gdk.h> | |
| 8 #include <gtk/gtk.h> | |
| 9 #include <stdlib.h> | |
| 10 | |
| 11 #include "base/basictypes.h" | |
| 12 #include "base/command_line.h" | |
| 13 #include "base/linux_util.h" | |
| 14 #include "gfx/rect.h" | |
| 15 #include "third_party/skia/include/core/SkBitmap.h" | |
| 16 #include "third_party/skia/include/core/SkUnPreMultiply.h" | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 // A process wide singleton that manages our usage of gdk | |
| 21 // cursors. gdk_cursor_new() hits the disk in several places and GdkCursor | |
| 22 // instances can be reused throughout the process. | |
| 23 class GdkCursorCache { | |
| 24 public: | |
| 25 GdkCursorCache() {} | |
| 26 ~GdkCursorCache() { | |
| 27 for (std::map<GdkCursorType, GdkCursor*>::iterator it = | |
| 28 cursor_cache_.begin(); it != cursor_cache_.end(); ++it) { | |
| 29 gdk_cursor_unref(it->second); | |
| 30 } | |
| 31 cursor_cache_.clear(); | |
| 32 } | |
| 33 | |
| 34 GdkCursor* GetCursorImpl(GdkCursorType type) { | |
| 35 std::map<GdkCursorType, GdkCursor*>::iterator it = cursor_cache_.find(type); | |
| 36 GdkCursor* cursor = NULL; | |
| 37 if (it == cursor_cache_.end()) { | |
| 38 cursor = gdk_cursor_new(type); | |
| 39 cursor_cache_.insert(std::make_pair(type, cursor)); | |
| 40 } else { | |
| 41 cursor = it->second; | |
| 42 } | |
| 43 | |
| 44 // It is not necessary to add a reference here. The callers can ref the | |
| 45 // cursor if they need it for something. | |
| 46 return cursor; | |
| 47 } | |
| 48 | |
| 49 std::map<GdkCursorType, GdkCursor*> cursor_cache_; | |
| 50 | |
| 51 DISALLOW_COPY_AND_ASSIGN(GdkCursorCache); | |
| 52 }; | |
| 53 | |
| 54 void FreePixels(guchar* pixels, gpointer data) { | |
| 55 free(data); | |
| 56 } | |
| 57 | |
| 58 // Common implementation of ConvertAcceleratorsFromWindowsStyle() and | |
| 59 // RemoveWindowsStyleAccelerators(). | |
| 60 // Replaces all ampersands (as used in our grd files to indicate mnemonics) | |
| 61 // to |target|. Similarly any underscores get replaced with two underscores as | |
| 62 // is needed by pango. | |
| 63 std::string ConvertAmperstandsTo(const std::string& label, | |
| 64 const std::string& target) { | |
| 65 std::string ret; | |
| 66 ret.reserve(label.length() * 2); | |
| 67 for (size_t i = 0; i < label.length(); ++i) { | |
| 68 if ('_' == label[i]) { | |
| 69 ret.push_back('_'); | |
| 70 ret.push_back('_'); | |
| 71 } else if ('&' == label[i]) { | |
| 72 if (i + 1 < label.length() && '&' == label[i + 1]) { | |
| 73 ret.push_back('&'); | |
| 74 ++i; | |
| 75 } else { | |
| 76 ret.append(target); | |
| 77 } | |
| 78 } else { | |
| 79 ret.push_back(label[i]); | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 return ret; | |
| 84 } | |
| 85 | |
| 86 } // namespace | |
| 87 | |
| 88 namespace gfx { | |
| 89 | |
| 90 void GtkInitFromCommandLine(const CommandLine& command_line) { | |
| 91 const std::vector<std::string>& args = command_line.argv(); | |
| 92 int argc = args.size(); | |
| 93 scoped_array<char *> argv(new char *[argc + 1]); | |
| 94 for (size_t i = 0; i < args.size(); ++i) { | |
| 95 // TODO(piman@google.com): can gtk_init modify argv? Just being safe | |
| 96 // here. | |
| 97 argv[i] = strdup(args[i].c_str()); | |
| 98 } | |
| 99 argv[argc] = NULL; | |
| 100 char **argv_pointer = argv.get(); | |
| 101 | |
| 102 gtk_init(&argc, &argv_pointer); | |
| 103 for (size_t i = 0; i < args.size(); ++i) { | |
| 104 free(argv[i]); | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap* bitmap) { | |
| 109 if (bitmap->isNull()) | |
| 110 return NULL; | |
| 111 | |
| 112 bitmap->lockPixels(); | |
| 113 | |
| 114 int width = bitmap->width(); | |
| 115 int height = bitmap->height(); | |
| 116 int stride = bitmap->rowBytes(); | |
| 117 | |
| 118 // SkBitmaps are premultiplied, we need to unpremultiply them. | |
| 119 const int kBytesPerPixel = 4; | |
| 120 uint8* divided = static_cast<uint8*>(malloc(height * stride)); | |
| 121 | |
| 122 for (int y = 0, i = 0; y < height; y++) { | |
| 123 for (int x = 0; x < width; x++) { | |
| 124 uint32 pixel = bitmap->getAddr32(0, y)[x]; | |
| 125 | |
| 126 int alpha = SkColorGetA(pixel); | |
| 127 if (alpha != 0 && alpha != 255) { | |
| 128 SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel); | |
| 129 divided[i + 0] = SkColorGetR(unmultiplied); | |
| 130 divided[i + 1] = SkColorGetG(unmultiplied); | |
| 131 divided[i + 2] = SkColorGetB(unmultiplied); | |
| 132 divided[i + 3] = alpha; | |
| 133 } else { | |
| 134 divided[i + 0] = SkColorGetR(pixel); | |
| 135 divided[i + 1] = SkColorGetG(pixel); | |
| 136 divided[i + 2] = SkColorGetB(pixel); | |
| 137 divided[i + 3] = alpha; | |
| 138 } | |
| 139 i += kBytesPerPixel; | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 // This pixbuf takes ownership of our malloc()ed data and will | |
| 144 // free it for us when it is destroyed. | |
| 145 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( | |
| 146 divided, | |
| 147 GDK_COLORSPACE_RGB, // The only colorspace gtk supports. | |
| 148 true, // There is an alpha channel. | |
| 149 8, | |
| 150 width, height, stride, &FreePixels, divided); | |
| 151 | |
| 152 bitmap->unlockPixels(); | |
| 153 return pixbuf; | |
| 154 } | |
| 155 | |
| 156 void SubtractRectanglesFromRegion(GdkRegion* region, | |
| 157 const std::vector<Rect>& cutouts) { | |
| 158 for (size_t i = 0; i < cutouts.size(); ++i) { | |
| 159 GdkRectangle rect = cutouts[i].ToGdkRectangle(); | |
| 160 GdkRegion* rect_region = gdk_region_rectangle(&rect); | |
| 161 gdk_region_subtract(region, rect_region); | |
| 162 // TODO(deanm): It would be nice to be able to reuse the GdkRegion here. | |
| 163 gdk_region_destroy(rect_region); | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 double GetPangoResolution() { | |
| 168 static double resolution; | |
| 169 static bool determined_resolution = false; | |
| 170 if (!determined_resolution) { | |
| 171 determined_resolution = true; | |
| 172 PangoContext* default_context = gdk_pango_context_get(); | |
| 173 resolution = pango_cairo_context_get_resolution(default_context); | |
| 174 g_object_unref(default_context); | |
| 175 } | |
| 176 return resolution; | |
| 177 } | |
| 178 | |
| 179 GdkCursor* GetCursor(int type) { | |
| 180 static GdkCursorCache impl; | |
| 181 return impl.GetCursorImpl(static_cast<GdkCursorType>(type)); | |
| 182 } | |
| 183 | |
| 184 std::string ConvertAcceleratorsFromWindowsStyle(const std::string& label) { | |
| 185 return ConvertAmperstandsTo(label, "_"); | |
| 186 } | |
| 187 | |
| 188 std::string RemoveWindowsStyleAccelerators(const std::string& label) { | |
| 189 return ConvertAmperstandsTo(label, ""); | |
| 190 } | |
| 191 | |
| 192 uint8_t* BGRAToRGBA(const uint8_t* pixels, int width, int height, int stride) { | |
| 193 if (stride == 0) | |
| 194 stride = width * 4; | |
| 195 | |
| 196 uint8_t* new_pixels = static_cast<uint8_t*>(malloc(height * stride)); | |
| 197 | |
| 198 // We have to copy the pixels and swap from BGRA to RGBA. | |
| 199 for (int i = 0; i < height; ++i) { | |
| 200 for (int j = 0; j < width; ++j) { | |
| 201 int idx = i * stride + j * 4; | |
| 202 new_pixels[idx] = pixels[idx + 2]; | |
| 203 new_pixels[idx + 1] = pixels[idx + 1]; | |
| 204 new_pixels[idx + 2] = pixels[idx]; | |
| 205 new_pixels[idx + 3] = pixels[idx + 3]; | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 return new_pixels; | |
| 210 } | |
| 211 | |
| 212 } // namespace gfx | |
| OLD | NEW |