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