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.
4 
5 #include "chrome/browser/themes/theme_properties.h"
6 
7 #include <memory>
8 
9 #include "base/macros.h"
10 #include "base/optional.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "build/build_config.h"
14 #include "chrome/browser/themes/browser_theme_pack.h"
15 #include "ui/gfx/color_palette.h"
16 #include "ui/native_theme/native_theme.h"
17 
18 #if defined(OS_WIN)
19 #include <windows.h>
20 #endif
21 
22 namespace {
23 
24 // Strings used in alignment properties.
25 constexpr char kAlignmentCenter[] = "center";
26 constexpr char kAlignmentTop[] = "top";
27 constexpr char kAlignmentBottom[] = "bottom";
28 constexpr char kAlignmentLeft[] = "left";
29 constexpr char kAlignmentRight[] = "right";
30 
31 // Strings used in background tiling repetition properties.
32 constexpr char kTilingNoRepeat[] = "no-repeat";
33 constexpr char kTilingRepeatX[] = "repeat-x";
34 constexpr char kTilingRepeatY[] = "repeat-y";
35 constexpr char kTilingRepeat[] = "repeat";
36 
GetLightModeColor(int id)37 SkColor GetLightModeColor(int id) {
38 #if defined(OS_WIN)
39   const SkColor kDefaultColorNTPBackground =
40       color_utils::GetSysSkColor(COLOR_WINDOW);
41   const SkColor kDefaultColorNTPText =
42       color_utils::GetSysSkColor(COLOR_WINDOWTEXT);
43   const SkColor kDefaultColorNTPLink =
44       color_utils::GetSysSkColor(COLOR_HOTLIGHT);
45 #else
46   // TODO(beng): source from theme provider.
47   constexpr SkColor kDefaultColorNTPBackground = SK_ColorWHITE;
48   constexpr SkColor kDefaultColorNTPText = SK_ColorBLACK;
49   constexpr SkColor kDefaultColorNTPLink = SkColorSetRGB(0x06, 0x37, 0x74);
50 #endif  // OS_WIN
51 
52   switch (id) {
53     // Properties stored in theme pack.  If you change these defaults, you must
54     // increment the version number in browser_theme_pack.cc.
55     case ThemeProperties::COLOR_FRAME_ACTIVE:
56     case ThemeProperties::COLOR_TAB_BACKGROUND_INACTIVE_FRAME_ACTIVE:
57     case ThemeProperties::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_ACTIVE:
58     case ThemeProperties::COLOR_STATUS_BUBBLE:
59       return SkColorSetRGB(0xDE, 0xE1, 0xE6);
60     case ThemeProperties::COLOR_FRAME_INACTIVE:
61     case ThemeProperties::COLOR_TAB_BACKGROUND_INACTIVE_FRAME_INACTIVE:
62     case ThemeProperties::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INACTIVE:
63       return color_utils::HSLShift(
64           GetLightModeColor(ThemeProperties::COLOR_FRAME_ACTIVE),
65           ThemeProperties::GetDefaultTint(ThemeProperties::TINT_FRAME_INACTIVE,
66                                           false));
67     case ThemeProperties::COLOR_DOWNLOAD_SHELF:
68     case ThemeProperties::COLOR_INFOBAR:
69     case ThemeProperties::COLOR_TOOLBAR:
70     case ThemeProperties::COLOR_TAB_BACKGROUND_ACTIVE_FRAME_ACTIVE:
71     case ThemeProperties::COLOR_TAB_BACKGROUND_ACTIVE_FRAME_INACTIVE:
72       return SK_ColorWHITE;
73     case ThemeProperties::COLOR_HOVER_CARD_NO_PREVIEW_FOREGROUND:
74       return gfx::kGoogleGrey300;
75     case ThemeProperties::COLOR_HOVER_CARD_NO_PREVIEW_BACKGROUND:
76       return gfx::kGoogleGrey050;
77     case ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE:
78     case ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE:
79     case ThemeProperties::COLOR_BOOKMARK_TEXT:
80     case ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE:
81     case ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_INACTIVE:
82       return gfx::kGoogleGrey800;
83     case ThemeProperties::COLOR_NTP_BACKGROUND:
84       return kDefaultColorNTPBackground;
85     case ThemeProperties::COLOR_NTP_TEXT:
86       return kDefaultColorNTPText;
87     case ThemeProperties::COLOR_NTP_LINK:
88       return kDefaultColorNTPLink;
89     case ThemeProperties::COLOR_NTP_HEADER:
90       return SkColorSetRGB(0x96, 0x96, 0x96);
91     case ThemeProperties::COLOR_CONTROL_BUTTON_BACKGROUND:
92       return SK_ColorTRANSPARENT;
93     case ThemeProperties::COLOR_NTP_LOGO:
94       return SkColorSetRGB(0xEE, 0xEE, 0xEE);
95     case ThemeProperties::COLOR_NTP_SHORTCUT:
96       return gfx::kGoogleGrey100;
97 
98     // Properties not stored in theme pack.
99     case ThemeProperties::COLOR_TAB_ALERT_AUDIO:
100       return gfx::kChromeIconGrey;
101     case ThemeProperties::COLOR_TAB_ALERT_RECORDING:
102       return gfx::kGoogleRed600;
103     case ThemeProperties::COLOR_TAB_ALERT_CAPTURING:
104     case ThemeProperties::COLOR_TAB_PIP_PLAYING:
105       return gfx::kGoogleBlue600;
106     case ThemeProperties::COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR:
107       return gfx::kGoogleGrey300;
108     case ThemeProperties::COLOR_TOOLBAR_TOP_SEPARATOR:
109     case ThemeProperties::COLOR_TOOLBAR_TOP_SEPARATOR_INACTIVE:
110       return SkColorSetA(SK_ColorBLACK, 0x40);
111     case ThemeProperties::COLOR_FEATURE_PROMO_BUBBLE_TEXT:
112       return SK_ColorWHITE;
113     case ThemeProperties::COLOR_FEATURE_PROMO_BUBBLE_BACKGROUND:
114       return gfx::kGoogleBlue700;
115     // TODO(http://crbug.com/878664): Remove COLOR_OMNIBOX_xxx when these are
116     // consistently autogenerated.
117     case ThemeProperties::COLOR_OMNIBOX_TEXT:
118       return gfx::kGoogleGrey900;
119     case ThemeProperties::COLOR_OMNIBOX_BACKGROUND:
120       return gfx::kGoogleGrey100;
121 
122     case ThemeProperties::COLOR_FRAME_ACTIVE_INCOGNITO:
123     case ThemeProperties::COLOR_FRAME_INACTIVE_INCOGNITO:
124     case ThemeProperties::COLOR_TAB_BACKGROUND_ACTIVE_FRAME_ACTIVE_INCOGNITO:
125     case ThemeProperties::COLOR_TAB_BACKGROUND_ACTIVE_FRAME_INACTIVE_INCOGNITO:
126     case ThemeProperties::COLOR_TAB_BACKGROUND_INACTIVE_FRAME_ACTIVE_INCOGNITO:
127     case ThemeProperties::
128         COLOR_TAB_BACKGROUND_INACTIVE_FRAME_INACTIVE_INCOGNITO:
129     case ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE_INCOGNITO:
130     case ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_INACTIVE_INCOGNITO:
131     case ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE_INCOGNITO:
132     case ThemeProperties::
133         COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE_INCOGNITO:
134     case ThemeProperties::
135         COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_ACTIVE:
136     case ThemeProperties::
137         COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INCOGNITO_INACTIVE:
138       NOTREACHED() << "This color should be queried via its non-incognito "
139                       "equivalent and an appropriate |incognito| value.";
140       return gfx::kPlaceholderColor;
141     default:
142       NOTREACHED() << "This color should only be queried through ThemeService.";
143       return gfx::kPlaceholderColor;
144   }
145 }
146 
GetIncognitoColor(int id)147 base::Optional<SkColor> GetIncognitoColor(int id) {
148   switch (id) {
149     case ThemeProperties::COLOR_FRAME_ACTIVE:
150     case ThemeProperties::COLOR_TAB_BACKGROUND_INACTIVE_FRAME_ACTIVE:
151       return color_utils::HSLShift(
152           GetLightModeColor(ThemeProperties::COLOR_FRAME_ACTIVE),
153           ThemeProperties::GetDefaultTint(ThemeProperties::TINT_FRAME, true));
154     case ThemeProperties::COLOR_FRAME_INACTIVE:
155     case ThemeProperties::COLOR_TAB_BACKGROUND_INACTIVE_FRAME_INACTIVE:
156       return color_utils::HSLShift(
157           GetLightModeColor(ThemeProperties::COLOR_FRAME_ACTIVE),
158           ThemeProperties::GetDefaultTint(ThemeProperties::TINT_FRAME_INACTIVE,
159                                           true));
160     case ThemeProperties::COLOR_DOWNLOAD_SHELF:
161     case ThemeProperties::COLOR_STATUS_BUBBLE:
162     case ThemeProperties::COLOR_INFOBAR:
163     case ThemeProperties::COLOR_TOOLBAR:
164     case ThemeProperties::COLOR_NTP_BACKGROUND:
165     case ThemeProperties::COLOR_TAB_BACKGROUND_ACTIVE_FRAME_ACTIVE:
166     case ThemeProperties::COLOR_TAB_BACKGROUND_ACTIVE_FRAME_INACTIVE:
167       return SkColorSetRGB(0x35, 0x36, 0x3A);
168     case ThemeProperties::COLOR_HOVER_CARD_NO_PREVIEW_FOREGROUND:
169       return gfx::kGoogleGrey700;
170     case ThemeProperties::COLOR_HOVER_CARD_NO_PREVIEW_BACKGROUND:
171     case ThemeProperties::COLOR_NTP_SHORTCUT:
172       return gfx::kGoogleGrey900;
173     case ThemeProperties::COLOR_BOOKMARK_TEXT:
174     case ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE:
175     case ThemeProperties::COLOR_TAB_FOREGROUND_ACTIVE_FRAME_INACTIVE:
176       return SK_ColorWHITE;
177     case ThemeProperties::COLOR_NTP_TEXT:
178       return gfx::kGoogleGrey200;
179     case ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_ACTIVE:
180     case ThemeProperties::COLOR_TAB_FOREGROUND_INACTIVE_FRAME_INACTIVE:
181     case ThemeProperties::COLOR_TAB_ALERT_AUDIO:
182     case ThemeProperties::COLOR_TAB_ALERT_CAPTURING:
183     case ThemeProperties::COLOR_TAB_PIP_PLAYING:
184     case ThemeProperties::COLOR_TAB_ALERT_RECORDING:
185       return gfx::kGoogleGrey400;
186     case ThemeProperties::COLOR_TOOLBAR_CONTENT_AREA_SEPARATOR:
187       return SkColorSetRGB(0x28, 0x28, 0x28);
188     case ThemeProperties::COLOR_NTP_LINK:
189       return gfx::kGoogleBlue300;
190     // TODO(http://crbug.com/878664): Remove COLOR_OMNIBOX_xxx when these are
191     // consistently autogenerated.
192     case ThemeProperties::COLOR_OMNIBOX_TEXT:
193       return SK_ColorWHITE;
194     case ThemeProperties::COLOR_OMNIBOX_BACKGROUND:
195       return gfx::kGoogleGrey900;
196     default:
197       return base::nullopt;
198   }
199 }
200 
GetDarkModeColor(int id)201 base::Optional<SkColor> GetDarkModeColor(int id) {
202   // Current UX thinking is to use the same colors for dark mode and incognito,
203   // but this is very subject to change. Additionally, dark mode incognito may
204   // end up having a different look. For now, just call into GetIncognitoColor
205   // for convenience, but maintain a separate interface.
206   return GetIncognitoColor(id);
207 }
208 
209 }  // namespace
210 
211 // static
212 constexpr int ThemeProperties::kFrameHeightAboveTabs;
213 
214 // static
StringToAlignment(const std::string & alignment)215 int ThemeProperties::StringToAlignment(const std::string& alignment) {
216   int alignment_mask = 0;
217   for (const std::string& component : base::SplitString(
218            alignment, base::kWhitespaceASCII,
219            base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
220     if (base::LowerCaseEqualsASCII(component, kAlignmentTop))
221       alignment_mask |= ALIGN_TOP;
222     else if (base::LowerCaseEqualsASCII(component, kAlignmentBottom))
223       alignment_mask |= ALIGN_BOTTOM;
224     else if (base::LowerCaseEqualsASCII(component, kAlignmentLeft))
225       alignment_mask |= ALIGN_LEFT;
226     else if (base::LowerCaseEqualsASCII(component, kAlignmentRight))
227       alignment_mask |= ALIGN_RIGHT;
228   }
229   return alignment_mask;
230 }
231 
232 // static
StringToTiling(const std::string & tiling)233 int ThemeProperties::StringToTiling(const std::string& tiling) {
234   if (base::LowerCaseEqualsASCII(tiling, kTilingRepeatX))
235     return REPEAT_X;
236   if (base::LowerCaseEqualsASCII(tiling, kTilingRepeatY))
237     return REPEAT_Y;
238   if (base::LowerCaseEqualsASCII(tiling, kTilingRepeat))
239     return REPEAT;
240   // NO_REPEAT is the default choice.
241   return NO_REPEAT;
242 }
243 
244 // static
AlignmentToString(int alignment)245 std::string ThemeProperties::AlignmentToString(int alignment) {
246   // Convert from an AlignmentProperty back into a string.
247   std::string vertical_string(kAlignmentCenter);
248   std::string horizontal_string(kAlignmentCenter);
249 
250   if (alignment & ALIGN_TOP)
251     vertical_string = kAlignmentTop;
252   else if (alignment & ALIGN_BOTTOM)
253     vertical_string = kAlignmentBottom;
254 
255   if (alignment & ALIGN_LEFT)
256     horizontal_string = kAlignmentLeft;
257   else if (alignment & ALIGN_RIGHT)
258     horizontal_string = kAlignmentRight;
259 
260   return horizontal_string + " " + vertical_string;
261 }
262 
263 // static
TilingToString(int tiling)264 std::string ThemeProperties::TilingToString(int tiling) {
265   // Convert from a TilingProperty back into a string.
266   if (tiling == REPEAT_X)
267     return kTilingRepeatX;
268   if (tiling == REPEAT_Y)
269     return kTilingRepeatY;
270   if (tiling == REPEAT)
271     return kTilingRepeat;
272   return kTilingNoRepeat;
273 }
274 
275 // static
GetDefaultTint(int id,bool incognito,bool dark_mode)276 color_utils::HSL ThemeProperties::GetDefaultTint(int id,
277                                                  bool incognito,
278                                                  bool dark_mode) {
279   DCHECK(id != TINT_FRAME_INCOGNITO && id != TINT_FRAME_INCOGNITO_INACTIVE)
280       << "These values should be queried via their respective non-incognito "
281          "equivalents and an appropriate |incognito| value.";
282 
283   // If you change these defaults, you must increment the version number in
284   // browser_theme_pack.cc.
285 
286   // TINT_BUTTONS is used by ThemeService::GetDefaultColor() for both incognito
287   // and dark mode, and so must be applied to both.
288   if ((id == TINT_BUTTONS) && (incognito || dark_mode))
289     return {-1, 0.57, 0.9605};  // kChromeIconGrey -> kGoogleGrey100
290 
291   if ((id == TINT_FRAME) && incognito)
292     return {-1, 0.7, 0.075};  // #DEE1E6 -> kGoogleGrey900
293   if (id == TINT_FRAME_INACTIVE) {
294     // |dark_mode| is only true here when attempting to tint the Windows native
295     // frame color while in dark mode when using OS accent titlebar colors.
296     // The goal in this case is to match the difference between Chrome default
297     // dark mode active and inactive frames as closely as possible without
298     // a hue change.
299     if (dark_mode)
300       return {-1, 0.54, 0.567};  // Roughly kGoogleGrey900 -> kGoogleGrey800
301 
302     if (incognito)
303       return {0.57, 0.65, 0.1405};  // #DEE1E6 -> kGoogleGrey800
304     return {-1, -1, 0.642};         // #DEE1E6 -> #E7EAED
305   }
306 
307   return {-1, -1, -1};
308 }
309 
310 // static
GetDefaultColor(int id,bool incognito,bool dark_mode)311 SkColor ThemeProperties::GetDefaultColor(int id,
312                                          bool incognito,
313                                          bool dark_mode) {
314   if (incognito) {
315     base::Optional<SkColor> incognito_color = GetIncognitoColor(id);
316     if (incognito_color.has_value())
317       return incognito_color.value();
318   }
319   if (dark_mode) {
320     base::Optional<SkColor> dark_mode_color = GetDarkModeColor(id);
321     if (dark_mode_color.has_value())
322       return dark_mode_color.value();
323   }
324   return GetLightModeColor(id);
325 }
326