OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/native_theme_gtk3.h" | 5 #include "chrome/browser/ui/libgtkui/native_theme_gtk3.h" |
6 | 6 |
7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
8 | 8 |
9 #include "chrome/browser/ui/libgtkui/chrome_gtk_frame.h" | 9 #include "chrome/browser/ui/libgtkui/chrome_gtk_frame.h" |
10 #include "chrome/browser/ui/libgtkui/chrome_gtk_menu_subclasses.h" | 10 #include "chrome/browser/ui/libgtkui/chrome_gtk_menu_subclasses.h" |
11 #include "chrome/browser/ui/libgtkui/gtk_util.h" | 11 #include "chrome/browser/ui/libgtkui/gtk_util.h" |
12 #include "chrome/browser/ui/libgtkui/skia_utils_gtk.h" | 12 #include "chrome/browser/ui/libgtkui/skia_utils_gtk.h" |
13 #include "ui/gfx/color_palette.h" | 13 #include "ui/gfx/color_palette.h" |
14 #include "ui/gfx/color_utils.h" | 14 #include "ui/gfx/color_utils.h" |
15 #include "ui/gfx/geometry/rect.h" | 15 #include "ui/gfx/geometry/rect.h" |
16 #include "ui/gfx/skbitmap_operations.h" | 16 #include "ui/gfx/skbitmap_operations.h" |
17 #include "ui/native_theme/native_theme_dark_aura.h" | 17 #include "ui/native_theme/native_theme_dark_aura.h" |
18 | 18 |
19 namespace libgtkui { | 19 namespace libgtkui { |
20 | 20 |
21 namespace { | 21 namespace { |
22 | 22 |
| 23 enum BackgroundRenderMode { |
| 24 BG_RENDER_NORMAL, |
| 25 BG_RENDER_NONE, |
| 26 BG_RENDER_RECURSIVE, |
| 27 }; |
| 28 |
23 SkBitmap GetWidgetBitmap(const gfx::Size& size, | 29 SkBitmap GetWidgetBitmap(const gfx::Size& size, |
24 GtkStyleContext* context) { | 30 GtkStyleContext* context, |
| 31 BackgroundRenderMode bg_mode, |
| 32 bool render_frame) { |
| 33 DCHECK(bg_mode != BG_RENDER_NONE || render_frame); |
25 SkBitmap bitmap; | 34 SkBitmap bitmap; |
26 bitmap.allocN32Pixels(size.width(), size.height()); | 35 bitmap.allocN32Pixels(size.width(), size.height()); |
27 bitmap.eraseColor(0); | 36 bitmap.eraseColor(0); |
28 | 37 |
29 cairo_surface_t* surface = cairo_image_surface_create_for_data( | 38 cairo_surface_t* surface = cairo_image_surface_create_for_data( |
30 static_cast<unsigned char*>(bitmap.getAddr(0, 0)), CAIRO_FORMAT_ARGB32, | 39 static_cast<unsigned char*>(bitmap.getAddr(0, 0)), CAIRO_FORMAT_ARGB32, |
31 size.width(), size.height(), | 40 size.width(), size.height(), |
32 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, size.width())); | 41 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, size.width())); |
33 cairo_t* cr = cairo_create(surface); | 42 cairo_t* cr = cairo_create(surface); |
34 | 43 |
35 RenderBackground(size, cr, context); | 44 switch (bg_mode) { |
36 gtk_render_frame(context, cr, 0, 0, size.width(), size.height()); | 45 case BG_RENDER_NORMAL: |
| 46 gtk_render_background(context, cr, 0, 0, size.width(), size.height()); |
| 47 break; |
| 48 case BG_RENDER_RECURSIVE: |
| 49 RenderBackground(size, cr, context); |
| 50 break; |
| 51 case BG_RENDER_NONE: |
| 52 break; |
| 53 } |
| 54 if (render_frame) |
| 55 gtk_render_frame(context, cr, 0, 0, size.width(), size.height()); |
37 cairo_destroy(cr); | 56 cairo_destroy(cr); |
38 cairo_surface_destroy(surface); | 57 cairo_surface_destroy(surface); |
39 return bitmap; | 58 return bitmap; |
40 } | 59 } |
41 | 60 |
42 void PaintWidget(SkCanvas* canvas, | 61 void PaintWidget(SkCanvas* canvas, |
43 const gfx::Rect& rect, | 62 const gfx::Rect& rect, |
44 GtkStyleContext* context) { | 63 GtkStyleContext* context, |
45 canvas->drawBitmap(GetWidgetBitmap(rect.size(), context), rect.x(), rect.y()); | 64 BackgroundRenderMode bg_mode, |
| 65 bool render_frame) { |
| 66 canvas->drawBitmap( |
| 67 GetWidgetBitmap(rect.size(), context, bg_mode, render_frame), rect.x(), |
| 68 rect.y()); |
46 } | 69 } |
47 | 70 |
48 GtkStateFlags StateToStateFlags(NativeThemeGtk3::State state) { | 71 GtkStateFlags StateToStateFlags(NativeThemeGtk3::State state) { |
49 switch (state) { | 72 switch (state) { |
50 case NativeThemeGtk3::kDisabled: | 73 case NativeThemeGtk3::kDisabled: |
51 return GTK_STATE_FLAG_INSENSITIVE; | 74 return GTK_STATE_FLAG_INSENSITIVE; |
52 case NativeThemeGtk3::kHovered: | 75 case NativeThemeGtk3::kHovered: |
53 return GTK_STATE_FLAG_PRELIGHT; | 76 return GTK_STATE_FLAG_PRELIGHT; |
54 case NativeThemeGtk3::kNormal: | 77 case NativeThemeGtk3::kNormal: |
55 return GTK_STATE_FLAG_NORMAL; | 78 return GTK_STATE_FLAG_NORMAL; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 case ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor: | 115 case ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor: |
93 return GetFgColor( | 116 return GetFgColor( |
94 "GtkMenu#menu GtkMenuItem#menuitem:selected GtkLabel#label"); | 117 "GtkMenu#menu GtkMenuItem#menuitem:selected GtkLabel#label"); |
95 case ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor: | 118 case ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor: |
96 return GetFgColor( | 119 return GetFgColor( |
97 "GtkMenu#menu GtkMenuItem#menuitem:disabled GtkLabel#label"); | 120 "GtkMenu#menu GtkMenuItem#menuitem:disabled GtkLabel#label"); |
98 case ui::NativeTheme::kColorId_MenuItemSubtitleColor: | 121 case ui::NativeTheme::kColorId_MenuItemSubtitleColor: |
99 return GetFgColor( | 122 return GetFgColor( |
100 "GtkMenu#menu GtkMenuItem#menuitem GtkLabel#label.accelerator"); | 123 "GtkMenu#menu GtkMenuItem#menuitem GtkLabel#label.accelerator"); |
101 case ui::NativeTheme::kColorId_MenuSeparatorColor: | 124 case ui::NativeTheme::kColorId_MenuSeparatorColor: |
102 // MenuButton borders are used the same way as menu separators in Chrome. | 125 // MenuButton borders are used as vertical menu separators in Chrome. |
103 case ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor: | 126 case ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor: |
104 case ui::NativeTheme::kColorId_FocusedMenuButtonBorderColor: | 127 case ui::NativeTheme::kColorId_FocusedMenuButtonBorderColor: |
105 case ui::NativeTheme::kColorId_HoverMenuButtonBorderColor: | 128 case ui::NativeTheme::kColorId_HoverMenuButtonBorderColor: |
106 if (GtkVersionCheck(3, 20)) | 129 if (GtkVersionCheck(3, 20)) |
107 return GetBgColor("GtkMenu#menu GtkSeparator#separator"); | 130 return GetBgColor("GtkMenu#menu GtkSeparator#separator"); |
108 else | 131 else |
109 return GetFgColor("GtkMenu#menu GtkMenuItem#menuitem.separator"); | 132 return GetFgColor("GtkMenu#menu GtkMenuItem#menuitem.separator"); |
110 | 133 |
111 // Label | 134 // Label |
112 case ui::NativeTheme::kColorId_LabelEnabledColor: | 135 case ui::NativeTheme::kColorId_LabelEnabledColor: |
113 return GetFgColor("GtkLabel#label"); | 136 return GetFgColor("GtkLabel#label"); |
114 case ui::NativeTheme::kColorId_LabelDisabledColor: | 137 case ui::NativeTheme::kColorId_LabelDisabledColor: |
115 return GetFgColor("GtkLabel#label:disabled"); | 138 return GetFgColor("GtkLabel#label:disabled"); |
116 case ui::NativeTheme::kColorId_LabelTextSelectionColor: | 139 case ui::NativeTheme::kColorId_LabelTextSelectionColor: |
117 return GetFgColor("GtkLabel#label #selection:selected"); | 140 return GetFgColor("GtkLabel#label #selection:selected"); |
118 case ui::NativeTheme::kColorId_LabelTextSelectionBackgroundFocused: | 141 case ui::NativeTheme::kColorId_LabelTextSelectionBackgroundFocused: |
119 return GetBgColor("GtkLabel#label #selection:selected"); | 142 return GetBgColor("GtkLabel#label #selection:selected"); |
120 | 143 |
121 // Link | 144 // Link |
122 case ui::NativeTheme::kColorId_LinkDisabled: | 145 case ui::NativeTheme::kColorId_LinkDisabled: |
123 return SkColorSetA( | 146 return SkColorSetA( |
124 SkColorFromColorId(ui::NativeTheme::kColorId_LinkEnabled), 0xBB); | 147 SkColorFromColorId(ui::NativeTheme::kColorId_LinkEnabled), 0xBB); |
125 case ui::NativeTheme::kColorId_LinkPressed: | 148 case ui::NativeTheme::kColorId_LinkPressed: |
126 if (GtkVersionCheck(3, 12)) | 149 if (GtkVersionCheck(3, 12)) |
127 return GetFgColor("GtkLabel#label.link:link:hover:active"); | 150 return GetFgColor("GtkLabel#label.link:link:hover:active"); |
128 // fallthrough | 151 // fallthrough |
129 case ui::NativeTheme::kColorId_LinkEnabled: { | 152 case ui::NativeTheme::kColorId_LinkEnabled: { |
130 if (GtkVersionCheck(3, 12)) { | 153 if (GtkVersionCheck(3, 12)) { |
131 return GetFgColor("GtkLabel#label.link:link"); | 154 return GetFgColor("GtkLabel#label.link:link"); |
132 } | 155 } |
133 auto link_context = GetStyleContextFromCss("GtkLabel#label.view"); | 156 auto link_context = GetStyleContextFromCss("GtkLabel#label.view"); |
134 GdkColor* color; | 157 GdkColor* color; |
135 gtk_style_context_get_style(link_context, "link-color", &color, nullptr); | 158 gtk_style_context_get_style(link_context, "link-color", &color, nullptr); |
136 if (color) { | 159 if (color) { |
137 SkColor ret_color = SkColorSetRGB(color->red / 255, color->green / 255, | 160 SkColor ret_color = SkColorSetRGB(color->red / 255, color->green / 255, |
138 color->blue / 255); | 161 color->blue / 255); |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 | 384 |
362 SkColor color = SkColorFromColorId(color_id); | 385 SkColor color = SkColorFromColorId(color_id); |
363 color_cache_[color_id] = color; | 386 color_cache_[color_id] = color; |
364 return color; | 387 return color; |
365 } | 388 } |
366 | 389 |
367 void NativeThemeGtk3::PaintMenuPopupBackground( | 390 void NativeThemeGtk3::PaintMenuPopupBackground( |
368 SkCanvas* canvas, | 391 SkCanvas* canvas, |
369 const gfx::Size& size, | 392 const gfx::Size& size, |
370 const MenuBackgroundExtraParams& menu_background) const { | 393 const MenuBackgroundExtraParams& menu_background) const { |
371 PaintWidget(canvas, gfx::Rect(size), GetStyleContextFromCss("GtkMenu#menu")); | 394 PaintWidget(canvas, gfx::Rect(size), GetStyleContextFromCss("GtkMenu#menu"), |
| 395 BG_RENDER_RECURSIVE, false); |
372 } | 396 } |
373 | 397 |
374 void NativeThemeGtk3::PaintMenuItemBackground( | 398 void NativeThemeGtk3::PaintMenuItemBackground( |
375 SkCanvas* canvas, | 399 SkCanvas* canvas, |
376 State state, | 400 State state, |
377 const gfx::Rect& rect, | 401 const gfx::Rect& rect, |
378 const MenuItemExtraParams& menu_item) const { | 402 const MenuItemExtraParams& menu_item) const { |
379 auto context = GetStyleContextFromCss("GtkMenu#menu GtkMenuItem#menuitem"); | 403 auto context = GetStyleContextFromCss("GtkMenu#menu GtkMenuItem#menuitem"); |
380 gtk_style_context_set_state(context, StateToStateFlags(state)); | 404 gtk_style_context_set_state(context, StateToStateFlags(state)); |
381 PaintWidget(canvas, rect, context); | 405 PaintWidget(canvas, rect, context, BG_RENDER_NORMAL, true); |
| 406 } |
| 407 |
| 408 void NativeThemeGtk3::PaintMenuSeparator( |
| 409 SkCanvas* canvas, |
| 410 State state, |
| 411 const gfx::Rect& rect, |
| 412 const MenuSeparatorExtraParams& menu_separator) const { |
| 413 auto separator_offset = [&](int separator_thickness) { |
| 414 switch (menu_separator.type) { |
| 415 case ui::LOWER_SEPARATOR: |
| 416 return rect.height() - separator_thickness; |
| 417 case ui::UPPER_SEPARATOR: |
| 418 return 0; |
| 419 default: |
| 420 return rect.height() / 2; |
| 421 } |
| 422 }; |
| 423 if (GtkVersionCheck(3, 20)) { |
| 424 auto context = |
| 425 GetStyleContextFromCss("GtkMenu#menu GtkSeparator#separator"); |
| 426 GtkBorder margin, border, padding; |
| 427 GtkStateFlags state = gtk_style_context_get_state(context); |
| 428 gtk_style_context_get_margin(context, state, &margin); |
| 429 gtk_style_context_get_border(context, state, &border); |
| 430 gtk_style_context_get_padding(context, state, &padding); |
| 431 int min_height = 0; |
| 432 gtk_style_context_get(context, state, "min-height", &min_height, NULL); |
| 433 int w = rect.width() - margin.left - margin.right; |
| 434 int h = |
| 435 min_height + padding.top + padding.bottom + border.top + border.bottom; |
| 436 int x = margin.left; |
| 437 int y = separator_offset(h); |
| 438 PaintWidget(canvas, gfx::Rect(x, y, w, h), context, BG_RENDER_NORMAL, true); |
| 439 } else { |
| 440 auto context = |
| 441 GetStyleContextFromCss("GtkMenu#menu GtkMenuItem#menuitem.separator"); |
| 442 gboolean wide_separators = false; |
| 443 gint separator_height = 0; |
| 444 gtk_style_context_get_style(context, "wide-separators", &wide_separators, |
| 445 "separator-height", &separator_height, nullptr); |
| 446 // This code was adapted from gtk/gtkmenuitem.c. For some reason, |
| 447 // padding is used as the margin. |
| 448 GtkBorder padding; |
| 449 gtk_style_context_get_padding(context, gtk_style_context_get_state(context), |
| 450 &padding); |
| 451 int w = rect.width() - padding.left - padding.right; |
| 452 int x = rect.x() + padding.left; |
| 453 int h = wide_separators ? separator_height : 1; |
| 454 int y = rect.y() + separator_offset(h); |
| 455 if (wide_separators) { |
| 456 PaintWidget(canvas, gfx::Rect(x, y, w, h), context, BG_RENDER_NONE, true); |
| 457 } else { |
| 458 SkPaint paint; |
| 459 paint.setColor(SkColorFromStyleContext(context)); |
| 460 canvas->drawLine(x, y, x + w, y, paint); |
| 461 } |
| 462 } |
382 } | 463 } |
383 | 464 |
384 void NativeThemeGtk3::PaintFrameTopArea( | 465 void NativeThemeGtk3::PaintFrameTopArea( |
385 SkCanvas* canvas, | 466 SkCanvas* canvas, |
386 State state, | 467 State state, |
387 const gfx::Rect& rect, | 468 const gfx::Rect& rect, |
388 const FrameTopAreaExtraParams& frame_top_area) const { | 469 const FrameTopAreaExtraParams& frame_top_area) const { |
389 auto context = GetStyleContextFromCss(frame_top_area.use_custom_frame | 470 auto context = GetStyleContextFromCss(frame_top_area.use_custom_frame |
390 ? "#headerbar.header-bar.titlebar" | 471 ? "#headerbar.header-bar.titlebar" |
391 : "GtkMenuBar#menubar"); | 472 : "GtkMenuBar#menubar"); |
392 RemoveBorders(context); | 473 RemoveBorders(context); |
393 gtk_style_context_set_state(context, | 474 gtk_style_context_set_state(context, frame_top_area.is_active |
394 frame_top_area.is_active | 475 ? GTK_STATE_FLAG_NORMAL |
395 ? GTK_STATE_FLAG_NORMAL | 476 : GTK_STATE_FLAG_BACKDROP); |
396 : GTK_STATE_FLAG_BACKDROP); | |
397 | 477 |
398 SkBitmap bitmap = GetWidgetBitmap(rect.size(), context); | 478 SkBitmap bitmap = |
| 479 GetWidgetBitmap(rect.size(), context, BG_RENDER_RECURSIVE, false); |
399 | 480 |
400 if (frame_top_area.incognito) { | 481 if (frame_top_area.incognito) { |
401 bitmap = SkBitmapOperations::CreateHSLShiftedBitmap( | 482 bitmap = SkBitmapOperations::CreateHSLShiftedBitmap( |
402 bitmap, kDefaultTintFrameIncognito); | 483 bitmap, kDefaultTintFrameIncognito); |
403 } | 484 } |
404 | 485 |
405 canvas->drawBitmap(bitmap, rect.x(), rect.y()); | 486 canvas->drawBitmap(bitmap, rect.x(), rect.y()); |
406 } | 487 } |
407 | 488 |
408 } // namespace libgtkui | 489 } // namespace libgtkui |
OLD | NEW |