Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(651)

Side by Side Diff: chrome/browser/ui/libgtkui/gtk_util.cc

Issue 2588993002: Gtk3: Refactor NativeThemeGtk3 to use foreign drawing only (Closed)
Patch Set: Add color cache Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/ui/libgtkui/gtk_util.h ('k') | chrome/browser/ui/libgtkui/native_theme_gtk3.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/libgtkui/gtk_util.h" 5 #include "chrome/browser/ui/libgtkui/gtk_util.h"
6 6
7 #include <gdk/gdk.h> 7 #include <gdk/gdk.h>
8 #include <gdk/gdkx.h> 8 #include <gdk/gdkx.h>
9 #include <gtk/gtk.h> 9 #include <gtk/gtk.h>
10 #include <stddef.h> 10 #include <stddef.h>
11 11
12 #include <memory> 12 #include <memory>
13 13
14 #include "base/command_line.h" 14 #include "base/command_line.h"
15 #include "base/debug/leak_annotations.h" 15 #include "base/debug/leak_annotations.h"
16 #include "base/environment.h" 16 #include "base/environment.h"
17 #include "base/strings/string_split.h"
18 #include "base/strings/string_tokenizer.h"
19 #include "base/strings/string_util.h"
17 #include "ui/aura/window.h" 20 #include "ui/aura/window.h"
18 #include "ui/aura/window_tree_host.h" 21 #include "ui/aura/window_tree_host.h"
19 #include "ui/base/accelerators/accelerator.h" 22 #include "ui/base/accelerators/accelerator.h"
20 #include "ui/events/event_constants.h" 23 #include "ui/events/event_constants.h"
21 #include "ui/events/keycodes/keyboard_code_conversion_x.h" 24 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
22 #include "ui/gfx/color_utils.h" 25 #include "ui/gfx/color_utils.h"
23 #include "ui/gfx/geometry/size.h" 26 #include "ui/gfx/geometry/size.h"
24 27
25 namespace { 28 namespace {
26 29
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 184
182 aura::Window* GetAuraTransientParent(GtkWidget* dialog) { 185 aura::Window* GetAuraTransientParent(GtkWidget* dialog) {
183 return reinterpret_cast<aura::Window*>( 186 return reinterpret_cast<aura::Window*>(
184 g_object_get_data(G_OBJECT(dialog), kAuraTransientParent)); 187 g_object_get_data(G_OBJECT(dialog), kAuraTransientParent));
185 } 188 }
186 189
187 void ClearAuraTransientParent(GtkWidget* dialog) { 190 void ClearAuraTransientParent(GtkWidget* dialog) {
188 g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, NULL); 191 g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, NULL);
189 } 192 }
190 193
194 #if GTK_MAJOR_VERSION > 2
195 ScopedStyleContext AppendNode(GtkStyleContext* context,
196 const std::string& css_node) {
197 GtkWidgetPath* path =
198 context ? gtk_widget_path_copy(gtk_style_context_get_path(context))
199 : gtk_widget_path_new();
200
201 enum {
202 // TODO(thomasanderson): Add CSS_NAME here to handle the Gtk3.20 case.
203 CSS_TYPE,
204 CSS_CLASS,
205 CSS_PSEUDOCLASS,
206 } part_type = CSS_TYPE;
207 static const struct {
208 const char* name;
209 GtkStateFlags state_flag;
210 } pseudo_classes[] = {
211 {"active", GTK_STATE_FLAG_ACTIVE},
212 {"hover", GTK_STATE_FLAG_PRELIGHT},
213 {"selected", GTK_STATE_FLAG_SELECTED},
214 {"disabled", GTK_STATE_FLAG_INSENSITIVE},
215 {"indeterminate", GTK_STATE_FLAG_INCONSISTENT},
216 {"focus", GTK_STATE_FLAG_FOCUSED},
217 {"backdrop", GTK_STATE_FLAG_BACKDROP},
218 // TODO(thomasanderson): These state flags are only available in
219 // GTK 3.10 or later, which is unavailable in the wheezy
220 // sysroot. Add them once the sysroot is updated to jessie.
221 // { "link", GTK_STATE_FLAG_LINK },
222 // { "visited", GTK_STATE_FLAG_VISITED },
223 // { "checked", GTK_STATE_FLAG_CHECKED },
224 };
225 GtkStateFlags state =
226 context ? gtk_style_context_get_state(context) : GTK_STATE_FLAG_NORMAL;
227 base::StringTokenizer t(css_node, ".:");
228 t.set_options(base::StringTokenizer::RETURN_DELIMS);
229 while (t.GetNext()) {
230 if (t.token_is_delim()) {
231 if (t.token_begin() == css_node.begin()) {
232 // Special case for the first token.
233 gtk_widget_path_append_type(path, G_TYPE_NONE);
234 }
235 switch (*t.token_begin()) {
236 case '.':
237 part_type = CSS_CLASS;
238 break;
239 case ':':
240 part_type = CSS_PSEUDOCLASS;
241 break;
242 default:
243 NOTREACHED();
244 }
245 } else {
246 switch (part_type) {
247 case CSS_TYPE: {
248 GType type = g_type_from_name(t.token().c_str());
249 DCHECK(type);
250 gtk_widget_path_append_type(path, type);
251 break;
252 }
253 case CSS_CLASS: {
254 gtk_widget_path_iter_add_class(path, -1, t.token().c_str());
255 break;
256 }
257 case CSS_PSEUDOCLASS: {
258 GtkStateFlags state_flag = GTK_STATE_FLAG_NORMAL;
259 for (const auto& pseudo_class_entry : pseudo_classes) {
260 if (strcmp(pseudo_class_entry.name, t.token().c_str()) == 0) {
261 state_flag = pseudo_class_entry.state_flag;
262 break;
263 }
264 }
265 state = static_cast<GtkStateFlags>(state | state_flag);
266 break;
267 }
268 }
269 }
270 }
271 auto child_context = ScopedStyleContext(gtk_style_context_new());
272 gtk_style_context_set_path(child_context, path);
273 gtk_style_context_set_state(child_context, state);
274 gtk_style_context_set_parent(child_context, context);
275 gtk_widget_path_unref(path);
276 return child_context;
277 }
278
279 ScopedStyleContext GetStyleContextFromCss(const char* css_selector) {
280 // Prepend "GtkWindow.background" to the selector since all widgets must live
281 // in a window, but we don't want to specify that every time.
282 auto context = AppendNode(nullptr, "GtkWindow.background");
283
284 for (const auto& widget_type :
285 base::SplitString(css_selector, base::kWhitespaceASCII,
286 base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
287 context = AppendNode(context, widget_type);
288 }
289 return context;
290 }
291
292 SkColor GdkRgbaToSkColor(const GdkRGBA& color) {
293 return SkColorSetARGB(color.alpha * 255, color.red * 255, color.green * 255,
294 color.blue * 255);
295 }
296
297 SkColor GetFGColor(const char* css_selector) {
298 auto context = GetStyleContextFromCss(css_selector);
299 GdkRGBA color;
300 gtk_style_context_get_color(context, gtk_style_context_get_state(context),
301 &color);
302 return GdkRgbaToSkColor(color);
303 }
304
305 GtkCssProvider* GetCssProvider(const char* css) {
306 GtkCssProvider* provider = gtk_css_provider_new();
307 GError* error = nullptr;
308 gtk_css_provider_load_from_data(provider, css, -1, &error);
309 DCHECK(!error);
310 return provider;
311 }
312
313 void ApplyCssToContext(GtkStyleContext* context, GtkCssProvider* provider) {
314 while (context) {
315 gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider),
316 G_MAXUINT);
317 context = gtk_style_context_get_parent(context);
318 }
319 }
320
321 void RemoveBorders(GtkStyleContext* context) {
322 static GtkCssProvider* provider = GetCssProvider(
323 "* {"
324 "border-style: none;"
325 "border-radius: 0px;"
326 "border-width: 0px;"
327 "border-image-width: 0px;"
328 "padding: 0px;"
329 "margin: 0px;"
330 "}");
331 ApplyCssToContext(context, provider);
332 }
333
334 void AddBorders(GtkStyleContext* context) {
335 static GtkCssProvider* provider = GetCssProvider(
336 "* {"
337 "border-style: solid;"
338 "border-radius: 0px;"
339 "border-width: 1px;"
340 "padding: 0px;"
341 "margin: 0px;"
342 "}");
343 ApplyCssToContext(context, provider);
344 }
345
346 // A 1x1 cairo surface that GTK can render into.
347 class PixelSurface {
348 public:
349 PixelSurface()
350 : surface_(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1)),
351 cairo_(cairo_create(surface_)) {}
352
353 ~PixelSurface() {
354 cairo_destroy(cairo_);
355 cairo_surface_destroy(surface_);
356 }
357
358 // Get the drawing context for GTK to use.
359 cairo_t* cairo() { return cairo_; }
360
361 // Get the color value of the single pixel.
362 SkColor GetPixelValue() {
363 return *reinterpret_cast<SkColor*>(cairo_image_surface_get_data(surface_));
364 }
365
366 private:
367 cairo_surface_t* surface_;
368 cairo_t* cairo_;
369 };
370
371 SkColor GetBGColor(const char* css_selector) {
372 // Backgrounds are more general than solid colors (eg. gradients),
373 // but chromium requires us to boil this down to one color. We
374 // cannot use the background-color here because some themes leave it
375 // set to a garbage color because a background-image will cover it
376 // anyway. So we instead render the background into a single pixel,
377 // removing any borders, and hope that we get a good color.
378 auto context = GetStyleContextFromCss(css_selector);
379 RemoveBorders(context);
380 PixelSurface surface;
381 gtk_render_background(context, surface.cairo(), 0, 0, 1, 1);
382 return surface.GetPixelValue();
383 }
384
385 SkColor GetBorderColor(const char* css_selector) {
386 // Borders have the same issue as backgrounds, due to the
387 // border-image property.
388 auto context = GetStyleContextFromCss(css_selector);
389 GtkStateFlags state = gtk_style_context_get_state(context);
390 GtkBorderStyle border_style = GTK_BORDER_STYLE_NONE;
391 gtk_style_context_get(context, state, GTK_STYLE_PROPERTY_BORDER_STYLE,
392 &border_style, nullptr);
393 GtkBorder border;
394 gtk_style_context_get_border(context, state, &border);
395 if ((border_style == GTK_BORDER_STYLE_NONE ||
396 border_style == GTK_BORDER_STYLE_HIDDEN) ||
397 (!border.left && !border.right && !border.top && !border.bottom)) {
398 return SK_ColorTRANSPARENT;
399 }
400
401 AddBorders(context);
402 PixelSurface surface;
403 gtk_render_frame(context, surface.cairo(), 0, 0, 1, 1);
404 return surface.GetPixelValue();
405 }
406 #endif
407
191 } // namespace libgtkui 408 } // namespace libgtkui
OLDNEW
« no previous file with comments | « chrome/browser/ui/libgtkui/gtk_util.h ('k') | chrome/browser/ui/libgtkui/native_theme_gtk3.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698