// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/browser_theme_provider.h" #include "base/gfx/png_decoder.h" #include "base/string_util.h" #include "base/values.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_window.h" #include "chrome/browser/metrics/user_metrics.h" #include "chrome/browser/profile.h" #include "chrome/browser/theme_resources_util.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" #include "grit/app_resources.h" #include "grit/theme_resources.h" #include "net/base/file_stream.h" #include "net/base/net_errors.h" #include "skia/ext/image_operations.h" #include "skia/ext/skia_utils.h" #include "third_party/skia/include/core/SkBitmap.h" #if defined(OS_WIN) #include "app/win_util.h" #endif // Strings used by themes to identify colors for different parts of our UI. static const char* kColorFrame = "frame"; static const char* kColorFrameInactive = "frame_inactive"; static const char* kColorFrameIncognito = "frame_incognito"; static const char* kColorFrameIncognitoInactive = "frame_incognito_inactive"; static const char* kColorToolbar = "toolbar"; static const char* kColorTabText = "tab_text"; static const char* kColorBackgroundTabText = "background_tab_text"; static const char* kColorBookmarkText = "bookmark_text"; static const char* kColorNTPBackground = "ntp_background"; static const char* kColorNTPText = "ntp_text"; static const char* kColorNTPLink = "ntp_link"; static const char* kColorNTPSection = "ntp_section"; static const char* kColorNTPSectionText = "ntp_section_text"; static const char* kColorNTPSectionLink = "ntp_section_link"; static const char* kColorControlBackground = "control_background"; static const char* kColorButtonBackground = "button_background"; // Strings used by themes to identify tints to apply to different parts of // our UI. The frame tints apply to the frame color and produce the // COLOR_FRAME* colors. static const char* kTintButtons = "buttons"; static const char* kTintFrame = "frame"; static const char* kTintFrameInactive = "frame_inactive"; static const char* kTintFrameIncognito = "frame_incognito"; static const char* kTintFrameIncognitoInactive = "frame_incognito_inactive"; static const char* kTintBackgroundTab = "background_tab"; // Strings used by themes to identify miscellaneous numerical properties. static const char* kDisplayPropertyNTPAlignment = "ntp_background_alignment"; // Strings used in alignment properties. static const char* kAlignmentTop = "top"; static const char* kAlignmentBottom = "bottom"; static const char* kAlignmentLeft = "left"; static const char* kAlignmentRight = "right"; // Default colors. static const SkColor kDefaultColorFrame = SkColorSetRGB(77, 139, 217); static const SkColor kDefaultColorFrameInactive = SkColorSetRGB(152, 188, 233); static const SkColor kDefaultColorFrameIncognito = SkColorSetRGB(83, 106, 139); static const SkColor kDefaultColorFrameIncognitoInactive = SkColorSetRGB(126, 139, 156); static const SkColor kDefaultColorToolbar = SkColorSetRGB(210, 225, 246); static const SkColor kDefaultColorTabText = SkColorSetRGB(0, 0, 0); static const SkColor kDefaultColorBackgroundTabText = SkColorSetRGB(64, 64, 64); static const SkColor kDefaultColorBookmarkText = SkColorSetRGB(64, 64, 64); static const SkColor kDefaultColorNTPBackground = SkColorSetRGB(255, 255, 255); static const SkColor kDefaultColorNTPText = SkColorSetRGB(0, 0, 0); static const SkColor kDefaultColorNTPLink = SkColorSetRGB(0, 0, 204); static const SkColor kDefaultColorNTPSection = SkColorSetRGB(225, 236, 254); static const SkColor kDefaultColorNTPSectionText = SkColorSetRGB(0, 0, 0); static const SkColor kDefaultColorNTPSectionLink = SkColorSetRGB(0, 0, 204); static const SkColor kDefaultColorControlBackground = NULL; static const SkColor kDefaultColorButtonBackground = NULL; // Default tints. static const skia::HSL kDefaultTintButtons = { -1, -1, -1 }; static const skia::HSL kDefaultTintFrame = { -1, -1, -1 }; static const skia::HSL kDefaultTintFrameInactive = { -1, 0.5f, 0.72f }; static const skia::HSL kDefaultTintFrameIncognito = { -1, 0.2f, 0.35f }; static const skia::HSL kDefaultTintFrameIncognitoInactive = { -1, 0.3f, 0.6f }; static const skia::HSL kDefaultTintBackgroundTab = { -1, 0.5, 0.75 }; // Default display properties. static const int kDefaultDisplayPropertyNTPAlignment = BrowserThemeProvider::ALIGN_BOTTOM; // The image resources that will be tinted by the 'button' tint value. static const int kToolbarButtonIDs[] = { IDR_BACK, IDR_BACK_D, IDR_BACK_H, IDR_BACK_P, IDR_FORWARD, IDR_FORWARD_D, IDR_FORWARD_H, IDR_FORWARD_P, IDR_RELOAD, IDR_RELOAD_H, IDR_RELOAD_P, IDR_HOME, IDR_HOME_H, IDR_HOME_P, IDR_STAR, IDR_STAR_D, IDR_STAR_H, IDR_STAR_P, IDR_STARRED, IDR_STARRED_H, IDR_STARRED_P, IDR_GO, IDR_GO_H, IDR_GO_P, IDR_STOP, IDR_STOP_H, IDR_STOP_P, IDR_MENU_PAGE, IDR_MENU_PAGE_RTL, IDR_MENU_CHROME, IDR_MENU_CHROME_RTL, IDR_MENU_DROPARROW, IDR_THROBBER, }; // A map for kToolbarButtonIDs. static std::map button_images_; // A map of frame image IDs to the tints for those ids. static std::map frame_tints_; BrowserThemeProvider::BrowserThemeProvider() : rb_(ResourceBundle::GetSharedInstance()) { static bool initialized = false; if (!initialized) { for (size_t i = 0; i < sizeof(kToolbarButtonIDs); ++i) { button_images_[kToolbarButtonIDs[i]] = true; } frame_tints_[IDR_THEME_FRAME] = TINT_FRAME; frame_tints_[IDR_THEME_FRAME_INACTIVE] = TINT_FRAME_INACTIVE; frame_tints_[IDR_THEME_FRAME_INCOGNITO] = TINT_FRAME_INCOGNITO; frame_tints_[IDR_THEME_FRAME_INCOGNITO_INACTIVE] = TINT_FRAME_INCOGNITO_INACTIVE; } } BrowserThemeProvider::~BrowserThemeProvider() { FreeImages(); } void BrowserThemeProvider::Init(Profile* profile) { DCHECK(CalledOnValidThread()); profile_ = profile; LoadThemePrefs(); } SkBitmap* BrowserThemeProvider::GetBitmapNamed(int id) { DCHECK(CalledOnValidThread()); // Check to see if we already have the Skia image in the cache. ImageCache::const_iterator found = image_cache_.find(id); if (found != image_cache_.end()) return found->second; scoped_ptr result; // Try to load the image from the extension. result.reset(LoadThemeBitmap(id)); // If the extension doesn't provide the requested image, but has provided // a custom frame, then we may be able to generate the image required. if (!result.get()) result.reset(GenerateBitmap(id)); // If we still don't have an image, load it from resourcebundle. if (!result.get()) result.reset(rb_.GetBitmapNamed(id)); if (result.get()) { // If the requested image is part of the toolbar button set, and we have // a provided tint for that set, tint it appropriately. if (button_images_.count(id) && tints_.count(kTintButtons)) { SkBitmap* tinted = new SkBitmap(TintBitmap(*result.release(), TINT_BUTTONS)); result.reset(tinted); } // We loaded successfully. Cache the bitmap. image_cache_[id] = result.get(); return result.release(); } else { NOTREACHED() << "Failed to load a requested image"; return NULL; } } SkColor BrowserThemeProvider::GetColor(int id) { DCHECK(CalledOnValidThread()); // TODO(glen): Figure out if we need to tint these. http://crbug.com/11578 switch (id) { case COLOR_FRAME: return FindColor(kColorFrame, kDefaultColorFrame); case COLOR_FRAME_INACTIVE: return FindColor(kColorFrameInactive, kDefaultColorFrameInactive); case COLOR_FRAME_INCOGNITO: return FindColor(kColorFrameIncognito, kDefaultColorFrameIncognito); case COLOR_FRAME_INCOGNITO_INACTIVE: return FindColor(kColorFrameIncognitoInactive, kDefaultColorFrameIncognitoInactive); case COLOR_TOOLBAR: return FindColor(kColorToolbar, kDefaultColorToolbar); case COLOR_TAB_TEXT: return FindColor(kColorTabText, kDefaultColorTabText); case COLOR_BACKGROUND_TAB_TEXT: return FindColor(kColorBackgroundTabText, kDefaultColorBackgroundTabText); case COLOR_BOOKMARK_TEXT: return FindColor(kColorBookmarkText, kDefaultColorBookmarkText); case COLOR_NTP_BACKGROUND: return (colors_.find(kColorNTPBackground) != colors_.end()) ? colors_[kColorNTPBackground] : kDefaultColorNTPBackground; case COLOR_NTP_TEXT: return FindColor(kColorNTPText, kDefaultColorNTPText); case COLOR_NTP_LINK: return FindColor(kColorNTPLink, kDefaultColorNTPLink); case COLOR_NTP_SECTION: return FindColor(kColorNTPSection, kDefaultColorNTPSection); case COLOR_NTP_SECTION_TEXT: return FindColor(kColorNTPSectionText, kDefaultColorNTPSectionText); case COLOR_NTP_SECTION_LINK: return FindColor(kColorNTPSectionLink, kDefaultColorNTPSectionLink); case COLOR_CONTROL_BACKGROUND: return FindColor(kColorControlBackground, kDefaultColorControlBackground); case COLOR_BUTTON_BACKGROUND: return FindColor(kColorButtonBackground, kDefaultColorButtonBackground); default: NOTREACHED() << "Unknown color requested"; } // Return a debugging red color. return 0xffff0000; } bool BrowserThemeProvider::GetDisplayProperty(int id, int* result) { switch (id) { case NTP_BACKGROUND_ALIGNMENT: if (display_properties_.find(kDisplayPropertyNTPAlignment) != display_properties_.end()) { *result = display_properties_[kDisplayPropertyNTPAlignment]; } else { *result = kDefaultDisplayPropertyNTPAlignment; } return true; default: NOTREACHED() << "Unknown property requested"; } return false; } bool BrowserThemeProvider::ShouldUseNativeFrame() { if (images_.find(IDR_THEME_FRAME) != images_.end()) return false; #if defined(OS_WIN) return win_util::ShouldUseVistaFrame(); #else return false; #endif } bool BrowserThemeProvider::HasCustomImage(int id) { return (images_.find(id) != images_.end()); } void BrowserThemeProvider::SetTheme(Extension* extension) { // Clear our image cache. FreeImages(); DCHECK(extension); DCHECK(extension->IsTheme()); SetImageData(extension->GetThemeImages(), extension->path()); SetColorData(extension->GetThemeColors()); SetTintData(extension->GetThemeTints()); SetDisplayPropertyData(extension->GetThemeDisplayProperties()); GenerateFrameColors(); GenerateFrameImages(); SaveImageData(extension->GetThemeImages()); SaveColorData(); SaveTintData(); SaveDisplayPropertyData(); NotifyThemeChanged(); UserMetrics::RecordAction(L"Themes_Installed", profile_); } void BrowserThemeProvider::UseDefaultTheme() { // Clear our image cache. FreeImages(); images_.clear(); colors_.clear(); tints_.clear(); display_properties_.clear(); SaveImageData(NULL); SaveColorData(); SaveTintData(); SaveDisplayPropertyData(); NotifyThemeChanged(); UserMetrics::RecordAction(L"Themes_Reset", profile_); } bool BrowserThemeProvider::ReadThemeFileData( int id, std::vector* raw_data) { if (images_.count(id)) { // First check to see if we have a registered theme extension and whether // it can handle this resource. #if defined(OS_WIN) FilePath path = FilePath(UTF8ToWide(images_[id])); #else FilePath path = FilePath(images_[id]); #endif if (!path.empty()) { net::FileStream file; int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ; if (file.Open(path, flags) == net::OK) { int64 avail = file.Available(); if (avail > 0 && avail < INT_MAX) { size_t size = static_cast(avail); raw_data->resize(size); char* data = reinterpret_cast(&(raw_data->front())); if (file.ReadUntilComplete(data, size) == avail) return true; } } } } return false; } SkBitmap* BrowserThemeProvider::LoadThemeBitmap(int id) { DCHECK(CalledOnValidThread()); // Attempt to find the image in our theme bundle. std::vector raw_data, png_data; if (ReadThemeFileData(id, &raw_data)) { // Decode the PNG. int image_width = 0; int image_height = 0; if (!PNGDecoder::Decode(&raw_data.front(), raw_data.size(), PNGDecoder::FORMAT_BGRA, &png_data, &image_width, &image_height)) { NOTREACHED() << "Unable to decode theme image resource " << id; return NULL; } return PNGDecoder::CreateSkBitmapFromBGRAFormat(png_data, image_width, image_height); } else { // TODO(glen): File no-longer exists, we're out of date. We should // clear the theme (or maybe just the pref that points to this // image). return NULL; } } skia::HSL BrowserThemeProvider::GetTint(int id) { DCHECK(CalledOnValidThread()); switch (id) { case TINT_FRAME: return (tints_.find(kTintFrame) != tints_.end()) ? tints_[kTintFrame] : kDefaultTintFrame; case TINT_FRAME_INACTIVE: return (tints_.find(kTintFrameInactive) != tints_.end()) ? tints_[kTintFrameInactive] : kDefaultTintFrameInactive; case TINT_FRAME_INCOGNITO: return (tints_.count(kTintFrameIncognito)) ? tints_[kTintFrameIncognito] : kDefaultTintFrameIncognito; case TINT_FRAME_INCOGNITO_INACTIVE: return (tints_.count(kTintFrameIncognitoInactive)) ? tints_[kTintFrameIncognitoInactive] : kDefaultTintFrameIncognitoInactive; case TINT_BUTTONS: return (tints_.find(kTintButtons) != tints_.end()) ? tints_[kTintButtons] : kDefaultTintButtons; case TINT_BACKGROUND_TAB: return (tints_.find(kTintBackgroundTab) != tints_.end()) ? tints_[kTintBackgroundTab] : kDefaultTintBackgroundTab; default: NOTREACHED() << "Unknown tint requested"; } skia::HSL result = {-1, -1, -1}; return result; } SkBitmap BrowserThemeProvider::TintBitmap(const SkBitmap& bitmap, int hsl_id) { return skia::ImageOperations::CreateHSLShiftedBitmap(bitmap, GetTint(hsl_id)); } void BrowserThemeProvider::SetImageData(DictionaryValue* images_value, FilePath images_path) { images_.clear(); if (!images_value) return; DictionaryValue::key_iterator iter = images_value->begin_keys(); while (iter != images_value->end_keys()) { std::string val; if (images_value->GetString(*iter, &val)) { int id = ThemeResourcesUtil::GetId(WideToUTF8(*iter)); if (id != -1) { if (!images_path.empty()) { images_[id] = WideToUTF8(images_path.AppendASCII(val) .ToWStringHack()); } else { images_[id] = val; } } } ++iter; } } void BrowserThemeProvider::SetColorData(DictionaryValue* colors_value) { colors_.clear(); if (!colors_value) return; DictionaryValue::key_iterator iter = colors_value->begin_keys(); while (iter != colors_value->end_keys()) { ListValue* color_list; if (colors_value->GetList(*iter, &color_list) && (color_list->GetSize() == 3 || color_list->GetSize() == 4)) { int r, g, b; color_list->GetInteger(0, &r); color_list->GetInteger(1, &g); color_list->GetInteger(2, &b); if (color_list->GetSize() == 4) { double alpha; color_list->GetReal(3, &alpha); colors_[WideToUTF8(*iter)] = SkColorSetARGB( static_cast(alpha * 255), r, g, b); } else { colors_[WideToUTF8(*iter)] = SkColorSetRGB(r, g, b); } } ++iter; } } void BrowserThemeProvider::SetTintData(DictionaryValue* tints_value) { tints_.clear(); if (!tints_value) return; DictionaryValue::key_iterator iter = tints_value->begin_keys(); while (iter != tints_value->end_keys()) { ListValue* tint_list; if (tints_value->GetList(*iter, &tint_list) && tint_list->GetSize() == 3) { skia::HSL hsl = { -1, -1, -1 }; // TODO(glen): Make this work with integer values. tint_list->GetReal(0, &hsl.h); tint_list->GetReal(1, &hsl.s); tint_list->GetReal(2, &hsl.l); tints_[WideToUTF8(*iter)] = hsl; } ++iter; } } void BrowserThemeProvider::SetDisplayPropertyData( DictionaryValue* display_properties_value) { display_properties_.clear(); if (!display_properties_value) return; DictionaryValue::key_iterator iter = display_properties_value->begin_keys(); while (iter != display_properties_value->end_keys()) { // New tab page alignment. if (base::strcasecmp(WideToUTF8(*iter).c_str(), kDisplayPropertyNTPAlignment) == 0) { std::string val; if (display_properties_value->GetString(*iter, &val)) display_properties_[kDisplayPropertyNTPAlignment] = StringToAlignment(val); } ++iter; } } // static int BrowserThemeProvider::StringToAlignment(const std::string& alignment) { std::vector split; SplitStringAlongWhitespace(UTF8ToWide(alignment), &split); std::vector::iterator alignments = split.begin(); int alignment_mask = 0; while (alignments != split.end()) { std::string comp = WideToUTF8(*alignments); const char* component = comp.c_str(); if (base::strcasecmp(component, kAlignmentTop) == 0) alignment_mask |= BrowserThemeProvider::ALIGN_TOP; else if (base::strcasecmp(component, kAlignmentBottom) == 0) alignment_mask |= BrowserThemeProvider::ALIGN_BOTTOM; if (base::strcasecmp(component, kAlignmentLeft) == 0) alignment_mask |= BrowserThemeProvider::ALIGN_LEFT; else if (base::strcasecmp(component, kAlignmentRight) == 0) alignment_mask |= BrowserThemeProvider::ALIGN_RIGHT; alignments++; } return alignment_mask; } // static std::string BrowserThemeProvider::AlignmentToString(int alignment) { // Convert from an AlignmentProperty back into a string. std::string vertical_string; std::string horizontal_string; if (alignment & BrowserThemeProvider::ALIGN_TOP) vertical_string = kAlignmentTop; else if (alignment & BrowserThemeProvider::ALIGN_BOTTOM) vertical_string = kAlignmentBottom; if (alignment & BrowserThemeProvider::ALIGN_LEFT) horizontal_string = kAlignmentLeft; else if (alignment & BrowserThemeProvider::ALIGN_RIGHT) horizontal_string = kAlignmentRight; if (!vertical_string.empty() && !horizontal_string.empty()) return vertical_string + " " + horizontal_string; else if (vertical_string.empty()) return horizontal_string; else return vertical_string; } void BrowserThemeProvider::GenerateFrameColors() { // Generate any secondary frame colors that weren't provided. skia::HSL frame_hsl = { 0, 0, 0 }; skia::SkColorToHSL(GetColor(COLOR_FRAME), frame_hsl); if (colors_.find(kColorFrame) == colors_.end()) colors_[kColorFrame] = HSLShift(frame_hsl, GetTint(TINT_FRAME)); if (colors_.find(kColorFrameInactive) == colors_.end()) { colors_[kColorFrameInactive] = HSLShift(frame_hsl, GetTint(TINT_FRAME_INACTIVE)); } if (colors_.find(kColorFrameIncognito) == colors_.end()) { colors_[kColorFrameIncognito] = HSLShift(frame_hsl, GetTint(TINT_FRAME_INCOGNITO)); } if (colors_.find(kColorFrameIncognitoInactive) == colors_.end()) { colors_[kColorFrameIncognitoInactive] = HSLShift(frame_hsl, GetTint(TINT_FRAME_INCOGNITO_INACTIVE)); } } void BrowserThemeProvider::GenerateFrameImages() { std::map::iterator iter = frame_tints_.begin(); while (iter != frame_tints_.end()) { int id = iter->first; SkBitmap* frame; // If there's no frame image provided for the specified id, then load // the default provided frame. If that's not provided, skip this whole // thing and just use the default images. int base_id = (id == IDR_THEME_FRAME_INCOGNITO || id == IDR_THEME_FRAME_INCOGNITO_INACTIVE) ? IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME; if (images_.find(id) != images_.end()) { frame = LoadThemeBitmap(id); } else if (base_id != id && images_.find(base_id) != images_.end()) { frame = LoadThemeBitmap(base_id); } else { // If the theme doesn't specify an image, then apply the tint to // the default frame. Note that the default theme provides default // bitmaps for all frame types, so this isn't strictly necessary // in the case where no tint is provided either. frame = rb_.GetBitmapNamed(IDR_THEME_FRAME); } if (frame) { SkBitmap* tinted = new SkBitmap(TintBitmap(*frame, iter->second)); image_cache_[id] = tinted; } ++iter; } } SkBitmap* BrowserThemeProvider::GenerateBitmap(int id) { if (id == IDR_THEME_TAB_BACKGROUND || id == IDR_THEME_TAB_BACKGROUND_INCOGNITO) { // The requested image is a background tab. Get a frame to create the // tab against. As themes don't use the glass frame, we don't have to // worry about compositing them together, as our default theme provides // the necessary bitmaps. int base_id = (id == IDR_THEME_TAB_BACKGROUND) ? IDR_THEME_FRAME : IDR_THEME_FRAME_INCOGNITO; std::map::iterator it = image_cache_.find(base_id); if (it != image_cache_.end()) { SkBitmap* frame = it->second; SkBitmap blurred = skia::ImageOperations::CreateBlurredBitmap(*frame, 5); SkBitmap* bg_tab = new SkBitmap(TintBitmap(blurred, TINT_BACKGROUND_TAB)); generated_images_.push_back(bg_tab); return bg_tab; } } return NULL; } void BrowserThemeProvider::SaveImageData(DictionaryValue* images_value) { // Save our images data. DictionaryValue* pref_images = profile_->GetPrefs()->GetMutableDictionary(prefs::kCurrentThemeImages); pref_images->Clear(); if (images_value) { DictionaryValue::key_iterator iter = images_value->begin_keys(); while (iter != images_value->end_keys()) { std::string val; if (images_value->GetString(*iter, &val)) { int id = ThemeResourcesUtil::GetId(WideToUTF8(*iter)); if (id != -1) pref_images->SetString(*iter, images_[id]); } ++iter; } } } void BrowserThemeProvider::SaveColorData() { // Save our color data. DictionaryValue* pref_colors = profile_->GetPrefs()->GetMutableDictionary(prefs::kCurrentThemeColors); pref_colors->Clear(); if (colors_.size()) { ColorMap::iterator iter = colors_.begin(); while (iter != colors_.end()) { SkColor rgb = (*iter).second; ListValue* rgb_list = new ListValue(); rgb_list->Set(0, Value::CreateIntegerValue(SkColorGetR(rgb))); rgb_list->Set(1, Value::CreateIntegerValue(SkColorGetG(rgb))); rgb_list->Set(2, Value::CreateIntegerValue(SkColorGetB(rgb))); pref_colors->Set(UTF8ToWide((*iter).first), rgb_list); ++iter; } } } void BrowserThemeProvider::SaveTintData() { // Save our tint data. DictionaryValue* pref_tints = profile_->GetPrefs()->GetMutableDictionary(prefs::kCurrentThemeTints); pref_tints->Clear(); if (tints_.size()) { TintMap::iterator iter = tints_.begin(); while (iter != tints_.end()) { skia::HSL hsl = (*iter).second; ListValue* hsl_list = new ListValue(); hsl_list->Set(0, Value::CreateRealValue(hsl.h)); hsl_list->Set(1, Value::CreateRealValue(hsl.s)); hsl_list->Set(2, Value::CreateRealValue(hsl.l)); pref_tints->Set(UTF8ToWide((*iter).first), hsl_list); ++iter; } } } void BrowserThemeProvider::SaveDisplayPropertyData() { // Save our display property data. DictionaryValue* pref_display_properties = profile_->GetPrefs()-> GetMutableDictionary(prefs::kCurrentThemeDisplayProperties); pref_display_properties->Clear(); if (display_properties_.size()) { DisplayPropertyMap::iterator iter = display_properties_.begin(); while (iter != display_properties_.end()) { if (base::strcasecmp((*iter).first.c_str(), kDisplayPropertyNTPAlignment) == 0) { pref_display_properties-> SetString(UTF8ToWide((*iter).first), AlignmentToString( (*iter).second)); } ++iter; } } } void BrowserThemeProvider::NotifyThemeChanged() { // Redraw! for (BrowserList::const_iterator browser = BrowserList::begin(); browser != BrowserList::end(); ++browser) { (*browser)->window()->UserChangedTheme(); } } void BrowserThemeProvider::LoadThemePrefs() { PrefService* prefs = profile_->GetPrefs(); // TODO(glen): Figure out if any custom prefs were loaded, and if so // UMA-log the fact that a theme was loaded. if (prefs->HasPrefPath(prefs::kCurrentThemeImages) || prefs->HasPrefPath(prefs::kCurrentThemeColors) || prefs->HasPrefPath(prefs::kCurrentThemeTints)) { // Our prefs already have the extension path baked in, so we don't need // to provide it. SetImageData(prefs->GetMutableDictionary(prefs::kCurrentThemeImages), FilePath()); SetColorData(prefs->GetMutableDictionary(prefs::kCurrentThemeColors)); SetTintData(prefs->GetMutableDictionary(prefs::kCurrentThemeTints)); GenerateFrameColors(); GenerateFrameImages(); UserMetrics::RecordAction(L"Themes_loaded", profile_); } } SkColor BrowserThemeProvider::FindColor(const char* id, SkColor default_color) { return (colors_.find(id) != colors_.end()) ? colors_[id] : default_color; } void BrowserThemeProvider::FreeImages() { FreePlatformImages(); for (std::vector::iterator i = generated_images_.begin(); i != generated_images_.end(); i++) { delete *i; } generated_images_.clear(); image_cache_.clear(); } #if defined(OS_WIN) void BrowserThemeProvider::FreePlatformImages() { // Windows has no platform image cache to clear. } #endif