[email protected] | f1567dd | 2012-01-12 18:15:47 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | 1828037 | 2011-03-22 18:05:22 | [diff] [blame] | 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_service.h" |
| 6 | |
avi | 664c07b | 2015-12-26 02:18:31 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | |
huangs | c23c198 | 2014-09-16 16:37:52 | [diff] [blame] | 9 | #include <algorithm> |
| 10 | |
[email protected] | 85bce4518 | 2011-11-29 03:10:52 | [diff] [blame] | 11 | #include "base/bind.h" |
estade | b8867dff | 2016-11-03 17:33:33 | [diff] [blame] | 12 | #include "base/files/file_util.h" |
skyostil | 0259835 | 2015-06-12 12:37:25 | [diff] [blame] | 13 | #include "base/location.h" |
[email protected] | 90fa265 | 2012-04-24 16:18:35 | [diff] [blame] | 14 | #include "base/memory/ref_counted_memory.h" |
bratell | 0a7406f | 2017-03-28 07:46:37 | [diff] [blame] | 15 | #include "base/metrics/user_metrics.h" |
[email protected] | fb44196 | 2013-05-08 05:35:24 | [diff] [blame] | 16 | #include "base/sequenced_task_runner.h" |
skyostil | 0259835 | 2015-06-12 12:37:25 | [diff] [blame] | 17 | #include "base/single_thread_task_runner.h" |
[email protected] | 9f0abdb | 2013-06-10 21:49:34 | [diff] [blame] | 18 | #include "base/strings/string_util.h" |
[email protected] | e309f31 | 2013-06-07 21:50:08 | [diff] [blame] | 19 | #include "base/strings/utf_string_conversions.h" |
gab | b15e1907 | 2016-05-11 20:45:41 | [diff] [blame] | 20 | #include "base/threading/thread_task_runner_handle.h" |
avi | 664c07b | 2015-12-26 02:18:31 | [diff] [blame] | 21 | #include "build/build_config.h" |
[email protected] | dcc8fbc | 2013-07-12 00:54:09 | [diff] [blame] | 22 | #include "chrome/browser/chrome_notification_types.h" |
[email protected] | 1828037 | 2011-03-22 18:05:22 | [diff] [blame] | 23 | #include "chrome/browser/extensions/extension_service.h" |
| 24 | #include "chrome/browser/profiles/profile.h" |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 25 | #include "chrome/browser/themes/browser_theme_pack.h" |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 26 | #include "chrome/browser/themes/custom_theme_supplier.h" |
[email protected] | e119b80 | 2013-02-18 18:55:39 | [diff] [blame] | 27 | #include "chrome/browser/themes/theme_properties.h" |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 28 | #include "chrome/browser/themes/theme_service_factory.h" |
[email protected] | 280453e | 2012-09-28 19:09:41 | [diff] [blame] | 29 | #include "chrome/browser/themes/theme_syncable_service.h" |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 30 | #include "chrome/common/chrome_constants.h" |
brettw | 9e85ef4 | 2016-11-01 21:01:24 | [diff] [blame] | 31 | #include "chrome/common/features.h" |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 32 | #include "chrome/common/pref_names.h" |
thestig | 4a9b0ef | 2016-08-29 08:22:12 | [diff] [blame] | 33 | #include "chrome/grit/theme_resources.h" |
| 34 | #include "components/grit/components_scaled_resources.h" |
brettw | b1fc1b8 | 2016-02-02 00:19:08 | [diff] [blame] | 35 | #include "components/prefs/pref_service.h" |
[email protected] | ad50def5 | 2011-10-19 23:17:07 | [diff] [blame] | 36 | #include "content/public/browser/notification_service.h" |
[email protected] | 7c82539c | 2014-02-19 06:09:17 | [diff] [blame] | 37 | #include "extensions/browser/extension_prefs.h" |
[email protected] | f47f717 | 2014-03-19 19:27:10 | [diff] [blame] | 38 | #include "extensions/browser/extension_registry.h" |
[email protected] | 59b0e60 | 2014-01-30 00:41:24 | [diff] [blame] | 39 | #include "extensions/browser/extension_system.h" |
[email protected] | e43c61f | 2014-07-20 21:46:34 | [diff] [blame] | 40 | #include "extensions/browser/uninstall_reason.h" |
[email protected] | 289c44b | 2013-12-17 03:26:57 | [diff] [blame] | 41 | #include "extensions/common/extension.h" |
| 42 | #include "extensions/common/extension_set.h" |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 43 | #include "extensions/features/features.h" |
[email protected] | c49201a | 2012-05-24 11:04:57 | [diff] [blame] | 44 | #include "ui/base/layout.h" |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 45 | #include "ui/base/resource/resource_bundle.h" |
estade | 756366e | 2015-09-23 20:26:19 | [diff] [blame] | 46 | #include "ui/gfx/color_palette.h" |
[email protected] | 546882b | 2012-05-11 00:53:32 | [diff] [blame] | 47 | #include "ui/gfx/image/image_skia.h" |
estade | 4b7d20a | 2015-05-03 20:21:26 | [diff] [blame] | 48 | #include "ui/native_theme/common_theme.h" |
| 49 | #include "ui/native_theme/native_theme.h" |
[email protected] | 1828037 | 2011-03-22 18:05:22 | [diff] [blame] | 50 | |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 51 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
limasdf | 96f0702b | 2015-03-13 21:57:09 | [diff] [blame] | 52 | #include "extensions/browser/extension_registry_observer.h" |
| 53 | #endif |
| 54 | |
brettw | 9e85ef4 | 2016-11-01 21:01:24 | [diff] [blame] | 55 | #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
mckev | a1a18dc | 2014-09-29 18:52:33 | [diff] [blame] | 56 | #include "chrome/browser/supervised_user/supervised_user_theme.h" |
| 57 | #endif |
| 58 | |
[email protected] | e6e30ac | 2014-01-13 21:24:39 | [diff] [blame] | 59 | using base::UserMetricsAction; |
[email protected] | 631bb74 | 2011-11-02 11:29:39 | [diff] [blame] | 60 | using content::BrowserThread; |
[email protected] | 1c321ee5 | 2012-05-21 03:02:34 | [diff] [blame] | 61 | using extensions::Extension; |
[email protected] | b0af479 | 2013-10-23 09:12:13 | [diff] [blame] | 62 | using extensions::UnloadedExtensionInfo; |
[email protected] | 8e7b2cf4 | 2012-04-18 14:26:58 | [diff] [blame] | 63 | using ui::ResourceBundle; |
[email protected] | 631bb74 | 2011-11-02 11:29:39 | [diff] [blame] | 64 | |
pkasting | f89f155 | 2016-03-03 01:50:50 | [diff] [blame] | 65 | |
| 66 | // Helpers -------------------------------------------------------------------- |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 67 | |
| 68 | namespace { |
| 69 | |
| 70 | // The default theme if we've gone to the theme gallery and installed the |
| 71 | // "Default" theme. We have to detect this case specifically. (By the time we |
| 72 | // realize we've installed the default theme, we already have an extension |
| 73 | // unpacked on the filesystem.) |
thestig | 53c883cd | 2015-12-17 03:09:33 | [diff] [blame] | 74 | const char kDefaultThemeGalleryID[] = "hkacjpbfdknhflllbcmjibkdeoafencn"; |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 75 | |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 76 | // Wait this many seconds after startup to garbage collect unused themes. |
| 77 | // Removing unused themes is done after a delay because there is no |
| 78 | // reason to do it at startup. |
| 79 | // ExtensionService::GarbageCollectExtensions() does something similar. |
| 80 | const int kRemoveUnusedThemesStartupDelay = 30; |
| 81 | |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 82 | SkColor IncreaseLightness(SkColor color, double percent) { |
| 83 | color_utils::HSL result; |
| 84 | color_utils::SkColorToHSL(color, &result); |
| 85 | result.l += (1 - result.l) * percent; |
| 86 | return color_utils::HSLToSkColor(result, SkColorGetA(color)); |
| 87 | } |
| 88 | |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 89 | // Writes the theme pack to disk on a separate thread. |
[email protected] | 7f8f24f | 2012-11-15 19:40:14 | [diff] [blame] | 90 | void WritePackToDiskCallback(BrowserThemePack* pack, |
estade | b8867dff | 2016-11-03 17:33:33 | [diff] [blame] | 91 | const base::FilePath& directory) { |
| 92 | base::FilePath path = directory.Append(chrome::kThemePackFilename); |
[email protected] | 85bce4518 | 2011-11-29 03:10:52 | [diff] [blame] | 93 | if (!pack->WriteToDisk(path)) |
| 94 | NOTREACHED() << "Could not write theme pack to disk"; |
estade | b8867dff | 2016-11-03 17:33:33 | [diff] [blame] | 95 | |
| 96 | // Clean up any theme .pak that was generated during the Material Design |
| 97 | // transitional period. |
| 98 | // TODO(estade): remove this line in Q2 2017. |
| 99 | base::DeleteFile(directory.AppendASCII("Cached Theme Material Design.pak"), |
| 100 | false); |
[email protected] | 85bce4518 | 2011-11-29 03:10:52 | [diff] [blame] | 101 | } |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 102 | |
huangs | c23c198 | 2014-09-16 16:37:52 | [diff] [blame] | 103 | // Heuristic to determine if color is grayscale. This is used to decide whether |
| 104 | // to use the colorful or white logo, if a theme fails to specify which. |
| 105 | bool IsColorGrayscale(SkColor color) { |
| 106 | const int kChannelTolerance = 9; |
| 107 | int r = SkColorGetR(color); |
| 108 | int g = SkColorGetG(color); |
| 109 | int b = SkColorGetB(color); |
| 110 | int range = std::max(r, std::max(g, b)) - std::min(r, std::min(g, b)); |
| 111 | return range < kChannelTolerance; |
| 112 | } |
| 113 | |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 114 | } // namespace |
| 115 | |
pkasting | f89f155 | 2016-03-03 01:50:50 | [diff] [blame] | 116 | |
| 117 | // ThemeService::BrowserThemeProvider ----------------------------------------- |
| 118 | |
| 119 | ThemeService::BrowserThemeProvider::BrowserThemeProvider( |
| 120 | const ThemeService& theme_service, |
| 121 | bool incognito) |
| 122 | : theme_service_(theme_service), incognito_(incognito) {} |
| 123 | |
| 124 | ThemeService::BrowserThemeProvider::~BrowserThemeProvider() {} |
| 125 | |
| 126 | gfx::ImageSkia* ThemeService::BrowserThemeProvider::GetImageSkiaNamed( |
| 127 | int id) const { |
| 128 | return theme_service_.GetImageSkiaNamed(id, incognito_); |
| 129 | } |
| 130 | |
| 131 | SkColor ThemeService::BrowserThemeProvider::GetColor(int id) const { |
| 132 | return theme_service_.GetColor(id, incognito_); |
| 133 | } |
| 134 | |
estade | 80c4766 | 2016-07-02 00:42:16 | [diff] [blame] | 135 | color_utils::HSL ThemeService::BrowserThemeProvider::GetTint(int id) const { |
| 136 | return theme_service_.GetTint(id, incognito_); |
| 137 | } |
| 138 | |
pkasting | f89f155 | 2016-03-03 01:50:50 | [diff] [blame] | 139 | int ThemeService::BrowserThemeProvider::GetDisplayProperty(int id) const { |
| 140 | return theme_service_.GetDisplayProperty(id); |
| 141 | } |
| 142 | |
| 143 | bool ThemeService::BrowserThemeProvider::ShouldUseNativeFrame() const { |
| 144 | return theme_service_.ShouldUseNativeFrame(); |
| 145 | } |
| 146 | |
| 147 | bool ThemeService::BrowserThemeProvider::HasCustomImage(int id) const { |
| 148 | return theme_service_.HasCustomImage(id); |
| 149 | } |
| 150 | |
| 151 | base::RefCountedMemory* ThemeService::BrowserThemeProvider::GetRawData( |
| 152 | int id, |
| 153 | ui::ScaleFactor scale_factor) const { |
| 154 | return theme_service_.GetRawData(id, scale_factor); |
| 155 | } |
| 156 | |
| 157 | |
| 158 | // ThemeService::ThemeObserver ------------------------------------------------ |
| 159 | |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 160 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
limasdf | 96f0702b | 2015-03-13 21:57:09 | [diff] [blame] | 161 | class ThemeService::ThemeObserver |
| 162 | : public extensions::ExtensionRegistryObserver { |
| 163 | public: |
| 164 | explicit ThemeObserver(ThemeService* service) : theme_service_(service) { |
| 165 | extensions::ExtensionRegistry::Get(theme_service_->profile_) |
| 166 | ->AddObserver(this); |
| 167 | } |
| 168 | |
| 169 | ~ThemeObserver() override { |
| 170 | extensions::ExtensionRegistry::Get(theme_service_->profile_) |
| 171 | ->RemoveObserver(this); |
| 172 | } |
| 173 | |
| 174 | private: |
| 175 | void OnExtensionWillBeInstalled(content::BrowserContext* browser_context, |
| 176 | const extensions::Extension* extension, |
| 177 | bool is_update, |
limasdf | 96f0702b | 2015-03-13 21:57:09 | [diff] [blame] | 178 | const std::string& old_name) override { |
| 179 | if (extension->is_theme()) { |
| 180 | // The theme may be initially disabled. Wait till it is loaded (if ever). |
| 181 | theme_service_->installed_pending_load_id_ = extension->id(); |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | void OnExtensionLoaded(content::BrowserContext* browser_context, |
| 186 | const extensions::Extension* extension) override { |
| 187 | if (extension->is_theme() && |
| 188 | theme_service_->installed_pending_load_id_ != kDefaultThemeID && |
| 189 | theme_service_->installed_pending_load_id_ == extension->id()) { |
| 190 | theme_service_->SetTheme(extension); |
| 191 | } |
| 192 | theme_service_->installed_pending_load_id_ = kDefaultThemeID; |
| 193 | } |
| 194 | |
| 195 | void OnExtensionUnloaded( |
| 196 | content::BrowserContext* browser_context, |
| 197 | const extensions::Extension* extension, |
| 198 | extensions::UnloadedExtensionInfo::Reason reason) override { |
| 199 | if (reason != extensions::UnloadedExtensionInfo::REASON_UPDATE && |
| 200 | reason != extensions::UnloadedExtensionInfo::REASON_LOCK_ALL && |
| 201 | extension->is_theme() && |
| 202 | extension->id() == theme_service_->GetThemeID()) { |
| 203 | theme_service_->UseDefaultTheme(); |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | ThemeService* theme_service_; |
| 208 | }; |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 209 | #endif // BUILDFLAG(ENABLE_EXTENSIONS) |
limasdf | 96f0702b | 2015-03-13 21:57:09 | [diff] [blame] | 210 | |
pkasting | f89f155 | 2016-03-03 01:50:50 | [diff] [blame] | 211 | |
| 212 | // ThemeService --------------------------------------------------------------- |
| 213 | |
| 214 | // The default theme if we haven't installed a theme yet or if we've clicked |
| 215 | // the "Use Classic" button. |
| 216 | const char ThemeService::kDefaultThemeID[] = ""; |
| 217 | |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 218 | ThemeService::ThemeService() |
[email protected] | 94d410e | 2013-08-07 21:51:30 | [diff] [blame] | 219 | : ready_(false), |
| 220 | rb_(ResourceBundle::GetSharedInstance()), |
limasdf | 96f0702b | 2015-03-13 21:57:09 | [diff] [blame] | 221 | profile_(nullptr), |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 222 | installed_pending_load_id_(kDefaultThemeID), |
[email protected] | 43b424e | 2013-08-12 04:51:13 | [diff] [blame] | 223 | number_of_infobars_(0), |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 224 | original_theme_provider_(*this, false), |
estade | 89bc30b | 2016-02-09 19:08:53 | [diff] [blame] | 225 | incognito_theme_provider_(*this, true), |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 226 | weak_ptr_factory_(this) {} |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 227 | |
| 228 | ThemeService::~ThemeService() { |
| 229 | FreePlatformCaches(); |
| 230 | } |
| 231 | |
| 232 | void ThemeService::Init(Profile* profile) { |
| 233 | DCHECK(CalledOnValidThread()); |
| 234 | profile_ = profile; |
| 235 | |
| 236 | LoadThemePrefs(); |
[email protected] | 280453e | 2012-09-28 19:09:41 | [diff] [blame] | 237 | |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 238 | registrar_.Add(this, |
[email protected] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 239 | extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED, |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 240 | content::Source<Profile>(profile_)); |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 241 | |
[email protected] | 280453e | 2012-09-28 19:09:41 | [diff] [blame] | 242 | theme_syncable_service_.reset(new ThemeSyncableService(profile_, this)); |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 243 | } |
| 244 | |
limasdf | 96f0702b | 2015-03-13 21:57:09 | [diff] [blame] | 245 | void ThemeService::Shutdown() { |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 246 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
limasdf | 96f0702b | 2015-03-13 21:57:09 | [diff] [blame] | 247 | theme_observer_.reset(); |
| 248 | #endif |
| 249 | } |
| 250 | |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 251 | void ThemeService::Observe(int type, |
| 252 | const content::NotificationSource& source, |
| 253 | const content::NotificationDetails& details) { |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 254 | using content::Details; |
| 255 | switch (type) { |
[email protected] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 256 | case extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED: |
| 257 | registrar_.Remove(this, |
| 258 | extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED, |
| 259 | content::Source<Profile>(profile_)); |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 260 | OnExtensionServiceReady(); |
| 261 | break; |
[email protected] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 262 | case extensions::NOTIFICATION_EXTENSION_ENABLED: { |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 263 | const Extension* extension = Details<const Extension>(details).ptr(); |
| 264 | if (extension->is_theme()) |
| 265 | SetTheme(extension); |
| 266 | break; |
| 267 | } |
limasdf | 96f0702b | 2015-03-13 21:57:09 | [diff] [blame] | 268 | default: |
| 269 | NOTREACHED(); |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 270 | } |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 271 | } |
| 272 | |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 273 | void ThemeService::SetTheme(const Extension* extension) { |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 274 | DCHECK(extension->is_theme()); |
| 275 | ExtensionService* service = |
| 276 | extensions::ExtensionSystem::Get(profile_)->extension_service(); |
| 277 | if (!service->IsExtensionEnabled(extension->id())) { |
| 278 | // |extension| is disabled when reverting to the previous theme via an |
| 279 | // infobar. |
| 280 | service->EnableExtension(extension->id()); |
| 281 | // Enabling the extension will call back to SetTheme(). |
| 282 | return; |
| 283 | } |
| 284 | |
| 285 | std::string previous_theme_id = GetThemeID(); |
| 286 | |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 287 | // Clear our image cache. |
| 288 | FreePlatformCaches(); |
| 289 | |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 290 | BuildFromExtension(extension); |
[email protected] | d594931 | 2012-12-03 22:13:30 | [diff] [blame] | 291 | SaveThemeID(extension->id()); |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 292 | |
[email protected] | a3e61e8 | 2011-04-15 20:32:08 | [diff] [blame] | 293 | NotifyThemeChanged(); |
bratell | 0a7406f | 2017-03-28 07:46:37 | [diff] [blame] | 294 | base::RecordAction(UserMetricsAction("Themes_Installed")); |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 295 | |
| 296 | if (previous_theme_id != kDefaultThemeID && |
pkotwicz | 315d1a31 | 2015-09-15 00:05:51 | [diff] [blame] | 297 | previous_theme_id != extension->id() && |
| 298 | service->GetInstalledExtension(previous_theme_id)) { |
| 299 | // Do not disable the previous theme if it is already uninstalled. Sending |
| 300 | // NOTIFICATION_BROWSER_THEME_CHANGED causes the previous theme to be |
| 301 | // uninstalled when the notification causes the remaining infobar to close |
| 302 | // and does not open any new infobars. See crbug.com/468280. |
| 303 | |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 304 | // Disable the old theme. |
| 305 | service->DisableExtension(previous_theme_id, |
| 306 | extensions::Extension::DISABLE_USER_ACTION); |
| 307 | } |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 308 | } |
| 309 | |
pkasting | f89f155 | 2016-03-03 01:50:50 | [diff] [blame] | 310 | void ThemeService::UseDefaultTheme() { |
| 311 | if (ready_) |
bratell | 0a7406f | 2017-03-28 07:46:37 | [diff] [blame] | 312 | base::RecordAction(UserMetricsAction("Themes_Reset")); |
brettw | 9e85ef4 | 2016-11-01 21:01:24 | [diff] [blame] | 313 | #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
pkasting | f89f155 | 2016-03-03 01:50:50 | [diff] [blame] | 314 | if (IsSupervisedUser()) { |
| 315 | SetSupervisedUserTheme(); |
| 316 | return; |
| 317 | } |
| 318 | #endif |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 319 | ClearAllThemeData(); |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 320 | NotifyThemeChanged(); |
| 321 | } |
| 322 | |
pkasting | f89f155 | 2016-03-03 01:50:50 | [diff] [blame] | 323 | void ThemeService::UseSystemTheme() { |
| 324 | UseDefaultTheme(); |
| 325 | } |
| 326 | |
| 327 | bool ThemeService::IsSystemThemeDistinctFromDefaultTheme() const { |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 328 | return false; |
| 329 | } |
| 330 | |
pkasting | f89f155 | 2016-03-03 01:50:50 | [diff] [blame] | 331 | bool ThemeService::UsingDefaultTheme() const { |
| 332 | std::string id = GetThemeID(); |
| 333 | return id == ThemeService::kDefaultThemeID || |
| 334 | id == kDefaultThemeGalleryID; |
| 335 | } |
| 336 | |
| 337 | bool ThemeService::UsingSystemTheme() const { |
| 338 | return UsingDefaultTheme(); |
| 339 | } |
| 340 | |
| 341 | std::string ThemeService::GetThemeID() const { |
| 342 | return profile_->GetPrefs()->GetString(prefs::kCurrentThemeID); |
| 343 | } |
| 344 | |
| 345 | void ThemeService::OnInfobarDisplayed() { |
| 346 | number_of_infobars_++; |
| 347 | } |
| 348 | |
| 349 | void ThemeService::OnInfobarDestroyed() { |
| 350 | number_of_infobars_--; |
| 351 | |
| 352 | if (number_of_infobars_ == 0) |
| 353 | RemoveUnusedThemes(false); |
| 354 | } |
| 355 | |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 356 | void ThemeService::RemoveUnusedThemes(bool ignore_infobars) { |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 357 | // We do not want to garbage collect themes on startup (|ready_| is false). |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 358 | // Themes will get garbage collected after |kRemoveUnusedThemesStartupDelay|. |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 359 | if (!profile_ || !ready_) |
[email protected] | d594931 | 2012-12-03 22:13:30 | [diff] [blame] | 360 | return; |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 361 | if (!ignore_infobars && number_of_infobars_ != 0) |
| 362 | return; |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 363 | |
[email protected] | f47f717 | 2014-03-19 19:27:10 | [diff] [blame] | 364 | ExtensionService* service = |
| 365 | extensions::ExtensionSystem::Get(profile_)->extension_service(); |
[email protected] | d594931 | 2012-12-03 22:13:30 | [diff] [blame] | 366 | if (!service) |
| 367 | return; |
[email protected] | f47f717 | 2014-03-19 19:27:10 | [diff] [blame] | 368 | |
[email protected] | d594931 | 2012-12-03 22:13:30 | [diff] [blame] | 369 | std::string current_theme = GetThemeID(); |
| 370 | std::vector<std::string> remove_list; |
dcheng | 4af4858 | 2016-04-19 00:29:35 | [diff] [blame] | 371 | std::unique_ptr<const extensions::ExtensionSet> extensions( |
[email protected] | f47f717 | 2014-03-19 19:27:10 | [diff] [blame] | 372 | extensions::ExtensionRegistry::Get(profile_) |
| 373 | ->GenerateInstalledExtensionsSet()); |
[email protected] | 7c82539c | 2014-02-19 06:09:17 | [diff] [blame] | 374 | extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_); |
[email protected] | 289c44b | 2013-12-17 03:26:57 | [diff] [blame] | 375 | for (extensions::ExtensionSet::const_iterator it = extensions->begin(); |
[email protected] | d594931 | 2012-12-03 22:13:30 | [diff] [blame] | 376 | it != extensions->end(); ++it) { |
dcheng | 319a2195 | 2014-08-26 22:52:40 | [diff] [blame] | 377 | const extensions::Extension* extension = it->get(); |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 378 | if (extension->is_theme() && |
| 379 | extension->id() != current_theme) { |
| 380 | // Only uninstall themes which are not disabled or are disabled with |
| 381 | // reason DISABLE_USER_ACTION. We cannot blanket uninstall all disabled |
| 382 | // themes because externally installed themes are initially disabled. |
| 383 | int disable_reason = prefs->GetDisableReasons(extension->id()); |
| 384 | if (!prefs->IsExtensionDisabled(extension->id()) || |
| 385 | disable_reason == Extension::DISABLE_USER_ACTION) { |
| 386 | remove_list.push_back((*it)->id()); |
| 387 | } |
[email protected] | d594931 | 2012-12-03 22:13:30 | [diff] [blame] | 388 | } |
| 389 | } |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 390 | // TODO: Garbage collect all unused themes. This method misses themes which |
| 391 | // are installed but not loaded because they are blacklisted by a management |
| 392 | // policy provider. |
| 393 | |
[email protected] | cc2f55c | 2014-07-08 02:19:04 | [diff] [blame] | 394 | for (size_t i = 0; i < remove_list.size(); ++i) { |
[email protected] | 42d58f6 | 2014-07-31 01:32:45 | [diff] [blame] | 395 | service->UninstallExtension(remove_list[i], |
| 396 | extensions::UNINSTALL_REASON_ORPHANED_THEME, |
limasdf | 96f0702b | 2015-03-13 21:57:09 | [diff] [blame] | 397 | base::Bind(&base::DoNothing), nullptr); |
[email protected] | cc2f55c | 2014-07-08 02:19:04 | [diff] [blame] | 398 | } |
[email protected] | d594931 | 2012-12-03 22:13:30 | [diff] [blame] | 399 | } |
| 400 | |
pkasting | f89f155 | 2016-03-03 01:50:50 | [diff] [blame] | 401 | ThemeSyncableService* ThemeService::GetThemeSyncableService() const { |
| 402 | return theme_syncable_service_.get(); |
| 403 | } |
| 404 | |
| 405 | // static |
| 406 | const ui::ThemeProvider& ThemeService::GetThemeProviderForProfile( |
| 407 | Profile* profile) { |
| 408 | ThemeService* service = ThemeServiceFactory::GetForProfile(profile); |
| 409 | bool incognito = profile->GetProfileType() == Profile::INCOGNITO_PROFILE; |
| 410 | return incognito ? service->incognito_theme_provider_ |
| 411 | : service->original_theme_provider_; |
| 412 | } |
| 413 | |
| 414 | void ThemeService::SetCustomDefaultTheme( |
| 415 | scoped_refptr<CustomThemeSupplier> theme_supplier) { |
[email protected] | 94d410e | 2013-08-07 21:51:30 | [diff] [blame] | 416 | ClearAllThemeData(); |
pkasting | f89f155 | 2016-03-03 01:50:50 | [diff] [blame] | 417 | SwapThemeSupplier(theme_supplier); |
[email protected] | 94d410e | 2013-08-07 21:51:30 | [diff] [blame] | 418 | NotifyThemeChanged(); |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 419 | } |
| 420 | |
pkasting | f89f155 | 2016-03-03 01:50:50 | [diff] [blame] | 421 | bool ThemeService::ShouldInitWithSystemTheme() const { |
| 422 | return false; |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 423 | } |
| 424 | |
pkasting | 20d38210d | 2016-03-08 09:45:54 | [diff] [blame] | 425 | SkColor ThemeService::GetDefaultColor(int id, bool incognito) const { |
| 426 | // For backward compat with older themes, some newer colors are generated from |
| 427 | // older ones if they are missing. |
| 428 | const int kNtpText = ThemeProperties::COLOR_NTP_TEXT; |
| 429 | const int kLabelBackground = |
| 430 | ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BACKGROUND; |
| 431 | switch (id) { |
| 432 | case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON: |
| 433 | return color_utils::HSLShift( |
| 434 | gfx::kChromeIconGrey, |
| 435 | GetTint(ThemeProperties::TINT_BUTTONS, incognito)); |
| 436 | case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON_INACTIVE: |
thomasanderson | b1f4989 | 2017-01-05 02:16:42 | [diff] [blame] | 437 | // The active color is overridden in GtkUi. |
pkasting | 20d38210d | 2016-03-08 09:45:54 | [diff] [blame] | 438 | return SkColorSetA( |
| 439 | GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON, incognito), |
| 440 | 0x33); |
thomasanderson | 307f9f29 | 2017-02-09 06:33:15 | [diff] [blame] | 441 | case ThemeProperties::COLOR_LOCATION_BAR_BORDER: |
| 442 | return SkColorSetA(SK_ColorBLACK, 0x4D); |
pkasting | e330ac6 | 2016-03-19 06:07:03 | [diff] [blame] | 443 | case ThemeProperties::COLOR_TOOLBAR_TOP_SEPARATOR: |
| 444 | case ThemeProperties::COLOR_TOOLBAR_TOP_SEPARATOR_INACTIVE: { |
pkasting | 3eb05e6 | 2016-03-17 01:01:02 | [diff] [blame] | 445 | const SkColor tab_color = |
| 446 | GetColor(ThemeProperties::COLOR_TOOLBAR, incognito); |
pkasting | e330ac6 | 2016-03-19 06:07:03 | [diff] [blame] | 447 | const int frame_id = (id == ThemeProperties::COLOR_TOOLBAR_TOP_SEPARATOR) |
| 448 | ? ThemeProperties::COLOR_FRAME |
| 449 | : ThemeProperties::COLOR_FRAME_INACTIVE; |
| 450 | const SkColor frame_color = GetColor(frame_id, incognito); |
pkasting | 3eb05e6 | 2016-03-17 01:01:02 | [diff] [blame] | 451 | const SeparatorColorKey key(tab_color, frame_color); |
| 452 | auto i = separator_color_cache_.find(key); |
| 453 | if (i != separator_color_cache_.end()) |
| 454 | return i->second; |
| 455 | const SkColor separator_color = GetSeparatorColor(tab_color, frame_color); |
| 456 | separator_color_cache_[key] = separator_color; |
| 457 | return separator_color; |
| 458 | } |
estade | 15814a7 | 2016-05-20 00:42:46 | [diff] [blame] | 459 | case ThemeProperties::COLOR_TOOLBAR_VERTICAL_SEPARATOR: { |
| 460 | return SkColorSetA( |
| 461 | GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON, incognito), |
| 462 | 0x4D); |
| 463 | } |
pkasting | 20d38210d | 2016-03-08 09:45:54 | [diff] [blame] | 464 | case ThemeProperties::COLOR_BACKGROUND_TAB: { |
| 465 | // The tints here serve a different purpose than TINT_BACKGROUND_TAB. |
| 466 | // That tint is used to create background tab images for custom themes by |
| 467 | // lightening the frame images. The tints here create solid colors for |
pkasting | 3eb05e6 | 2016-03-17 01:01:02 | [diff] [blame] | 468 | // background tabs by darkening the foreground tab (toolbar) color. These |
| 469 | // values are chosen to turn the default normal and incognito MD frame |
| 470 | // colors (0xf2f2f2 and 0x505050) into 0xd0d0d0 and 0x373737, |
| 471 | // respectively. |
| 472 | const color_utils::HSL kTint = {-1, -1, 0.42975}; |
pkasting | 20d38210d | 2016-03-08 09:45:54 | [diff] [blame] | 473 | const color_utils::HSL kTintIncognito = {-1, -1, 0.34375}; |
| 474 | return color_utils::HSLShift( |
| 475 | GetColor(ThemeProperties::COLOR_TOOLBAR, incognito), |
| 476 | incognito ? kTintIncognito : kTint); |
| 477 | } |
kylixrd | 6b6a68d | 2016-06-20 14:05:20 | [diff] [blame] | 478 | case ThemeProperties::COLOR_BOOKMARK_BAR_INSTRUCTIONS_TEXT: |
| 479 | if (UsingDefaultTheme()) |
| 480 | break; |
| 481 | return GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT, incognito); |
estade | 88c37583 | 2016-07-18 22:25:50 | [diff] [blame] | 482 | case ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND: |
| 483 | if (UsingDefaultTheme()) |
| 484 | break; |
| 485 | return GetColor(ThemeProperties::COLOR_TOOLBAR, incognito); |
pkasting | 20d38210d | 2016-03-08 09:45:54 | [diff] [blame] | 486 | case ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR: |
| 487 | if (UsingDefaultTheme()) |
| 488 | break; |
| 489 | // Use 50% of bookmark text color as separator color. |
| 490 | return SkColorSetA( |
| 491 | GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT, incognito), 128); |
pkasting | 20d38210d | 2016-03-08 09:45:54 | [diff] [blame] | 492 | case ThemeProperties::COLOR_NTP_TEXT_LIGHT: |
| 493 | return IncreaseLightness(GetColor(kNtpText, incognito), 0.40); |
| 494 | case ThemeProperties::COLOR_TAB_THROBBER_SPINNING: |
| 495 | case ThemeProperties::COLOR_TAB_THROBBER_WAITING: { |
| 496 | SkColor base_color = |
| 497 | ui::GetAuraColor(id == ThemeProperties::COLOR_TAB_THROBBER_SPINNING |
| 498 | ? ui::NativeTheme::kColorId_ThrobberSpinningColor |
| 499 | : ui::NativeTheme::kColorId_ThrobberWaitingColor, |
| 500 | nullptr); |
| 501 | color_utils::HSL hsl = GetTint(ThemeProperties::TINT_BUTTONS, incognito); |
| 502 | return color_utils::HSLShift(base_color, hsl); |
| 503 | } |
brettw | 9e85ef4 | 2016-11-01 21:01:24 | [diff] [blame] | 504 | #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
pkasting | 20d38210d | 2016-03-08 09:45:54 | [diff] [blame] | 505 | case ThemeProperties::COLOR_SUPERVISED_USER_LABEL: |
| 506 | return color_utils::GetReadableColor( |
| 507 | SK_ColorWHITE, GetColor(kLabelBackground, incognito)); |
| 508 | case ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BACKGROUND: |
| 509 | return color_utils::BlendTowardOppositeLuma( |
| 510 | GetColor(ThemeProperties::COLOR_FRAME, incognito), 0x80); |
| 511 | case ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BORDER: |
| 512 | return color_utils::AlphaBlend(GetColor(kLabelBackground, incognito), |
| 513 | SK_ColorBLACK, 230); |
| 514 | #endif |
| 515 | } |
| 516 | |
estade | 66736a7 | 2016-03-30 01:26:23 | [diff] [blame] | 517 | // Always fall back to the non-incognito color when there's a custom theme |
| 518 | // because the default (classic) incognito color may be dramatically different |
| 519 | // (optimized for a light-on-dark color). |
| 520 | return ThemeProperties::GetDefaultColor(id, incognito && !theme_supplier_); |
pkasting | 20d38210d | 2016-03-08 09:45:54 | [diff] [blame] | 521 | } |
| 522 | |
estade | 89bc30b | 2016-02-09 19:08:53 | [diff] [blame] | 523 | color_utils::HSL ThemeService::GetTint(int id, bool incognito) const { |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 524 | DCHECK(CalledOnValidThread()); |
| 525 | |
| 526 | color_utils::HSL hsl; |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 527 | if (theme_supplier_ && theme_supplier_->GetTint(id, &hsl)) |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 528 | return hsl; |
| 529 | |
estade | 66736a7 | 2016-03-30 01:26:23 | [diff] [blame] | 530 | // Always fall back to the non-incognito tint when there's a custom theme. |
| 531 | // See comment in GetDefaultColor(). |
| 532 | return ThemeProperties::GetDefaultTint(id, incognito && !theme_supplier_); |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 533 | } |
| 534 | |
| 535 | void ThemeService::ClearAllThemeData() { |
[email protected] | 94d410e | 2013-08-07 21:51:30 | [diff] [blame] | 536 | if (!ready_) |
| 537 | return; |
| 538 | |
limasdf | 96f0702b | 2015-03-13 21:57:09 | [diff] [blame] | 539 | SwapThemeSupplier(nullptr); |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 540 | |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 541 | // Clear our image cache. |
| 542 | FreePlatformCaches(); |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 543 | |
| 544 | profile_->GetPrefs()->ClearPref(prefs::kCurrentThemePackFilename); |
[email protected] | d594931 | 2012-12-03 22:13:30 | [diff] [blame] | 545 | SaveThemeID(kDefaultThemeID); |
[email protected] | 8b1058bb | 2013-04-08 20:15:27 | [diff] [blame] | 546 | |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 547 | // There should be no more infobars. This may not be the case because of |
| 548 | // http://crbug.com/62154 |
| 549 | // RemoveUnusedThemes is called on a task because ClearAllThemeData() may |
limasdf | 53f32be1 | 2017-04-25 12:13:27 | [diff] [blame] | 550 | // be called as a result of OnExtensionUnloaded(). |
skyostil | 0259835 | 2015-06-12 12:37:25 | [diff] [blame] | 551 | base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 552 | FROM_HERE, base::Bind(&ThemeService::RemoveUnusedThemes, |
| 553 | weak_ptr_factory_.GetWeakPtr(), true)); |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 554 | } |
| 555 | |
| 556 | void ThemeService::LoadThemePrefs() { |
| 557 | PrefService* prefs = profile_->GetPrefs(); |
| 558 | |
| 559 | std::string current_id = GetThemeID(); |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 560 | if (current_id == kDefaultThemeID) { |
brettw | 9e85ef4 | 2016-11-01 21:01:24 | [diff] [blame] | 561 | #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
[email protected] | d20d043 | 2014-06-12 17:14:05 | [diff] [blame] | 562 | // Supervised users have a different default theme. |
mckev | a1a18dc | 2014-09-29 18:52:33 | [diff] [blame] | 563 | if (IsSupervisedUser()) { |
[email protected] | d20d043 | 2014-06-12 17:14:05 | [diff] [blame] | 564 | SetSupervisedUserTheme(); |
mckev | a1a18dc | 2014-09-29 18:52:33 | [diff] [blame] | 565 | set_ready(); |
| 566 | return; |
| 567 | } |
| 568 | #endif |
| 569 | if (ShouldInitWithSystemTheme()) |
[email protected] | 448d7dc | 2014-05-13 03:22:55 | [diff] [blame] | 570 | UseSystemTheme(); |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 571 | else |
| 572 | UseDefaultTheme(); |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 573 | set_ready(); |
| 574 | return; |
| 575 | } |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 576 | |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 577 | bool loaded_pack = false; |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 578 | |
estade | b8867dff | 2016-11-03 17:33:33 | [diff] [blame] | 579 | // If we don't have a file pack, we're updating from an old version. |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 580 | base::FilePath path = prefs->GetFilePath(prefs::kCurrentThemePackFilename); |
| 581 | if (path != base::FilePath()) { |
estade | b8867dff | 2016-11-03 17:33:33 | [diff] [blame] | 582 | path = path.Append(chrome::kThemePackFilename); |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 583 | SwapThemeSupplier(BrowserThemePack::BuildFromDataPack(path, current_id)); |
scheib | 4dac7f0 | 2016-05-12 00:55:03 | [diff] [blame] | 584 | if (theme_supplier_) |
| 585 | loaded_pack = true; |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 586 | } |
| 587 | |
| 588 | if (loaded_pack) { |
bratell | 0a7406f | 2017-03-28 07:46:37 | [diff] [blame] | 589 | base::RecordAction(UserMetricsAction("Themes.Loaded")); |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 590 | set_ready(); |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 591 | } |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 592 | // Else: wait for the extension service to be ready so that the theme pack |
| 593 | // can be recreated from the extension. |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 594 | } |
| 595 | |
[email protected] | a3e61e8 | 2011-04-15 20:32:08 | [diff] [blame] | 596 | void ThemeService::NotifyThemeChanged() { |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 597 | if (!ready_) |
| 598 | return; |
| 599 | |
[email protected] | 8e88ca1 | 2011-11-04 20:45:39 | [diff] [blame] | 600 | DVLOG(1) << "Sending BROWSER_THEME_CHANGED"; |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 601 | // Redraw! |
[email protected] | ad50def5 | 2011-10-19 23:17:07 | [diff] [blame] | 602 | content::NotificationService* service = |
| 603 | content::NotificationService::current(); |
[email protected] | 43211582 | 2011-07-10 15:52:27 | [diff] [blame] | 604 | service->Notify(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, |
[email protected] | 6c2381d | 2011-10-19 02:52:53 | [diff] [blame] | 605 | content::Source<ThemeService>(this), |
[email protected] | ad50def5 | 2011-10-19 23:17:07 | [diff] [blame] | 606 | content::NotificationService::NoDetails()); |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 607 | #if defined(OS_MACOSX) |
| 608 | NotifyPlatformThemeChanged(); |
| 609 | #endif // OS_MACOSX |
[email protected] | 280453e | 2012-09-28 19:09:41 | [diff] [blame] | 610 | |
| 611 | // Notify sync that theme has changed. |
| 612 | if (theme_syncable_service_.get()) { |
| 613 | theme_syncable_service_->OnThemeChange(); |
| 614 | } |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 615 | } |
| 616 | |
[email protected] | f9db7d2d | 2014-04-11 16:07:11 | [diff] [blame] | 617 | #if defined(USE_AURA) |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 618 | void ThemeService::FreePlatformCaches() { |
| 619 | // Views (Skia) has no platform image cache to clear. |
| 620 | } |
| 621 | #endif |
| 622 | |
pkasting | 20d38210d | 2016-03-08 09:45:54 | [diff] [blame] | 623 | bool ThemeService::ShouldUseNativeFrame() const { |
| 624 | return false; |
| 625 | } |
| 626 | |
| 627 | bool ThemeService::HasCustomImage(int id) const { |
| 628 | return BrowserThemePack::IsPersistentImageID(id) && theme_supplier_ && |
| 629 | theme_supplier_->HasCustomImage(id); |
| 630 | } |
| 631 | |
pkasting | 3eb05e6 | 2016-03-17 01:01:02 | [diff] [blame] | 632 | // static |
| 633 | SkColor ThemeService::GetSeparatorColor(SkColor tab_color, |
| 634 | SkColor frame_color) { |
| 635 | // We use this alpha value for the separator if possible. |
| 636 | const SkAlpha kAlpha = 0x40; |
| 637 | |
| 638 | // In most cases, if the tab is lighter than the frame, we darken the |
| 639 | // frame; if the tab is darker than the frame, we lighten the frame. |
| 640 | // However, if the frame is already very dark or very light, respectively, |
| 641 | // this won't contrast sufficiently with the frame color, so we'll need to |
| 642 | // reverse when we're lightening and darkening. |
| 643 | const double tab_luminance = color_utils::GetRelativeLuminance(tab_color); |
| 644 | const double frame_luminance = color_utils::GetRelativeLuminance(frame_color); |
| 645 | const bool lighten = tab_luminance < frame_luminance; |
| 646 | SkColor separator_color = lighten ? SK_ColorWHITE : SK_ColorBLACK; |
| 647 | double separator_luminance = color_utils::GetRelativeLuminance( |
| 648 | color_utils::AlphaBlend(separator_color, frame_color, kAlpha)); |
| 649 | // The minimum contrast ratio here is just under the ~1.1469 in the default MD |
| 650 | // incognito theme. We want the separator to still darken the frame in that |
| 651 | // theme, but that's about as low of contrast as we're willing to accept. |
| 652 | const double kMinContrastRatio = 1.1465; |
| 653 | if (color_utils::GetContrastRatio(separator_luminance, frame_luminance) >= |
| 654 | kMinContrastRatio) |
| 655 | return SkColorSetA(separator_color, kAlpha); |
| 656 | |
| 657 | // We need to reverse whether we're darkening or lightening. We know the new |
| 658 | // separator color will contrast with the frame; check whether it also |
| 659 | // contrasts at least as well with the tab. |
| 660 | separator_color = color_utils::InvertColor(separator_color); |
| 661 | separator_luminance = color_utils::GetRelativeLuminance( |
| 662 | color_utils::AlphaBlend(separator_color, frame_color, kAlpha)); |
| 663 | if (color_utils::GetContrastRatio(separator_luminance, tab_luminance) >= |
| 664 | color_utils::GetContrastRatio(separator_luminance, frame_luminance)) |
| 665 | return SkColorSetA(separator_color, kAlpha); |
| 666 | |
| 667 | // The reversed separator doesn't contrast enough with the tab. Compute the |
| 668 | // resulting luminance from adjusting the tab color, instead of the frame |
| 669 | // color, by the separator color. |
| 670 | const double target_luminance = color_utils::GetRelativeLuminance( |
| 671 | color_utils::AlphaBlend(separator_color, tab_color, kAlpha)); |
| 672 | |
| 673 | // Now try to compute an alpha for the separator such that, when blended with |
| 674 | // the frame, it results in the above luminance. Because the luminance |
| 675 | // computation is not easily invertible, we use a binary search over the |
| 676 | // possible range of alpha values. |
| 677 | SkAlpha alpha = 128; |
| 678 | for (int delta = lighten ? 64 : -64; delta != 0; delta /= 2) { |
| 679 | const double luminance = color_utils::GetRelativeLuminance( |
| 680 | color_utils::AlphaBlend(separator_color, frame_color, alpha)); |
| 681 | if (luminance == target_luminance) |
| 682 | break; |
| 683 | alpha += (luminance < target_luminance) ? -delta : delta; |
| 684 | } |
| 685 | return SkColorSetA(separator_color, alpha); |
| 686 | } |
| 687 | |
estade | 89bc30b | 2016-02-09 19:08:53 | [diff] [blame] | 688 | gfx::ImageSkia* ThemeService::GetImageSkiaNamed(int id, bool incognito) const { |
| 689 | gfx::Image image = GetImageNamed(id, incognito); |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 690 | if (image.IsEmpty()) |
| 691 | return nullptr; |
| 692 | // TODO(pkotwicz): Remove this const cast. The gfx::Image interface returns |
| 693 | // its images const. GetImageSkiaNamed() also should but has many callsites. |
| 694 | return const_cast<gfx::ImageSkia*>(image.ToImageSkia()); |
| 695 | } |
| 696 | |
estade | 89bc30b | 2016-02-09 19:08:53 | [diff] [blame] | 697 | SkColor ThemeService::GetColor(int id, bool incognito) const { |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 698 | DCHECK(CalledOnValidThread()); |
estade | 42d476e | 2015-12-18 00:28:11 | [diff] [blame] | 699 | |
| 700 | // For legacy reasons, |theme_supplier_| requires the incognito variants |
| 701 | // of color IDs. |
| 702 | int theme_supplier_id = id; |
estade | 89bc30b | 2016-02-09 19:08:53 | [diff] [blame] | 703 | if (incognito) { |
pkasting | 0918e57 | 2016-01-15 22:15:47 | [diff] [blame] | 704 | if (id == ThemeProperties::COLOR_FRAME) |
| 705 | theme_supplier_id = ThemeProperties::COLOR_FRAME_INCOGNITO; |
| 706 | else if (id == ThemeProperties::COLOR_FRAME_INACTIVE) |
| 707 | theme_supplier_id = ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE; |
estade | 42d476e | 2015-12-18 00:28:11 | [diff] [blame] | 708 | } |
| 709 | |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 710 | SkColor color; |
estade | 42d476e | 2015-12-18 00:28:11 | [diff] [blame] | 711 | if (theme_supplier_ && theme_supplier_->GetColor(theme_supplier_id, &color)) |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 712 | return color; |
| 713 | |
pkasting | 20d38210d | 2016-03-08 09:45:54 | [diff] [blame] | 714 | return GetDefaultColor(id, incognito); |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 715 | } |
| 716 | |
| 717 | int ThemeService::GetDisplayProperty(int id) const { |
| 718 | int result = 0; |
| 719 | if (theme_supplier_ && theme_supplier_->GetDisplayProperty(id, &result)) { |
| 720 | return result; |
| 721 | } |
| 722 | |
| 723 | switch (id) { |
pkasting | 0918e57 | 2016-01-15 22:15:47 | [diff] [blame] | 724 | case ThemeProperties::NTP_BACKGROUND_ALIGNMENT: |
| 725 | return ThemeProperties::ALIGN_CENTER; |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 726 | |
pkasting | 0918e57 | 2016-01-15 22:15:47 | [diff] [blame] | 727 | case ThemeProperties::NTP_BACKGROUND_TILING: |
| 728 | return ThemeProperties::NO_REPEAT; |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 729 | |
pkasting | 0918e57 | 2016-01-15 22:15:47 | [diff] [blame] | 730 | case ThemeProperties::NTP_LOGO_ALTERNATE: { |
| 731 | if (UsingDefaultTheme() || UsingSystemTheme()) |
| 732 | return 0; |
| 733 | if (HasCustomImage(IDR_THEME_NTP_BACKGROUND)) |
| 734 | return 1; |
| 735 | return IsColorGrayscale( |
| 736 | GetColor(ThemeProperties::COLOR_NTP_BACKGROUND, false)) ? 0 : 1; |
| 737 | } |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 738 | |
| 739 | default: |
| 740 | return -1; |
| 741 | } |
| 742 | } |
| 743 | |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 744 | base::RefCountedMemory* ThemeService::GetRawData( |
| 745 | int id, |
| 746 | ui::ScaleFactor scale_factor) const { |
| 747 | // Check to see whether we should substitute some images. |
pkasting | 0918e57 | 2016-01-15 22:15:47 | [diff] [blame] | 748 | int ntp_alternate = GetDisplayProperty(ThemeProperties::NTP_LOGO_ALTERNATE); |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 749 | if (id == IDR_PRODUCT_LOGO && ntp_alternate != 0) |
| 750 | id = IDR_PRODUCT_LOGO_WHITE; |
| 751 | |
| 752 | base::RefCountedMemory* data = nullptr; |
| 753 | if (theme_supplier_) |
| 754 | data = theme_supplier_->GetRawData(id, scale_factor); |
| 755 | if (!data) |
| 756 | data = rb_.LoadDataResourceBytesForScale(id, ui::SCALE_FACTOR_100P); |
| 757 | |
| 758 | return data; |
| 759 | } |
| 760 | |
estade | 89bc30b | 2016-02-09 19:08:53 | [diff] [blame] | 761 | gfx::Image ThemeService::GetImageNamed(int id, bool incognito) const { |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 762 | DCHECK(CalledOnValidThread()); |
| 763 | |
estade | 89bc30b | 2016-02-09 19:08:53 | [diff] [blame] | 764 | int adjusted_id = id; |
| 765 | if (incognito) { |
| 766 | if (id == IDR_THEME_FRAME) |
| 767 | adjusted_id = IDR_THEME_FRAME_INCOGNITO; |
| 768 | else if (id == IDR_THEME_FRAME_INACTIVE) |
| 769 | adjusted_id = IDR_THEME_FRAME_INCOGNITO_INACTIVE; |
| 770 | } |
| 771 | |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 772 | gfx::Image image; |
| 773 | if (theme_supplier_) |
estade | 89bc30b | 2016-02-09 19:08:53 | [diff] [blame] | 774 | image = theme_supplier_->GetImageNamed(adjusted_id); |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 775 | |
| 776 | if (image.IsEmpty()) |
estade | 89bc30b | 2016-02-09 19:08:53 | [diff] [blame] | 777 | image = rb_.GetNativeImageNamed(adjusted_id); |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 778 | |
| 779 | return image; |
| 780 | } |
| 781 | |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 782 | void ThemeService::OnExtensionServiceReady() { |
| 783 | if (!ready_) { |
| 784 | // If the ThemeService is not ready yet, the custom theme data pack needs to |
| 785 | // be recreated from the extension. |
| 786 | MigrateTheme(); |
| 787 | set_ready(); |
| 788 | |
| 789 | // Send notification in case anyone requested data and cached it when the |
| 790 | // theme service was not ready yet. |
| 791 | NotifyThemeChanged(); |
| 792 | } |
| 793 | |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 794 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
limasdf | 96f0702b | 2015-03-13 21:57:09 | [diff] [blame] | 795 | theme_observer_.reset(new ThemeObserver(this)); |
| 796 | #endif |
| 797 | |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 798 | registrar_.Add(this, |
[email protected] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 799 | extensions::NOTIFICATION_EXTENSION_ENABLED, |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 800 | content::Source<Profile>(profile_)); |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 801 | |
skyostil | 0259835 | 2015-06-12 12:37:25 | [diff] [blame] | 802 | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 803 | FROM_HERE, base::Bind(&ThemeService::RemoveUnusedThemes, |
| 804 | weak_ptr_factory_.GetWeakPtr(), false), |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 805 | base::TimeDelta::FromSeconds(kRemoveUnusedThemesStartupDelay)); |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 806 | } |
| 807 | |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 808 | void ThemeService::MigrateTheme() { |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 809 | // TODO(erg): We need to pop up a dialog informing the user that their |
| 810 | // theme is being migrated. |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 811 | ExtensionService* service = |
| 812 | extensions::ExtensionSystem::Get(profile_)->extension_service(); |
limasdf | 96f0702b | 2015-03-13 21:57:09 | [diff] [blame] | 813 | const Extension* extension = |
| 814 | service ? service->GetExtensionById(GetThemeID(), false) : nullptr; |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 815 | if (extension) { |
| 816 | DLOG(ERROR) << "Migrating theme"; |
| 817 | BuildFromExtension(extension); |
bratell | 0a7406f | 2017-03-28 07:46:37 | [diff] [blame] | 818 | base::RecordAction(UserMetricsAction("Themes.Migrated")); |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 819 | } else { |
| 820 | DLOG(ERROR) << "Theme is mysteriously gone."; |
| 821 | ClearAllThemeData(); |
bratell | 0a7406f | 2017-03-28 07:46:37 | [diff] [blame] | 822 | base::RecordAction(UserMetricsAction("Themes.Gone")); |
[email protected] | 264c60b | 2013-03-20 01:30:54 | [diff] [blame] | 823 | } |
| 824 | } |
| 825 | |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 826 | void ThemeService::SwapThemeSupplier( |
| 827 | scoped_refptr<CustomThemeSupplier> theme_supplier) { |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 828 | if (theme_supplier_) |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 829 | theme_supplier_->StopUsingTheme(); |
| 830 | theme_supplier_ = theme_supplier; |
estade | 68691b28 | 2015-12-11 21:50:40 | [diff] [blame] | 831 | if (theme_supplier_) |
[email protected] | b1ac7046 | 2013-08-14 21:33:30 | [diff] [blame] | 832 | theme_supplier_->StartUsingTheme(); |
| 833 | } |
| 834 | |
[email protected] | 650b2d5 | 2013-02-10 03:41:45 | [diff] [blame] | 835 | void ThemeService::SavePackName(const base::FilePath& pack_path) { |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 836 | profile_->GetPrefs()->SetFilePath( |
| 837 | prefs::kCurrentThemePackFilename, pack_path); |
| 838 | } |
| 839 | |
[email protected] | d594931 | 2012-12-03 22:13:30 | [diff] [blame] | 840 | void ThemeService::SaveThemeID(const std::string& id) { |
| 841 | profile_->GetPrefs()->SetString(prefs::kCurrentThemeID, id); |
| 842 | } |
| 843 | |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 844 | void ThemeService::BuildFromExtension(const Extension* extension) { |
| 845 | scoped_refptr<BrowserThemePack> pack( |
| 846 | BrowserThemePack::BuildFromExtension(extension)); |
| 847 | if (!pack.get()) { |
| 848 | // TODO(erg): We've failed to install the theme; perhaps we should tell the |
| 849 | // user? http://crbug.com/34780 |
| 850 | LOG(ERROR) << "Could not load theme."; |
| 851 | return; |
| 852 | } |
| 853 | |
[email protected] | 7f8f24f | 2012-11-15 19:40:14 | [diff] [blame] | 854 | ExtensionService* service = |
| 855 | extensions::ExtensionSystem::Get(profile_)->extension_service(); |
| 856 | if (!service) |
| 857 | return; |
| 858 | |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 859 | // Write the packed file to disk. |
[email protected] | 7f8f24f | 2012-11-15 19:40:14 | [diff] [blame] | 860 | service->GetFileTaskRunner()->PostTask( |
estade | b8867dff | 2016-11-03 17:33:33 | [diff] [blame] | 861 | FROM_HERE, base::Bind(&WritePackToDiskCallback, base::RetainedRef(pack), |
| 862 | extension->path())); |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 863 | |
estade | b8867dff | 2016-11-03 17:33:33 | [diff] [blame] | 864 | // Save only the extension path. The packed file will be loaded via |
| 865 | // LoadThemePrefs(). |
jonross | c38cce9b | 2015-09-24 15:42:22 | [diff] [blame] | 866 | SavePackName(extension->path()); |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 867 | SwapThemeSupplier(pack); |
[email protected] | a0ea76c | 2011-03-23 17:36:42 | [diff] [blame] | 868 | } |
| 869 | |
brettw | 9e85ef4 | 2016-11-01 21:01:24 | [diff] [blame] | 870 | #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
[email protected] | d20d043 | 2014-06-12 17:14:05 | [diff] [blame] | 871 | bool ThemeService::IsSupervisedUser() const { |
| 872 | return profile_->IsSupervised(); |
[email protected] | 768c0ff | 2013-06-21 02:50:55 | [diff] [blame] | 873 | } |
| 874 | |
[email protected] | d20d043 | 2014-06-12 17:14:05 | [diff] [blame] | 875 | void ThemeService::SetSupervisedUserTheme() { |
[email protected] | cce15bb | 2014-06-17 13:43:51 | [diff] [blame] | 876 | SetCustomDefaultTheme(new SupervisedUserTheme); |
[email protected] | ed0cef0 | 2013-07-26 12:41:11 | [diff] [blame] | 877 | } |
mckev | a1a18dc | 2014-09-29 18:52:33 | [diff] [blame] | 878 | #endif |