Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / libgtk2ui / native_theme_gtk2.cc
blobe40efd7ecfceaecb679c58b493063617be280fbb
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/libgtk2ui/native_theme_gtk2.h"
7 #include <gtk/gtk.h>
9 #include "chrome/browser/ui/libgtk2ui/chrome_gtk_frame.h"
10 #include "chrome/browser/ui/libgtk2ui/chrome_gtk_menu_subclasses.h"
11 #include "chrome/browser/ui/libgtk2ui/gtk2_ui.h"
12 #include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
13 #include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
14 #include "third_party/skia/include/core/SkColor.h"
15 #include "ui/gfx/color_utils.h"
16 #include "ui/gfx/geometry/rect.h"
17 #include "ui/gfx/geometry/size.h"
18 #include "ui/gfx/path.h"
19 #include "ui/gfx/skia_util.h"
20 #include "ui/native_theme/common_theme.h"
23 namespace {
25 // Theme colors returned by GetSystemColor().
26 const SkColor kInvalidColorIdColor = SkColorSetRGB(255, 0, 128);
27 const SkColor kURLTextColor = SkColorSetRGB(0x0b, 0x80, 0x43);
29 // Generates the normal URL color, a green color used in unhighlighted URL
30 // text. It is a mix of |kURLTextColor| and the current text color. Unlike the
31 // selected text color, it is more important to match the qualities of the
32 // foreground typeface color instead of taking the background into account.
33 SkColor NormalURLColor(SkColor foreground) {
34 color_utils::HSL fg_hsl, hue_hsl;
35 color_utils::SkColorToHSL(foreground, &fg_hsl);
36 color_utils::SkColorToHSL(kURLTextColor, &hue_hsl);
38 // Only allow colors that have a fair amount of saturation in them (color vs
39 // white). This means that our output color will always be fairly green.
40 double s = std::max(0.5, fg_hsl.s);
42 // Make sure the luminance is at least as bright as the |kURLTextColor| green
43 // would be if we were to use that.
44 double l;
45 if (fg_hsl.l < hue_hsl.l)
46 l = hue_hsl.l;
47 else
48 l = (fg_hsl.l + hue_hsl.l) / 2;
50 color_utils::HSL output = { hue_hsl.h, s, l };
51 return color_utils::HSLToSkColor(output, 255);
54 // Generates the selected URL color, a green color used on URL text in the
55 // currently highlighted entry in the autocomplete popup. It's a mix of
56 // |kURLTextColor|, the current text color, and the background color (the
57 // select highlight). It is more important to contrast with the background
58 // saturation than to look exactly like the foreground color.
59 SkColor SelectedURLColor(SkColor foreground, SkColor background) {
60 color_utils::HSL fg_hsl, bg_hsl, hue_hsl;
61 color_utils::SkColorToHSL(foreground, &fg_hsl);
62 color_utils::SkColorToHSL(background, &bg_hsl);
63 color_utils::SkColorToHSL(kURLTextColor, &hue_hsl);
65 // The saturation of the text should be opposite of the background, clamped
66 // to 0.2-0.8. We make sure it's greater than 0.2 so there's some color, but
67 // less than 0.8 so it's not the oversaturated neon-color.
68 double opposite_s = 1 - bg_hsl.s;
69 double s = std::max(0.2, std::min(0.8, opposite_s));
71 // The luminance should match the luminance of the foreground text. Again,
72 // we clamp so as to have at some amount of color (green) in the text.
73 double opposite_l = fg_hsl.l;
74 double l = std::max(0.1, std::min(0.9, opposite_l));
76 color_utils::HSL output = { hue_hsl.h, s, l };
77 return color_utils::HSLToSkColor(output, 255);
80 } // namespace
83 namespace libgtk2ui {
85 enum WidgetState {
86 NORMAL = 0,
87 ACTIVE = 1,
88 PRELIGHT = 2,
89 SELECTED = 3,
90 INSENSITIVE = 4,
93 #if GTK_MAJOR_VERSION == 2
94 // Same order as enum WidgetState above
95 const GtkStateType stateMap[] = {
96 GTK_STATE_NORMAL,
97 GTK_STATE_ACTIVE,
98 GTK_STATE_PRELIGHT,
99 GTK_STATE_SELECTED,
100 GTK_STATE_INSENSITIVE,
104 SkColor GetFGColor(GtkWidget* widget, WidgetState state) {
105 return GdkColorToSkColor(gtk_rc_get_style(widget)->fg[stateMap[state]]);
107 SkColor GetBGColor(GtkWidget* widget, WidgetState state) {
108 return GdkColorToSkColor(gtk_rc_get_style(widget)->bg[stateMap[state]]);
111 SkColor GetTextColor(GtkWidget* widget, WidgetState state) {
112 return GdkColorToSkColor(gtk_rc_get_style(widget)->text[stateMap[state]]);
114 SkColor GetTextAAColor(GtkWidget* widget, WidgetState state) {
115 return GdkColorToSkColor(gtk_rc_get_style(widget)->text_aa[stateMap[state]]);
117 SkColor GetBaseColor(GtkWidget* widget, WidgetState state) {
118 return GdkColorToSkColor(gtk_rc_get_style(widget)->base[stateMap[state]]);
122 #else
123 // Same order as enum WidgetState above
124 const GtkStateFlags stateMap[] = {
125 GTK_STATE_FLAG_NORMAL,
126 GTK_STATE_FLAG_ACTIVE,
127 GTK_STATE_FLAG_PRELIGHT,
128 GTK_STATE_FLAG_SELECTED,
129 GTK_STATE_FLAG_INSENSITIVE,
133 SkColor GetFGColor(GtkWidget* widget, WidgetState state) {
134 GdkRGBA color;
135 gtk_style_context_get_color(
136 gtk_widget_get_style_context(widget), stateMap[state], &color);
137 return SkColorSetRGB(color.red * 255, color.green * 255, color.blue * 255);
139 SkColor GetBGColor(GtkWidget* widget, WidgetState state) {
140 GdkRGBA color;
142 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
143 gtk_style_context_get_background_color(
144 gtk_widget_get_style_context(widget), stateMap[state], &color);
145 G_GNUC_END_IGNORE_DEPRECATIONS
147 // Hack for default color
148 if (color.alpha == 0.0)
149 color = {1, 1, 1, 1};
151 return SkColorSetRGB(color.red * 255, color.green * 255, color.blue * 255);
154 SkColor GetTextColor(GtkWidget* widget, WidgetState state) {
155 return GetFGColor(widget, state);
157 SkColor GetTextAAColor(GtkWidget* widget, WidgetState state) {
158 return GetFGColor(widget, state);
160 SkColor GetBaseColor(GtkWidget* widget, WidgetState state) {
161 return GetBGColor(widget, state);
163 #endif
165 // static
166 NativeThemeGtk2* NativeThemeGtk2::instance() {
167 CR_DEFINE_STATIC_LOCAL(NativeThemeGtk2, s_native_theme, ());
168 return &s_native_theme;
171 // Constructors automatically called
172 NativeThemeGtk2::NativeThemeGtk2() {}
173 // This doesn't actually get called
174 NativeThemeGtk2::~NativeThemeGtk2() {}
176 void NativeThemeGtk2::PaintMenuPopupBackground(
177 SkCanvas* canvas,
178 const gfx::Size& size,
179 const MenuBackgroundExtraParams& menu_background) const {
180 if (menu_background.corner_radius > 0) {
181 SkPaint paint;
182 paint.setStyle(SkPaint::kFill_Style);
183 paint.setFlags(SkPaint::kAntiAlias_Flag);
184 paint.setColor(GetSystemColor(kColorId_MenuBackgroundColor));
186 gfx::Path path;
187 SkRect rect = SkRect::MakeWH(SkIntToScalar(size.width()),
188 SkIntToScalar(size.height()));
189 SkScalar radius = SkIntToScalar(menu_background.corner_radius);
190 SkScalar radii[8] = {radius, radius, radius, radius,
191 radius, radius, radius, radius};
192 path.addRoundRect(rect, radii);
194 canvas->drawPath(path, paint);
195 } else {
196 canvas->drawColor(GetSystemColor(kColorId_MenuBackgroundColor),
197 SkXfermode::kSrc_Mode);
201 void NativeThemeGtk2::PaintMenuItemBackground(
202 SkCanvas* canvas,
203 State state,
204 const gfx::Rect& rect,
205 const MenuListExtraParams& menu_list) const {
206 SkColor color;
207 SkPaint paint;
208 switch (state) {
209 case NativeTheme::kNormal:
210 case NativeTheme::kDisabled:
211 color = GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor);
212 paint.setColor(color);
213 break;
214 case NativeTheme::kHovered:
215 color = GetSystemColor(
216 NativeTheme::kColorId_FocusedMenuItemBackgroundColor);
217 paint.setColor(color);
218 break;
219 default:
220 NOTREACHED() << "Invalid state " << state;
221 break;
223 canvas->drawRect(gfx::RectToSkRect(rect), paint);
226 SkColor NativeThemeGtk2::GetSystemColor(ColorId color_id) const {
227 const SkColor kPositiveTextColor = SkColorSetRGB(0x0b, 0x80, 0x43);
228 const SkColor kNegativeTextColor = SkColorSetRGB(0xc5, 0x39, 0x29);
230 switch (color_id) {
231 // Windows
232 case kColorId_WindowBackground:
233 return GetBGColor(GetWindow(), SELECTED);
235 // Dialogs
236 case kColorId_DialogBackground:
237 return GetBGColor(GetWindow(), NORMAL);
239 // FocusableBorder
240 case kColorId_FocusedBorderColor:
241 return GetBGColor(GetEntry(), SELECTED);
242 case kColorId_UnfocusedBorderColor:
243 return GetTextAAColor(GetEntry(), NORMAL);
245 // MenuItem
246 case kColorId_EnabledMenuItemForegroundColor:
247 case kColorId_DisabledEmphasizedMenuItemForegroundColor:
248 return GetTextColor(GetMenuItem(), NORMAL);
249 case kColorId_DisabledMenuItemForegroundColor:
250 return GetTextColor(GetMenuItem(), INSENSITIVE);
251 case kColorId_SelectedMenuItemForegroundColor:
252 return GetTextColor(GetMenuItem(), SELECTED);
253 case kColorId_FocusedMenuItemBackgroundColor:
254 return GetBGColor(GetMenuItem(), SELECTED);
255 case kColorId_HoverMenuItemBackgroundColor:
256 return GetBGColor(GetMenuItem(), PRELIGHT);
257 case kColorId_FocusedMenuButtonBorderColor:
258 return GetBGColor(GetEntry(), NORMAL);
259 case kColorId_HoverMenuButtonBorderColor:
260 return GetTextAAColor(GetEntry(), PRELIGHT);
261 case kColorId_MenuBorderColor:
262 case kColorId_EnabledMenuButtonBorderColor:
263 case kColorId_MenuSeparatorColor: {
264 return GetTextColor(GetMenuItem(), INSENSITIVE);
266 case kColorId_MenuBackgroundColor:
267 return GetBGColor(GetMenu(), NORMAL);
269 // Label
270 case kColorId_LabelEnabledColor:
271 return GetTextColor(GetEntry(), NORMAL);
272 case kColorId_LabelDisabledColor:
273 return GetTextColor(GetLabel(), INSENSITIVE);
274 case kColorId_LabelBackgroundColor:
275 return GetBGColor(GetWindow(), NORMAL);
277 // Link
278 // TODO(estade): get these from the gtk theme instead of hardcoding.
279 case kColorId_LinkDisabled:
280 return SK_ColorBLACK;
281 case kColorId_LinkEnabled:
282 return SkColorSetRGB(0x33, 0x67, 0xD6);
283 case kColorId_LinkPressed:
284 return SK_ColorRED;
286 // Button
287 case kColorId_ButtonBackgroundColor:
288 return GetBGColor(GetButton(), NORMAL);
289 case kColorId_ButtonEnabledColor:
290 return GetTextColor(GetButton(), NORMAL);
291 case kColorId_BlueButtonEnabledColor:
292 return GetTextColor(GetBlueButton(), NORMAL);
293 case kColorId_ButtonDisabledColor:
294 return GetTextColor(GetButton(), INSENSITIVE);
295 case kColorId_BlueButtonDisabledColor:
296 return GetTextColor(GetBlueButton(), INSENSITIVE);
297 case kColorId_ButtonHighlightColor:
298 return GetBaseColor(GetButton(), SELECTED);
299 case kColorId_ButtonHoverColor:
300 return GetTextColor(GetButton(), PRELIGHT);
301 case kColorId_BlueButtonHoverColor:
302 return GetTextColor(GetBlueButton(), PRELIGHT);
303 case kColorId_ButtonHoverBackgroundColor:
304 return GetBGColor(GetButton(), PRELIGHT);
305 case kColorId_BlueButtonPressedColor:
306 return GetTextColor(GetBlueButton(), ACTIVE);
307 case kColorId_BlueButtonShadowColor:
308 return SK_ColorTRANSPARENT;
309 // return GetTextColor(GetButton(), NORMAL);
311 // Textfield
312 case kColorId_TextfieldDefaultColor:
313 return GetTextColor(GetEntry(), NORMAL);
314 case kColorId_TextfieldDefaultBackground:
315 return GetBaseColor(GetEntry(), NORMAL);
316 case kColorId_TextfieldReadOnlyColor:
317 return GetTextColor(GetEntry(), INSENSITIVE);
318 case kColorId_TextfieldReadOnlyBackground:
319 return GetBaseColor(GetEntry(), INSENSITIVE);
320 case kColorId_TextfieldSelectionColor:
321 return GetTextColor(GetEntry(), SELECTED);
322 case kColorId_TextfieldSelectionBackgroundFocused:
323 return GetBaseColor(GetEntry(), SELECTED);
325 // Tooltips
326 case kColorId_TooltipBackground:
327 return GetBGColor(GetTooltip(), NORMAL);
328 case kColorId_TooltipText:
329 return GetFGColor(GetTooltip(), NORMAL);
331 // Trees and Tables (implemented on GTK using the same class)
332 case kColorId_TableBackground:
333 case kColorId_TreeBackground:
334 return GetBGColor(GetTree(), NORMAL);
335 case kColorId_TableText:
336 case kColorId_TreeText:
337 return GetTextColor(GetTree(), NORMAL);
338 case kColorId_TableSelectedText:
339 case kColorId_TableSelectedTextUnfocused:
340 case kColorId_TreeSelectedText:
341 case kColorId_TreeSelectedTextUnfocused:
342 return GetTextColor(GetTree(), SELECTED);
343 case kColorId_TableSelectionBackgroundFocused:
344 case kColorId_TableSelectionBackgroundUnfocused:
345 case kColorId_TreeSelectionBackgroundFocused:
346 case kColorId_TreeSelectionBackgroundUnfocused:
347 return GetBGColor(GetTree(), SELECTED);
348 case kColorId_TreeArrow:
349 return GetFGColor(GetTree(), NORMAL);
350 case kColorId_TableGroupingIndicatorColor:
351 return GetTextAAColor(GetTree(), NORMAL);
353 // Results Table
354 case kColorId_ResultsTableNormalBackground:
355 return GetBaseColor(GetEntry(), NORMAL);
356 case kColorId_ResultsTableHoveredBackground:
357 return color_utils::AlphaBlend(GetBaseColor(GetEntry(), NORMAL),
358 GetBaseColor(GetEntry(), SELECTED),
359 0x80);
360 case kColorId_ResultsTableSelectedBackground:
361 return GetBaseColor(GetEntry(), SELECTED);
362 case kColorId_ResultsTableNormalText:
363 case kColorId_ResultsTableHoveredText:
364 return GetTextColor(GetEntry(), NORMAL);
365 case kColorId_ResultsTableSelectedText:
366 return GetTextColor(GetEntry(), SELECTED);
367 case kColorId_ResultsTableNormalDimmedText:
368 case kColorId_ResultsTableHoveredDimmedText:
369 return color_utils::AlphaBlend(GetTextColor(GetEntry(), NORMAL),
370 GetBaseColor(GetEntry(), NORMAL),
371 0x80);
372 case kColorId_ResultsTableSelectedDimmedText:
373 return color_utils::AlphaBlend(GetTextColor(GetEntry(), SELECTED),
374 GetBaseColor(GetEntry(), NORMAL),
375 0x80);
376 case kColorId_ResultsTableNormalUrl:
377 case kColorId_ResultsTableHoveredUrl:
378 return NormalURLColor(GetTextColor(GetEntry(), NORMAL));
380 case kColorId_ResultsTableSelectedUrl:
381 return SelectedURLColor(GetTextColor(GetEntry(), SELECTED),
382 GetBaseColor(GetEntry(), SELECTED));
383 case kColorId_ResultsTableNormalDivider:
384 return color_utils::AlphaBlend(GetTextColor(GetWindow(), NORMAL),
385 GetBGColor(GetWindow(), NORMAL),
386 0x34);
387 case kColorId_ResultsTableHoveredDivider:
388 return color_utils::AlphaBlend(GetTextColor(GetWindow(), PRELIGHT),
389 GetBGColor(GetWindow(), PRELIGHT),
390 0x34);
391 case kColorId_ResultsTableSelectedDivider:
392 return color_utils::AlphaBlend(GetTextColor(GetWindow(), SELECTED),
393 GetBGColor(GetWindow(), SELECTED),
394 0x34);
396 case kColorId_ResultsTablePositiveText: {
397 return color_utils::GetReadableColor(kPositiveTextColor,
398 GetBaseColor(GetEntry(), NORMAL));
400 case kColorId_ResultsTablePositiveHoveredText: {
401 return color_utils::GetReadableColor(kPositiveTextColor,
402 GetBaseColor(GetEntry(), PRELIGHT));
404 case kColorId_ResultsTablePositiveSelectedText: {
405 return color_utils::GetReadableColor(kPositiveTextColor,
406 GetBaseColor(GetEntry(), SELECTED));
408 case kColorId_ResultsTableNegativeText: {
409 return color_utils::GetReadableColor(kNegativeTextColor,
410 GetBaseColor(GetEntry(), NORMAL));
412 case kColorId_ResultsTableNegativeHoveredText: {
413 return color_utils::GetReadableColor(kNegativeTextColor,
414 GetBaseColor(GetEntry(), PRELIGHT));
416 case kColorId_ResultsTableNegativeSelectedText: {
417 return color_utils::GetReadableColor(kNegativeTextColor,
418 GetBaseColor(GetEntry(), SELECTED));
421 // Throbber
422 case kColorId_ThrobberSpinningColor:
423 case kColorId_ThrobberLightColor: {
424 return GetBGColor(GetEntry(), SELECTED);
427 case kColorId_ThrobberWaitingColor: {
428 return color_utils::AlphaBlend(GetBGColor(GetEntry(), SELECTED),
429 GetBGColor(GetWindow(), NORMAL),
430 0x80);
433 case kColorId_Amber:
434 case kColorId_ChromeIconGrey:
435 case kColorId_GoogleBlue:
436 case kColorId_NumColors:
437 NOTREACHED();
438 break;
441 return kInvalidColorIdColor;
444 GtkWidget* NativeThemeGtk2::GetWindow() const {
445 if (!fake_window_.get()) {
446 fake_window_.Own(chrome_gtk_frame_new());
447 gtk_widget_realize(fake_window_.get());
450 return fake_window_.get();
453 GtkWidget* NativeThemeGtk2::GetEntry() const {
454 if (!fake_entry_.get()) {
455 fake_entry_.Own(gtk_entry_new());
457 // The fake entry needs to be in the window so it can be realized so we can
458 // use the computed parts of the style.
459 gtk_container_add(GTK_CONTAINER(GetWindow()), fake_entry_.get());
460 gtk_widget_realize(fake_entry_.get());
463 return fake_entry_.get();
466 GtkWidget* NativeThemeGtk2::GetLabel() const {
467 if (!fake_label_.get())
468 fake_label_.Own(gtk_label_new(""));
470 return fake_label_.get();
473 GtkWidget* NativeThemeGtk2::GetButton() const {
474 if (!fake_button_.get())
475 fake_button_.Own(gtk_button_new());
477 return fake_button_.get();
480 GtkWidget* NativeThemeGtk2::GetBlueButton() const {
481 if (!fake_bluebutton_.get()) {
482 fake_bluebutton_.Own(gtk_button_new());
483 TurnButtonBlue(fake_bluebutton_.get());
486 return fake_bluebutton_.get();
489 GtkWidget* NativeThemeGtk2::GetTree() const {
490 if (!fake_tree_.get())
491 fake_tree_.Own(gtk_tree_view_new());
493 return fake_tree_.get();
496 GtkWidget* NativeThemeGtk2::GetTooltip() const {
497 if (!fake_tooltip_.get()) {
498 fake_tooltip_.Own(gtk_window_new(GTK_WINDOW_TOPLEVEL));
499 gtk_widget_set_name(fake_tooltip_.get(), "gtk-tooltip");
500 gtk_widget_realize(fake_tooltip_.get());
503 return fake_tooltip_.get();
506 GtkWidget* NativeThemeGtk2::GetMenu() const {
507 if (!fake_menu_.get())
508 fake_menu_.Own(gtk_custom_menu_new());
510 return fake_menu_.get();
513 GtkWidget* NativeThemeGtk2::GetMenuItem() const {
514 if (!fake_menu_item_.get()) {
515 fake_menu_item_.Own(gtk_custom_menu_item_new());
516 gtk_menu_shell_append(GTK_MENU_SHELL(GetMenu()), fake_menu_item_.get());
519 return fake_menu_item_.get();
522 } // namespace libgtk2ui