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 |