| OLD | NEW |
| 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 <dlfcn.h> | 7 #include <dlfcn.h> |
| 8 #include <gdk/gdk.h> | 8 #include <gdk/gdk.h> |
| 9 #include <gdk/gdkx.h> | 9 #include <gdk/gdkx.h> |
| 10 #include <gtk/gtk.h> | 10 #include <gtk/gtk.h> |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 CAIRO_FORMAT_ARGB32, | 213 CAIRO_FORMAT_ARGB32, |
| 214 bitmap.width(), | 214 bitmap.width(), |
| 215 bitmap.height(), | 215 bitmap.height(), |
| 216 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, bitmap.width()))), | 216 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, bitmap.width()))), |
| 217 cairo_(cairo_create(surface_)) {} | 217 cairo_(cairo_create(surface_)) {} |
| 218 | 218 |
| 219 CairoSurface::CairoSurface(const gfx::Size& size) | 219 CairoSurface::CairoSurface(const gfx::Size& size) |
| 220 : surface_(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, | 220 : surface_(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, |
| 221 size.width(), | 221 size.width(), |
| 222 size.height())), | 222 size.height())), |
| 223 cairo_(cairo_create(surface_)) {} | 223 cairo_(cairo_create(surface_)) { |
| 224 DCHECK(cairo_surface_status(surface_) == CAIRO_STATUS_SUCCESS); |
| 225 // Clear the surface. |
| 226 cairo_save(cairo_); |
| 227 cairo_set_source_rgba(cairo_, 0, 0, 0, 0); |
| 228 cairo_set_operator(cairo_, CAIRO_OPERATOR_SOURCE); |
| 229 cairo_paint(cairo_); |
| 230 cairo_restore(cairo_); |
| 231 } |
| 224 | 232 |
| 225 CairoSurface::~CairoSurface() { | 233 CairoSurface::~CairoSurface() { |
| 226 cairo_destroy(cairo_); | 234 cairo_destroy(cairo_); |
| 227 cairo_surface_destroy(surface_); | 235 cairo_surface_destroy(surface_); |
| 228 } | 236 } |
| 229 | 237 |
| 230 SkColor CairoSurface::GetAveragePixelValue(bool only_frame_pixels) { | 238 SkColor CairoSurface::GetAveragePixelValue(bool frame) { |
| 231 cairo_surface_flush(surface_); | 239 cairo_surface_flush(surface_); |
| 232 int num_samples = 0; | |
| 233 long a = 0, r = 0, g = 0, b = 0; | |
| 234 SkColor* data = | 240 SkColor* data = |
| 235 reinterpret_cast<SkColor*>(cairo_image_surface_get_data(surface_)); | 241 reinterpret_cast<SkColor*>(cairo_image_surface_get_data(surface_)); |
| 236 int width = cairo_image_surface_get_width(surface_); | 242 int width = cairo_image_surface_get_width(surface_); |
| 237 int height = cairo_image_surface_get_height(surface_); | 243 int height = cairo_image_surface_get_height(surface_); |
| 238 DCHECK(4 * width == cairo_image_surface_get_stride(surface_)); | 244 DCHECK(4 * width == cairo_image_surface_get_stride(surface_)); |
| 239 auto accumulate = [&](int x, int y) mutable { | 245 long a = 0, r = 0, g = 0, b = 0; |
| 240 SkColor color = data[y * width + x]; | 246 unsigned int max_alpha = 0; |
| 241 int alpha = SkColorGetA(color); | 247 for (int i = 0; i < width * height; i++) { |
| 242 a += alpha; | 248 SkColor color = data[i]; |
| 243 r += alpha * SkColorGetR(color); | 249 max_alpha = std::max(SkColorGetA(color), max_alpha); |
| 244 g += alpha * SkColorGetG(color); | 250 a += SkColorGetA(color); |
| 245 b += alpha * SkColorGetB(color); | 251 r += SkColorGetR(color); |
| 246 num_samples++; | 252 g += SkColorGetG(color); |
| 247 }; | 253 b += SkColorGetB(color); |
| 248 if (width == 1 || height == 1 || !only_frame_pixels) { | |
| 249 // Count every pixel in the surface. | |
| 250 for (int x = 0; x < width; x++) | |
| 251 for (int y = 0; y < height; y++) | |
| 252 accumulate(x, y); | |
| 253 } else { | |
| 254 // Count the pixels in the top and bottom rows. | |
| 255 for (int x = 0; x < width; x++) | |
| 256 for (int y : {0, height - 1}) | |
| 257 accumulate(x, y); | |
| 258 // Count the pixels in the left and right columns. | |
| 259 for (int x : {0, width - 1}) | |
| 260 for (int y = 1; y < height - 1; y++) | |
| 261 accumulate(x, y); | |
| 262 } | 254 } |
| 263 if (a == 0) | 255 if (a == 0) |
| 264 return SK_ColorTRANSPARENT; | 256 return SK_ColorTRANSPARENT; |
| 265 return SkColorSetARGB(a / num_samples, r / a, g / a, b / a); | 257 return SkColorSetARGB(frame ? max_alpha : a / (width * height), r * 255 / a, |
| 258 g * 255 / a, b * 255 / a); |
| 266 } | 259 } |
| 267 | 260 |
| 268 bool GtkVersionCheck(int major, int minor, int micro) { | 261 bool GtkVersionCheck(int major, int minor, int micro) { |
| 269 static int actual_major = gtk_get_major_version(); | 262 static int actual_major = gtk_get_major_version(); |
| 270 if (actual_major > major) | 263 if (actual_major > major) |
| 271 return true; | 264 return true; |
| 272 else if (actual_major < major) | 265 else if (actual_major < major) |
| 273 return false; | 266 return false; |
| 274 | 267 |
| 275 static int actual_minor = gtk_get_minor_version(); | 268 static int actual_minor = gtk_get_minor_version(); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 329 case '.': | 322 case '.': |
| 330 part_type = CSS_CLASS; | 323 part_type = CSS_CLASS; |
| 331 break; | 324 break; |
| 332 case ':': | 325 case ':': |
| 333 part_type = CSS_PSEUDOCLASS; | 326 part_type = CSS_PSEUDOCLASS; |
| 334 break; | 327 break; |
| 335 default: | 328 default: |
| 336 NOTREACHED(); | 329 NOTREACHED(); |
| 337 } | 330 } |
| 338 } else { | 331 } else { |
| 332 static auto* _gtk_widget_path_iter_set_object_name = |
| 333 reinterpret_cast<void (*)(GtkWidgetPath*, gint, const char*)>(dlsym( |
| 334 GetGtk3SharedLibrary(), "gtk_widget_path_iter_set_object_name")); |
| 339 switch (part_type) { | 335 switch (part_type) { |
| 340 case CSS_NAME: { | 336 case CSS_NAME: { |
| 341 if (GtkVersionCheck(3, 20)) { | 337 if (GtkVersionCheck(3, 20)) { |
| 342 static auto* _gtk_widget_path_iter_set_object_name = | |
| 343 reinterpret_cast<void (*)(GtkWidgetPath*, gint, const char*)>( | |
| 344 dlsym(GetGtk3SharedLibrary(), | |
| 345 "gtk_widget_path_iter_set_object_name")); | |
| 346 DCHECK(_gtk_widget_path_iter_set_object_name); | |
| 347 _gtk_widget_path_iter_set_object_name(path, -1, t.token().c_str()); | 338 _gtk_widget_path_iter_set_object_name(path, -1, t.token().c_str()); |
| 348 } else { | 339 } else { |
| 349 gtk_widget_path_iter_add_class(path, -1, t.token().c_str()); | 340 gtk_widget_path_iter_add_class(path, -1, t.token().c_str()); |
| 350 } | 341 } |
| 351 break; | 342 break; |
| 352 } | 343 } |
| 353 case CSS_TYPE: { | 344 case CSS_TYPE: { |
| 354 GType type = g_type_from_name(t.token().c_str()); | 345 GType type = g_type_from_name(t.token().c_str()); |
| 355 DCHECK(type); | 346 DCHECK(type); |
| 356 gtk_widget_path_append_type(path, type); | 347 gtk_widget_path_append_type(path, type); |
| 348 if (GtkVersionCheck(3, 20)) { |
| 349 if (t.token() == "GtkLabel") |
| 350 _gtk_widget_path_iter_set_object_name(path, -1, "label"); |
| 351 } |
| 357 break; | 352 break; |
| 358 } | 353 } |
| 359 case CSS_CLASS: { | 354 case CSS_CLASS: { |
| 360 gtk_widget_path_iter_add_class(path, -1, t.token().c_str()); | 355 gtk_widget_path_iter_add_class(path, -1, t.token().c_str()); |
| 361 break; | 356 break; |
| 362 } | 357 } |
| 363 case CSS_PSEUDOCLASS: { | 358 case CSS_PSEUDOCLASS: { |
| 364 GtkStateFlags state_flag = GTK_STATE_FLAG_NORMAL; | 359 GtkStateFlags state_flag = GTK_STATE_FLAG_NORMAL; |
| 365 for (const auto& pseudo_class_entry : pseudo_classes) { | 360 for (const auto& pseudo_class_entry : pseudo_classes) { |
| 366 if (strcmp(pseudo_class_entry.name, t.token().c_str()) == 0) { | 361 if (strcmp(pseudo_class_entry.name, t.token().c_str()) == 0) { |
| 367 state_flag = pseudo_class_entry.state_flag; | 362 state_flag = pseudo_class_entry.state_flag; |
| 368 break; | 363 break; |
| 369 } | 364 } |
| 370 } | 365 } |
| 371 state = static_cast<GtkStateFlags>(state | state_flag); | 366 state = static_cast<GtkStateFlags>(state | state_flag); |
| 372 break; | 367 break; |
| 373 } | 368 } |
| 374 } | 369 } |
| 375 } | 370 } |
| 376 } | 371 } |
| 377 | 372 |
| 378 // Always add a "chromium" class so that themes can style chromium | 373 // Always add a "chromium" class so that themes can style chromium |
| 379 // widgets specially if they want to. | 374 // widgets specially if they want to. |
| 380 gtk_widget_path_iter_add_class(path, -1, "chromium"); | 375 gtk_widget_path_iter_add_class(path, -1, "chromium"); |
| 381 | 376 |
| 382 auto child_context = ScopedStyleContext(gtk_style_context_new()); | 377 ScopedStyleContext child_context(gtk_style_context_new()); |
| 383 gtk_style_context_set_path(child_context, path); | 378 gtk_style_context_set_path(child_context, path); |
| 384 gtk_style_context_set_state(child_context, state); | 379 gtk_style_context_set_state(child_context, state); |
| 385 gtk_style_context_set_parent(child_context, context); | 380 gtk_style_context_set_parent(child_context, context); |
| 386 gtk_widget_path_unref(path); | 381 gtk_widget_path_unref(path); |
| 387 return child_context; | 382 return child_context; |
| 388 } | 383 } |
| 389 | 384 |
| 390 ScopedStyleContext GetStyleContextFromCss(const char* css_selector) { | 385 ScopedStyleContext GetStyleContextFromCss(const char* css_selector) { |
| 391 // Prepend "GtkWindow.background" to the selector since all widgets must live | 386 // Prepend a window node to the selector since all widgets must live |
| 392 // in a window, but we don't want to specify that every time. | 387 // in a window, but we don't want to specify that every time. |
| 393 auto context = AppendCssNodeToStyleContext(nullptr, "GtkWindow.background"); | 388 auto context = |
| 389 AppendCssNodeToStyleContext(nullptr, "GtkWindow#window.background"); |
| 394 | 390 |
| 395 for (const auto& widget_type : | 391 for (const auto& widget_type : |
| 396 base::SplitString(css_selector, base::kWhitespaceASCII, | 392 base::SplitString(css_selector, base::kWhitespaceASCII, |
| 397 base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { | 393 base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { |
| 398 context = AppendCssNodeToStyleContext(context, widget_type); | 394 context = AppendCssNodeToStyleContext(context, widget_type); |
| 399 } | 395 } |
| 400 return context; | 396 return context; |
| 401 } | 397 } |
| 402 | 398 |
| 403 SkColor GdkRgbaToSkColor(const GdkRGBA& color) { | 399 SkColor GdkRgbaToSkColor(const GdkRGBA& color) { |
| 404 return SkColorSetARGB(color.alpha * 255, color.red * 255, color.green * 255, | 400 return SkColorSetARGB(color.alpha * 255, color.red * 255, color.green * 255, |
| 405 color.blue * 255); | 401 color.blue * 255); |
| 406 } | 402 } |
| 407 | 403 |
| 408 SkColor SkColorFromStyleContext(GtkStyleContext* context) { | 404 SkColor GetFgColorFromStyleContext(GtkStyleContext* context) { |
| 409 GdkRGBA color; | 405 GdkRGBA color; |
| 410 gtk_style_context_get_color(context, gtk_style_context_get_state(context), | 406 gtk_style_context_get_color(context, gtk_style_context_get_state(context), |
| 411 &color); | 407 &color); |
| 412 return GdkRgbaToSkColor(color); | 408 return GdkRgbaToSkColor(color); |
| 413 } | 409 } |
| 414 | 410 |
| 415 SkColor GetFgColor(const char* css_selector) { | 411 SkColor GetBgColorFromStyleContext(GtkStyleContext* context) { |
| 416 return SkColorFromStyleContext(GetStyleContextFromCss(css_selector)); | 412 // Backgrounds are more general than solid colors (eg. gradients), |
| 413 // but chromium requires us to boil this down to one color. We |
| 414 // cannot use the background-color here because some themes leave it |
| 415 // set to a garbage color because a background-image will cover it |
| 416 // anyway. So we instead render the background into a 24x24 bitmap, |
| 417 // removing any borders, and hope that we get a good color. |
| 418 ApplyCssToContext(context, |
| 419 "* {" |
| 420 "border-radius: 0px;" |
| 421 "border-style: none;" |
| 422 "box-shadow: none;" |
| 423 "}"); |
| 424 gfx::Size size(24, 24); |
| 425 CairoSurface surface(size); |
| 426 RenderBackground(size, surface.cairo(), context); |
| 427 return surface.GetAveragePixelValue(false); |
| 417 } | 428 } |
| 418 | 429 |
| 419 GtkCssProvider* GetCssProvider(const char* css) { | 430 SkColor GetFgColor(const char* css_selector) { |
| 431 return GetFgColorFromStyleContext(GetStyleContextFromCss(css_selector)); |
| 432 } |
| 433 |
| 434 ScopedCssProvider GetCssProvider(const char* css) { |
| 420 GtkCssProvider* provider = gtk_css_provider_new(); | 435 GtkCssProvider* provider = gtk_css_provider_new(); |
| 421 GError* error = nullptr; | 436 GError* error = nullptr; |
| 422 gtk_css_provider_load_from_data(provider, css, -1, &error); | 437 gtk_css_provider_load_from_data(provider, css, -1, &error); |
| 423 DCHECK(!error); | 438 DCHECK(!error); |
| 424 return provider; | 439 return ScopedCssProvider(provider); |
| 425 } | 440 } |
| 426 | 441 |
| 427 void ApplyCssToContext(GtkStyleContext* context, GtkCssProvider* provider) { | 442 void ApplyCssProviderToContext(GtkStyleContext* context, |
| 443 GtkCssProvider* provider) { |
| 428 while (context) { | 444 while (context) { |
| 429 gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider), | 445 gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider), |
| 430 G_MAXUINT); | 446 G_MAXUINT); |
| 431 context = gtk_style_context_get_parent(context); | 447 context = gtk_style_context_get_parent(context); |
| 432 } | 448 } |
| 433 } | 449 } |
| 434 | 450 |
| 435 void RemoveBorders(GtkStyleContext* context) { | 451 void ApplyCssToContext(GtkStyleContext* context, const char* css) { |
| 436 static GtkCssProvider* provider = GetCssProvider( | 452 auto provider = GetCssProvider(css); |
| 437 "* {" | 453 ApplyCssProviderToContext(context, provider); |
| 438 "border-style: none;" | |
| 439 "border-radius: 0px;" | |
| 440 "border-width: 0px;" | |
| 441 "border-image-width: 0px;" | |
| 442 "box-shadow: none;" | |
| 443 "padding: 0px;" | |
| 444 "margin: 0px;" | |
| 445 "outline: none;" | |
| 446 "outline-width: 0px;" | |
| 447 "}"); | |
| 448 ApplyCssToContext(context, provider); | |
| 449 } | |
| 450 | |
| 451 void AddBorders(GtkStyleContext* context) { | |
| 452 static GtkCssProvider* provider = GetCssProvider( | |
| 453 "* {" | |
| 454 "border-style: solid;" | |
| 455 "border-radius: 0px;" | |
| 456 "border-width: 1px;" | |
| 457 "box-shadow: none;" | |
| 458 "padding: 0px;" | |
| 459 "margin: 0px;" | |
| 460 "outline: none;" | |
| 461 "outline-width: 0px;" | |
| 462 "}"); | |
| 463 ApplyCssToContext(context, provider); | |
| 464 } | 454 } |
| 465 | 455 |
| 466 void RenderBackground(const gfx::Size& size, | 456 void RenderBackground(const gfx::Size& size, |
| 467 cairo_t* cr, | 457 cairo_t* cr, |
| 468 GtkStyleContext* context) { | 458 GtkStyleContext* context) { |
| 469 if (!context) | 459 if (!context) |
| 470 return; | 460 return; |
| 471 RenderBackground(size, cr, gtk_style_context_get_parent(context)); | 461 RenderBackground(size, cr, gtk_style_context_get_parent(context)); |
| 472 gtk_render_background(context, cr, 0, 0, size.width(), size.height()); | 462 gtk_render_background(context, cr, 0, 0, size.width(), size.height()); |
| 473 } | 463 } |
| 474 | 464 |
| 475 gfx::Size GetMinimumWidgetSize(GtkStyleContext* context) { | |
| 476 if (!GtkVersionCheck(3, 20)) | |
| 477 return gfx::Size(1, 1); | |
| 478 int w = 1, h = 1; | |
| 479 gtk_style_context_get(context, gtk_style_context_get_state(context), | |
| 480 "min-width", &w, "min-height", &h, NULL); | |
| 481 DCHECK(w >= 0 && h >= 0); | |
| 482 return gfx::Size(w ? w : 1, h ? h : 1); | |
| 483 } | |
| 484 | |
| 485 SkColor GetBgColor(const char* css_selector) { | 465 SkColor GetBgColor(const char* css_selector) { |
| 486 // Backgrounds are more general than solid colors (eg. gradients), | 466 return GetBgColorFromStyleContext(GetStyleContextFromCss(css_selector)); |
| 487 // but chromium requires us to boil this down to one color. We | |
| 488 // cannot use the background-color here because some themes leave it | |
| 489 // set to a garbage color because a background-image will cover it | |
| 490 // anyway. So we instead render the background into a single pixel, | |
| 491 // removing any borders, and hope that we get a good color. | |
| 492 auto context = GetStyleContextFromCss(css_selector); | |
| 493 RemoveBorders(context); | |
| 494 gfx::Size size = GetMinimumWidgetSize(context); | |
| 495 CairoSurface surface(size); | |
| 496 RenderBackground(size, surface.cairo(), context); | |
| 497 return surface.GetAveragePixelValue(false); | |
| 498 } | 467 } |
| 499 | 468 |
| 500 SkColor GetBorderColor(const char* css_selector) { | 469 SkColor GetBorderColor(const char* css_selector) { |
| 501 // Borders have the same issue as backgrounds, due to the | 470 // Borders have the same issue as backgrounds, due to the |
| 502 // border-image property. | 471 // border-image property. |
| 503 auto context = GetStyleContextFromCss(css_selector); | 472 auto context = GetStyleContextFromCss(css_selector); |
| 504 GtkStateFlags state = gtk_style_context_get_state(context); | 473 gfx::Size size(24, 24); |
| 505 GtkBorderStyle border_style = GTK_BORDER_STYLE_NONE; | |
| 506 gtk_style_context_get(context, state, GTK_STYLE_PROPERTY_BORDER_STYLE, | |
| 507 &border_style, nullptr); | |
| 508 GtkBorder border; | |
| 509 gtk_style_context_get_border(context, state, &border); | |
| 510 if ((border_style == GTK_BORDER_STYLE_NONE || | |
| 511 border_style == GTK_BORDER_STYLE_HIDDEN) || | |
| 512 (!border.left && !border.right && !border.top && !border.bottom)) { | |
| 513 return SK_ColorTRANSPARENT; | |
| 514 } | |
| 515 | |
| 516 AddBorders(context); | |
| 517 gfx::Size size = GetMinimumWidgetSize(context); | |
| 518 CairoSurface surface(size); | 474 CairoSurface surface(size); |
| 519 RenderBackground(size, surface.cairo(), context); | |
| 520 gtk_render_frame(context, surface.cairo(), 0, 0, size.width(), size.height()); | 475 gtk_render_frame(context, surface.cairo(), 0, 0, size.width(), size.height()); |
| 521 return surface.GetAveragePixelValue(true); | 476 return surface.GetAveragePixelValue(true); |
| 522 } | 477 } |
| 523 | 478 |
| 479 ScopedStyleContext GetSelectedStyleContext(const char* css_selector) { |
| 480 auto context = GetStyleContextFromCss(css_selector); |
| 481 if (GtkVersionCheck(3, 20)) { |
| 482 context = AppendCssNodeToStyleContext(context, "#selection"); |
| 483 } else { |
| 484 GtkStateFlags state = gtk_style_context_get_state(context); |
| 485 state = static_cast<GtkStateFlags>(state | GTK_STATE_FLAG_SELECTED); |
| 486 gtk_style_context_set_state(context, state); |
| 487 } |
| 488 return context; |
| 489 } |
| 490 |
| 491 SkColor GetSelectedTextColor(const char* css_selector) { |
| 492 return GetFgColorFromStyleContext(GetSelectedStyleContext(css_selector)); |
| 493 } |
| 494 |
| 495 SkColor GetSelectedBgColor(const char* css_selector) { |
| 496 auto context = GetSelectedStyleContext(css_selector); |
| 497 if (GtkVersionCheck(3, 20)) |
| 498 return GetBgColorFromStyleContext(context); |
| 499 // This is verbatim how Gtk gets the selection color on versions before 3.20. |
| 500 GdkRGBA selection_color; |
| 501 G_GNUC_BEGIN_IGNORE_DEPRECATIONS; |
| 502 gtk_style_context_get_background_color( |
| 503 context, gtk_style_context_get_state(context), &selection_color); |
| 504 G_GNUC_END_IGNORE_DEPRECATIONS; |
| 505 return GdkRgbaToSkColor(selection_color); |
| 506 } |
| 507 |
| 524 SkColor GetSeparatorColor(const char* css_selector) { | 508 SkColor GetSeparatorColor(const char* css_selector) { |
| 525 if (!GtkVersionCheck(3, 20)) | 509 if (!GtkVersionCheck(3, 20)) |
| 526 return GetFgColor(css_selector); | 510 return GetFgColor(css_selector); |
| 527 | 511 |
| 528 // Some themes use borders to render separators, others use a | 512 auto context = GetStyleContextFromCss(css_selector); |
| 529 // background color. Only return the border color if there is one. | 513 int w = 1, h = 1; |
| 530 SkColor border = GetBorderColor(css_selector); | 514 gtk_style_context_get(context, gtk_style_context_get_state(context), |
| 531 if (SkColorGetA(border)) | 515 "min-width", &w, "min-height", &h, nullptr); |
| 532 return border; | 516 GtkBorder border, padding; |
| 517 GtkStateFlags state = gtk_style_context_get_state(context); |
| 518 gtk_style_context_get_border(context, state, &border); |
| 519 gtk_style_context_get_padding(context, state, &padding); |
| 520 w += border.left + padding.left + padding.right + border.right; |
| 521 h += border.top + padding.top + padding.bottom + border.bottom; |
| 533 | 522 |
| 534 return GetBgColor(css_selector); | 523 bool horizontal = gtk_style_context_has_class(context, "horizontal"); |
| 524 if (horizontal) { |
| 525 w = 24; |
| 526 h = std::max(h, 1); |
| 527 } else { |
| 528 DCHECK(gtk_style_context_has_class(context, "vertical")); |
| 529 h = 24; |
| 530 w = std::max(w, 1); |
| 531 } |
| 532 |
| 533 CairoSurface surface(gfx::Size(w, h)); |
| 534 gtk_render_background(context, surface.cairo(), 0, 0, w, h); |
| 535 gtk_render_frame(context, surface.cairo(), 0, 0, w, h); |
| 536 return surface.GetAveragePixelValue(false); |
| 535 } | 537 } |
| 536 #endif | 538 #endif |
| 537 | 539 |
| 538 } // namespace libgtkui | 540 } // namespace libgtkui |
| OLD | NEW |