| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/browser_theme_provider.h" | 5 #include "chrome/browser/browser_theme_provider.h" |
| 6 | 6 |
| 7 #include "app/gfx/codec/png_codec.h" | 7 #include "app/gfx/codec/png_codec.h" |
| 8 #include "app/gfx/skbitmap_operations.h" | 8 #include "app/gfx/skbitmap_operations.h" |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/stl_util-inl.h" | 10 #include "base/stl_util-inl.h" |
| 11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 12 #include "base/thread.h" | 12 #include "base/thread.h" |
| 13 #include "base/values.h" | 13 #include "base/values.h" |
| 14 #include "chrome/browser/browser_list.h" | 14 #include "chrome/browser/browser_list.h" |
| 15 #include "chrome/browser/browser_process.h" | 15 #include "chrome/browser/browser_process.h" |
| 16 #include "chrome/browser/browser_theme_pack.h" |
| 16 #include "chrome/browser/browser_window.h" | 17 #include "chrome/browser/browser_window.h" |
| 17 #include "chrome/browser/extensions/extensions_service.h" | 18 #include "chrome/browser/extensions/extensions_service.h" |
| 18 #include "chrome/browser/metrics/user_metrics.h" | 19 #include "chrome/browser/metrics/user_metrics.h" |
| 19 #include "chrome/browser/profile.h" | 20 #include "chrome/browser/profile.h" |
| 20 #include "chrome/browser/theme_resources_util.h" | 21 #include "chrome/browser/theme_resources_util.h" |
| 21 #include "chrome/common/chrome_constants.h" | 22 #include "chrome/common/chrome_constants.h" |
| 22 #include "chrome/common/extensions/extension.h" | 23 #include "chrome/common/extensions/extension.h" |
| 23 #include "chrome/common/notification_service.h" | 24 #include "chrome/common/notification_service.h" |
| 24 #include "chrome/common/notification_type.h" | 25 #include "chrome/common/notification_type.h" |
| 25 #include "chrome/common/pref_names.h" | 26 #include "chrome/common/pref_names.h" |
| 26 #include "chrome/common/pref_service.h" | 27 #include "chrome/common/pref_service.h" |
| 27 #include "grit/app_resources.h" | 28 #include "grit/app_resources.h" |
| 28 #include "grit/theme_resources.h" | 29 #include "grit/theme_resources.h" |
| 29 #include "net/base/file_stream.h" | 30 #include "net/base/file_stream.h" |
| 30 #include "net/base/net_errors.h" | 31 #include "net/base/net_errors.h" |
| 31 #include "third_party/skia/include/core/SkBitmap.h" | 32 #include "third_party/skia/include/core/SkBitmap.h" |
| 32 #include "third_party/skia/include/core/SkCanvas.h" | 33 #include "third_party/skia/include/core/SkCanvas.h" |
| 33 #include "third_party/skia/include/core/SkUnPreMultiply.h" | 34 #include "third_party/skia/include/core/SkUnPreMultiply.h" |
| 34 | 35 |
| 35 #if defined(OS_WIN) | 36 #if defined(OS_WIN) |
| 36 #include "app/win_util.h" | 37 #include "app/win_util.h" |
| 37 #endif | 38 #endif |
| 38 | 39 |
| 39 // Strings used by themes to identify colors for different parts of our UI. | |
| 40 const char* BrowserThemeProvider::kColorFrame = "frame"; | |
| 41 const char* BrowserThemeProvider::kColorFrameInactive = "frame_inactive"; | |
| 42 const char* BrowserThemeProvider::kColorFrameIncognito = "frame_incognito"; | |
| 43 const char* BrowserThemeProvider::kColorFrameIncognitoInactive = | |
| 44 "frame_incognito_inactive"; | |
| 45 const char* BrowserThemeProvider::kColorToolbar = "toolbar"; | |
| 46 const char* BrowserThemeProvider::kColorTabText = "tab_text"; | |
| 47 const char* BrowserThemeProvider::kColorBackgroundTabText = | |
| 48 "tab_background_text"; | |
| 49 const char* BrowserThemeProvider::kColorBookmarkText = "bookmark_text"; | |
| 50 const char* BrowserThemeProvider::kColorNTPBackground = "ntp_background"; | |
| 51 const char* BrowserThemeProvider::kColorNTPText = "ntp_text"; | |
| 52 const char* BrowserThemeProvider::kColorNTPLink = "ntp_link"; | |
| 53 const char* BrowserThemeProvider::kColorNTPLinkUnderline = "ntp_link_underline"; | |
| 54 const char* BrowserThemeProvider::kColorNTPHeader = "ntp_header"; | |
| 55 const char* BrowserThemeProvider::kColorNTPSection = "ntp_section"; | |
| 56 const char* BrowserThemeProvider::kColorNTPSectionText = "ntp_section_text"; | |
| 57 const char* BrowserThemeProvider::kColorNTPSectionLink = "ntp_section_link"; | |
| 58 const char* BrowserThemeProvider::kColorNTPSectionLinkUnderline = | |
| 59 "ntp_section_link_underline"; | |
| 60 const char* BrowserThemeProvider::kColorControlBackground = | |
| 61 "control_background"; | |
| 62 const char* BrowserThemeProvider::kColorButtonBackground = "button_background"; | |
| 63 | |
| 64 // Strings used by themes to identify tints to apply to different parts of | |
| 65 // our UI. The frame tints apply to the frame color and produce the | |
| 66 // COLOR_FRAME* colors. | |
| 67 const char* BrowserThemeProvider::kTintButtons = "buttons"; | |
| 68 const char* BrowserThemeProvider::kTintFrame = "frame"; | |
| 69 const char* BrowserThemeProvider::kTintFrameInactive = "frame_inactive"; | |
| 70 const char* BrowserThemeProvider::kTintFrameIncognito = "frame_incognito"; | |
| 71 const char* BrowserThemeProvider::kTintFrameIncognitoInactive = | |
| 72 "frame_incognito_inactive"; | |
| 73 const char* BrowserThemeProvider::kTintBackgroundTab = "background_tab"; | |
| 74 | |
| 75 // Strings used by themes to identify miscellaneous numerical properties. | |
| 76 const char* BrowserThemeProvider::kDisplayPropertyNTPAlignment = | |
| 77 "ntp_background_alignment"; | |
| 78 const char* BrowserThemeProvider::kDisplayPropertyNTPTiling = | |
| 79 "ntp_background_repeat"; | |
| 80 const char* BrowserThemeProvider::kDisplayPropertyNTPInverseLogo = | |
| 81 "ntp_logo_alternate"; | |
| 82 | |
| 83 // Strings used in alignment properties. | 40 // Strings used in alignment properties. |
| 84 const char* BrowserThemeProvider::kAlignmentTop = "top"; | 41 const char* BrowserThemeProvider::kAlignmentTop = "top"; |
| 85 const char* BrowserThemeProvider::kAlignmentBottom = "bottom"; | 42 const char* BrowserThemeProvider::kAlignmentBottom = "bottom"; |
| 86 const char* BrowserThemeProvider::kAlignmentLeft = "left"; | 43 const char* BrowserThemeProvider::kAlignmentLeft = "left"; |
| 87 const char* BrowserThemeProvider::kAlignmentRight = "right"; | 44 const char* BrowserThemeProvider::kAlignmentRight = "right"; |
| 88 | 45 |
| 89 // Strings used in background tiling repetition properties. | 46 // Strings used in background tiling repetition properties. |
| 90 const char* BrowserThemeProvider::kTilingNoRepeat = "no-repeat"; | 47 const char* BrowserThemeProvider::kTilingNoRepeat = "no-repeat"; |
| 91 const char* BrowserThemeProvider::kTilingRepeatX = "repeat-x"; | 48 const char* BrowserThemeProvider::kTilingRepeatX = "repeat-x"; |
| 92 const char* BrowserThemeProvider::kTilingRepeatY = "repeat-y"; | 49 const char* BrowserThemeProvider::kTilingRepeatY = "repeat-y"; |
| 93 const char* BrowserThemeProvider::kTilingRepeat = "repeat"; | 50 const char* BrowserThemeProvider::kTilingRepeat = "repeat"; |
| 94 | 51 |
| 95 // Default colors. | |
| 96 const SkColor BrowserThemeProvider::kDefaultColorFrame = | |
| 97 SkColorSetRGB(77, 139, 217); | |
| 98 const SkColor BrowserThemeProvider::kDefaultColorFrameInactive = | |
| 99 SkColorSetRGB(152, 188, 233); | |
| 100 const SkColor BrowserThemeProvider::kDefaultColorFrameIncognito = | |
| 101 SkColorSetRGB(83, 106, 139); | |
| 102 const SkColor BrowserThemeProvider::kDefaultColorFrameIncognitoInactive = | |
| 103 SkColorSetRGB(126, 139, 156); | |
| 104 const SkColor BrowserThemeProvider::kDefaultColorToolbar = | |
| 105 SkColorSetRGB(210, 225, 246); | |
| 106 const SkColor BrowserThemeProvider::kDefaultColorTabText = SK_ColorBLACK; | |
| 107 const SkColor BrowserThemeProvider::kDefaultColorBackgroundTabText = | |
| 108 SkColorSetRGB(64, 64, 64); | |
| 109 const SkColor BrowserThemeProvider::kDefaultColorBookmarkText = | |
| 110 SkColorSetRGB(18, 50, 114); | |
| 111 #if defined(OS_WIN) | |
| 112 const SkColor BrowserThemeProvider::kDefaultColorNTPBackground = | |
| 113 color_utils::GetSysSkColor(COLOR_WINDOW); | |
| 114 const SkColor BrowserThemeProvider::kDefaultColorNTPText = | |
| 115 color_utils::GetSysSkColor(COLOR_WINDOWTEXT); | |
| 116 const SkColor BrowserThemeProvider::kDefaultColorNTPLink = | |
| 117 color_utils::GetSysSkColor(COLOR_HOTLIGHT); | |
| 118 #else | |
| 119 // TODO(beng): source from theme provider. | |
| 120 const SkColor BrowserThemeProvider::kDefaultColorNTPBackground = SK_ColorWHITE; | |
| 121 const SkColor BrowserThemeProvider::kDefaultColorNTPText = SK_ColorBLACK; | |
| 122 const SkColor BrowserThemeProvider::kDefaultColorNTPLink = | |
| 123 SkColorSetRGB(6, 55, 116); | |
| 124 #endif | |
| 125 const SkColor BrowserThemeProvider::kDefaultColorNTPHeader = | |
| 126 SkColorSetRGB(75, 140, 220); | |
| 127 const SkColor BrowserThemeProvider::kDefaultColorNTPSection = | |
| 128 SkColorSetRGB(229, 239, 254); | |
| 129 const SkColor BrowserThemeProvider::kDefaultColorNTPSectionText = SK_ColorBLACK; | |
| 130 const SkColor BrowserThemeProvider::kDefaultColorNTPSectionLink = | |
| 131 SkColorSetRGB(6, 55, 116); | |
| 132 const SkColor BrowserThemeProvider::kDefaultColorControlBackground = | |
| 133 SkColorSetARGB(0, 0, 0, 0); | |
| 134 const SkColor BrowserThemeProvider::kDefaultColorButtonBackground = | |
| 135 SkColorSetARGB(0, 0, 0, 0); | |
| 136 | |
| 137 // Default tints. | |
| 138 const color_utils::HSL BrowserThemeProvider::kDefaultTintButtons = | |
| 139 { -1, -1, -1 }; | |
| 140 const color_utils::HSL BrowserThemeProvider::kDefaultTintFrame = { -1, -1, -1 }; | |
| 141 const color_utils::HSL BrowserThemeProvider::kDefaultTintFrameInactive = | |
| 142 { -1, -1, 0.75f }; | |
| 143 const color_utils::HSL BrowserThemeProvider::kDefaultTintFrameIncognito = | |
| 144 { -1, 0.2f, 0.35f }; | |
| 145 const color_utils::HSL | |
| 146 BrowserThemeProvider::kDefaultTintFrameIncognitoInactive = | |
| 147 { -1, 0.3f, 0.6f }; | |
| 148 const color_utils::HSL BrowserThemeProvider::kDefaultTintBackgroundTab = | |
| 149 { -1, 0.5, 0.75 }; | |
| 150 | |
| 151 // Saved default values. | 52 // Saved default values. |
| 152 const char* BrowserThemeProvider::kDefaultThemeID = ""; | 53 const char* BrowserThemeProvider::kDefaultThemeID = ""; |
| 153 | 54 |
| 154 Lock BrowserThemeProvider::themed_image_cache_lock_; | 55 namespace { |
| 155 | 56 |
| 156 namespace { | 57 SkColor TintForUnderline(SkColor input) { |
| 58 return SkColorSetA(input, SkColorGetA(input) / 3); |
| 59 } |
| 60 |
| 61 // Default colors. |
| 62 const SkColor kDefaultColorFrame = SkColorSetRGB(77, 139, 217); |
| 63 const SkColor kDefaultColorFrameInactive = SkColorSetRGB(152, 188, 233); |
| 64 const SkColor kDefaultColorFrameIncognito = SkColorSetRGB(83, 106, 139); |
| 65 const SkColor kDefaultColorFrameIncognitoInactive = |
| 66 SkColorSetRGB(126, 139, 156); |
| 67 const SkColor kDefaultColorToolbar = SkColorSetRGB(210, 225, 246); |
| 68 const SkColor kDefaultColorTabText = SK_ColorBLACK; |
| 69 const SkColor kDefaultColorBackgroundTabText = SkColorSetRGB(64, 64, 64); |
| 70 const SkColor kDefaultColorBookmarkText = SkColorSetRGB(18, 50, 114); |
| 71 #if defined(OS_WIN) |
| 72 const SkColor kDefaultColorNTPBackground = |
| 73 color_utils::GetSysSkColor(COLOR_WINDOW); |
| 74 const SkColor kDefaultColorNTPText = |
| 75 color_utils::GetSysSkColor(COLOR_WINDOWTEXT); |
| 76 const SkColor kDefaultColorNTPLink = |
| 77 color_utils::GetSysSkColor(COLOR_HOTLIGHT); |
| 78 #else |
| 79 // TODO(beng): source from theme provider. |
| 80 const SkColor kDefaultColorNTPBackground = SK_ColorWHITE; |
| 81 const SkColor kDefaultColorNTPText = SK_ColorBLACK; |
| 82 const SkColor kDefaultColorNTPLink = SkColorSetRGB(6, 55, 116); |
| 83 #endif |
| 84 const SkColor kDefaultColorNTPHeader = SkColorSetRGB(75, 140, 220); |
| 85 const SkColor kDefaultColorNTPSection = SkColorSetRGB(229, 239, 254); |
| 86 const SkColor kDefaultColorNTPSectionText = SK_ColorBLACK; |
| 87 const SkColor kDefaultColorNTPSectionLink = SkColorSetRGB(6, 55, 116); |
| 88 const SkColor kDefaultColorControlBackground = SkColorSetARGB(0, 0, 0, 0); |
| 89 const SkColor kDefaultColorButtonBackground = SkColorSetARGB(0, 0, 0, 0); |
| 90 |
| 91 // Default tints. |
| 92 const color_utils::HSL kDefaultTintButtons = { -1, -1, -1 }; |
| 93 const color_utils::HSL kDefaultTintFrame = { -1, -1, -1 }; |
| 94 const color_utils::HSL kDefaultTintFrameInactive = { -1, -1, 0.75f }; |
| 95 const color_utils::HSL kDefaultTintFrameIncognito = { -1, 0.2f, 0.35f }; |
| 96 const color_utils::HSL kDefaultTintFrameIncognitoInactive = { -1, 0.3f, 0.6f }; |
| 97 const color_utils::HSL kDefaultTintBackgroundTab = { -1, 0.5, 0.75 }; |
| 157 | 98 |
| 158 // Default display properties. | 99 // Default display properties. |
| 159 const int kDefaultDisplayPropertyNTPAlignment = | 100 const int kDefaultDisplayPropertyNTPAlignment = |
| 160 BrowserThemeProvider::ALIGN_BOTTOM; | 101 BrowserThemeProvider::ALIGN_BOTTOM; |
| 161 const int kDefaultDisplayPropertyNTPTiling = | 102 const int kDefaultDisplayPropertyNTPTiling = |
| 162 BrowserThemeProvider::NO_REPEAT; | 103 BrowserThemeProvider::NO_REPEAT; |
| 163 const int kDefaultDisplayPropertyNTPInverseLogo = 0; | 104 const int kDefaultDisplayPropertyNTPInverseLogo = 0; |
| 164 | 105 |
| 165 // The sum of kFrameBorderThickness and kNonClientRestoredExtraThickness from | 106 // The sum of kFrameBorderThickness and kNonClientRestoredExtraThickness from |
| 166 // OpaqueBrowserFrameView. | 107 // OpaqueBrowserFrameView. |
| 167 const int kRestoredTabVerticalOffset = 15; | 108 const int kRestoredTabVerticalOffset = 15; |
| 168 | 109 |
| 169 // The image resources that will be tinted by the 'button' tint value. | |
| 170 const int kToolbarButtonIDs[] = { | |
| 171 IDR_BACK, IDR_BACK_D, IDR_BACK_H, IDR_BACK_P, | |
| 172 IDR_FORWARD, IDR_FORWARD_D, IDR_FORWARD_H, IDR_FORWARD_P, | |
| 173 IDR_RELOAD, IDR_RELOAD_H, IDR_RELOAD_P, | |
| 174 IDR_HOME, IDR_HOME_H, IDR_HOME_P, | |
| 175 IDR_STAR, IDR_STAR_NOBORDER, IDR_STAR_NOBORDER_CENTER, IDR_STAR_D, IDR_STAR_H, | |
| 176 IDR_STAR_P, | |
| 177 IDR_STARRED, IDR_STARRED_NOBORDER, IDR_STARRED_NOBORDER_CENTER, IDR_STARRED_H, | |
| 178 IDR_STARRED_P, | |
| 179 IDR_GO, IDR_GO_NOBORDER, IDR_GO_NOBORDER_CENTER, IDR_GO_H, IDR_GO_P, | |
| 180 IDR_STOP, IDR_STOP_NOBORDER, IDR_STOP_NOBORDER_CENTER, IDR_STOP_H, IDR_STOP_P, | |
| 181 IDR_MENU_BOOKMARK, | |
| 182 IDR_MENU_PAGE, IDR_MENU_PAGE_RTL, | |
| 183 IDR_MENU_CHROME, IDR_MENU_CHROME_RTL, | |
| 184 IDR_MENU_DROPARROW, | |
| 185 IDR_THROBBER, IDR_THROBBER_WAITING, IDR_THROBBER_LIGHT, | |
| 186 IDR_LOCATIONBG | |
| 187 }; | |
| 188 | |
| 189 bool HasButtonImage(int toolbar_button_id) { | |
| 190 static std::map<int, bool> button_images; | |
| 191 if (button_images.empty()) { | |
| 192 for (size_t i = 0; i < arraysize(kToolbarButtonIDs); ++i) | |
| 193 button_images[kToolbarButtonIDs[i]] = true; | |
| 194 } | |
| 195 return button_images.count(toolbar_button_id) > 0; | |
| 196 } | |
| 197 | |
| 198 // The image resources we will allow people to theme. | 110 // The image resources we will allow people to theme. |
| 199 const int kThemeableImages[] = { | 111 const int kThemeableImages[] = { |
| 200 IDR_THEME_FRAME, | 112 IDR_THEME_FRAME, |
| 201 IDR_THEME_FRAME_INACTIVE, | 113 IDR_THEME_FRAME_INACTIVE, |
| 202 IDR_THEME_FRAME_INCOGNITO, | 114 IDR_THEME_FRAME_INCOGNITO, |
| 203 IDR_THEME_FRAME_INCOGNITO_INACTIVE, | 115 IDR_THEME_FRAME_INCOGNITO_INACTIVE, |
| 204 IDR_THEME_TOOLBAR, | 116 IDR_THEME_TOOLBAR, |
| 205 IDR_THEME_TAB_BACKGROUND, | 117 IDR_THEME_TAB_BACKGROUND, |
| 206 IDR_THEME_TAB_BACKGROUND_INCOGNITO, | 118 IDR_THEME_TAB_BACKGROUND_INCOGNITO, |
| 207 IDR_THEME_TAB_BACKGROUND_V, | 119 IDR_THEME_TAB_BACKGROUND_V, |
| 208 IDR_THEME_NTP_BACKGROUND, | 120 IDR_THEME_NTP_BACKGROUND, |
| 209 IDR_THEME_FRAME_OVERLAY, | 121 IDR_THEME_FRAME_OVERLAY, |
| 210 IDR_THEME_FRAME_OVERLAY_INACTIVE, | 122 IDR_THEME_FRAME_OVERLAY_INACTIVE, |
| 211 IDR_THEME_BUTTON_BACKGROUND, | 123 IDR_THEME_BUTTON_BACKGROUND, |
| 212 IDR_THEME_NTP_ATTRIBUTION, | 124 IDR_THEME_NTP_ATTRIBUTION, |
| 213 IDR_THEME_WINDOW_CONTROL_BACKGROUND | 125 IDR_THEME_WINDOW_CONTROL_BACKGROUND |
| 214 }; | 126 }; |
| 215 | 127 |
| 216 bool HasThemeableImage(int themeable_image_id) { | 128 bool HasThemeableImage(int themeable_image_id) { |
| 217 static std::map<int, bool> themeable_images; | 129 static std::map<int, bool> themeable_images; |
| 218 if (themeable_images.empty()) { | 130 if (themeable_images.empty()) { |
| 219 for (size_t i = 0; i < arraysize(kThemeableImages); ++i) | 131 for (size_t i = 0; i < arraysize(kThemeableImages); ++i) |
| 220 themeable_images[kThemeableImages[i]] = true; | 132 themeable_images[kThemeableImages[i]] = true; |
| 221 } | 133 } |
| 222 return themeable_images.count(themeable_image_id) > 0; | 134 return themeable_images.count(themeable_image_id) > 0; |
| 223 } | 135 } |
| 224 | 136 |
| 225 | 137 // Writes the theme pack to disk on a separate thread. |
| 226 class WriteImagesToDiskTask : public Task { | 138 class WritePackToDiskTask : public Task { |
| 227 public: | 139 public: |
| 228 WriteImagesToDiskTask( | 140 WritePackToDiskTask(BrowserThemePack* pack, const FilePath& path) |
| 229 const BrowserThemeProvider::ImagesDiskCache& images_disk_cache, | 141 : theme_pack_(pack), pack_path_(path) {} |
| 230 const BrowserThemeProvider::ImageCache& themed_image_cache) : | |
| 231 images_disk_cache_(images_disk_cache), | |
| 232 themed_image_cache_(themed_image_cache) { | |
| 233 } | |
| 234 | 142 |
| 235 virtual void Run() { | 143 virtual void Run() { |
| 236 AutoLock lock(BrowserThemeProvider::themed_image_cache_lock_); | 144 if (!theme_pack_->WriteToDisk(pack_path_)) { |
| 237 for (BrowserThemeProvider::ImagesDiskCache::const_iterator iter( | 145 NOTREACHED() << "Could not write theme pack to disk"; |
| 238 images_disk_cache_.begin()); iter != images_disk_cache_.end(); | |
| 239 ++iter) { | |
| 240 FilePath image_path = iter->first; | |
| 241 BrowserThemeProvider::ImageCache::const_iterator themed_iter = | |
| 242 themed_image_cache_.find(iter->second); | |
| 243 if (themed_iter != themed_image_cache_.end()) { | |
| 244 SkBitmap* bitmap = themed_iter->second; | |
| 245 std::vector<unsigned char> image_data; | |
| 246 if (!gfx::PNGCodec::EncodeBGRASkBitmap(*bitmap, false, &image_data)) { | |
| 247 NOTREACHED() << "Image file could not be encoded."; | |
| 248 return; | |
| 249 } | |
| 250 const char* image_data_ptr = | |
| 251 reinterpret_cast<const char*>(&image_data[0]); | |
| 252 if (!file_util::WriteFile(image_path, | |
| 253 image_data_ptr, image_data.size())) { | |
| 254 NOTREACHED() << "Image file could not be written to disk."; | |
| 255 return; | |
| 256 } | |
| 257 } else { | |
| 258 NOTREACHED() << "Themed image missing from cache."; | |
| 259 return; | |
| 260 } | |
| 261 } | 146 } |
| 262 } | 147 } |
| 263 | 148 |
| 264 private: | 149 private: |
| 265 // References to data held in the BrowserThemeProvider. | 150 scoped_refptr<BrowserThemePack> theme_pack_; |
| 266 const BrowserThemeProvider::ImagesDiskCache& images_disk_cache_; | 151 FilePath pack_path_; |
| 267 const BrowserThemeProvider::ImageCache& themed_image_cache_; | |
| 268 }; | 152 }; |
| 269 | 153 |
| 270 } // namespace | 154 } // namespace |
| 271 | 155 |
| 272 bool BrowserThemeProvider::IsThemeableImage(int resource_id) { | 156 bool BrowserThemeProvider::IsThemeableImage(int resource_id) { |
| 273 return HasThemeableImage(resource_id); | 157 return HasThemeableImage(resource_id); |
| 274 } | 158 } |
| 275 | 159 |
| 276 BrowserThemeProvider::BrowserThemeProvider() | 160 BrowserThemeProvider::BrowserThemeProvider() |
| 277 : rb_(ResourceBundle::GetSharedInstance()), | 161 : rb_(ResourceBundle::GetSharedInstance()), |
| 278 profile_(NULL), | 162 profile_(NULL) { |
| 279 process_images_(false) { | |
| 280 // Initialize the themeable image map so we can use it on other threads. | 163 // Initialize the themeable image map so we can use it on other threads. |
| 281 HasThemeableImage(0); | 164 HasThemeableImage(0); |
| 282 resource_names_[IDR_THEME_FRAME] = "theme_frame"; | |
| 283 resource_names_[IDR_THEME_FRAME_INACTIVE] = "theme_frame_inactive"; | |
| 284 resource_names_[IDR_THEME_FRAME_OVERLAY] = "theme_frame_overlay"; | |
| 285 resource_names_[IDR_THEME_FRAME_OVERLAY_INACTIVE] = | |
| 286 "theme_frame_overlay_inactive"; | |
| 287 resource_names_[IDR_THEME_FRAME_INCOGNITO] = "theme_frame_incognito"; | |
| 288 resource_names_[IDR_THEME_FRAME_INCOGNITO_INACTIVE] = | |
| 289 "theme_frame_incognito_inactive"; | |
| 290 resource_names_[IDR_THEME_TAB_BACKGROUND] = "theme_tab_background"; | |
| 291 resource_names_[IDR_THEME_TAB_BACKGROUND_INCOGNITO] = | |
| 292 "theme_tab_background_incognito"; | |
| 293 resource_names_[IDR_THEME_TOOLBAR] = "theme_toolbar"; | |
| 294 resource_names_[IDR_THEME_TAB_BACKGROUND_V] = "theme_tab_background_v"; | |
| 295 resource_names_[IDR_THEME_NTP_BACKGROUND] = "theme_ntp_background"; | |
| 296 resource_names_[IDR_THEME_BUTTON_BACKGROUND] = "theme_button_background"; | |
| 297 resource_names_[IDR_THEME_NTP_ATTRIBUTION] = "theme_ntp_attribution"; | |
| 298 resource_names_[IDR_THEME_WINDOW_CONTROL_BACKGROUND] = | |
| 299 "theme_window_control_background"; | |
| 300 } | 165 } |
| 301 | 166 |
| 302 BrowserThemeProvider::~BrowserThemeProvider() { | 167 BrowserThemeProvider::~BrowserThemeProvider() { |
| 303 ClearCaches(); | 168 FreePlatformCaches(); |
| 304 | 169 |
| 305 RemoveUnusedThemes(); | 170 RemoveUnusedThemes(); |
| 306 } | 171 } |
| 307 | 172 |
| 308 void BrowserThemeProvider::Init(Profile* profile) { | 173 void BrowserThemeProvider::Init(Profile* profile) { |
| 309 DCHECK(CalledOnValidThread()); | 174 DCHECK(CalledOnValidThread()); |
| 310 profile_ = profile; | 175 profile_ = profile; |
| 311 | 176 |
| 312 image_dir_ = profile_->GetPath().Append(chrome::kThemeImagesDirname); | |
| 313 if (!file_util::PathExists(image_dir_)) | |
| 314 file_util::CreateDirectory(image_dir_); | |
| 315 | |
| 316 LoadThemePrefs(); | 177 LoadThemePrefs(); |
| 317 } | 178 } |
| 318 | 179 |
| 319 SkBitmap* BrowserThemeProvider::GetBitmapNamed(int id) const { | 180 SkBitmap* BrowserThemeProvider::GetBitmapNamed(int id) const { |
| 320 DCHECK(CalledOnValidThread()); | 181 DCHECK(CalledOnValidThread()); |
| 321 | 182 |
| 322 // First check to see if the Skia image is in the themed cache. The themed | 183 SkBitmap* bitmap = NULL; |
| 323 // cache is not changed in this method, so it can remain unlocked. | |
| 324 ImageCache::const_iterator themed_iter = themed_image_cache_.find(id); | |
| 325 if (themed_iter != themed_image_cache_.end()) | |
| 326 return themed_iter->second; | |
| 327 | 184 |
| 328 // If Skia image is not in themed cache, check regular cache, and possibly | 185 if (theme_pack_.get()) |
| 329 // generate and store. | 186 bitmap = theme_pack_->GetBitmapNamed(id); |
| 330 ImageCache::const_iterator image_iter = image_cache_.find(id); | |
| 331 if (image_iter != image_cache_.end()) | |
| 332 return image_iter->second; | |
| 333 | 187 |
| 334 scoped_ptr<SkBitmap> result; | 188 if (!bitmap) |
| 189 bitmap = rb_.GetBitmapNamed(id); |
| 335 | 190 |
| 336 // Try to load the image from the extension. | 191 return bitmap; |
| 337 result.reset(LoadThemeBitmap(id)); | |
| 338 | |
| 339 // If we still don't have an image, load it from resourcebundle. | |
| 340 if (!result.get()) | |
| 341 result.reset(new SkBitmap(*rb_.GetBitmapNamed(id))); | |
| 342 | |
| 343 if (result.get()) { | |
| 344 // If the requested image is part of the toolbar button set, and we have | |
| 345 // a provided tint for that set, tint it appropriately. | |
| 346 if (HasButtonImage(id) && tints_.count(kTintButtons)) { | |
| 347 SkBitmap* tinted = | |
| 348 new SkBitmap(TintBitmap(*result.release(), TINT_BUTTONS)); | |
| 349 result.reset(tinted); | |
| 350 } | |
| 351 | |
| 352 // We loaded successfully. Cache the bitmap. | |
| 353 image_cache_[id] = result.get(); | |
| 354 return result.release(); | |
| 355 } else { | |
| 356 NOTREACHED() << "Failed to load a requested image"; | |
| 357 return NULL; | |
| 358 } | |
| 359 } | 192 } |
| 360 | 193 |
| 361 SkColor BrowserThemeProvider::GetColor(int id) const { | 194 SkColor BrowserThemeProvider::GetColor(int id) const { |
| 362 DCHECK(CalledOnValidThread()); | 195 DCHECK(CalledOnValidThread()); |
| 363 | 196 |
| 364 // Special-case NTP header - if the color isn't provided, we fall back to | 197 SkColor color; |
| 365 // the section color. | 198 if (theme_pack_.get() && theme_pack_->GetColor(id, &color)) |
| 366 if (id == COLOR_NTP_HEADER) { | 199 return color; |
| 367 ColorMap::const_iterator color_iter = colors_.find(kColorNTPHeader); | |
| 368 if (color_iter != colors_.end()) | |
| 369 return color_iter->second; | |
| 370 color_iter = colors_.find(kColorNTPSection); | |
| 371 return (color_iter == colors_.end()) ? | |
| 372 GetDefaultColor(id) : color_iter->second; | |
| 373 } | |
| 374 | 200 |
| 375 // Special case the underline colors to use semi transparent in case not | 201 return GetDefaultColor(id); |
| 376 // defined. | |
| 377 if (id == COLOR_NTP_SECTION_LINK_UNDERLINE) { | |
| 378 ColorMap::const_iterator color_iter = | |
| 379 colors_.find(kColorNTPSectionLinkUnderline); | |
| 380 if (color_iter != colors_.end()) | |
| 381 return color_iter->second; | |
| 382 SkColor color_section_link = GetColor(COLOR_NTP_SECTION_LINK); | |
| 383 return SkColorSetA(color_section_link, SkColorGetA(color_section_link) / 3); | |
| 384 } | |
| 385 | |
| 386 if (id == COLOR_NTP_LINK_UNDERLINE) { | |
| 387 ColorMap::const_iterator color_iter = colors_.find(kColorNTPLinkUnderline); | |
| 388 if (color_iter != colors_.end()) | |
| 389 return color_iter->second; | |
| 390 SkColor color_link = GetColor(COLOR_NTP_LINK); | |
| 391 return SkColorSetA(color_link, SkColorGetA(color_link) / 3); | |
| 392 } | |
| 393 | |
| 394 // TODO(glen): Figure out if we need to tint these. http://crbug.com/11578 | |
| 395 ColorMap::const_iterator color_iter = colors_.find(GetColorKey(id)); | |
| 396 return (color_iter == colors_.end()) ? | |
| 397 GetDefaultColor(id) : color_iter->second; | |
| 398 } | 202 } |
| 399 | 203 |
| 400 bool BrowserThemeProvider::GetDisplayProperty(int id, int* result) const { | 204 bool BrowserThemeProvider::GetDisplayProperty(int id, int* result) const { |
| 401 switch (id) { | 205 if (theme_pack_.get()) |
| 402 case NTP_BACKGROUND_ALIGNMENT: { | 206 return theme_pack_->GetDisplayProperty(id, result); |
| 403 DisplayPropertyMap::const_iterator display_iter = | 207 |
| 404 display_properties_.find(kDisplayPropertyNTPAlignment); | 208 return GetDefaultDisplayProperty(id, result); |
| 405 *result = (display_iter == display_properties_.end()) ? | |
| 406 kDefaultDisplayPropertyNTPAlignment : display_iter->second; | |
| 407 return true; | |
| 408 } | |
| 409 case NTP_BACKGROUND_TILING: { | |
| 410 DisplayPropertyMap::const_iterator display_iter = | |
| 411 display_properties_.find(kDisplayPropertyNTPTiling); | |
| 412 *result = (display_iter == display_properties_.end()) ? | |
| 413 kDefaultDisplayPropertyNTPTiling : display_iter->second; | |
| 414 return true; | |
| 415 } | |
| 416 case NTP_LOGO_ALTERNATE: { | |
| 417 DisplayPropertyMap::const_iterator display_iter = | |
| 418 display_properties_.find(kDisplayPropertyNTPInverseLogo); | |
| 419 *result = (display_iter == display_properties_.end()) ? | |
| 420 kDefaultDisplayPropertyNTPInverseLogo : display_iter->second; | |
| 421 return true; | |
| 422 } | |
| 423 default: | |
| 424 NOTREACHED() << "Unknown property requested"; | |
| 425 } | |
| 426 return false; | |
| 427 } | 209 } |
| 428 | 210 |
| 429 bool BrowserThemeProvider::ShouldUseNativeFrame() const { | 211 bool BrowserThemeProvider::ShouldUseNativeFrame() const { |
| 430 if (HasCustomImage(IDR_THEME_FRAME)) | 212 if (HasCustomImage(IDR_THEME_FRAME)) |
| 431 return false; | 213 return false; |
| 432 #if defined(OS_WIN) | 214 #if defined(OS_WIN) |
| 433 return win_util::ShouldUseVistaFrame(); | 215 return win_util::ShouldUseVistaFrame(); |
| 434 #else | 216 #else |
| 435 return false; | 217 return false; |
| 436 #endif | 218 #endif |
| 437 } | 219 } |
| 438 | 220 |
| 439 bool BrowserThemeProvider::HasCustomImage(int id) const { | 221 bool BrowserThemeProvider::HasCustomImage(int id) const { |
| 440 if (!HasThemeableImage(id)) | 222 if (!HasThemeableImage(id)) |
| 441 return false; | 223 return false; |
| 442 | 224 |
| 443 // A custom image = base name is NOT equal to resource name. See note in | 225 if (theme_pack_) |
| 444 // SaveThemeBitmap describing the process by which an original image is | 226 return theme_pack_->HasCustomImage(id); |
| 445 // tagged. | 227 |
| 446 ImageMap::const_iterator images_iter = images_.find(id); | 228 return false; |
| 447 ResourceNameMap::const_iterator names_iter = resource_names_.find(id); | |
| 448 if ((images_iter == images_.end()) || (names_iter == resource_names_.end())) | |
| 449 return false; | |
| 450 return !EndsWith(UTF8ToWide(images_iter->second), | |
| 451 UTF8ToWide(names_iter->second), false); | |
| 452 } | 229 } |
| 453 | 230 |
| 454 RefCountedMemory* BrowserThemeProvider::GetRawData(int id) const { | 231 RefCountedMemory* BrowserThemeProvider::GetRawData(int id) const { |
| 455 // Check to see whether we should substitute some images. | 232 // Check to see whether we should substitute some images. |
| 456 int ntp_alternate; | 233 int ntp_alternate; |
| 457 GetDisplayProperty(NTP_LOGO_ALTERNATE, &ntp_alternate); | 234 GetDisplayProperty(NTP_LOGO_ALTERNATE, &ntp_alternate); |
| 458 if (id == IDR_PRODUCT_LOGO && ntp_alternate != 0) | 235 if (id == IDR_PRODUCT_LOGO && ntp_alternate != 0) |
| 459 id = IDR_PRODUCT_LOGO_WHITE; | 236 id = IDR_PRODUCT_LOGO_WHITE; |
| 460 | 237 |
| 461 RawDataMap::const_iterator data_iter = raw_data_.find(id); | 238 RefCountedMemory* data = NULL; |
| 462 if (data_iter != raw_data_.end()) | 239 if (theme_pack_.get()) |
| 463 return data_iter->second; | 240 data = theme_pack_->GetRawData(id); |
| 464 | |
| 465 RefCountedMemory* data = ReadThemeFileData(id); | |
| 466 if (!data) | 241 if (!data) |
| 467 data = rb_.LoadDataResourceBytes(id); | 242 data = rb_.LoadDataResourceBytes(id); |
| 468 if (!data) | |
| 469 return NULL; | |
| 470 | 243 |
| 471 raw_data_[id] = data; | |
| 472 return data; | 244 return data; |
| 473 } | 245 } |
| 474 | 246 |
| 475 void BrowserThemeProvider::SetTheme(Extension* extension) { | 247 void BrowserThemeProvider::SetTheme(Extension* extension) { |
| 476 // Clear our image cache. | 248 // Clear our image cache. |
| 477 ClearCaches(); | 249 FreePlatformCaches(); |
| 478 | 250 |
| 479 DCHECK(extension); | 251 DCHECK(extension); |
| 480 DCHECK(extension->IsTheme()); | 252 DCHECK(extension->IsTheme()); |
| 481 SetImageData(extension->GetThemeImages(), | |
| 482 extension->path()); | |
| 483 SetColorData(extension->GetThemeColors()); | |
| 484 SetTintData(extension->GetThemeTints()); | |
| 485 | 253 |
| 486 // Drop out to default theme if the theme data is empty. | 254 BuildFromExtension(extension); |
| 487 if (images_.empty() && colors_.empty() && tints_.empty()) { | |
| 488 UseDefaultTheme(); | |
| 489 return; | |
| 490 } | |
| 491 | |
| 492 SetDisplayPropertyData(extension->GetThemeDisplayProperties()); | |
| 493 raw_data_.clear(); | |
| 494 | |
| 495 SaveImageData(extension->GetThemeImages()); | |
| 496 SaveColorData(); | |
| 497 SaveTintData(); | |
| 498 SaveDisplayPropertyData(); | |
| 499 SaveThemeID(extension->id()); | 255 SaveThemeID(extension->id()); |
| 500 | 256 |
| 501 // Process all images when we first set theme. | |
| 502 process_images_ = true; | |
| 503 | |
| 504 GenerateFrameColors(); | |
| 505 if (ShouldTintFrames()) { | |
| 506 AutoLock lock(themed_image_cache_lock_); | |
| 507 GenerateFrameImages(); | |
| 508 GenerateTabImages(); | |
| 509 } | |
| 510 | |
| 511 WriteImagesToDisk(); | |
| 512 NotifyThemeChanged(); | 257 NotifyThemeChanged(); |
| 513 UserMetrics::RecordAction("Themes_Installed", profile_); | 258 UserMetrics::RecordAction("Themes_Installed", profile_); |
| 514 } | 259 } |
| 515 | 260 |
| 516 void BrowserThemeProvider::RemoveUnusedThemes() { | 261 void BrowserThemeProvider::RemoveUnusedThemes() { |
| 517 if (!profile_) | 262 if (!profile_) |
| 518 return; | 263 return; |
| 519 ExtensionsService* service = profile_->GetExtensionsService(); | 264 ExtensionsService* service = profile_->GetExtensionsService(); |
| 520 if (!service) | 265 if (!service) |
| 521 return; | 266 return; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 536 ClearAllThemeData(); | 281 ClearAllThemeData(); |
| 537 NotifyThemeChanged(); | 282 NotifyThemeChanged(); |
| 538 UserMetrics::RecordAction("Themes_Reset", profile_); | 283 UserMetrics::RecordAction("Themes_Reset", profile_); |
| 539 } | 284 } |
| 540 | 285 |
| 541 std::string BrowserThemeProvider::GetThemeID() const { | 286 std::string BrowserThemeProvider::GetThemeID() const { |
| 542 std::wstring id = profile_->GetPrefs()->GetString(prefs::kCurrentThemeID); | 287 std::wstring id = profile_->GetPrefs()->GetString(prefs::kCurrentThemeID); |
| 543 return WideToUTF8(id); | 288 return WideToUTF8(id); |
| 544 } | 289 } |
| 545 | 290 |
| 546 RefCountedMemory* BrowserThemeProvider::ReadThemeFileData(int id) const { | |
| 547 ImageMap::const_iterator images_iter = images_.find(id); | |
| 548 if (images_iter != images_.end()) { | |
| 549 // First check to see if we have a registered theme extension and whether | |
| 550 // it can handle this resource. | |
| 551 #if defined(OS_WIN) | |
| 552 FilePath path = FilePath(UTF8ToWide(images_iter->second)); | |
| 553 #else | |
| 554 FilePath path = FilePath(images_iter->second); | |
| 555 #endif | |
| 556 if (!path.empty()) { | |
| 557 net::FileStream file; | |
| 558 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ; | |
| 559 if (file.Open(path, flags) == net::OK) { | |
| 560 int64 avail = file.Available(); | |
| 561 if (avail > 0 && avail < INT_MAX) { | |
| 562 size_t size = static_cast<size_t>(avail); | |
| 563 std::vector<unsigned char> raw_data; | |
| 564 raw_data.resize(size); | |
| 565 char* data = reinterpret_cast<char*>(&(raw_data.front())); | |
| 566 if (file.ReadUntilComplete(data, size) == avail) | |
| 567 return RefCountedBytes::TakeVector(&raw_data); | |
| 568 } | |
| 569 } | |
| 570 } | |
| 571 } | |
| 572 | |
| 573 return NULL; | |
| 574 } | |
| 575 | |
| 576 // static | 291 // static |
| 577 std::string BrowserThemeProvider::AlignmentToString(int alignment) { | 292 std::string BrowserThemeProvider::AlignmentToString(int alignment) { |
| 578 // Convert from an AlignmentProperty back into a string. | 293 // Convert from an AlignmentProperty back into a string. |
| 579 std::string vertical_string; | 294 std::string vertical_string; |
| 580 std::string horizontal_string; | 295 std::string horizontal_string; |
| 581 | 296 |
| 582 if (alignment & BrowserThemeProvider::ALIGN_TOP) | 297 if (alignment & BrowserThemeProvider::ALIGN_TOP) |
| 583 vertical_string = kAlignmentTop; | 298 vertical_string = kAlignmentTop; |
| 584 else if (alignment & BrowserThemeProvider::ALIGN_BOTTOM) | 299 else if (alignment & BrowserThemeProvider::ALIGN_BOTTOM) |
| 585 vertical_string = kAlignmentBottom; | 300 vertical_string = kAlignmentBottom; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 639 if (base::strcasecmp(component, kTilingRepeatX) == 0) | 354 if (base::strcasecmp(component, kTilingRepeatX) == 0) |
| 640 return BrowserThemeProvider::REPEAT_X; | 355 return BrowserThemeProvider::REPEAT_X; |
| 641 if (base::strcasecmp(component, kTilingRepeatY) == 0) | 356 if (base::strcasecmp(component, kTilingRepeatY) == 0) |
| 642 return BrowserThemeProvider::REPEAT_Y; | 357 return BrowserThemeProvider::REPEAT_Y; |
| 643 if (base::strcasecmp(component, kTilingRepeat) == 0) | 358 if (base::strcasecmp(component, kTilingRepeat) == 0) |
| 644 return BrowserThemeProvider::REPEAT; | 359 return BrowserThemeProvider::REPEAT; |
| 645 // NO_REPEAT is the default choice. | 360 // NO_REPEAT is the default choice. |
| 646 return BrowserThemeProvider::NO_REPEAT; | 361 return BrowserThemeProvider::NO_REPEAT; |
| 647 } | 362 } |
| 648 | 363 |
| 649 void BrowserThemeProvider::SetColor(const char* key, const SkColor& color) { | 364 // static |
| 650 colors_[key] = color; | 365 color_utils::HSL BrowserThemeProvider::GetDefaultTint(int id) { |
| 651 } | |
| 652 | |
| 653 void BrowserThemeProvider::SetTint(const char* key, | |
| 654 const color_utils::HSL& tint) { | |
| 655 tints_[key] = tint; | |
| 656 } | |
| 657 | |
| 658 color_utils::HSL BrowserThemeProvider::GetTint(int id) const { | |
| 659 DCHECK(CalledOnValidThread()); | |
| 660 | |
| 661 TintMap::const_iterator tint_iter = tints_.find(GetTintKey(id)); | |
| 662 return (tint_iter == tints_.end()) ? GetDefaultTint(id) : tint_iter->second; | |
| 663 } | |
| 664 | |
| 665 void BrowserThemeProvider::GenerateFrameColors() { | |
| 666 // Generate any secondary frame colors that weren't provided. | |
| 667 SkColor frame = GetColor(COLOR_FRAME); | |
| 668 | |
| 669 if (!colors_.count(kColorFrame)) | |
| 670 colors_[kColorFrame] = HSLShift(frame, GetTint(TINT_FRAME)); | |
| 671 if (!colors_.count(kColorFrameInactive)) { | |
| 672 colors_[kColorFrameInactive] = | |
| 673 HSLShift(frame, GetTint(TINT_FRAME_INACTIVE)); | |
| 674 } | |
| 675 if (!colors_.count(kColorFrameIncognito)) { | |
| 676 colors_[kColorFrameIncognito] = | |
| 677 HSLShift(frame, GetTint(TINT_FRAME_INCOGNITO)); | |
| 678 } | |
| 679 if (!colors_.count(kColorFrameIncognitoInactive)) { | |
| 680 colors_[kColorFrameIncognitoInactive] = | |
| 681 HSLShift(frame, GetTint(TINT_FRAME_INCOGNITO_INACTIVE)); | |
| 682 } | |
| 683 } | |
| 684 | |
| 685 void BrowserThemeProvider::GenerateFrameImages() const { | |
| 686 // A map of frame image IDs to the tints for those ids. | |
| 687 typedef std::map<int, int> FrameTintMap; | |
| 688 static FrameTintMap frame_tints; | |
| 689 if (frame_tints.empty()) { | |
| 690 frame_tints[IDR_THEME_FRAME] = TINT_FRAME; | |
| 691 frame_tints[IDR_THEME_FRAME_INACTIVE] = TINT_FRAME_INACTIVE; | |
| 692 frame_tints[IDR_THEME_FRAME_OVERLAY] = TINT_FRAME; | |
| 693 frame_tints[IDR_THEME_FRAME_OVERLAY_INACTIVE] = TINT_FRAME_INACTIVE; | |
| 694 frame_tints[IDR_THEME_FRAME_INCOGNITO] = TINT_FRAME_INCOGNITO; | |
| 695 frame_tints[IDR_THEME_FRAME_INCOGNITO_INACTIVE] = | |
| 696 TINT_FRAME_INCOGNITO_INACTIVE; | |
| 697 } | |
| 698 | |
| 699 for (FrameTintMap::const_iterator iter(frame_tints.begin()); | |
| 700 iter != frame_tints.end(); ++iter) { | |
| 701 int id = iter->first; | |
| 702 scoped_ptr<SkBitmap> frame; | |
| 703 // If there's no frame image provided for the specified id, then load | |
| 704 // the default provided frame. If that's not provided, skip this whole | |
| 705 // thing and just use the default images. | |
| 706 int base_id; | |
| 707 std::string resource_name; | |
| 708 | |
| 709 // If we've already processed the images for this theme, they're all | |
| 710 // waiting on disk -- just load them in. | |
| 711 if (!process_images_) { | |
| 712 frame.reset(LoadThemeBitmap(id)); | |
| 713 if (frame.get()) | |
| 714 themed_image_cache_[id] = new SkBitmap(*frame.get()); | |
| 715 } else { | |
| 716 resource_name = resource_names_.find(id)->second; | |
| 717 if (id == IDR_THEME_FRAME_INCOGNITO_INACTIVE) { | |
| 718 base_id = HasCustomImage(IDR_THEME_FRAME_INCOGNITO) ? | |
| 719 IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME; | |
| 720 } else if (id == IDR_THEME_FRAME_OVERLAY_INACTIVE) { | |
| 721 base_id = IDR_THEME_FRAME_OVERLAY; | |
| 722 } else if (id == IDR_THEME_FRAME_INACTIVE) { | |
| 723 base_id = IDR_THEME_FRAME; | |
| 724 } else if (id == IDR_THEME_FRAME_INCOGNITO && | |
| 725 !HasCustomImage(IDR_THEME_FRAME_INCOGNITO)) { | |
| 726 base_id = IDR_THEME_FRAME; | |
| 727 } else { | |
| 728 base_id = id; | |
| 729 } | |
| 730 | |
| 731 if (HasCustomImage(id)) { | |
| 732 frame.reset(LoadThemeBitmap(id)); | |
| 733 } else if (base_id != id && HasCustomImage(base_id)) { | |
| 734 frame.reset(LoadThemeBitmap(base_id)); | |
| 735 } else if (base_id == IDR_THEME_FRAME_OVERLAY && | |
| 736 HasCustomImage(IDR_THEME_FRAME)) { | |
| 737 // If there is no theme overlay, don't tint the default frame, | |
| 738 // because it will overwrite the custom frame image when we cache and | |
| 739 // reload from disk. | |
| 740 frame.reset(NULL); | |
| 741 } else { | |
| 742 // If the theme doesn't specify an image, then apply the tint to | |
| 743 // the default frame. | |
| 744 frame.reset(new SkBitmap(*rb_.GetBitmapNamed(IDR_THEME_FRAME))); | |
| 745 } | |
| 746 | |
| 747 if (frame.get()) { | |
| 748 SkBitmap* tinted = new SkBitmap(TintBitmap(*frame, iter->second)); | |
| 749 themed_image_cache_[id] = tinted; | |
| 750 SaveThemeBitmap(resource_name, id); | |
| 751 } | |
| 752 } | |
| 753 } | |
| 754 } | |
| 755 | |
| 756 void BrowserThemeProvider::GenerateTabImages() const { | |
| 757 GenerateTabBackgroundBitmap(IDR_THEME_TAB_BACKGROUND); | |
| 758 GenerateTabBackgroundBitmap(IDR_THEME_TAB_BACKGROUND_INCOGNITO); | |
| 759 } | |
| 760 | |
| 761 void BrowserThemeProvider::ClearAllThemeData() { | |
| 762 // Clear our image cache. | |
| 763 ClearCaches(); | |
| 764 | |
| 765 images_.clear(); | |
| 766 colors_.clear(); | |
| 767 tints_.clear(); | |
| 768 display_properties_.clear(); | |
| 769 raw_data_.clear(); | |
| 770 | |
| 771 SaveImageData(NULL); | |
| 772 SaveColorData(); | |
| 773 SaveTintData(); | |
| 774 SaveDisplayPropertyData(); | |
| 775 SaveThemeID(kDefaultThemeID); | |
| 776 } | |
| 777 | |
| 778 void BrowserThemeProvider::LoadThemePrefs() { | |
| 779 process_images_ = false; | |
| 780 PrefService* prefs = profile_->GetPrefs(); | |
| 781 | |
| 782 // TODO(glen): Figure out if any custom prefs were loaded, and if so UMA-log | |
| 783 // the fact that a theme was loaded. | |
| 784 if (!prefs->HasPrefPath(prefs::kCurrentThemeImages) && | |
| 785 !prefs->HasPrefPath(prefs::kCurrentThemeColors) && | |
| 786 !prefs->HasPrefPath(prefs::kCurrentThemeTints)) | |
| 787 return; | |
| 788 | |
| 789 // Our prefs already have the extension path baked in, so we don't need to | |
| 790 // provide it. | |
| 791 SetImageData(prefs->GetMutableDictionary(prefs::kCurrentThemeImages), | |
| 792 FilePath()); | |
| 793 SetColorData(prefs->GetMutableDictionary(prefs::kCurrentThemeColors)); | |
| 794 SetTintData(prefs->GetMutableDictionary(prefs::kCurrentThemeTints)); | |
| 795 SetDisplayPropertyData( | |
| 796 prefs->GetMutableDictionary(prefs::kCurrentThemeDisplayProperties)); | |
| 797 | |
| 798 // If we're not loading the frame from the cached image dir, we are using an | |
| 799 // old preferences file, or the processed images were not saved correctly. | |
| 800 // Force image reprocessing and caching. | |
| 801 ImageMap::const_iterator images_iter = images_.find(IDR_THEME_FRAME); | |
| 802 if (images_iter != images_.end()) { | |
| 803 #if defined(OS_WIN) | |
| 804 FilePath cache_path = FilePath(UTF8ToWide(images_iter->second)); | |
| 805 #else | |
| 806 FilePath cache_path = FilePath(images_iter->second); | |
| 807 #endif | |
| 808 process_images_ = !file_util::ContainsPath(image_dir_, cache_path); | |
| 809 } | |
| 810 | |
| 811 GenerateFrameColors(); | |
| 812 // Scope for AutoLock on themed_image_cache. | |
| 813 { | |
| 814 AutoLock lock(themed_image_cache_lock_); | |
| 815 GenerateFrameImages(); | |
| 816 GenerateTabImages(); | |
| 817 } | |
| 818 | |
| 819 if (process_images_) { | |
| 820 WriteImagesToDisk(); | |
| 821 UserMetrics::RecordAction("Migrated noncached to cached theme.", profile_); | |
| 822 } | |
| 823 UserMetrics::RecordAction("Themes_loaded", profile_); | |
| 824 } | |
| 825 | |
| 826 void BrowserThemeProvider::NotifyThemeChanged() { | |
| 827 // Redraw! | |
| 828 NotificationService* service = NotificationService::current(); | |
| 829 service->Notify(NotificationType::BROWSER_THEME_CHANGED, | |
| 830 Source<BrowserThemeProvider>(this), | |
| 831 NotificationService::NoDetails()); | |
| 832 } | |
| 833 | |
| 834 SkBitmap* BrowserThemeProvider::LoadThemeBitmap(int id) const { | |
| 835 DCHECK(CalledOnValidThread()); | |
| 836 | |
| 837 if (!HasThemeableImage(id)) | |
| 838 return NULL; | |
| 839 | |
| 840 scoped_refptr<RefCountedMemory> raw_data; | |
| 841 | |
| 842 // We special case images related to the NTP so we first try raw data. Why? | |
| 843 // Because the DOMUI stuff uses that interface to return raw PNG data instead | |
| 844 // of the normal theme interface which returns SkBitmaps. GetRawData() also | |
| 845 // caches the PNG data so it opens new tab pages faster. If we didn't try and | |
| 846 // otherwise we would be loading big images twice, once through GetRawData() | |
| 847 // and once here. Ouch. So either we prime the GetRawData() cache for when | |
| 848 // DOMUIThemeSource requests our image, or we take advantage of the already | |
| 849 // loaded data, saving a trip to disk. | |
| 850 if (id == IDR_THEME_NTP_BACKGROUND) | |
| 851 raw_data = GetRawData(id); | |
| 852 | |
| 853 if (!raw_data) | |
| 854 raw_data = ReadThemeFileData(id); | |
| 855 | |
| 856 if (raw_data) { | |
| 857 // Decode the PNG. | |
| 858 SkBitmap bitmap; | |
| 859 if (!gfx::PNGCodec::Decode(raw_data->front(), raw_data->size(), | |
| 860 &bitmap)) { | |
| 861 NOTREACHED() << "Unable to decode theme image resource " << id; | |
| 862 return NULL; | |
| 863 } | |
| 864 | |
| 865 return new SkBitmap(bitmap); | |
| 866 } else { | |
| 867 // TODO(glen): File no-longer exists, we're out of date. We should | |
| 868 // clear the theme (or maybe just the pref that points to this | |
| 869 // image). | |
| 870 return NULL; | |
| 871 } | |
| 872 } | |
| 873 | |
| 874 void BrowserThemeProvider::SaveThemeBitmap(std::string resource_name, | |
| 875 int id) const { | |
| 876 DCHECK(CalledOnValidThread()); | |
| 877 if (!themed_image_cache_.count(id)) { | |
| 878 NOTREACHED(); | |
| 879 return; | |
| 880 } | |
| 881 | |
| 882 // The images_ directory, at this point, contains only the custom images | |
| 883 // provided by the extension. We tag these images "_original" in the prefs | |
| 884 // file so we can distinguish them from images which have been generated and | |
| 885 // saved to disk by the theme caching process (WriteImagesToDisk). This way, | |
| 886 // when we call HasCustomImage, we can check for the "_original" tag to see | |
| 887 // whether an image was originally provided by the extension, or saved | |
| 888 // in the caching process. | |
| 889 if (images_.count(id)) | |
| 890 resource_name.append("_original"); | |
| 891 | |
| 892 #if defined(OS_WIN) | |
| 893 FilePath image_path = image_dir_.Append(UTF8ToWide(resource_name)); | |
| 894 #elif defined(OS_POSIX) | |
| 895 FilePath image_path = image_dir_.Append(resource_name); | |
| 896 #endif | |
| 897 | |
| 898 images_disk_cache_[image_path] = id; | |
| 899 } | |
| 900 | |
| 901 #if defined(OS_WIN) | |
| 902 void BrowserThemeProvider::FreePlatformCaches() { | |
| 903 // Views (Skia) has no platform image cache to clear. | |
| 904 } | |
| 905 #endif | |
| 906 | |
| 907 SkBitmap* BrowserThemeProvider::GenerateTabBackgroundBitmapImpl(int id) const { | |
| 908 int base_id = (id == IDR_THEME_TAB_BACKGROUND) ? | |
| 909 IDR_THEME_FRAME : IDR_THEME_FRAME_INCOGNITO; | |
| 910 // According to Miranda, it is safe to read from the themed_image_cache_ here | |
| 911 // because we only lock to write on the UI thread, and we only lock to read | |
| 912 // on the cache writing thread. | |
| 913 ImageCache::const_iterator themed_iter = themed_image_cache_.find(base_id); | |
| 914 if (themed_iter == themed_image_cache_.end()) | |
| 915 return NULL; | |
| 916 | |
| 917 SkBitmap bg_tint = TintBitmap(*(themed_iter->second), TINT_BACKGROUND_TAB); | |
| 918 int vertical_offset = HasCustomImage(id) ? kRestoredTabVerticalOffset : 0; | |
| 919 SkBitmap* bg_tab = new SkBitmap(SkBitmapOperations::CreateTiledBitmap( | |
| 920 bg_tint, 0, vertical_offset, bg_tint.width(), bg_tint.height())); | |
| 921 | |
| 922 // If they've provided a custom image, overlay it. | |
| 923 if (HasCustomImage(id)) { | |
| 924 SkBitmap* overlay = LoadThemeBitmap(id); | |
| 925 if (overlay) { | |
| 926 SkCanvas canvas(*bg_tab); | |
| 927 for (int x = 0; x < bg_tab->width(); x += overlay->width()) | |
| 928 canvas.drawBitmap(*overlay, static_cast<SkScalar>(x), 0, NULL); | |
| 929 } | |
| 930 } | |
| 931 | |
| 932 return bg_tab; | |
| 933 } | |
| 934 | |
| 935 const std::string BrowserThemeProvider::GetTintKey(int id) const { | |
| 936 switch (id) { | |
| 937 case TINT_FRAME: | |
| 938 return kTintFrame; | |
| 939 case TINT_FRAME_INACTIVE: | |
| 940 return kTintFrameInactive; | |
| 941 case TINT_FRAME_INCOGNITO: | |
| 942 return kTintFrameIncognito; | |
| 943 case TINT_FRAME_INCOGNITO_INACTIVE: | |
| 944 return kTintFrameIncognitoInactive; | |
| 945 case TINT_BUTTONS: | |
| 946 return kTintButtons; | |
| 947 case TINT_BACKGROUND_TAB: | |
| 948 return kTintBackgroundTab; | |
| 949 default: | |
| 950 NOTREACHED() << "Unknown tint requested"; | |
| 951 return ""; | |
| 952 } | |
| 953 } | |
| 954 | |
| 955 color_utils::HSL BrowserThemeProvider::GetDefaultTint(int id) const { | |
| 956 switch (id) { | 366 switch (id) { |
| 957 case TINT_FRAME: | 367 case TINT_FRAME: |
| 958 return kDefaultTintFrame; | 368 return kDefaultTintFrame; |
| 959 case TINT_FRAME_INACTIVE: | 369 case TINT_FRAME_INACTIVE: |
| 960 return kDefaultTintFrameInactive; | 370 return kDefaultTintFrameInactive; |
| 961 case TINT_FRAME_INCOGNITO: | 371 case TINT_FRAME_INCOGNITO: |
| 962 return kDefaultTintFrameIncognito; | 372 return kDefaultTintFrameIncognito; |
| 963 case TINT_FRAME_INCOGNITO_INACTIVE: | 373 case TINT_FRAME_INCOGNITO_INACTIVE: |
| 964 return kDefaultTintFrameIncognitoInactive; | 374 return kDefaultTintFrameIncognitoInactive; |
| 965 case TINT_BUTTONS: | 375 case TINT_BUTTONS: |
| 966 return kDefaultTintButtons; | 376 return kDefaultTintButtons; |
| 967 case TINT_BACKGROUND_TAB: | 377 case TINT_BACKGROUND_TAB: |
| 968 return kDefaultTintBackgroundTab; | 378 return kDefaultTintBackgroundTab; |
| 969 default: | 379 default: |
| 970 color_utils::HSL result = {-1, -1, -1}; | 380 color_utils::HSL result = {-1, -1, -1}; |
| 971 return result; | 381 return result; |
| 972 } | 382 } |
| 973 } | 383 } |
| 974 | 384 |
| 975 const std::string BrowserThemeProvider::GetColorKey(int id) const { | 385 // static |
| 976 switch (id) { | 386 SkColor BrowserThemeProvider::GetDefaultColor(int id) { |
| 977 case COLOR_FRAME: | |
| 978 return kColorFrame; | |
| 979 case COLOR_FRAME_INACTIVE: | |
| 980 return kColorFrameInactive; | |
| 981 case COLOR_FRAME_INCOGNITO: | |
| 982 return kColorFrameIncognito; | |
| 983 case COLOR_FRAME_INCOGNITO_INACTIVE: | |
| 984 return kColorFrameIncognitoInactive; | |
| 985 case COLOR_TOOLBAR: | |
| 986 return kColorToolbar; | |
| 987 case COLOR_TAB_TEXT: | |
| 988 return kColorTabText; | |
| 989 case COLOR_BACKGROUND_TAB_TEXT: | |
| 990 return kColorBackgroundTabText; | |
| 991 case COLOR_BOOKMARK_TEXT: | |
| 992 return kColorBookmarkText; | |
| 993 case COLOR_NTP_BACKGROUND: | |
| 994 return kColorNTPBackground; | |
| 995 case COLOR_NTP_TEXT: | |
| 996 return kColorNTPText; | |
| 997 case COLOR_NTP_LINK: | |
| 998 return kColorNTPLink; | |
| 999 case COLOR_NTP_LINK_UNDERLINE: | |
| 1000 return kColorNTPLinkUnderline; | |
| 1001 case COLOR_NTP_HEADER: | |
| 1002 return kColorNTPHeader; | |
| 1003 case COLOR_NTP_SECTION: | |
| 1004 return kColorNTPSection; | |
| 1005 case COLOR_NTP_SECTION_TEXT: | |
| 1006 return kColorNTPSectionText; | |
| 1007 case COLOR_NTP_SECTION_LINK: | |
| 1008 return kColorNTPSectionLink; | |
| 1009 case COLOR_NTP_SECTION_LINK_UNDERLINE: | |
| 1010 return kColorNTPSectionLinkUnderline; | |
| 1011 case COLOR_CONTROL_BACKGROUND: | |
| 1012 return kColorControlBackground; | |
| 1013 case COLOR_BUTTON_BACKGROUND: | |
| 1014 return kColorButtonBackground; | |
| 1015 default: | |
| 1016 NOTREACHED() << "Unknown color requested"; | |
| 1017 return ""; | |
| 1018 } | |
| 1019 } | |
| 1020 | |
| 1021 SkColor BrowserThemeProvider::GetDefaultColor(int id) const { | |
| 1022 switch (id) { | 387 switch (id) { |
| 1023 case COLOR_FRAME: | 388 case COLOR_FRAME: |
| 1024 return kDefaultColorFrame; | 389 return kDefaultColorFrame; |
| 1025 case COLOR_FRAME_INACTIVE: | 390 case COLOR_FRAME_INACTIVE: |
| 1026 return kDefaultColorFrameInactive; | 391 return kDefaultColorFrameInactive; |
| 1027 case COLOR_FRAME_INCOGNITO: | 392 case COLOR_FRAME_INCOGNITO: |
| 1028 return kDefaultColorFrameIncognito; | 393 return kDefaultColorFrameIncognito; |
| 1029 case COLOR_FRAME_INCOGNITO_INACTIVE: | 394 case COLOR_FRAME_INCOGNITO_INACTIVE: |
| 1030 return kDefaultColorFrameIncognitoInactive; | 395 return kDefaultColorFrameIncognitoInactive; |
| 1031 case COLOR_TOOLBAR: | 396 case COLOR_TOOLBAR: |
| 1032 return kDefaultColorToolbar; | 397 return kDefaultColorToolbar; |
| 1033 case COLOR_TAB_TEXT: | 398 case COLOR_TAB_TEXT: |
| 1034 return kDefaultColorTabText; | 399 return kDefaultColorTabText; |
| 1035 case COLOR_BACKGROUND_TAB_TEXT: | 400 case COLOR_BACKGROUND_TAB_TEXT: |
| 1036 return kDefaultColorBackgroundTabText; | 401 return kDefaultColorBackgroundTabText; |
| 1037 case COLOR_BOOKMARK_TEXT: | 402 case COLOR_BOOKMARK_TEXT: |
| 1038 return kDefaultColorBookmarkText; | 403 return kDefaultColorBookmarkText; |
| 1039 case COLOR_NTP_BACKGROUND: | 404 case COLOR_NTP_BACKGROUND: |
| 1040 return kDefaultColorNTPBackground; | 405 return kDefaultColorNTPBackground; |
| 1041 case COLOR_NTP_TEXT: | 406 case COLOR_NTP_TEXT: |
| 1042 return kDefaultColorNTPText; | 407 return kDefaultColorNTPText; |
| 1043 case COLOR_NTP_LINK: | 408 case COLOR_NTP_LINK: |
| 1044 return kDefaultColorNTPLink; | 409 return kDefaultColorNTPLink; |
| 410 case COLOR_NTP_LINK_UNDERLINE: |
| 411 return TintForUnderline(kDefaultColorNTPLink); |
| 1045 case COLOR_NTP_HEADER: | 412 case COLOR_NTP_HEADER: |
| 1046 return kDefaultColorNTPHeader; | 413 return kDefaultColorNTPHeader; |
| 1047 case COLOR_NTP_SECTION: | 414 case COLOR_NTP_SECTION: |
| 1048 return kDefaultColorNTPSection; | 415 return kDefaultColorNTPSection; |
| 1049 case COLOR_NTP_SECTION_TEXT: | 416 case COLOR_NTP_SECTION_TEXT: |
| 1050 return kDefaultColorNTPSectionText; | 417 return kDefaultColorNTPSectionText; |
| 1051 case COLOR_NTP_SECTION_LINK: | 418 case COLOR_NTP_SECTION_LINK: |
| 1052 return kDefaultColorNTPSectionLink; | 419 return kDefaultColorNTPSectionLink; |
| 420 case COLOR_NTP_SECTION_LINK_UNDERLINE: |
| 421 return TintForUnderline(kDefaultColorNTPSectionLink); |
| 1053 case COLOR_CONTROL_BACKGROUND: | 422 case COLOR_CONTROL_BACKGROUND: |
| 1054 return kDefaultColorControlBackground; | 423 return kDefaultColorControlBackground; |
| 1055 case COLOR_BUTTON_BACKGROUND: | 424 case COLOR_BUTTON_BACKGROUND: |
| 1056 return kDefaultColorButtonBackground; | 425 return kDefaultColorButtonBackground; |
| 1057 default: | 426 default: |
| 1058 // Return a debugging red color. | 427 // Return a debugging red color. |
| 1059 return 0xffff0000; | 428 return 0xffff0000; |
| 1060 } | 429 } |
| 1061 } | 430 } |
| 1062 | 431 |
| 1063 SkBitmap BrowserThemeProvider::TintBitmap(const SkBitmap& bitmap, | 432 // static |
| 1064 int hsl_id) const { | 433 bool BrowserThemeProvider::GetDefaultDisplayProperty(int id, int* result) { |
| 1065 return SkBitmapOperations::CreateHSLShiftedBitmap(bitmap, GetTint(hsl_id)); | 434 switch (id) { |
| 435 case NTP_BACKGROUND_ALIGNMENT: |
| 436 *result = kDefaultDisplayPropertyNTPAlignment; |
| 437 return true; |
| 438 case NTP_BACKGROUND_TILING: |
| 439 *result = kDefaultDisplayPropertyNTPTiling; |
| 440 return true; |
| 441 case NTP_LOGO_ALTERNATE: |
| 442 *result = kDefaultDisplayPropertyNTPInverseLogo; |
| 443 return true; |
| 444 } |
| 445 |
| 446 return false; |
| 1066 } | 447 } |
| 1067 | 448 |
| 1068 void BrowserThemeProvider::SetImageData(DictionaryValue* images_value, | 449 color_utils::HSL BrowserThemeProvider::GetTint(int id) const { |
| 1069 FilePath images_path) { | 450 DCHECK(CalledOnValidThread()); |
| 1070 images_.clear(); | |
| 1071 | 451 |
| 1072 if (!images_value) | 452 color_utils::HSL hsl; |
| 1073 return; | 453 if (theme_pack_.get() && theme_pack_->GetTint(id, &hsl)) |
| 454 return hsl; |
| 1074 | 455 |
| 1075 for (DictionaryValue::key_iterator iter(images_value->begin_keys()); | 456 return GetDefaultTint(id); |
| 1076 iter != images_value->end_keys(); ++iter) { | 457 } |
| 1077 std::string val; | 458 |
| 1078 if (images_value->GetStringWithoutPathExpansion(*iter, &val)) { | 459 void BrowserThemeProvider::ClearAllThemeData() { |
| 1079 int id = ThemeResourcesUtil::GetId(WideToUTF8(*iter)); | 460 // Clear our image cache. |
| 1080 if (id != -1) { | 461 FreePlatformCaches(); |
| 1081 if (!images_path.empty()) { | 462 theme_pack_ = NULL; |
| 1082 images_[id] = | 463 |
| 1083 WideToUTF8(images_path.AppendASCII(val).ToWStringHack()); | 464 profile_->GetPrefs()->ClearPref(prefs::kCurrentThemePackFilename); |
| 1084 resource_names_[id] = WideToASCII(*iter); | 465 SaveThemeID(kDefaultThemeID); |
| 466 } |
| 467 |
| 468 void BrowserThemeProvider::LoadThemePrefs() { |
| 469 PrefService* prefs = profile_->GetPrefs(); |
| 470 |
| 471 std::string current_id = GetThemeID(); |
| 472 if (current_id != kDefaultThemeID) { |
| 473 bool loaded_pack = false; |
| 474 |
| 475 // If we don't have a file pack, we're updating from an old version. |
| 476 FilePath path = prefs->GetFilePath(prefs::kCurrentThemePackFilename); |
| 477 if (path != FilePath()) { |
| 478 theme_pack_ = BrowserThemePack::BuildFromDataPack(path, current_id); |
| 479 loaded_pack = theme_pack_.get() != NULL; |
| 480 } |
| 481 |
| 482 if (loaded_pack) { |
| 483 UserMetrics::RecordAction("Themes.Loaded", profile_); |
| 484 } else { |
| 485 // TODO(erg): We need to pop up a dialog informing the user that their |
| 486 // theme is being migrated. |
| 487 ExtensionsService* service = profile_->GetExtensionsService(); |
| 488 if (service) { |
| 489 Extension* extension = service->GetExtensionById(current_id, false); |
| 490 if (extension) { |
| 491 DLOG(ERROR) << "Migrating theme"; |
| 492 BuildFromExtension(extension); |
| 493 UserMetrics::RecordAction("Themes.Migrated", profile_); |
| 1085 } else { | 494 } else { |
| 1086 images_[id] = val; | 495 DLOG(ERROR) << "Theme is mysteriously gone."; |
| 496 ClearAllThemeData(); |
| 497 UserMetrics::RecordAction("Themes.Gone", profile_); |
| 1087 } | 498 } |
| 1088 } | 499 } |
| 1089 } | 500 } |
| 1090 } | 501 } |
| 1091 } | 502 } |
| 1092 | 503 |
| 1093 void BrowserThemeProvider::SetColorData(DictionaryValue* colors_value) { | 504 void BrowserThemeProvider::NotifyThemeChanged() { |
| 1094 colors_.clear(); | 505 // Redraw! |
| 1095 | 506 NotificationService* service = NotificationService::current(); |
| 1096 if (!colors_value) | 507 service->Notify(NotificationType::BROWSER_THEME_CHANGED, |
| 1097 return; | 508 Source<BrowserThemeProvider>(this), |
| 1098 | 509 NotificationService::NoDetails()); |
| 1099 for (DictionaryValue::key_iterator iter(colors_value->begin_keys()); | |
| 1100 iter != colors_value->end_keys(); ++iter) { | |
| 1101 ListValue* color_list; | |
| 1102 if (colors_value->GetListWithoutPathExpansion(*iter, &color_list) && | |
| 1103 ((color_list->GetSize() == 3) || (color_list->GetSize() == 4))) { | |
| 1104 int r, g, b; | |
| 1105 color_list->GetInteger(0, &r); | |
| 1106 color_list->GetInteger(1, &g); | |
| 1107 color_list->GetInteger(2, &b); | |
| 1108 if (color_list->GetSize() == 4) { | |
| 1109 double alpha; | |
| 1110 int alpha_int; | |
| 1111 if (color_list->GetReal(3, &alpha)) { | |
| 1112 colors_[WideToUTF8(*iter)] = | |
| 1113 SkColorSetARGB(static_cast<int>(alpha * 255), r, g, b); | |
| 1114 } else if (color_list->GetInteger(3, &alpha_int) && | |
| 1115 (alpha_int == 0 || alpha_int == 1)) { | |
| 1116 colors_[WideToUTF8(*iter)] = | |
| 1117 SkColorSetARGB(alpha_int ? 255 : 0, r, g, b); | |
| 1118 } | |
| 1119 } else { | |
| 1120 colors_[WideToUTF8(*iter)] = SkColorSetRGB(r, g, b); | |
| 1121 } | |
| 1122 } | |
| 1123 } | |
| 1124 } | 510 } |
| 1125 | 511 |
| 1126 void BrowserThemeProvider::SetTintData(DictionaryValue* tints_value) { | 512 #if defined(OS_WIN) |
| 1127 tints_.clear(); | 513 void BrowserThemeProvider::FreePlatformCaches() { |
| 514 // Views (Skia) has no platform image cache to clear. |
| 515 } |
| 516 #endif |
| 1128 | 517 |
| 1129 if (!tints_value) | 518 void BrowserThemeProvider::SavePackName(const FilePath& pack_path) { |
| 1130 return; | 519 profile_->GetPrefs()->SetFilePath( |
| 1131 | 520 prefs::kCurrentThemePackFilename, pack_path); |
| 1132 for (DictionaryValue::key_iterator iter(tints_value->begin_keys()); | |
| 1133 iter != tints_value->end_keys(); ++iter) { | |
| 1134 ListValue* tint_list; | |
| 1135 if (tints_value->GetListWithoutPathExpansion(*iter, &tint_list) && | |
| 1136 (tint_list->GetSize() == 3)) { | |
| 1137 color_utils::HSL hsl = { -1, -1, -1 }; | |
| 1138 int value = 0; | |
| 1139 if (!tint_list->GetReal(0, &hsl.h) && tint_list->GetInteger(0, &value)) | |
| 1140 hsl.h = value; | |
| 1141 if (!tint_list->GetReal(1, &hsl.s) && tint_list->GetInteger(1, &value)) | |
| 1142 hsl.s = value; | |
| 1143 if (!tint_list->GetReal(2, &hsl.l) && tint_list->GetInteger(2, &value)) | |
| 1144 hsl.l = value; | |
| 1145 | |
| 1146 tints_[WideToUTF8(*iter)] = hsl; | |
| 1147 } | |
| 1148 } | |
| 1149 } | |
| 1150 | |
| 1151 void BrowserThemeProvider::SetDisplayPropertyData( | |
| 1152 DictionaryValue* display_properties_value) { | |
| 1153 display_properties_.clear(); | |
| 1154 | |
| 1155 if (!display_properties_value) | |
| 1156 return; | |
| 1157 | |
| 1158 for (DictionaryValue::key_iterator iter( | |
| 1159 display_properties_value->begin_keys()); | |
| 1160 iter != display_properties_value->end_keys(); ++iter) { | |
| 1161 // New tab page alignment and background tiling. | |
| 1162 if (base::strcasecmp(WideToUTF8(*iter).c_str(), | |
| 1163 kDisplayPropertyNTPAlignment) == 0) { | |
| 1164 std::string val; | |
| 1165 if (display_properties_value->GetStringWithoutPathExpansion(*iter, | |
| 1166 &val)) { | |
| 1167 display_properties_[kDisplayPropertyNTPAlignment] = | |
| 1168 StringToAlignment(val); | |
| 1169 } | |
| 1170 } else if (base::strcasecmp(WideToUTF8(*iter).c_str(), | |
| 1171 kDisplayPropertyNTPTiling) == 0) { | |
| 1172 std::string val; | |
| 1173 if (display_properties_value->GetStringWithoutPathExpansion(*iter, &val)) | |
| 1174 display_properties_[kDisplayPropertyNTPTiling] = StringToTiling(val); | |
| 1175 } | |
| 1176 if (base::strcasecmp(WideToUTF8(*iter).c_str(), | |
| 1177 kDisplayPropertyNTPInverseLogo) == 0) { | |
| 1178 int val = 0; | |
| 1179 if (display_properties_value->GetIntegerWithoutPathExpansion(*iter, &val)) | |
| 1180 display_properties_[kDisplayPropertyNTPInverseLogo] = val; | |
| 1181 } | |
| 1182 } | |
| 1183 } | |
| 1184 | |
| 1185 SkBitmap* BrowserThemeProvider::GenerateTabBackgroundBitmap(int id) const { | |
| 1186 if (id == IDR_THEME_TAB_BACKGROUND || | |
| 1187 id == IDR_THEME_TAB_BACKGROUND_INCOGNITO) { | |
| 1188 // The requested image is a background tab. Get a frame to create the | |
| 1189 // tab against. As themes don't use the glass frame, we don't have to | |
| 1190 // worry about compositing them together, as our default theme provides | |
| 1191 // the necessary bitmaps. | |
| 1192 if (!process_images_) { | |
| 1193 scoped_ptr<SkBitmap> frame; | |
| 1194 frame.reset(LoadThemeBitmap(id)); | |
| 1195 if (frame.get()) | |
| 1196 themed_image_cache_[id] = new SkBitmap(*frame.get()); | |
| 1197 } else { | |
| 1198 SkBitmap* bg_tab = GenerateTabBackgroundBitmapImpl(id); | |
| 1199 | |
| 1200 if (bg_tab) { | |
| 1201 std::string resource_name((id == IDR_THEME_TAB_BACKGROUND) ? | |
| 1202 "theme_tab_background" : "theme_tab_background_incognito"); | |
| 1203 themed_image_cache_[id] = bg_tab; | |
| 1204 SaveThemeBitmap(resource_name, id); | |
| 1205 return bg_tab; | |
| 1206 } | |
| 1207 } | |
| 1208 } | |
| 1209 return NULL; | |
| 1210 } | |
| 1211 | |
| 1212 void BrowserThemeProvider::SaveImageData(DictionaryValue* images_value) const { | |
| 1213 // Save our images data. | |
| 1214 DictionaryValue* pref_images = | |
| 1215 profile_->GetPrefs()->GetMutableDictionary(prefs::kCurrentThemeImages); | |
| 1216 pref_images->Clear(); | |
| 1217 | |
| 1218 if (!images_value) | |
| 1219 return; | |
| 1220 | |
| 1221 for (DictionaryValue::key_iterator iter(images_value->begin_keys()); | |
| 1222 iter != images_value->end_keys(); ++iter) { | |
| 1223 std::string val; | |
| 1224 if (images_value->GetStringWithoutPathExpansion(*iter, &val)) { | |
| 1225 int id = ThemeResourcesUtil::GetId(WideToUTF8(*iter)); | |
| 1226 if (id != -1) { | |
| 1227 pref_images->SetWithoutPathExpansion(*iter, | |
| 1228 Value::CreateStringValue(images_.find(id)->second)); | |
| 1229 } | |
| 1230 } | |
| 1231 } | |
| 1232 } | |
| 1233 | |
| 1234 void BrowserThemeProvider::SaveColorData() const { | |
| 1235 // Save our color data. | |
| 1236 DictionaryValue* pref_colors = | |
| 1237 profile_->GetPrefs()->GetMutableDictionary(prefs::kCurrentThemeColors); | |
| 1238 pref_colors->Clear(); | |
| 1239 | |
| 1240 if (colors_.empty()) | |
| 1241 return; | |
| 1242 | |
| 1243 for (ColorMap::const_iterator iter(colors_.begin()); iter != colors_.end(); | |
| 1244 ++iter) { | |
| 1245 SkColor rgba = iter->second; | |
| 1246 ListValue* rgb_list = new ListValue(); | |
| 1247 rgb_list->Set(0, Value::CreateIntegerValue(SkColorGetR(rgba))); | |
| 1248 rgb_list->Set(1, Value::CreateIntegerValue(SkColorGetG(rgba))); | |
| 1249 rgb_list->Set(2, Value::CreateIntegerValue(SkColorGetB(rgba))); | |
| 1250 if (SkColorGetA(rgba) != 255) | |
| 1251 rgb_list->Set(3, Value::CreateRealValue(SkColorGetA(rgba) / 255.0)); | |
| 1252 pref_colors->Set(UTF8ToWide(iter->first), rgb_list); | |
| 1253 } | |
| 1254 } | |
| 1255 | |
| 1256 void BrowserThemeProvider::SaveTintData() const { | |
| 1257 // Save our tint data. | |
| 1258 DictionaryValue* pref_tints = | |
| 1259 profile_->GetPrefs()->GetMutableDictionary(prefs::kCurrentThemeTints); | |
| 1260 pref_tints->Clear(); | |
| 1261 | |
| 1262 if (tints_.empty()) | |
| 1263 return; | |
| 1264 | |
| 1265 for (TintMap::const_iterator iter(tints_.begin()); iter != tints_.end(); | |
| 1266 ++iter) { | |
| 1267 color_utils::HSL hsl = iter->second; | |
| 1268 ListValue* hsl_list = new ListValue(); | |
| 1269 hsl_list->Set(0, Value::CreateRealValue(hsl.h)); | |
| 1270 hsl_list->Set(1, Value::CreateRealValue(hsl.s)); | |
| 1271 hsl_list->Set(2, Value::CreateRealValue(hsl.l)); | |
| 1272 pref_tints->Set(UTF8ToWide(iter->first), hsl_list); | |
| 1273 } | |
| 1274 } | |
| 1275 | |
| 1276 void BrowserThemeProvider::SaveDisplayPropertyData() const { | |
| 1277 // Save our display property data. | |
| 1278 DictionaryValue* pref_display_properties = | |
| 1279 profile_->GetPrefs()-> | |
| 1280 GetMutableDictionary(prefs::kCurrentThemeDisplayProperties); | |
| 1281 pref_display_properties->Clear(); | |
| 1282 | |
| 1283 if (display_properties_.empty()) | |
| 1284 return; | |
| 1285 | |
| 1286 for (DisplayPropertyMap::const_iterator iter(display_properties_.begin()); | |
| 1287 iter != display_properties_.end(); ++iter) { | |
| 1288 if (base::strcasecmp(iter->first.c_str(), | |
| 1289 kDisplayPropertyNTPAlignment) == 0) { | |
| 1290 pref_display_properties->SetString(UTF8ToWide(iter->first), | |
| 1291 AlignmentToString(iter->second)); | |
| 1292 } else if (base::strcasecmp(iter->first.c_str(), | |
| 1293 kDisplayPropertyNTPTiling) == 0) { | |
| 1294 pref_display_properties->SetString(UTF8ToWide(iter->first), | |
| 1295 TilingToString(iter->second)); | |
| 1296 } | |
| 1297 if (base::strcasecmp(iter->first.c_str(), | |
| 1298 kDisplayPropertyNTPInverseLogo) == 0) { | |
| 1299 pref_display_properties->SetInteger(UTF8ToWide(iter->first), | |
| 1300 iter->second); | |
| 1301 } | |
| 1302 } | |
| 1303 } | |
| 1304 | |
| 1305 void BrowserThemeProvider::SaveCachedImageData() const { | |
| 1306 DictionaryValue* pref_images = | |
| 1307 profile_->GetPrefs()->GetMutableDictionary(prefs::kCurrentThemeImages); | |
| 1308 | |
| 1309 for (ImagesDiskCache::const_iterator it(images_disk_cache_.begin()); | |
| 1310 it != images_disk_cache_.end(); ++it) { | |
| 1311 std::wstring disk_path = it->first.ToWStringHack(); | |
| 1312 std::string pref_name = resource_names_.find(it->second)->second; | |
| 1313 pref_images->SetString(UTF8ToWide(pref_name), WideToUTF8(disk_path)); | |
| 1314 } | |
| 1315 profile_->GetPrefs()->ScheduleSavePersistentPrefs(); | |
| 1316 } | 521 } |
| 1317 | 522 |
| 1318 void BrowserThemeProvider::SaveThemeID(const std::string& id) { | 523 void BrowserThemeProvider::SaveThemeID(const std::string& id) { |
| 1319 profile_->GetPrefs()->SetString(prefs::kCurrentThemeID, UTF8ToWide(id)); | 524 profile_->GetPrefs()->SetString(prefs::kCurrentThemeID, UTF8ToWide(id)); |
| 1320 } | 525 } |
| 1321 | 526 |
| 1322 void BrowserThemeProvider::ClearCaches() { | 527 void BrowserThemeProvider::BuildFromExtension(Extension* extension) { |
| 1323 FreePlatformCaches(); | 528 scoped_refptr<BrowserThemePack> pack = |
| 1324 STLDeleteValues(&image_cache_); | 529 BrowserThemePack::BuildFromExtension(extension); |
| 1325 | 530 if (!pack.get()) { |
| 1326 // Scope for AutoLock on themed_image_cache. | 531 NOTREACHED() << "Could not load theme."; |
| 1327 { | 532 return; |
| 1328 AutoLock lock(themed_image_cache_lock_); | |
| 1329 STLDeleteValues(&themed_image_cache_); | |
| 1330 } | 533 } |
| 1331 | 534 |
| 1332 images_disk_cache_.clear(); | 535 // Write the packed file to disk. |
| 536 FilePath pack_path = extension->path().Append(chrome::kThemePackFilename); |
| 537 ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, |
| 538 new WritePackToDiskTask(pack, pack_path)); |
| 539 |
| 540 SavePackName(pack_path); |
| 541 theme_pack_ = pack; |
| 1333 } | 542 } |
| 1334 | |
| 1335 void BrowserThemeProvider::WriteImagesToDisk() const { | |
| 1336 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, | |
| 1337 new WriteImagesToDiskTask(images_disk_cache_, themed_image_cache_)); | |
| 1338 SaveCachedImageData(); | |
| 1339 } | |
| 1340 | |
| 1341 bool BrowserThemeProvider::ShouldTintFrames() const { | |
| 1342 return (HasCustomImage(IDR_THEME_FRAME) || | |
| 1343 tints_.count(GetTintKey(TINT_BACKGROUND_TAB)) || | |
| 1344 tints_.count(GetTintKey(TINT_FRAME)) || | |
| 1345 tints_.count(GetTintKey(TINT_FRAME_INACTIVE)) || | |
| 1346 tints_.count(GetTintKey(TINT_FRAME_INCOGNITO)) || | |
| 1347 tints_.count(GetTintKey(TINT_FRAME_INCOGNITO_INACTIVE))); | |
| 1348 } | |
| OLD | NEW |