| 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 0f6144f81fe5901ffb770c64104401e462bef738..87579d29aa07b808abc29b0866c2c9e670e778d6 100644
|
| --- a/chrome/browser/ui/libgtkui/gtk_util.cc
|
| +++ b/chrome/browser/ui/libgtkui/gtk_util.cc
|
| @@ -220,49 +220,42 @@ CairoSurface::CairoSurface(const gfx::Size& size)
|
| : surface_(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
|
| size.width(),
|
| size.height())),
|
| - cairo_(cairo_create(surface_)) {}
|
| + cairo_(cairo_create(surface_)) {
|
| + DCHECK(cairo_surface_status(surface_) == CAIRO_STATUS_SUCCESS);
|
| + // Clear the surface.
|
| + cairo_save(cairo_);
|
| + cairo_set_source_rgba(cairo_, 0, 0, 0, 0);
|
| + cairo_set_operator(cairo_, CAIRO_OPERATOR_SOURCE);
|
| + cairo_paint(cairo_);
|
| + cairo_restore(cairo_);
|
| +}
|
|
|
| CairoSurface::~CairoSurface() {
|
| cairo_destroy(cairo_);
|
| cairo_surface_destroy(surface_);
|
| }
|
|
|
| -SkColor CairoSurface::GetAveragePixelValue(bool only_frame_pixels) {
|
| +SkColor CairoSurface::GetAveragePixelValue(bool frame) {
|
| cairo_surface_flush(surface_);
|
| - int num_samples = 0;
|
| - long a = 0, r = 0, g = 0, b = 0;
|
| SkColor* data =
|
| reinterpret_cast<SkColor*>(cairo_image_surface_get_data(surface_));
|
| int width = cairo_image_surface_get_width(surface_);
|
| int height = cairo_image_surface_get_height(surface_);
|
| DCHECK(4 * width == cairo_image_surface_get_stride(surface_));
|
| - auto accumulate = [&](int x, int y) mutable {
|
| - SkColor color = data[y * width + x];
|
| - int alpha = SkColorGetA(color);
|
| - a += alpha;
|
| - r += alpha * SkColorGetR(color);
|
| - g += alpha * SkColorGetG(color);
|
| - b += alpha * SkColorGetB(color);
|
| - num_samples++;
|
| - };
|
| - if (width == 1 || height == 1 || !only_frame_pixels) {
|
| - // Count every pixel in the surface.
|
| - for (int x = 0; x < width; x++)
|
| - for (int y = 0; y < height; y++)
|
| - accumulate(x, y);
|
| - } else {
|
| - // Count the pixels in the top and bottom rows.
|
| - for (int x = 0; x < width; x++)
|
| - for (int y : {0, height - 1})
|
| - accumulate(x, y);
|
| - // Count the pixels in the left and right columns.
|
| - for (int x : {0, width - 1})
|
| - for (int y = 1; y < height - 1; y++)
|
| - accumulate(x, y);
|
| + long a = 0, r = 0, g = 0, b = 0;
|
| + unsigned int max_alpha = 0;
|
| + for (int i = 0; i < width * height; i++) {
|
| + SkColor color = data[i];
|
| + max_alpha = std::max(SkColorGetA(color), max_alpha);
|
| + a += SkColorGetA(color);
|
| + r += SkColorGetR(color);
|
| + g += SkColorGetG(color);
|
| + b += SkColorGetB(color);
|
| }
|
| if (a == 0)
|
| return SK_ColorTRANSPARENT;
|
| - return SkColorSetARGB(a / num_samples, r / a, g / a, b / a);
|
| + return SkColorSetARGB(frame ? max_alpha : a / (width * height), r * 255 / a,
|
| + g * 255 / a, b * 255 / a);
|
| }
|
|
|
| bool GtkVersionCheck(int major, int minor, int micro) {
|
| @@ -336,14 +329,12 @@ ScopedStyleContext AppendCssNodeToStyleContext(GtkStyleContext* context,
|
| NOTREACHED();
|
| }
|
| } else {
|
| + static auto* _gtk_widget_path_iter_set_object_name =
|
| + reinterpret_cast<void (*)(GtkWidgetPath*, gint, const char*)>(dlsym(
|
| + GetGtk3SharedLibrary(), "gtk_widget_path_iter_set_object_name"));
|
| switch (part_type) {
|
| case CSS_NAME: {
|
| if (GtkVersionCheck(3, 20)) {
|
| - static auto* _gtk_widget_path_iter_set_object_name =
|
| - reinterpret_cast<void (*)(GtkWidgetPath*, gint, const char*)>(
|
| - dlsym(GetGtk3SharedLibrary(),
|
| - "gtk_widget_path_iter_set_object_name"));
|
| - DCHECK(_gtk_widget_path_iter_set_object_name);
|
| _gtk_widget_path_iter_set_object_name(path, -1, t.token().c_str());
|
| } else {
|
| gtk_widget_path_iter_add_class(path, -1, t.token().c_str());
|
| @@ -354,6 +345,10 @@ ScopedStyleContext AppendCssNodeToStyleContext(GtkStyleContext* context,
|
| GType type = g_type_from_name(t.token().c_str());
|
| DCHECK(type);
|
| gtk_widget_path_append_type(path, type);
|
| + if (GtkVersionCheck(3, 20)) {
|
| + if (t.token() == "GtkLabel")
|
| + _gtk_widget_path_iter_set_object_name(path, -1, "label");
|
| + }
|
| break;
|
| }
|
| case CSS_CLASS: {
|
| @@ -379,7 +374,7 @@ ScopedStyleContext AppendCssNodeToStyleContext(GtkStyleContext* context,
|
| // widgets specially if they want to.
|
| gtk_widget_path_iter_add_class(path, -1, "chromium");
|
|
|
| - auto child_context = ScopedStyleContext(gtk_style_context_new());
|
| + ScopedStyleContext child_context(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);
|
| @@ -388,9 +383,10 @@ ScopedStyleContext AppendCssNodeToStyleContext(GtkStyleContext* context,
|
| }
|
|
|
| ScopedStyleContext GetStyleContextFromCss(const char* css_selector) {
|
| - // Prepend "GtkWindow.background" to the selector since all widgets must live
|
| + // Prepend a window node to the selector since all widgets must live
|
| // in a window, but we don't want to specify that every time.
|
| - auto context = AppendCssNodeToStyleContext(nullptr, "GtkWindow.background");
|
| + auto context =
|
| + AppendCssNodeToStyleContext(nullptr, "GtkWindow#window.background");
|
|
|
| for (const auto& widget_type :
|
| base::SplitString(css_selector, base::kWhitespaceASCII,
|
| @@ -405,26 +401,46 @@ SkColor GdkRgbaToSkColor(const GdkRGBA& color) {
|
| color.blue * 255);
|
| }
|
|
|
| -SkColor SkColorFromStyleContext(GtkStyleContext* context) {
|
| +SkColor GetFgColorFromStyleContext(GtkStyleContext* context) {
|
| GdkRGBA color;
|
| gtk_style_context_get_color(context, gtk_style_context_get_state(context),
|
| &color);
|
| return GdkRgbaToSkColor(color);
|
| }
|
|
|
| +SkColor GetBgColorFromStyleContext(GtkStyleContext* context) {
|
| + // 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 24x24 bitmap,
|
| + // removing any borders, and hope that we get a good color.
|
| + ApplyCssToContext(context,
|
| + "* {"
|
| + "border-radius: 0px;"
|
| + "border-style: none;"
|
| + "box-shadow: none;"
|
| + "}");
|
| + gfx::Size size(24, 24);
|
| + CairoSurface surface(size);
|
| + RenderBackground(size, surface.cairo(), context);
|
| + return surface.GetAveragePixelValue(false);
|
| +}
|
| +
|
| SkColor GetFgColor(const char* css_selector) {
|
| - return SkColorFromStyleContext(GetStyleContextFromCss(css_selector));
|
| + return GetFgColorFromStyleContext(GetStyleContextFromCss(css_selector));
|
| }
|
|
|
| -GtkCssProvider* GetCssProvider(const char* css) {
|
| +ScopedCssProvider 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;
|
| + return ScopedCssProvider(provider);
|
| }
|
|
|
| -void ApplyCssToContext(GtkStyleContext* context, GtkCssProvider* provider) {
|
| +void ApplyCssProviderToContext(GtkStyleContext* context,
|
| + GtkCssProvider* provider) {
|
| while (context) {
|
| gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider),
|
| G_MAXUINT);
|
| @@ -432,35 +448,9 @@ void ApplyCssToContext(GtkStyleContext* context, GtkCssProvider* provider) {
|
| }
|
| }
|
|
|
| -void RemoveBorders(GtkStyleContext* context) {
|
| - static GtkCssProvider* provider = GetCssProvider(
|
| - "* {"
|
| - "border-style: none;"
|
| - "border-radius: 0px;"
|
| - "border-width: 0px;"
|
| - "border-image-width: 0px;"
|
| - "box-shadow: none;"
|
| - "padding: 0px;"
|
| - "margin: 0px;"
|
| - "outline: none;"
|
| - "outline-width: 0px;"
|
| - "}");
|
| - ApplyCssToContext(context, provider);
|
| -}
|
| -
|
| -void AddBorders(GtkStyleContext* context) {
|
| - static GtkCssProvider* provider = GetCssProvider(
|
| - "* {"
|
| - "border-style: solid;"
|
| - "border-radius: 0px;"
|
| - "border-width: 1px;"
|
| - "box-shadow: none;"
|
| - "padding: 0px;"
|
| - "margin: 0px;"
|
| - "outline: none;"
|
| - "outline-width: 0px;"
|
| - "}");
|
| - ApplyCssToContext(context, provider);
|
| +void ApplyCssToContext(GtkStyleContext* context, const char* css) {
|
| + auto provider = GetCssProvider(css);
|
| + ApplyCssProviderToContext(context, provider);
|
| }
|
|
|
| void RenderBackground(const gfx::Size& size,
|
| @@ -472,66 +462,78 @@ void RenderBackground(const gfx::Size& size,
|
| gtk_render_background(context, cr, 0, 0, size.width(), size.height());
|
| }
|
|
|
| -gfx::Size GetMinimumWidgetSize(GtkStyleContext* context) {
|
| - if (!GtkVersionCheck(3, 20))
|
| - return gfx::Size(1, 1);
|
| - int w = 1, h = 1;
|
| - gtk_style_context_get(context, gtk_style_context_get_state(context),
|
| - "min-width", &w, "min-height", &h, NULL);
|
| - DCHECK(w >= 0 && h >= 0);
|
| - return gfx::Size(w ? w : 1, h ? h : 1);
|
| -}
|
| -
|
| 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);
|
| - gfx::Size size = GetMinimumWidgetSize(context);
|
| - CairoSurface surface(size);
|
| - RenderBackground(size, surface.cairo(), context);
|
| - return surface.GetAveragePixelValue(false);
|
| + return GetBgColorFromStyleContext(GetStyleContextFromCss(css_selector));
|
| }
|
|
|
| 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);
|
| - gfx::Size size = GetMinimumWidgetSize(context);
|
| + gfx::Size size(24, 24);
|
| CairoSurface surface(size);
|
| - RenderBackground(size, surface.cairo(), context);
|
| gtk_render_frame(context, surface.cairo(), 0, 0, size.width(), size.height());
|
| return surface.GetAveragePixelValue(true);
|
| }
|
|
|
| +ScopedStyleContext GetSelectedStyleContext(const char* css_selector) {
|
| + auto context = GetStyleContextFromCss(css_selector);
|
| + if (GtkVersionCheck(3, 20)) {
|
| + context = AppendCssNodeToStyleContext(context, "#selection");
|
| + } else {
|
| + GtkStateFlags state = gtk_style_context_get_state(context);
|
| + state = static_cast<GtkStateFlags>(state | GTK_STATE_FLAG_SELECTED);
|
| + gtk_style_context_set_state(context, state);
|
| + }
|
| + return context;
|
| +}
|
| +
|
| +SkColor GetSelectedTextColor(const char* css_selector) {
|
| + return GetFgColorFromStyleContext(GetSelectedStyleContext(css_selector));
|
| +}
|
| +
|
| +SkColor GetSelectedBgColor(const char* css_selector) {
|
| + auto context = GetSelectedStyleContext(css_selector);
|
| + if (GtkVersionCheck(3, 20))
|
| + return GetBgColorFromStyleContext(context);
|
| + // This is verbatim how Gtk gets the selection color on versions before 3.20.
|
| + GdkRGBA selection_color;
|
| + G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
|
| + gtk_style_context_get_background_color(
|
| + context, gtk_style_context_get_state(context), &selection_color);
|
| + G_GNUC_END_IGNORE_DEPRECATIONS;
|
| + return GdkRgbaToSkColor(selection_color);
|
| +}
|
| +
|
| SkColor GetSeparatorColor(const char* css_selector) {
|
| if (!GtkVersionCheck(3, 20))
|
| return GetFgColor(css_selector);
|
|
|
| - // Some themes use borders to render separators, others use a
|
| - // background color. Only return the border color if there is one.
|
| - SkColor border = GetBorderColor(css_selector);
|
| - if (SkColorGetA(border))
|
| - return border;
|
| + auto context = GetStyleContextFromCss(css_selector);
|
| + int w = 1, h = 1;
|
| + gtk_style_context_get(context, gtk_style_context_get_state(context),
|
| + "min-width", &w, "min-height", &h, nullptr);
|
| + GtkBorder border, padding;
|
| + GtkStateFlags state = gtk_style_context_get_state(context);
|
| + gtk_style_context_get_border(context, state, &border);
|
| + gtk_style_context_get_padding(context, state, &padding);
|
| + w += border.left + padding.left + padding.right + border.right;
|
| + h += border.top + padding.top + padding.bottom + border.bottom;
|
|
|
| - return GetBgColor(css_selector);
|
| + bool horizontal = gtk_style_context_has_class(context, "horizontal");
|
| + if (horizontal) {
|
| + w = 24;
|
| + h = std::max(h, 1);
|
| + } else {
|
| + DCHECK(gtk_style_context_has_class(context, "vertical"));
|
| + h = 24;
|
| + w = std::max(w, 1);
|
| + }
|
| +
|
| + CairoSurface surface(gfx::Size(w, h));
|
| + gtk_render_background(context, surface.cairo(), 0, 0, w, h);
|
| + gtk_render_frame(context, surface.cairo(), 0, 0, w, h);
|
| + return surface.GetAveragePixelValue(false);
|
| }
|
| #endif
|
|
|
|
|