| 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 "base/strings/string_split.h" | |
| 10 #include "base/strings/string_util.h" | |
| 11 #include "chrome/browser/ui/libgtkui/chrome_gtk_frame.h" | 9 #include "chrome/browser/ui/libgtkui/chrome_gtk_frame.h" |
| 12 #include "chrome/browser/ui/libgtkui/chrome_gtk_menu_subclasses.h" | 10 #include "chrome/browser/ui/libgtkui/chrome_gtk_menu_subclasses.h" |
| 13 #include "chrome/browser/ui/libgtkui/gtk_util.h" | 11 #include "chrome/browser/ui/libgtkui/gtk_util.h" |
| 14 #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" |
| 15 #include "ui/gfx/color_utils.h" | 14 #include "ui/gfx/color_utils.h" |
| 16 #include "ui/gfx/geometry/rect.h" | 15 #include "ui/gfx/geometry/rect.h" |
| 17 #include "ui/native_theme/native_theme_dark_aura.h" | 16 #include "ui/native_theme/native_theme_dark_aura.h" |
| 18 | 17 |
| 19 namespace libgtkui { | 18 namespace libgtkui { |
| 20 | 19 |
| 21 namespace { | 20 namespace { |
| 22 | 21 |
| 23 enum WidgetState { | |
| 24 NORMAL = 0, | |
| 25 ACTIVE = 1, | |
| 26 PRELIGHT = 2, | |
| 27 SELECTED = 3, | |
| 28 INSENSITIVE = 4, | |
| 29 }; | |
| 30 | |
| 31 // Same order as enum WidgetState above | |
| 32 const GtkStateFlags stateMap[] = { | |
| 33 GTK_STATE_FLAG_NORMAL, GTK_STATE_FLAG_ACTIVE, | |
| 34 GTK_STATE_FLAG_PRELIGHT, GTK_STATE_FLAG_SELECTED, | |
| 35 GTK_STATE_FLAG_INSENSITIVE, | |
| 36 }; | |
| 37 | |
| 38 // The caller must g_object_unref the returned context. | |
| 39 GtkStyleContext* GetStyleContextFromCss(const char* css_selector) { | |
| 40 GtkWidgetPath* path = gtk_widget_path_new(); | |
| 41 for (const auto& widget_type : | |
| 42 base::SplitString(css_selector, base::kWhitespaceASCII, | |
| 43 base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { | |
| 44 gtk_widget_path_append_type(path, G_TYPE_NONE); | |
| 45 for (const auto& widget_class : | |
| 46 base::SplitString(widget_type, ".", base::TRIM_WHITESPACE, | |
| 47 base::SPLIT_WANT_NONEMPTY)) { | |
| 48 gtk_widget_path_iter_add_class(path, -1, widget_class.c_str()); | |
| 49 } | |
| 50 } | |
| 51 | |
| 52 GtkStyleContext* context = gtk_style_context_new(); | |
| 53 gtk_style_context_set_path(context, path); | |
| 54 gtk_widget_path_unref(path); | |
| 55 return context; | |
| 56 } | |
| 57 | |
| 58 SkColor GdkRgbaToSkColor(const GdkRGBA& color) { | |
| 59 return SkColorSetARGB(color.alpha * 255, color.red * 255, color.green * 255, | |
| 60 color.blue * 255); | |
| 61 } | |
| 62 | |
| 63 SkColor ColorFromContext(GtkStyleContext* context, | |
| 64 GtkStateFlags state, | |
| 65 const char* color_name) { | |
| 66 GdkRGBA* color = nullptr; | |
| 67 gtk_style_context_get(context, state, color_name, &color, nullptr); | |
| 68 DCHECK(color); | |
| 69 SkColor sk_color = GdkRgbaToSkColor(*color); | |
| 70 gdk_rgba_free(color); | |
| 71 return sk_color; | |
| 72 } | |
| 73 | |
| 74 SkColor GetFGColor(GtkWidget* widget, WidgetState state) { | |
| 75 return ColorFromContext(gtk_widget_get_style_context(widget), stateMap[state], | |
| 76 "color"); | |
| 77 } | |
| 78 | |
| 79 SkColor GetBGColor(GtkWidget* widget, WidgetState state) { | |
| 80 return ColorFromContext(gtk_widget_get_style_context(widget), stateMap[state], | |
| 81 "background-color"); | |
| 82 } | |
| 83 | |
| 84 SkColor GetFGColor(const char* css_selector, GtkStateFlags state) { | |
| 85 GtkStyleContext* context = GetStyleContextFromCss(css_selector); | |
| 86 SkColor color = ColorFromContext(context, state, "color"); | |
| 87 g_object_unref(context); | |
| 88 return color; | |
| 89 } | |
| 90 | |
| 91 SkColor GetBGColor(const char* css_selector, GtkStateFlags state) { | |
| 92 GtkStyleContext* context = GetStyleContextFromCss(css_selector); | |
| 93 SkColor color = ColorFromContext(context, state, "background-color"); | |
| 94 g_object_unref(context); | |
| 95 return color; | |
| 96 } | |
| 97 | |
| 98 SkColor GetBorderColor(const char* css_selector, GtkStateFlags state) { | |
| 99 GtkStyleContext* context = GetStyleContextFromCss(css_selector); | |
| 100 GtkBorder border; | |
| 101 gtk_style_context_get_border(context, state, &border); | |
| 102 bool has_border = border.left || border.right || border.top || border.bottom; | |
| 103 SkColor color = ColorFromContext( | |
| 104 context, state, has_border ? "border-color" : "background-color"); | |
| 105 g_object_unref(context); | |
| 106 return color; | |
| 107 } | |
| 108 | |
| 109 void PaintWidget(SkCanvas* canvas, | 22 void PaintWidget(SkCanvas* canvas, |
| 110 const gfx::Rect& rect, | 23 const gfx::Rect& rect, |
| 111 const char* css_selector, | 24 const char* css_selector, |
| 112 GtkStateFlags state) { | 25 GtkStateFlags state) { |
| 113 SkBitmap bitmap; | 26 SkBitmap bitmap; |
| 114 bitmap.allocN32Pixels(rect.width(), rect.height()); | 27 bitmap.allocN32Pixels(rect.width(), rect.height()); |
| 115 bitmap.eraseColor(0); | 28 bitmap.eraseColor(0); |
| 116 | 29 |
| 117 cairo_surface_t* surface = cairo_image_surface_create_for_data( | 30 cairo_surface_t* surface = cairo_image_surface_create_for_data( |
| 118 static_cast<unsigned char*>(bitmap.getAddr(0, 0)), CAIRO_FORMAT_ARGB32, | 31 static_cast<unsigned char*>(bitmap.getAddr(0, 0)), CAIRO_FORMAT_ARGB32, |
| 119 rect.width(), rect.height(), | 32 rect.width(), rect.height(), |
| 120 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, rect.width())); | 33 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, rect.width())); |
| 121 cairo_t* cr = cairo_create(surface); | 34 cairo_t* cr = cairo_create(surface); |
| 122 | 35 |
| 123 GtkStyleContext* context = GetStyleContextFromCss(css_selector); | 36 auto context = GetStyleContextFromCss(css_selector); |
| 124 gtk_style_context_set_state(context, state); | 37 gtk_style_context_set_state(context, state); |
| 125 | 38 |
| 126 gtk_render_background(context, cr, 0, 0, rect.width(), rect.height()); | 39 gtk_render_background(context, cr, 0, 0, rect.width(), rect.height()); |
| 127 gtk_render_frame(context, cr, 0, 0, rect.width(), rect.height()); | 40 gtk_render_frame(context, cr, 0, 0, rect.width(), rect.height()); |
| 128 cairo_destroy(cr); | 41 cairo_destroy(cr); |
| 129 cairo_surface_destroy(surface); | 42 cairo_surface_destroy(surface); |
| 130 canvas->drawBitmap(bitmap, rect.x(), rect.y()); | 43 canvas->drawBitmap(bitmap, rect.x(), rect.y()); |
| 131 | |
| 132 g_object_unref(context); | |
| 133 } | 44 } |
| 134 | 45 |
| 135 GtkStateFlags StateToStateFlags(NativeThemeGtk3::State state) { | 46 GtkStateFlags StateToStateFlags(NativeThemeGtk3::State state) { |
| 136 switch (state) { | 47 switch (state) { |
| 137 case NativeThemeGtk3::kDisabled: | 48 case NativeThemeGtk3::kDisabled: |
| 138 return GTK_STATE_FLAG_INSENSITIVE; | 49 return GTK_STATE_FLAG_INSENSITIVE; |
| 139 case NativeThemeGtk3::kHovered: | 50 case NativeThemeGtk3::kHovered: |
| 140 return GTK_STATE_FLAG_PRELIGHT; | 51 return GTK_STATE_FLAG_PRELIGHT; |
| 141 case NativeThemeGtk3::kNormal: | 52 case NativeThemeGtk3::kNormal: |
| 142 return GTK_STATE_FLAG_NORMAL; | 53 return GTK_STATE_FLAG_NORMAL; |
| 143 case NativeThemeGtk3::kPressed: | 54 case NativeThemeGtk3::kPressed: |
| 144 return static_cast<GtkStateFlags>(GTK_STATE_FLAG_PRELIGHT | | 55 return static_cast<GtkStateFlags>(GTK_STATE_FLAG_PRELIGHT | |
| 145 GTK_STATE_FLAG_ACTIVE); | 56 GTK_STATE_FLAG_ACTIVE); |
| 146 default: | 57 default: |
| 147 NOTREACHED(); | 58 NOTREACHED(); |
| 148 return GTK_STATE_FLAG_NORMAL; | 59 return GTK_STATE_FLAG_NORMAL; |
| 149 } | 60 } |
| 150 } | 61 } |
| 151 | 62 |
| 63 SkColor SkColorFromColorId(ui::NativeTheme::ColorId color_id) { |
| 64 const SkColor kPositiveTextColor = SkColorSetRGB(0x0b, 0x80, 0x43); |
| 65 const SkColor kNegativeTextColor = SkColorSetRGB(0xc5, 0x39, 0x29); |
| 66 |
| 67 switch (color_id) { |
| 68 // Windows |
| 69 case ui::NativeTheme::kColorId_WindowBackground: |
| 70 // Dialogs |
| 71 case ui::NativeTheme::kColorId_DialogBackground: |
| 72 case ui::NativeTheme::kColorId_BubbleBackground: |
| 73 return GetBGColor(""); |
| 74 |
| 75 // FocusableBorder |
| 76 case ui::NativeTheme::kColorId_FocusedBorderColor: |
| 77 return GetBorderColor("GtkEntry.entry:focus"); |
| 78 case ui::NativeTheme::kColorId_UnfocusedBorderColor: |
| 79 return GetBorderColor("GtkEntry.entry"); |
| 80 |
| 81 // Menu |
| 82 case ui::NativeTheme::kColorId_MenuBackgroundColor: |
| 83 return GetBGColor("GtkMenu.menu"); |
| 84 case ui::NativeTheme::kColorId_MenuBorderColor: |
| 85 return GetBorderColor("GtkMenu.menu"); |
| 86 case ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor: |
| 87 return GetBGColor("GtkMenu.menu GtkMenuItem.menuitem:focus"); |
| 88 case ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor: |
| 89 return GetFGColor("GtkMenu.menu GtkMenuItem.menuitem GtkLabel.label"); |
| 90 case ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor: |
| 91 return GetFGColor( |
| 92 "GtkMenu.menu GtkMenuItem.menuitem:selected GtkLabel.label"); |
| 93 case ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor: |
| 94 return GetFGColor( |
| 95 "GtkMenu.menu GtkMenuItem.menuitem:disabled GtkLabel.label"); |
| 96 case ui::NativeTheme::kColorId_MenuItemSubtitleColor: |
| 97 return GetFGColor( |
| 98 "GtkMenu.menu GtkMenuItem.menuitem GtkLabel.label.accelerator"); |
| 99 case ui::NativeTheme::kColorId_MenuSeparatorColor: |
| 100 // MenuButton borders are used the same way as menu separators in Chrome. |
| 101 case ui::NativeTheme::kColorId_EnabledMenuButtonBorderColor: |
| 102 case ui::NativeTheme::kColorId_FocusedMenuButtonBorderColor: |
| 103 case ui::NativeTheme::kColorId_HoverMenuButtonBorderColor: |
| 104 return GetFGColor("GtkMenu.menu GtkMenuItem.menuitem.separator:disabled"); |
| 105 |
| 106 // Label |
| 107 case ui::NativeTheme::kColorId_LabelEnabledColor: |
| 108 return GetFGColor("GtkLabel.label"); |
| 109 case ui::NativeTheme::kColorId_LabelDisabledColor: |
| 110 return GetFGColor("GtkLabel.label:disabled"); |
| 111 case ui::NativeTheme::kColorId_LabelTextSelectionColor: |
| 112 return GetFGColor("GtkLabel.label .selection:selected"); |
| 113 case ui::NativeTheme::kColorId_LabelTextSelectionBackgroundFocused: |
| 114 return GetBGColor("GtkLabel.label .selection:selected"); |
| 115 |
| 116 // Link |
| 117 case ui::NativeTheme::kColorId_LinkDisabled: |
| 118 return SkColorSetA( |
| 119 SkColorFromColorId(ui::NativeTheme::kColorId_LinkEnabled), 0xBB); |
| 120 case ui::NativeTheme::kColorId_LinkPressed: |
| 121 case ui::NativeTheme::kColorId_LinkEnabled: { |
| 122 // TODO(thomasanderson): Gtk changed the way links are colored in 3.12. |
| 123 // Add code for later versions. |
| 124 auto link_context = GetStyleContextFromCss("GtkLabel.label.view"); |
| 125 GdkColor* color; |
| 126 gtk_style_context_get_style(link_context, "link-color", &color, nullptr); |
| 127 if (color) { |
| 128 SkColor ret_color = SkColorSetRGB(color->red / 255, color->green / 255, |
| 129 color->blue / 255); |
| 130 gdk_color_free(color); |
| 131 return ret_color; |
| 132 } else { |
| 133 // Default color comes from gtklinkbutton.c. |
| 134 return SkColorSetRGB(0x00, 0x00, 0xEE); |
| 135 } |
| 136 } |
| 137 |
| 138 // Button |
| 139 case ui::NativeTheme::kColorId_ButtonEnabledColor: |
| 140 return GetFGColor("GtkButton.button.text-button GtkLabel.label"); |
| 141 case ui::NativeTheme::kColorId_ButtonDisabledColor: |
| 142 return GetFGColor("GtkButton.button.text-button:disabled GtkLabel.label"); |
| 143 case ui::NativeTheme::kColorId_ButtonHoverColor: |
| 144 return GetFGColor("GtkButton.button.text-button:hover GtkLabel.label"); |
| 145 case ui::NativeTheme::kColorId_ButtonPressedShade: |
| 146 return SK_ColorTRANSPARENT; |
| 147 |
| 148 case ui::NativeTheme::kColorId_BlueButtonEnabledColor: |
| 149 return GetFGColor( |
| 150 "GtkButton.button.text-button.suggested-action GtkLabel.label"); |
| 151 case ui::NativeTheme::kColorId_BlueButtonDisabledColor: |
| 152 return GetFGColor( |
| 153 "GtkButton.button.text-button.suggested-action:disabled " |
| 154 "GtkLabel.label"); |
| 155 case ui::NativeTheme::kColorId_BlueButtonHoverColor: |
| 156 return GetFGColor( |
| 157 "GtkButton.button.text-button.suggested-action:hover GtkLabel.label"); |
| 158 case ui::NativeTheme::kColorId_BlueButtonPressedColor: |
| 159 return GetFGColor( |
| 160 "GtkButton.button.text-button.suggested-action:hover:active " |
| 161 "GtkLabel.label"); |
| 162 case ui::NativeTheme::kColorId_BlueButtonShadowColor: |
| 163 return SK_ColorTRANSPARENT; |
| 164 |
| 165 case ui::NativeTheme::kColorId_ProminentButtonColor: |
| 166 return GetBGColor("GtkButton.button.text-button.destructive-action"); |
| 167 case ui::NativeTheme::kColorId_TextOnProminentButtonColor: |
| 168 return GetFGColor( |
| 169 "GtkButton.button.text-button.destructive-action GtkLabel.label"); |
| 170 |
| 171 // Textfield |
| 172 case ui::NativeTheme::kColorId_TextfieldDefaultColor: |
| 173 return GetFGColor("GtkEntry.entry"); |
| 174 case ui::NativeTheme::kColorId_TextfieldDefaultBackground: |
| 175 return GetBGColor("GtkEntry.entry"); |
| 176 case ui::NativeTheme::kColorId_TextfieldReadOnlyColor: |
| 177 return GetFGColor("GtkEntry.entry:disabled"); |
| 178 case ui::NativeTheme::kColorId_TextfieldReadOnlyBackground: |
| 179 return GetBGColor("GtkEntry.entry:disabled"); |
| 180 case ui::NativeTheme::kColorId_TextfieldSelectionColor: |
| 181 return GetFGColor("GtkEntry.entry .selection:selected"); |
| 182 case ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused: |
| 183 return GetBGColor("GtkEntry.entry .selection:selected"); |
| 184 |
| 185 // Tooltips |
| 186 case ui::NativeTheme::kColorId_TooltipBackground: |
| 187 return GetBGColor("GtkTooltip.tooltip"); |
| 188 case ui::NativeTheme::kColorId_TooltipText: |
| 189 return color_utils::GetReadableColor(GetFGColor("GtkTooltip.tooltip"), |
| 190 GetBGColor("GtkTooltip.tooltip")); |
| 191 |
| 192 // Trees and Tables (implemented on GTK using the same class) |
| 193 case ui::NativeTheme::kColorId_TableBackground: |
| 194 case ui::NativeTheme::kColorId_TreeBackground: |
| 195 return GetBGColor("GtkTreeView.view"); |
| 196 case ui::NativeTheme::kColorId_TableText: |
| 197 case ui::NativeTheme::kColorId_TreeText: |
| 198 case ui::NativeTheme::kColorId_TreeArrow: |
| 199 case ui::NativeTheme::kColorId_TableGroupingIndicatorColor: |
| 200 return GetFGColor("GtkTreeView.view .cell"); |
| 201 case ui::NativeTheme::kColorId_TableSelectedText: |
| 202 case ui::NativeTheme::kColorId_TableSelectedTextUnfocused: |
| 203 case ui::NativeTheme::kColorId_TreeSelectedText: |
| 204 case ui::NativeTheme::kColorId_TreeSelectedTextUnfocused: |
| 205 return GetFGColor("GtkTreeView.view .cell:selected"); |
| 206 case ui::NativeTheme::kColorId_TableSelectionBackgroundFocused: |
| 207 case ui::NativeTheme::kColorId_TableSelectionBackgroundUnfocused: |
| 208 case ui::NativeTheme::kColorId_TreeSelectionBackgroundFocused: |
| 209 case ui::NativeTheme::kColorId_TreeSelectionBackgroundUnfocused: |
| 210 return GetBGColor("GtkTreeView.view .cell:selected"); |
| 211 |
| 212 // Results Table |
| 213 // TODO(thomasanderson): The GtkEntry selectors was how the gtk2 theme got |
| 214 // these colors. Update this code to use a different widget. |
| 215 case ui::NativeTheme::kColorId_ResultsTableNormalBackground: |
| 216 return GetBGColor("GtkEntry.entry"); |
| 217 case ui::NativeTheme::kColorId_ResultsTableHoveredBackground: |
| 218 return color_utils::AlphaBlend( |
| 219 GetBGColor("GtkEntry.entry"), |
| 220 GetBGColor("GtkEntry.entry .selection:selected"), 0x80); |
| 221 case ui::NativeTheme::kColorId_ResultsTableSelectedBackground: |
| 222 return GetBGColor("GtkEntry.entry .selection:selected"); |
| 223 case ui::NativeTheme::kColorId_ResultsTableNormalText: |
| 224 case ui::NativeTheme::kColorId_ResultsTableHoveredText: |
| 225 return GetFGColor("GtkEntry.entry"); |
| 226 case ui::NativeTheme::kColorId_ResultsTableSelectedText: |
| 227 return GetFGColor("GtkEntry.entry .selection:selected"); |
| 228 case ui::NativeTheme::kColorId_ResultsTableNormalDimmedText: |
| 229 case ui::NativeTheme::kColorId_ResultsTableHoveredDimmedText: |
| 230 return color_utils::AlphaBlend(GetFGColor("GtkEntry.entry"), |
| 231 GetBGColor("GtkEntry.entry"), 0x80); |
| 232 case ui::NativeTheme::kColorId_ResultsTableSelectedDimmedText: |
| 233 return color_utils::AlphaBlend( |
| 234 GetFGColor("GtkEntry.entry .selection:selected"), |
| 235 GetBGColor("GtkEntry.entry"), 0x80); |
| 236 case ui::NativeTheme::kColorId_ResultsTableNormalUrl: |
| 237 case ui::NativeTheme::kColorId_ResultsTableHoveredUrl: |
| 238 return NormalURLColor(GetFGColor("GtkEntry.entry")); |
| 239 case ui::NativeTheme::kColorId_ResultsTableSelectedUrl: |
| 240 return SelectedURLColor(GetFGColor("GtkEntry.entry .selection:selected"), |
| 241 GetBGColor("GtkEntry.entry .selection:selected")); |
| 242 |
| 243 case ui::NativeTheme::kColorId_ResultsTablePositiveText: |
| 244 return color_utils::GetReadableColor(kPositiveTextColor, |
| 245 GetBGColor("GtkEntry.entry")); |
| 246 case ui::NativeTheme::kColorId_ResultsTablePositiveHoveredText: |
| 247 return color_utils::GetReadableColor(kPositiveTextColor, |
| 248 GetBGColor("GtkEntry.entry:hover")); |
| 249 case ui::NativeTheme::kColorId_ResultsTablePositiveSelectedText: |
| 250 return color_utils::GetReadableColor( |
| 251 kPositiveTextColor, GetBGColor("GtkEntry.entry:selected")); |
| 252 case ui::NativeTheme::kColorId_ResultsTableNegativeText: |
| 253 return color_utils::GetReadableColor(kNegativeTextColor, |
| 254 GetBGColor("GtkEntry.entry")); |
| 255 case ui::NativeTheme::kColorId_ResultsTableNegativeHoveredText: |
| 256 return color_utils::GetReadableColor(kNegativeTextColor, |
| 257 GetBGColor("GtkEntry.entry:hover")); |
| 258 case ui::NativeTheme::kColorId_ResultsTableNegativeSelectedText: |
| 259 return color_utils::GetReadableColor( |
| 260 kNegativeTextColor, GetBGColor("GtkEntry.entry:selected")); |
| 261 |
| 262 // Throbber |
| 263 // TODO(thomasanderson): Render GtkSpinner directly. |
| 264 case ui::NativeTheme::kColorId_ThrobberSpinningColor: |
| 265 case ui::NativeTheme::kColorId_ThrobberWaitingColor: |
| 266 return GetFGColor("GtkMenu.menu GtkSpinner.spinner"); |
| 267 case ui::NativeTheme::kColorId_ThrobberLightColor: |
| 268 return GetFGColor("GtkMenu.menu GtkSpinner.spinner:disabled"); |
| 269 |
| 270 // Alert icons |
| 271 case ui::NativeTheme::kColorId_AlertSeverityLow: |
| 272 return GetBGColor("GtkInfoBar.infobar.info"); |
| 273 case ui::NativeTheme::kColorId_AlertSeverityMedium: |
| 274 return GetBGColor("GtkInfoBar.infobar.warning"); |
| 275 case ui::NativeTheme::kColorId_AlertSeverityHigh: |
| 276 return GetBGColor("GtkInfoBar.infobar.error"); |
| 277 |
| 278 case ui::NativeTheme::kColorId_NumColors: |
| 279 NOTREACHED(); |
| 280 break; |
| 281 } |
| 282 return kInvalidColorIdColor; |
| 283 } |
| 284 |
| 285 void OnThemeChanged(GObject* obj, GParamSpec* param, NativeThemeGtk3* theme) { |
| 286 theme->ResetColorCache(); |
| 287 } |
| 288 |
| 152 } // namespace | 289 } // namespace |
| 153 | 290 |
| 154 // static | 291 // static |
| 155 NativeThemeGtk3* NativeThemeGtk3::instance() { | 292 NativeThemeGtk3* NativeThemeGtk3::instance() { |
| 156 CR_DEFINE_STATIC_LOCAL(NativeThemeGtk3, s_native_theme, ()); | 293 CR_DEFINE_STATIC_LOCAL(NativeThemeGtk3, s_native_theme, ()); |
| 157 return &s_native_theme; | 294 return &s_native_theme; |
| 158 } | 295 } |
| 159 | 296 |
| 160 // Constructors automatically called | 297 // Constructors automatically called |
| 161 NativeThemeGtk3::NativeThemeGtk3() {} | 298 NativeThemeGtk3::NativeThemeGtk3() { |
| 299 // These types are needed by g_type_from_name(), but may not be registered at |
| 300 // this point. We need the g_type_class magic to make sure the compiler |
| 301 // doesn't optimize away this code. |
| 302 g_type_class_unref(g_type_class_ref(gtk_button_get_type())); |
| 303 g_type_class_unref(g_type_class_ref(gtk_label_get_type())); |
| 304 g_type_class_unref(g_type_class_ref(gtk_window_get_type())); |
| 305 g_type_class_unref(g_type_class_ref(gtk_link_button_get_type())); |
| 306 g_type_class_unref(g_type_class_ref(gtk_spinner_get_type())); |
| 307 g_type_class_unref(g_type_class_ref(gtk_menu_get_type())); |
| 308 g_type_class_unref(g_type_class_ref(gtk_menu_item_get_type())); |
| 309 g_type_class_unref(g_type_class_ref(gtk_entry_get_type())); |
| 310 g_type_class_unref(g_type_class_ref(gtk_info_bar_get_type())); |
| 311 g_type_class_unref(g_type_class_ref(gtk_tooltip_get_type())); |
| 312 g_type_class_unref(g_type_class_ref(gtk_scrollbar_get_type())); |
| 313 g_type_class_unref(g_type_class_ref(gtk_toolbar_get_type())); |
| 314 g_type_class_unref(g_type_class_ref(gtk_text_view_get_type())); |
| 315 |
| 316 g_signal_connect_after(gtk_settings_get_default(), "notify::gtk-theme-name", |
| 317 G_CALLBACK(OnThemeChanged), this); |
| 318 } |
| 319 |
| 162 // This doesn't actually get called | 320 // This doesn't actually get called |
| 163 NativeThemeGtk3::~NativeThemeGtk3() {} | 321 NativeThemeGtk3::~NativeThemeGtk3() {} |
| 164 | 322 |
| 165 SkColor NativeThemeGtk3::LookupGtkThemeColor(ColorId color_id) const { | 323 void NativeThemeGtk3::ResetColorCache() { |
| 166 const SkColor kPositiveTextColor = SkColorSetRGB(0x0b, 0x80, 0x43); | 324 for (auto& color : color_cache_) |
| 167 const SkColor kNegativeTextColor = SkColorSetRGB(0xc5, 0x39, 0x29); | 325 color = base::nullopt; |
| 168 | |
| 169 switch (color_id) { | |
| 170 // Windows | |
| 171 case kColorId_WindowBackground: | |
| 172 return GetBGColor(GetWindow(), SELECTED); | |
| 173 | |
| 174 // Dialogs | |
| 175 case kColorId_DialogBackground: | |
| 176 case kColorId_BubbleBackground: | |
| 177 return GetBGColor(GetWindow(), NORMAL); | |
| 178 | |
| 179 // FocusableBorder | |
| 180 case kColorId_FocusedBorderColor: | |
| 181 return GetBGColor(GetEntry(), SELECTED); | |
| 182 case kColorId_UnfocusedBorderColor: | |
| 183 return GetFGColor(GetEntry(), NORMAL); | |
| 184 | |
| 185 // Menu | |
| 186 case kColorId_MenuBackgroundColor: | |
| 187 return GetBGColor("menu", GTK_STATE_FLAG_NORMAL); | |
| 188 case kColorId_MenuBorderColor: | |
| 189 return GetBorderColor("menu", GTK_STATE_FLAG_NORMAL); | |
| 190 case kColorId_FocusedMenuItemBackgroundColor: | |
| 191 return GetBGColor("menu menuitem", GTK_STATE_FLAG_FOCUSED); | |
| 192 case kColorId_EnabledMenuItemForegroundColor: | |
| 193 return GetFGColor("menu menuitem label", GTK_STATE_FLAG_NORMAL); | |
| 194 case kColorId_SelectedMenuItemForegroundColor: | |
| 195 return GetFGColor("menu menuitem label", GTK_STATE_FLAG_SELECTED); | |
| 196 case kColorId_DisabledMenuItemForegroundColor: | |
| 197 return GetFGColor("menu menuitem label", GTK_STATE_FLAG_INSENSITIVE); | |
| 198 case kColorId_MenuItemSubtitleColor: | |
| 199 return GetFGColor("menu menuitem accelerator", GTK_STATE_FLAG_NORMAL); | |
| 200 case kColorId_MenuSeparatorColor: | |
| 201 // MenuButton borders are used the same way as menu separtors in Chrome. | |
| 202 case kColorId_EnabledMenuButtonBorderColor: | |
| 203 case kColorId_FocusedMenuButtonBorderColor: | |
| 204 case kColorId_HoverMenuButtonBorderColor: | |
| 205 return GetFGColor("menu menuitem.separator", GTK_STATE_FLAG_INSENSITIVE); | |
| 206 | |
| 207 // Label | |
| 208 case kColorId_LabelEnabledColor: | |
| 209 return GetFGColor(GetEntry(), NORMAL); | |
| 210 case kColorId_LabelDisabledColor: | |
| 211 return GetFGColor(GetLabel(), INSENSITIVE); | |
| 212 case kColorId_LabelTextSelectionColor: | |
| 213 return GetFGColor(GetLabel(), SELECTED); | |
| 214 case kColorId_LabelTextSelectionBackgroundFocused: | |
| 215 return GetBGColor(GetLabel(), SELECTED); | |
| 216 | |
| 217 // Link | |
| 218 case kColorId_LinkDisabled: | |
| 219 return SkColorSetA(GetSystemColor(kColorId_LinkEnabled), 0xBB); | |
| 220 case kColorId_LinkEnabled: { | |
| 221 SkColor link_color = SK_ColorTRANSPARENT; | |
| 222 GdkColor* style_color = nullptr; | |
| 223 gtk_widget_style_get(GetWindow(), "link-color", &style_color, nullptr); | |
| 224 if (style_color) { | |
| 225 link_color = GdkColorToSkColor(*style_color); | |
| 226 gdk_color_free(style_color); | |
| 227 } | |
| 228 if (link_color != SK_ColorTRANSPARENT) | |
| 229 return link_color; | |
| 230 // Default color comes from gtklinkbutton.c. | |
| 231 return SkColorSetRGB(0x00, 0x00, 0xEE); | |
| 232 } | |
| 233 case kColorId_LinkPressed: | |
| 234 return SK_ColorRED; | |
| 235 | |
| 236 // Button | |
| 237 case kColorId_ButtonEnabledColor: | |
| 238 return GetFGColor(GetButton(), NORMAL); | |
| 239 case kColorId_BlueButtonEnabledColor: | |
| 240 return GetFGColor(GetBlueButton(), NORMAL); | |
| 241 case kColorId_ButtonDisabledColor: | |
| 242 return GetFGColor(GetButton(), INSENSITIVE); | |
| 243 case kColorId_BlueButtonDisabledColor: | |
| 244 return GetFGColor(GetBlueButton(), INSENSITIVE); | |
| 245 case kColorId_ButtonHoverColor: | |
| 246 return GetFGColor(GetButton(), PRELIGHT); | |
| 247 case kColorId_BlueButtonHoverColor: | |
| 248 return GetFGColor(GetBlueButton(), PRELIGHT); | |
| 249 case kColorId_BlueButtonPressedColor: | |
| 250 return GetFGColor(GetBlueButton(), ACTIVE); | |
| 251 case kColorId_BlueButtonShadowColor: | |
| 252 return SK_ColorTRANSPARENT; | |
| 253 case kColorId_ProminentButtonColor: | |
| 254 return GetSystemColor(kColorId_LinkEnabled); | |
| 255 case kColorId_TextOnProminentButtonColor: | |
| 256 return GetFGColor(GetLabel(), SELECTED); | |
| 257 case kColorId_ButtonPressedShade: | |
| 258 return SK_ColorTRANSPARENT; | |
| 259 | |
| 260 // Textfield | |
| 261 case kColorId_TextfieldDefaultColor: | |
| 262 return GetFGColor(GetEntry(), NORMAL); | |
| 263 case kColorId_TextfieldDefaultBackground: | |
| 264 return GetBGColor(GetEntry(), NORMAL); | |
| 265 | |
| 266 case kColorId_TextfieldReadOnlyColor: | |
| 267 return GetFGColor(GetEntry(), SELECTED); | |
| 268 case kColorId_TextfieldReadOnlyBackground: | |
| 269 return GetBGColor(GetEntry(), SELECTED); | |
| 270 case kColorId_TextfieldSelectionColor: | |
| 271 return GetFGColor(GetLabel(), SELECTED); | |
| 272 case kColorId_TextfieldSelectionBackgroundFocused: | |
| 273 return GetBGColor(GetLabel(), SELECTED); | |
| 274 | |
| 275 // Tooltips | |
| 276 case kColorId_TooltipBackground: | |
| 277 return GetBGColor(GetTooltip(), NORMAL); | |
| 278 case kColorId_TooltipText: | |
| 279 return GetFGColor(GetTooltip(), NORMAL); | |
| 280 | |
| 281 // Trees and Tables (implemented on GTK using the same class) | |
| 282 case kColorId_TableBackground: | |
| 283 case kColorId_TreeBackground: | |
| 284 return GetBGColor(GetTree(), NORMAL); | |
| 285 case kColorId_TableText: | |
| 286 case kColorId_TreeText: | |
| 287 return GetFGColor(GetTree(), NORMAL); | |
| 288 case kColorId_TableSelectedText: | |
| 289 case kColorId_TableSelectedTextUnfocused: | |
| 290 case kColorId_TreeSelectedText: | |
| 291 case kColorId_TreeSelectedTextUnfocused: | |
| 292 return GetFGColor(GetTree(), SELECTED); | |
| 293 case kColorId_TableSelectionBackgroundFocused: | |
| 294 case kColorId_TableSelectionBackgroundUnfocused: | |
| 295 case kColorId_TreeSelectionBackgroundFocused: | |
| 296 case kColorId_TreeSelectionBackgroundUnfocused: | |
| 297 return GetBGColor(GetTree(), SELECTED); | |
| 298 case kColorId_TreeArrow: | |
| 299 return GetFGColor(GetTree(), NORMAL); | |
| 300 case kColorId_TableGroupingIndicatorColor: | |
| 301 return GetFGColor(GetTree(), NORMAL); | |
| 302 | |
| 303 // Results Table | |
| 304 case kColorId_ResultsTableNormalBackground: | |
| 305 return GetSystemColor(kColorId_TextfieldDefaultBackground); | |
| 306 case kColorId_ResultsTableHoveredBackground: | |
| 307 return color_utils::AlphaBlend( | |
| 308 GetSystemColor(kColorId_TextfieldDefaultBackground), | |
| 309 GetSystemColor(kColorId_TextfieldSelectionBackgroundFocused), 0x80); | |
| 310 case kColorId_ResultsTableSelectedBackground: | |
| 311 return GetSystemColor(kColorId_TextfieldSelectionBackgroundFocused); | |
| 312 case kColorId_ResultsTableNormalText: | |
| 313 case kColorId_ResultsTableHoveredText: | |
| 314 return GetSystemColor(kColorId_TextfieldDefaultColor); | |
| 315 case kColorId_ResultsTableSelectedText: | |
| 316 return GetSystemColor(kColorId_TextfieldSelectionColor); | |
| 317 case kColorId_ResultsTableNormalDimmedText: | |
| 318 case kColorId_ResultsTableHoveredDimmedText: | |
| 319 return color_utils::AlphaBlend( | |
| 320 GetSystemColor(kColorId_TextfieldDefaultColor), | |
| 321 GetSystemColor(kColorId_TextfieldDefaultBackground), 0x80); | |
| 322 case kColorId_ResultsTableSelectedDimmedText: | |
| 323 return color_utils::AlphaBlend( | |
| 324 GetSystemColor(kColorId_TextfieldSelectionColor), | |
| 325 GetSystemColor(kColorId_TextfieldDefaultBackground), 0x80); | |
| 326 case kColorId_ResultsTableNormalUrl: | |
| 327 case kColorId_ResultsTableHoveredUrl: | |
| 328 return NormalURLColor(GetSystemColor(kColorId_TextfieldDefaultColor)); | |
| 329 | |
| 330 case kColorId_ResultsTableSelectedUrl: | |
| 331 return SelectedURLColor( | |
| 332 GetSystemColor(kColorId_TextfieldSelectionColor), | |
| 333 GetSystemColor(kColorId_TextfieldSelectionBackgroundFocused)); | |
| 334 | |
| 335 case kColorId_ResultsTablePositiveText: | |
| 336 return color_utils::GetReadableColor(kPositiveTextColor, | |
| 337 GetBGColor(GetEntry(), NORMAL)); | |
| 338 case kColorId_ResultsTablePositiveHoveredText: | |
| 339 return color_utils::GetReadableColor(kPositiveTextColor, | |
| 340 GetBGColor(GetEntry(), PRELIGHT)); | |
| 341 case kColorId_ResultsTablePositiveSelectedText: | |
| 342 return color_utils::GetReadableColor(kPositiveTextColor, | |
| 343 GetBGColor(GetEntry(), SELECTED)); | |
| 344 case kColorId_ResultsTableNegativeText: | |
| 345 return color_utils::GetReadableColor(kNegativeTextColor, | |
| 346 GetBGColor(GetEntry(), NORMAL)); | |
| 347 case kColorId_ResultsTableNegativeHoveredText: | |
| 348 return color_utils::GetReadableColor(kNegativeTextColor, | |
| 349 GetBGColor(GetEntry(), PRELIGHT)); | |
| 350 case kColorId_ResultsTableNegativeSelectedText: | |
| 351 return color_utils::GetReadableColor(kNegativeTextColor, | |
| 352 GetBGColor(GetEntry(), SELECTED)); | |
| 353 | |
| 354 // Throbber | |
| 355 case kColorId_ThrobberSpinningColor: | |
| 356 case kColorId_ThrobberLightColor: | |
| 357 return GetSystemColor(kColorId_TextfieldSelectionBackgroundFocused); | |
| 358 | |
| 359 case kColorId_ThrobberWaitingColor: | |
| 360 return color_utils::AlphaBlend( | |
| 361 GetSystemColor(kColorId_TextfieldSelectionBackgroundFocused), | |
| 362 GetBGColor(GetWindow(), NORMAL), 0x80); | |
| 363 | |
| 364 // Alert icons | |
| 365 // Just fall back to the same colors as Aura. | |
| 366 case kColorId_AlertSeverityLow: | |
| 367 case kColorId_AlertSeverityMedium: | |
| 368 case kColorId_AlertSeverityHigh: | |
| 369 return SK_ColorTRANSPARENT; | |
| 370 | |
| 371 case kColorId_NumColors: | |
| 372 NOTREACHED(); | |
| 373 break; | |
| 374 } | |
| 375 | |
| 376 return kInvalidColorIdColor; | |
| 377 } | 326 } |
| 378 | 327 |
| 379 SkColor NativeThemeGtk3::GetSystemColor(ColorId color_id) const { | 328 SkColor NativeThemeGtk3::GetSystemColor(ColorId color_id) const { |
| 380 SkColor color = LookupGtkThemeColor(color_id); | 329 if (color_cache_[color_id]) |
| 381 if (SkColorGetA(color)) | 330 return color_cache_[color_id].value(); |
| 382 return color; | 331 |
| 383 gboolean prefer_dark_theme = FALSE; | 332 SkColor color = SkColorFromColorId(color_id); |
| 384 g_object_get(gtk_settings_get_default(), "gtk-application-prefer-dark-theme", | 333 color_cache_[color_id] = color; |
| 385 &prefer_dark_theme, nullptr); | 334 return color; |
| 386 ui::NativeTheme* fallback_theme = | |
| 387 prefer_dark_theme ? ui::NativeThemeDarkAura::instance() | |
| 388 : ui::NativeTheme::GetInstanceForNativeUi(); | |
| 389 return fallback_theme->GetSystemColor(color_id); | |
| 390 } | 335 } |
| 391 | 336 |
| 392 void NativeThemeGtk3::PaintMenuPopupBackground( | 337 void NativeThemeGtk3::PaintMenuPopupBackground( |
| 393 SkCanvas* canvas, | 338 SkCanvas* canvas, |
| 394 const gfx::Size& size, | 339 const gfx::Size& size, |
| 395 const MenuBackgroundExtraParams& menu_background) const { | 340 const MenuBackgroundExtraParams& menu_background) const { |
| 396 PaintWidget(canvas, gfx::Rect(size), "menu", GTK_STATE_FLAG_NORMAL); | 341 PaintWidget(canvas, gfx::Rect(size), "GtkMenu.menu", GTK_STATE_FLAG_NORMAL); |
| 397 } | 342 } |
| 398 | 343 |
| 399 void NativeThemeGtk3::PaintMenuItemBackground( | 344 void NativeThemeGtk3::PaintMenuItemBackground( |
| 400 SkCanvas* canvas, | 345 SkCanvas* canvas, |
| 401 State state, | 346 State state, |
| 402 const gfx::Rect& rect, | 347 const gfx::Rect& rect, |
| 403 const MenuItemExtraParams& menu_item) const { | 348 const MenuItemExtraParams& menu_item) const { |
| 404 PaintWidget(canvas, rect, "menu menuitem", StateToStateFlags(state)); | 349 PaintWidget(canvas, rect, "GtkMenu.menu GtkMenuItem.menuitem", |
| 405 } | 350 StateToStateFlags(state)); |
| 406 | |
| 407 GtkWidget* NativeThemeGtk3::GetWindow() const { | |
| 408 static GtkWidget* fake_window = NULL; | |
| 409 | |
| 410 if (!fake_window) { | |
| 411 fake_window = chrome_gtk_frame_new(); | |
| 412 gtk_widget_realize(fake_window); | |
| 413 } | |
| 414 | |
| 415 return fake_window; | |
| 416 } | |
| 417 | |
| 418 GtkWidget* NativeThemeGtk3::GetEntry() const { | |
| 419 static GtkWidget* fake_entry = NULL; | |
| 420 | |
| 421 if (!fake_entry) { | |
| 422 fake_entry = gtk_entry_new(); | |
| 423 | |
| 424 // The fake entry needs to be in the window so it can be realized so we can | |
| 425 // use the computed parts of the style. | |
| 426 gtk_container_add(GTK_CONTAINER(GetWindow()), fake_entry); | |
| 427 gtk_widget_realize(fake_entry); | |
| 428 } | |
| 429 | |
| 430 return fake_entry; | |
| 431 } | |
| 432 | |
| 433 GtkWidget* NativeThemeGtk3::GetLabel() const { | |
| 434 static GtkWidget* fake_label = NULL; | |
| 435 | |
| 436 if (!fake_label) | |
| 437 fake_label = gtk_label_new(""); | |
| 438 | |
| 439 return fake_label; | |
| 440 } | |
| 441 | |
| 442 GtkWidget* NativeThemeGtk3::GetButton() const { | |
| 443 static GtkWidget* fake_button = NULL; | |
| 444 | |
| 445 if (!fake_button) | |
| 446 fake_button = gtk_button_new(); | |
| 447 | |
| 448 return fake_button; | |
| 449 } | |
| 450 | |
| 451 GtkWidget* NativeThemeGtk3::GetBlueButton() const { | |
| 452 static GtkWidget* fake_bluebutton = NULL; | |
| 453 | |
| 454 if (!fake_bluebutton) { | |
| 455 fake_bluebutton = gtk_button_new(); | |
| 456 TurnButtonBlue(fake_bluebutton); | |
| 457 } | |
| 458 | |
| 459 return fake_bluebutton; | |
| 460 } | |
| 461 | |
| 462 GtkWidget* NativeThemeGtk3::GetTree() const { | |
| 463 static GtkWidget* fake_tree = NULL; | |
| 464 | |
| 465 if (!fake_tree) | |
| 466 fake_tree = gtk_tree_view_new(); | |
| 467 | |
| 468 return fake_tree; | |
| 469 } | |
| 470 | |
| 471 GtkWidget* NativeThemeGtk3::GetTooltip() const { | |
| 472 static GtkWidget* fake_tooltip = NULL; | |
| 473 | |
| 474 if (!fake_tooltip) { | |
| 475 fake_tooltip = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
| 476 gtk_widget_set_name(fake_tooltip, "gtk-tooltip"); | |
| 477 gtk_widget_realize(fake_tooltip); | |
| 478 } | |
| 479 | |
| 480 return fake_tooltip; | |
| 481 } | |
| 482 | |
| 483 GtkWidget* NativeThemeGtk3::GetMenu() const { | |
| 484 static GtkWidget* fake_menu = NULL; | |
| 485 | |
| 486 if (!fake_menu) | |
| 487 fake_menu = gtk_custom_menu_new(); | |
| 488 | |
| 489 return fake_menu; | |
| 490 } | |
| 491 | |
| 492 GtkWidget* NativeThemeGtk3::GetMenuItem() const { | |
| 493 static GtkWidget* fake_menu_item = NULL; | |
| 494 | |
| 495 if (!fake_menu_item) { | |
| 496 fake_menu_item = gtk_custom_menu_item_new(); | |
| 497 gtk_menu_shell_append(GTK_MENU_SHELL(GetMenu()), fake_menu_item); | |
| 498 } | |
| 499 | |
| 500 return fake_menu_item; | |
| 501 } | 351 } |
| 502 | 352 |
| 503 } // namespace libgtkui | 353 } // namespace libgtkui |
| OLD | NEW |