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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/libgtkui/gtk_util.cc
diff --git a/chrome/browser/ui/libgtkui/gtk_util.cc b/chrome/browser/ui/libgtkui/gtk_util.cc
index aab971785907c7b330a0fd56d43f49e7cde63823..caed0237fab0b4900d9c69d4db49dfc7998aadcd 100644
--- a/chrome/browser/ui/libgtkui/gtk_util.cc
+++ b/chrome/browser/ui/libgtkui/gtk_util.cc
@@ -14,6 +14,9 @@
#include "base/command_line.h"
#include "base/debug/leak_annotations.h"
#include "base/environment.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/accelerators/accelerator.h"
@@ -188,4 +191,218 @@ void ClearAuraTransientParent(GtkWidget* dialog) {
g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, NULL);
}
+#if GTK_MAJOR_VERSION > 2
+ScopedStyleContext AppendNode(GtkStyleContext* context,
+ const std::string& css_node) {
+ GtkWidgetPath* path =
+ context ? gtk_widget_path_copy(gtk_style_context_get_path(context))
+ : gtk_widget_path_new();
+
+ enum {
+ // TODO(thomasanderson): Add CSS_NAME here to handle the Gtk3.20 case.
+ CSS_TYPE,
+ CSS_CLASS,
+ CSS_PSEUDOCLASS,
+ } part_type = CSS_TYPE;
+ static const struct {
+ const char* name;
+ GtkStateFlags state_flag;
+ } pseudo_classes[] = {
+ {"active", GTK_STATE_FLAG_ACTIVE},
+ {"hover", GTK_STATE_FLAG_PRELIGHT},
+ {"selected", GTK_STATE_FLAG_SELECTED},
+ {"disabled", GTK_STATE_FLAG_INSENSITIVE},
+ {"indeterminate", GTK_STATE_FLAG_INCONSISTENT},
+ {"focus", GTK_STATE_FLAG_FOCUSED},
+ {"backdrop", GTK_STATE_FLAG_BACKDROP},
+ // TODO(thomasanderson): These state flags are only available in
+ // GTK 3.10 or later, which is unavailable in the wheezy
+ // sysroot. Add them once the sysroot is updated to jessie.
+ // { "link", GTK_STATE_FLAG_LINK },
+ // { "visited", GTK_STATE_FLAG_VISITED },
+ // { "checked", GTK_STATE_FLAG_CHECKED },
+ };
+ GtkStateFlags state =
+ context ? gtk_style_context_get_state(context) : GTK_STATE_FLAG_NORMAL;
+ base::StringTokenizer t(css_node, ".:");
+ t.set_options(base::StringTokenizer::RETURN_DELIMS);
+ while (t.GetNext()) {
+ if (t.token_is_delim()) {
+ if (t.token_begin() == css_node.begin()) {
+ // Special case for the first token.
+ gtk_widget_path_append_type(path, G_TYPE_NONE);
+ }
+ switch (*t.token_begin()) {
+ case '.':
+ part_type = CSS_CLASS;
+ break;
+ case ':':
+ part_type = CSS_PSEUDOCLASS;
+ break;
+ default:
+ NOTREACHED();
+ }
+ } else {
+ switch (part_type) {
+ case CSS_TYPE: {
+ GType type = g_type_from_name(t.token().c_str());
+ DCHECK(type);
+ gtk_widget_path_append_type(path, type);
+ break;
+ }
+ case CSS_CLASS: {
+ gtk_widget_path_iter_add_class(path, -1, t.token().c_str());
+ break;
+ }
+ case CSS_PSEUDOCLASS: {
+ GtkStateFlags state_flag = GTK_STATE_FLAG_NORMAL;
+ for (const auto& pseudo_class_entry : pseudo_classes) {
+ if (strcmp(pseudo_class_entry.name, t.token().c_str()) == 0) {
+ state_flag = pseudo_class_entry.state_flag;
+ break;
+ }
+ }
+ state = static_cast<GtkStateFlags>(state | state_flag);
+ break;
+ }
+ }
+ }
+ }
+ auto child_context = ScopedStyleContext(gtk_style_context_new());
+ gtk_style_context_set_path(child_context, path);
+ gtk_style_context_set_state(child_context, state);
+ gtk_style_context_set_parent(child_context, context);
+ gtk_widget_path_unref(path);
+ return child_context;
+}
+
+ScopedStyleContext GetStyleContextFromCss(const char* css_selector) {
+ // Prepend "GtkWindow.background" to the selector since all widgets must live
+ // in a window, but we don't want to specify that every time.
+ auto context = AppendNode(nullptr, "GtkWindow.background");
+
+ for (const auto& widget_type :
+ base::SplitString(css_selector, base::kWhitespaceASCII,
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
+ context = AppendNode(context, widget_type);
+ }
+ return context;
+}
+
+SkColor GdkRgbaToSkColor(const GdkRGBA& color) {
+ return SkColorSetARGB(color.alpha * 255, color.red * 255, color.green * 255,
+ color.blue * 255);
+}
+
+SkColor GetFGColor(const char* css_selector) {
+ auto context = GetStyleContextFromCss(css_selector);
+ GdkRGBA color;
+ gtk_style_context_get_color(context, gtk_style_context_get_state(context),
+ &color);
+ return GdkRgbaToSkColor(color);
+}
+
+GtkCssProvider* GetCssProvider(const char* css) {
+ GtkCssProvider* provider = gtk_css_provider_new();
+ GError* error = nullptr;
+ gtk_css_provider_load_from_data(provider, css, -1, &error);
+ DCHECK(!error);
+ return provider;
+}
+
+void ApplyCssToContext(GtkStyleContext* context, GtkCssProvider* provider) {
+ while (context) {
+ gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider),
+ G_MAXUINT);
+ context = gtk_style_context_get_parent(context);
+ }
+}
+
+void RemoveBorders(GtkStyleContext* context) {
+ static GtkCssProvider* provider = GetCssProvider(
+ "* {"
+ "border-style: none;"
+ "border-radius: 0px;"
+ "border-width: 0px;"
+ "border-image-width: 0px;"
+ "padding: 0px;"
+ "margin: 0px;"
+ "}");
+ ApplyCssToContext(context, provider);
+}
+
+void AddBorders(GtkStyleContext* context) {
+ static GtkCssProvider* provider = GetCssProvider(
+ "* {"
+ "border-style: solid;"
+ "border-radius: 0px;"
+ "border-width: 1px;"
+ "padding: 0px;"
+ "margin: 0px;"
+ "}");
+ ApplyCssToContext(context, provider);
+}
+
+// A 1x1 cairo surface that GTK can render into.
+class PixelSurface {
+ public:
+ PixelSurface()
+ : surface_(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1)),
+ cairo_(cairo_create(surface_)) {}
+
+ ~PixelSurface() {
+ cairo_destroy(cairo_);
+ cairo_surface_destroy(surface_);
+ }
+
+ // Get the drawing context for GTK to use.
+ cairo_t* cairo() { return cairo_; }
+
+ // Get the color value of the single pixel.
+ SkColor GetPixelValue() {
+ return *reinterpret_cast<SkColor*>(cairo_image_surface_get_data(surface_));
+ }
+
+ private:
+ cairo_surface_t* surface_;
+ cairo_t* cairo_;
+};
+
+SkColor GetBGColor(const char* css_selector) {
+ // Backgrounds are more general than solid colors (eg. gradients),
+ // but chromium requires us to boil this down to one color. We
+ // cannot use the background-color here because some themes leave it
+ // set to a garbage color because a background-image will cover it
+ // anyway. So we instead render the background into a single pixel,
+ // removing any borders, and hope that we get a good color.
+ auto context = GetStyleContextFromCss(css_selector);
+ RemoveBorders(context);
+ PixelSurface surface;
+ gtk_render_background(context, surface.cairo(), 0, 0, 1, 1);
+ return surface.GetPixelValue();
+}
+
+SkColor GetBorderColor(const char* css_selector) {
+ // Borders have the same issue as backgrounds, due to the
+ // border-image property.
+ auto context = GetStyleContextFromCss(css_selector);
+ GtkStateFlags state = gtk_style_context_get_state(context);
+ GtkBorderStyle border_style = GTK_BORDER_STYLE_NONE;
+ gtk_style_context_get(context, state, GTK_STYLE_PROPERTY_BORDER_STYLE,
+ &border_style, nullptr);
+ GtkBorder border;
+ gtk_style_context_get_border(context, state, &border);
+ if ((border_style == GTK_BORDER_STYLE_NONE ||
+ border_style == GTK_BORDER_STYLE_HIDDEN) ||
+ (!border.left && !border.right && !border.top && !border.bottom)) {
+ return SK_ColorTRANSPARENT;
+ }
+
+ AddBorders(context);
+ PixelSurface surface;
+ gtk_render_frame(context, surface.cairo(), 0, 0, 1, 1);
+ return surface.GetPixelValue();
+}
+#endif
+
} // namespace libgtkui
« 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