diff options
-rw-r--r-- | app/l10n_util.cc | 24 | ||||
-rw-r--r-- | app/l10n_util.h | 10 | ||||
-rw-r--r-- | base/string_util.cc | 85 | ||||
-rw-r--r-- | base/string_util.h | 25 | ||||
-rw-r--r-- | base/string_util_unittest.cc | 43 | ||||
-rw-r--r-- | chrome/app/generated_resources.grd | 4 | ||||
-rw-r--r-- | chrome/app/theme/ntp_background.png | bin | 1885 -> 144 bytes | |||
-rw-r--r-- | chrome/app/theme/theme_resources.grd | 7 | ||||
-rw-r--r-- | chrome/browser/browser_resources.grd | 1 | ||||
-rw-r--r-- | chrome/browser/browser_theme_provider.cc | 81 | ||||
-rw-r--r-- | chrome/browser/browser_theme_provider.h | 4 | ||||
-rw-r--r-- | chrome/browser/dom_ui/dom_ui_theme_source.cc | 125 | ||||
-rw-r--r-- | chrome/browser/dom_ui/dom_ui_theme_source.h | 14 | ||||
-rw-r--r-- | chrome/browser/dom_ui/dom_ui_theme_source_unittest.cc | 84 | ||||
-rw-r--r-- | chrome/browser/dom_ui/new_tab_ui.cc | 16 | ||||
-rw-r--r-- | chrome/browser/dom_ui/new_tab_ui.h | 8 | ||||
-rw-r--r-- | chrome/browser/resources/new_tab.html | 29 | ||||
-rw-r--r-- | chrome/browser/resources/new_tab_theme.css | 11 | ||||
-rw-r--r-- | chrome/chrome.gyp | 1 | ||||
-rw-r--r-- | chrome/test/unit/unittests.vcproj | 4 |
20 files changed, 436 insertions, 140 deletions
diff --git a/app/l10n_util.cc b/app/l10n_util.cc index 285b8ab..15b4211 100644 --- a/app/l10n_util.cc +++ b/app/l10n_util.cc @@ -312,7 +312,12 @@ static string16 GetStringF(int message_id, std::vector<size_t>* offsets) { ResourceBundle& rb = ResourceBundle::GetSharedInstance(); const string16& format_string = rb.GetLocalizedString(message_id); - string16 formatted = ReplaceStringPlaceholders(format_string, a, b, c, d, + std::vector<const string16> subst; + subst.push_back(a); + subst.push_back(b); + subst.push_back(c); + subst.push_back(d); + string16 formatted = ReplaceStringPlaceholders(format_string, subst, offsets); return formatted; } @@ -337,6 +342,15 @@ std::wstring GetStringF(int message_id, WideToUTF16(c), string16(), NULL)); } +std::wstring GetStringF(int message_id, + const std::wstring& a, + const std::wstring& b, + const std::wstring& c, + const std::wstring& d) { + return UTF16ToWide(GetStringF(message_id, WideToUTF16(a), WideToUTF16(b), + WideToUTF16(c), WideToUTF16(d), NULL)); +} + std::string GetStringFUTF8(int message_id, const string16& a) { return UTF16ToUTF8(GetStringF(message_id, a, string16(), string16(), @@ -357,6 +371,14 @@ std::string GetStringFUTF8(int message_id, return UTF16ToUTF8(GetStringF(message_id, a, b, c, string16(), NULL)); } +std::string GetStringFUTF8(int message_id, + const string16& a, + const string16& b, + const string16& c, + const string16& d) { + return UTF16ToUTF8(GetStringF(message_id, a, b, c, d, NULL)); +} + std::wstring GetStringF(int message_id, const std::wstring& a, size_t* offset) { DCHECK(offset); std::vector<size_t> offsets; diff --git a/app/l10n_util.h b/app/l10n_util.h index aafd658..01575a5 100644 --- a/app/l10n_util.h +++ b/app/l10n_util.h @@ -79,6 +79,11 @@ std::wstring GetStringF(int message_id, const std::wstring& a, const std::wstring& b, const std::wstring& c); +std::wstring GetStringF(int message_id, + const std::wstring& a, + const std::wstring& b, + const std::wstring& c, + const std::wstring& d); std::string GetStringFUTF8(int message_id, const string16& a); std::string GetStringFUTF8(int message_id, @@ -88,6 +93,11 @@ std::string GetStringFUTF8(int message_id, const string16& a, const string16& b, const string16& c); +std::string GetStringFUTF8(int message_id, + const string16& a, + const string16& b, + const string16& c, + const string16& d); // Variants that return the offset(s) of the replaced parameters. The // vector based version returns offsets ordered by parameter. For example if diff --git a/base/string_util.cc b/base/string_util.cc index 2e6f7b3..790cc7b 100644 --- a/base/string_util.cc +++ b/base/string_util.cc @@ -1270,74 +1270,42 @@ void SplitStringAlongWhitespace(const std::wstring& str, } string16 ReplaceStringPlaceholders(const string16& format_string, - const string16& a, - size_t* offset) { - std::vector<size_t> offsets; - string16 result = ReplaceStringPlaceholders(format_string, a, - string16(), - string16(), - string16(), &offsets); - DCHECK(offsets.size() == 1); - if (offset) { - *offset = offsets[0]; - } - return result; -} - -string16 ReplaceStringPlaceholders(const string16& format_string, - const string16& a, - const string16& b, - std::vector<size_t>* offsets) { - return ReplaceStringPlaceholders(format_string, a, b, string16(), - string16(), offsets); -} - -string16 ReplaceStringPlaceholders(const string16& format_string, - const string16& a, - const string16& b, - const string16& c, + const std::vector<const string16>& subst, std::vector<size_t>* offsets) { - return ReplaceStringPlaceholders(format_string, a, b, c, string16(), - offsets); -} - -string16 ReplaceStringPlaceholders(const string16& format_string, - const string16& a, - const string16& b, - const string16& c, - const string16& d, - std::vector<size_t>* offsets) { - // We currently only support up to 4 place holders ($1 through $4), although - // it's easy enough to add more. - const string16* subst_texts[] = { &a, &b, &c, &d }; + int substitutions = subst.size(); + DCHECK(substitutions < 10); + + int sub_length = 0; + for (std::vector<const string16>::const_iterator iter = subst.begin(); + iter != subst.end(); + ++iter) { + sub_length += (*iter).length(); + } string16 formatted; - formatted.reserve(format_string.length() + a.length() + - b.length() + c.length() + d.length()); + formatted.reserve(format_string.length() + sub_length); std::vector<ReplacementOffset> r_offsets; - - // Replace $$ with $ and $1-$4 with placeholder text if it exists. for (string16::const_iterator i = format_string.begin(); i != format_string.end(); ++i) { if ('$' == *i) { if (i + 1 != format_string.end()) { ++i; - DCHECK('$' == *i || ('1' <= *i && *i <= '4')) << - "Invalid placeholder: " << *i; + DCHECK('$' == *i || '1' <= *i) << "Invalid placeholder: " << *i; if ('$' == *i) { formatted.push_back('$'); } else { int index = *i - '1'; if (offsets) { ReplacementOffset r_offset(index, - static_cast<int>(formatted.size())); + static_cast<int>(formatted.size())); r_offsets.insert(std::lower_bound(r_offsets.begin(), - r_offsets.end(), r_offset, - &CompareParameter), - r_offset); + r_offsets.end(), r_offset, + &CompareParameter), + r_offset); } - formatted.append(*subst_texts[index]); + if (index < substitutions) + formatted.append(subst.at(index)); } } } else { @@ -1346,13 +1314,28 @@ string16 ReplaceStringPlaceholders(const string16& format_string, } if (offsets) { for (std::vector<ReplacementOffset>::const_iterator i = r_offsets.begin(); - i != r_offsets.end(); ++i) { + i != r_offsets.end(); ++i) { offsets->push_back(i->offset); } } return formatted; } +string16 ReplaceStringPlaceholders(const string16& format_string, + const string16& a, + size_t* offset) { + std::vector<size_t> offsets; + std::vector<const string16> subst; + subst.push_back(a); + string16 result = ReplaceStringPlaceholders(format_string, subst, &offsets); + + DCHECK(offsets.size() == 1); + if (offset) { + *offset = offsets[0]; + } + return result; +} + template <class CHAR> static bool IsWildcard(CHAR character) { return character == '*' || character == '?'; diff --git a/base/string_util.h b/base/string_util.h index c32bef3..5a51b2d 100644 --- a/base/string_util.h +++ b/base/string_util.h @@ -553,30 +553,17 @@ std::string JoinString(const std::vector<std::string>& parts, char s); void SplitStringAlongWhitespace(const std::wstring& str, std::vector<std::wstring>* result); -// Replace $1-$2-$3 in the format string with |a| and |b| respectively. -// Additionally, $$ is replaced by $. The offset/offsets parameter here can be -// NULL. +// Replace $1-$2-$3..$9 in the format string with |a|-|b|-|c|..|i| respectively. +// Additionally, $$ is replaced by $. The offsets parameter here can +// be NULL. This only allows you to use up to nine replacements. string16 ReplaceStringPlaceholders(const string16& format_string, - const string16& a, - size_t* offset); - -string16 ReplaceStringPlaceholders(const string16& format_string, - const string16& a, - const string16& b, + const std::vector<const string16>& subst, std::vector<size_t>* offsets); +// Single-string shortcut for ReplaceStringHolders. string16 ReplaceStringPlaceholders(const string16& format_string, const string16& a, - const string16& b, - const string16& c, - std::vector<size_t>* offsets); - -string16 ReplaceStringPlaceholders(const string16& format_string, - const string16& a, - const string16& b, - const string16& c, - const string16& d, - std::vector<size_t>* offsets); + size_t* offset); // If the size of |input| is more than |max_len|, this function returns true and // |input| is shortened into |output| by removing chars in the middle (they are diff --git a/base/string_util_unittest.cc b/base/string_util_unittest.cc index ed6b68f..581cb1f 100644 --- a/base/string_util_unittest.cc +++ b/base/string_util_unittest.cc @@ -1423,11 +1423,13 @@ TEST(StringUtilTest, StartsWith) { } TEST(StringUtilTest, GetStringFWithOffsets) { + std::vector<const string16> subst; + subst.push_back(ASCIIToUTF16("1")); + subst.push_back(ASCIIToUTF16("2")); std::vector<size_t> offsets; ReplaceStringPlaceholders(ASCIIToUTF16("Hello, $1. Your number is $2."), - ASCIIToUTF16("1"), - ASCIIToUTF16("2"), + subst, &offsets); EXPECT_EQ(2U, offsets.size()); EXPECT_EQ(7U, offsets[0]); @@ -1435,8 +1437,7 @@ TEST(StringUtilTest, GetStringFWithOffsets) { offsets.clear(); ReplaceStringPlaceholders(ASCIIToUTF16("Hello, $2. Your number is $1."), - ASCIIToUTF16("1"), - ASCIIToUTF16("2"), + subst, &offsets); EXPECT_EQ(2U, offsets.size()); EXPECT_EQ(25U, offsets[0]); @@ -1444,6 +1445,40 @@ TEST(StringUtilTest, GetStringFWithOffsets) { offsets.clear(); } +TEST(StringUtilTest, ReplaceStringPlaceholders) { + std::vector<const string16> subst; + subst.push_back(ASCIIToUTF16("9a")); + subst.push_back(ASCIIToUTF16("8b")); + subst.push_back(ASCIIToUTF16("7c")); + subst.push_back(ASCIIToUTF16("6d")); + subst.push_back(ASCIIToUTF16("5e")); + subst.push_back(ASCIIToUTF16("4f")); + subst.push_back(ASCIIToUTF16("3g")); + subst.push_back(ASCIIToUTF16("2h")); + subst.push_back(ASCIIToUTF16("1i")); + + string16 formatted = + ReplaceStringPlaceholders( + ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i"), subst, NULL); + + EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii")); +} + +TEST(StringUtilTest, ReplaceStringPlaceholdersTooFew) { + // Test whether replacestringplaceholders works as expected when there + // are fewer inputs than outputs. + std::vector<const string16> subst; + subst.push_back(ASCIIToUTF16("9a")); + subst.push_back(ASCIIToUTF16("8b")); + subst.push_back(ASCIIToUTF16("7c")); + + string16 formatted = + ReplaceStringPlaceholders( + ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$1g,$2h,$3i"), subst, NULL); + + EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,d,e,f,9ag,8bh,7ci")); +} + TEST(StringUtilTest, SplitStringAlongWhitespace) { struct TestData { const std::wstring input; diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 33bbbf3..ffc5ab6 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -3814,6 +3814,10 @@ each locale. --> Don't ask again </message> + <message name="IDS_RGBA_CSS_FORMAT_STRING" translateable="false" desc="The format string to use when converting colors to CSS rgba()."> + rgba($1, $2, $3, $4) + </message> + </messages> </release> </grit> diff --git a/chrome/app/theme/ntp_background.png b/chrome/app/theme/ntp_background.png Binary files differindex fb75b9f..490e723 100644 --- a/chrome/app/theme/ntp_background.png +++ b/chrome/app/theme/ntp_background.png diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index c89f5db..b0080d5 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd @@ -175,6 +175,11 @@ <include name="IDR_NEWTAB_BUTTON" file="newtab.png" type="BINDATA" /> <include name="IDR_NEWTAB_BUTTON_H" file="newtab_h.png" type="BINDATA" /> <include name="IDR_NEWTAB_BUTTON_P" file="newtab_p.png" type="BINDATA" /> + <include name="IDR_NEWTAB_REMOVE_ICON" file="ntp_x_icon_small.png" type="BINDATA" /> + <include name="IDR_NEWTAB_REMOVE_THUMBNAIL" file="ntp_x_icon.png" type="BINDATA" /> + <include name="IDR_NEWTAB_REMOVE_THUMBNAIL_HOVER" file="ntp_x_icon_hover.png" type="BINDATA" /> + <include name="IDR_NEWTAB_REMOVE_THUMBNAIL_ACTIVE" file="ntp_x_icon_active.png" type="BINDATA" /> + <include name="IDR_NEWTAB_CLOSED_WINDOW" file="closed_window.png" type="BINDATA" /> <include name="IDR_ARROW_RIGHT" file="arrow_right.png" type="BINDATA" /> <include name="IDR_TEXTBUTTON_TOP_LEFT_H" file="textbutton_tl_h.png" type="BINDATA" /> <include name="IDR_TEXTBUTTON_TOP_H" file="textbutton_t_h.png" type="BINDATA" /> @@ -304,7 +309,7 @@ <include name="IDR_THEME_TAB_BACKGROUND" file="theme_tab_background.png" type="BINDATA" /> <include name="IDR_THEME_TAB_BACKGROUND_INCOGNITO" file="theme_tab_background_incognito.png" type="BINDATA" /> <include name="IDR_THEME_TAB_BACKGROUND_V" file="theme_tab_background_glass.png" type="BINDATA" /> - <include name="IDR_THEME_NEWTAB_BACKGROUND" file="ntp_background.png" type="BINDATA" /> + <include name="IDR_THEME_NTP_BACKGROUND" file="ntp_background.png" type="BINDATA" /> <if expr="pp_ifdef('_google_chrome')"> <include name="IDR_ABOUT_BACKGROUND" file="google_chrome/about_background.png" type="BINDATA" /> diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index f0f36df6..b4eff3d 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd @@ -18,6 +18,7 @@ without changes to the corresponding grd file. --> <include name="IDR_SSL_ROAD_BLOCK_HTML" file="security\resources\ssl_roadblock.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_SSL_ERROR_HTML" file="security\resources\ssl_error.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_NEW_TAB_HTML" file="resources\new_tab.html" flattenhtml="true" type="BINDATA" /> + <include name="IDR_NEW_TAB_THEME_CSS" file="resources\new_tab_theme.css" flattenhtml="true" type="BINDATA" /> <include name="IDR_SAFE_BROWSING_MALWARE_BLOCK" file="resources\safe_browsing_malware_block.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_SAFE_BROWSING_PHISHING_BLOCK" file="resources\safe_browsing_phishing_block.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_SAFE_BROWSING_MULTIPLE_THREAT_BLOCK" file="resources\safe_browsing_multiple_threat_block.html" flattenhtml="true" type="BINDATA" /> diff --git a/chrome/browser/browser_theme_provider.cc b/chrome/browser/browser_theme_provider.cc index 5774f36..64124bc 100644 --- a/chrome/browser/browser_theme_provider.cc +++ b/chrome/browser/browser_theme_provider.cc @@ -22,29 +22,29 @@ #include "SkBitmap.h" // Strings used by themes to identify colors for different parts of our UI. -static const std::string kColorFrame = "frame"; -static const std::string kColorFrameInactive = "frame_inactive"; -static const std::string kColorFrameIncognito = "frame_incognito"; -static const std::string kColorFrameIncognitoInactive = +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 std::string kColorToolbar = "toolbar"; -static const std::string kColorTabText = "tab_text"; -static const std::string kColorBackgroundTabText = "background_tab_text"; -static const std::string kColorBookmarkText = "bookmark_text"; -static const std::string kColorNTPText = "ntp_text"; -static const std::string kColorNTPLink = "ntp_link"; -static const std::string kColorNTPSection = "ntp_section"; +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* kColorNTPText = "ntp_text"; +static const char* kColorNTPLink = "ntp_link"; +static const char* kColorNTPSection = "ntp_section"; // 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 std::string kTintButtons = "buttons"; -static const std::string kTintFrame = "frame"; -static const std::string kTintFrameInactive = "frame_inactive"; -static const std::string kTintFrameIncognito = "frame_incognito"; -static const std::string kTintFrameIncognitoInactive = +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 std::string kTintBackgroundTab = "background_tab"; +static const char* kTintBackgroundTab = "background_tab"; // Default colors. static const SkColor kDefaultColorFrame = SkColorSetRGB(77, 139, 217); @@ -55,6 +55,10 @@ static const SkColor kDefaultColorFrameIncognitoInactive = 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 kDefaultColorNTPText = SkColorSetRGB(0, 0, 0); +static const SkColor kDefaultColorNTPLink = SkColorSetRGB(0, 0, 204); +static const SkColor kDefaultColorNTPSection = SkColorSetRGB(225, 236, 254); // Default tints. static const skia::HSL kDefaultTintButtons = { -1, -1, -1 }; @@ -104,11 +108,14 @@ BrowserThemeProvider::BrowserThemeProvider() BrowserThemeProvider::~BrowserThemeProvider() { } 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()) @@ -128,15 +135,15 @@ SkBitmap* BrowserThemeProvider::GetBitmapNamed(int id) { if (!result.get()) result.reset(rb_.GetBitmapNamed(id)); - // 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); - } - 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(); @@ -147,6 +154,8 @@ SkBitmap* BrowserThemeProvider::GetBitmapNamed(int id) { } 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: @@ -172,6 +181,22 @@ SkColor BrowserThemeProvider::GetColor(int id) { return (colors_.find(kColorBackgroundTabText) != colors_.end()) ? colors_[kColorBackgroundTabText] : kDefaultColorBackgroundTabText; + case COLOR_BOOKMARK_TEXT: + return (colors_.find(kColorBookmarkText) != colors_.end()) ? + colors_[kColorBookmarkText] : + kDefaultColorBookmarkText; + case COLOR_NTP_TEXT: + return (colors_.find(kColorNTPText) != colors_.end()) ? + colors_[kColorNTPText] : + kDefaultColorNTPText; + case COLOR_NTP_LINK: + return (colors_.find(kColorNTPLink) != colors_.end()) ? + colors_[kColorNTPLink] : + kDefaultColorNTPLink; + case COLOR_NTP_SECTION: + return (colors_.find(kColorNTPSection) != colors_.end()) ? + colors_[kColorNTPSection] : + kDefaultColorNTPSection; default: NOTREACHED() << "Unknown color requested"; } @@ -217,6 +242,7 @@ void BrowserThemeProvider::UseDefaultTheme() { } SkBitmap* BrowserThemeProvider::LoadThemeBitmap(int id) { + DCHECK(CalledOnValidThread()); // Attempt to find the image in our theme bundle. std::vector<unsigned char> raw_data, png_data; if (images_.count(id)) { @@ -266,6 +292,7 @@ SkBitmap* BrowserThemeProvider::LoadThemeBitmap(int id) { } skia::HSL BrowserThemeProvider::GetTint(int id) { + DCHECK(CalledOnValidThread()); switch (id) { case TINT_FRAME: return (tints_.find(kTintFrame) != tints_.end()) ? @@ -447,8 +474,8 @@ void BrowserThemeProvider::NotifyThemeChanged() { // Redraw! for (BrowserList::const_iterator browser = BrowserList::begin(); - browser != BrowserList::end(); ++browser) { - (*browser)->window()->UserChangedTheme(); + browser != BrowserList::end(); ++browser) { + (*browser)->window()->UserChangedTheme(); } } diff --git a/chrome/browser/browser_theme_provider.h b/chrome/browser/browser_theme_provider.h index bf16a0d..d9996f0c 100644 --- a/chrome/browser/browser_theme_provider.h +++ b/chrome/browser/browser_theme_provider.h @@ -7,6 +7,7 @@ #include "app/resource_bundle.h" #include "app/theme_provider.h" +#include "base/non_thread_safe.h" #include "base/ref_counted.h" #include "skia/ext/skia_utils.h" @@ -15,7 +16,8 @@ class Profile; class DictionaryValue; class BrowserThemeProvider : - public base::RefCountedThreadSafe<BrowserThemeProvider>, + public base::RefCounted<BrowserThemeProvider>, + public NonThreadSafe, public ThemeProvider { public: BrowserThemeProvider(); diff --git a/chrome/browser/dom_ui/dom_ui_theme_source.cc b/chrome/browser/dom_ui/dom_ui_theme_source.cc index 31ff1f8..1ff0492 100644 --- a/chrome/browser/dom_ui/dom_ui_theme_source.cc +++ b/chrome/browser/dom_ui/dom_ui_theme_source.cc @@ -4,34 +4,129 @@ #include "chrome/browser/dom_ui/dom_ui_theme_source.h" +#include "app/l10n_util.h" #include "app/resource_bundle.h" #include "app/theme_provider.h" #include "base/gfx/png_encoder.h" #include "base/message_loop.h" +#include "base/string_util.h" +#include "base/time.h" +#include "chrome/browser/browser_theme_provider.h" #include "chrome/browser/profile.h" #include "chrome/browser/theme_resources_util.h" #include "chrome/common/url_constants.h" +#include "googleurl/src/gurl.h" +#include "grit/browser_resources.h" +#include "grit/generated_resources.h" #include "grit/theme_resources.h" +// Path for the New Tab CSS. When we get more than a few of these, we should +// use a resource map rather than hard-coded strings. +static const char* kNewTabCSSPath = "css/newtab.css"; + +static string16 SkColorToRGBAString(SkColor color) { + return WideToUTF16(l10n_util::GetStringF(IDS_RGBA_CSS_FORMAT_STRING, + IntToWString(SkColorGetR(color)), + IntToWString(SkColorGetG(color)), + IntToWString(SkColorGetB(color)), + DoubleToWString(SkColorGetA(color) / 255.0))); +} + +static std::string StripQueryParams(const std::string& path) { + GURL path_url = GURL(std::string(chrome::kChromeUIScheme) + "://" + + std::string(chrome::kChromeUIThemePath) + "/" + path); + return path_url.path().substr(1); // path() always includes a leading '/'. +} + +//////////////////////////////////////////////////////////////////////////////// +// DOMUIThemeSource, public: + DOMUIThemeSource::DOMUIThemeSource(Profile* profile) - : DataSource(chrome::kChromeUIThemePath, MessageLoop::current()), - profile_(profile) { + : DataSource(chrome::kChromeUIThemePath, MessageLoop::current()), + profile_(profile) { } void DOMUIThemeSource::StartDataRequest(const std::string& path, - int request_id) { - ThemeProvider* tp = profile_->GetThemeProvider(); - if (tp) { - int id = ThemeResourcesUtil::GetId(path); - if (id != -1) { - SkBitmap* image = tp->GetBitmapNamed(id); - if (image) { - std::vector<unsigned char> png_bytes; - PNGEncoder::EncodeBGRASkBitmap(*image, false, &png_bytes); - - scoped_refptr<RefCountedBytes> image_data = new RefCountedBytes(png_bytes); - SendResponse(request_id, image_data); - } + int request_id) { + // Our path may include cachebuster arguments, so trim them off. + std::string uncached_path = StripQueryParams(path); + + if (strcmp(uncached_path.c_str(), kNewTabCSSPath) == 0) { + SendNewTabCSS(request_id); + return; + } else { + int resource_id = ThemeResourcesUtil::GetId(uncached_path); + if (resource_id != -1) { + SendThemeBitmap(request_id, resource_id); + return; } } + // We don't have any data to send back. + SendResponse(request_id, NULL); +} + +std::string DOMUIThemeSource::GetMimeType(const std::string& path) const { + std::string uncached_path = StripQueryParams(path); + + if (strcmp(uncached_path.c_str(), kNewTabCSSPath) == 0) + return "text/css"; + return "image/png"; +} + +//////////////////////////////////////////////////////////////////////////////// +// DOMUIThemeSource, private: + +void DOMUIThemeSource::SendNewTabCSS(int request_id) { + ThemeProvider* tp = profile_->GetThemeProvider(); + DCHECK(tp); + + // Get our theme colors + SkColor color_text = tp->GetColor(BrowserThemeProvider::COLOR_NTP_TEXT); + SkColor color_link = tp->GetColor(BrowserThemeProvider::COLOR_NTP_LINK); + SkColor color_section = + tp->GetColor(BrowserThemeProvider::COLOR_NTP_SECTION); + + // Generate the replacements. + std::vector<const string16> subst; + + // Cache-buster for background. + subst.push_back(UTF8ToUTF16(IntToString(static_cast<int>( + base::Time::Now().ToDoubleT())))); + + // Colors. + subst.push_back(SkColorToRGBAString(color_text)); + subst.push_back(SkColorToRGBAString(color_link)); + subst.push_back(SkColorToRGBAString(color_section)); + + // Get our template. + static const StringPiece new_tab_theme_css( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_NEW_TAB_THEME_CSS)); + + // Create the string from our template and the replacements. + string16 format_string = ASCIIToUTF16(new_tab_theme_css.as_string()); + const std::string css_string = UTF16ToASCII(ReplaceStringPlaceholders( + format_string, subst, NULL)); + + // Convert to a format appropriate for sending. + scoped_refptr<RefCountedBytes> css_bytes(new RefCountedBytes); + css_bytes->data.resize(css_string.size()); + std::copy(css_string.begin(), css_string.end(), css_bytes->data.begin()); + + // Send. + SendResponse(request_id, css_bytes); +} + +void DOMUIThemeSource::SendThemeBitmap(int request_id, int resource_id) { + ThemeProvider* tp = profile_->GetThemeProvider(); + DCHECK(tp); + + SkBitmap* image = tp->GetBitmapNamed(resource_id); + DCHECK(image); + std::vector<unsigned char> png_bytes; + PNGEncoder::EncodeBGRASkBitmap(*image, false, &png_bytes); + + scoped_refptr<RefCountedBytes> image_data = + new RefCountedBytes(png_bytes); + SendResponse(request_id, image_data); } diff --git a/chrome/browser/dom_ui/dom_ui_theme_source.h b/chrome/browser/dom_ui/dom_ui_theme_source.h index 279042d..4dc9bc1 100644 --- a/chrome/browser/dom_ui/dom_ui_theme_source.h +++ b/chrome/browser/dom_ui/dom_ui_theme_source.h @@ -12,17 +12,21 @@ class Profile; // ThumbnailSource is the gateway between network-level chrome: // requests for thumbnails and the history backend that serves these. class DOMUIThemeSource : public ChromeURLDataManager::DataSource { -public: + public: explicit DOMUIThemeSource(Profile* profile); // Called when the network layer has requested a resource underneath // the path we registered. virtual void StartDataRequest(const std::string& path, int request_id); - virtual std::string GetMimeType(const std::string& path) const { - return "image/png"; - } + virtual std::string GetMimeType(const std::string& path) const; + + private: + // Generate and send the CSS for the new tab. + void SendNewTabCSS(int request_id); + + // Fetch and send the theme bitmap. + void SendThemeBitmap(int request_id, int resource_id); -private: Profile* profile_; DISALLOW_COPY_AND_ASSIGN(DOMUIThemeSource); }; diff --git a/chrome/browser/dom_ui/dom_ui_theme_source_unittest.cc b/chrome/browser/dom_ui/dom_ui_theme_source_unittest.cc new file mode 100644 index 0000000..7eae052 --- /dev/null +++ b/chrome/browser/dom_ui/dom_ui_theme_source_unittest.cc @@ -0,0 +1,84 @@ +// 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 "base/gfx/png_encoder.h" +#include "chrome/browser/browser_theme_provider.h" +#include "chrome/browser/dom_ui/dom_ui_theme_source.h" +#include "chrome/browser/profile.h" +#include "chrome/common/url_constants.h" +#include "chrome/test/testing_profile.h" +#include "grit/theme_resources.h" +#include "testing/gtest/include/gtest/gtest.h" + +// A mock ThemeSource (so we can override SendResponse to get at its data). +class MockThemeSource : public DOMUIThemeSource { + public: + explicit MockThemeSource(Profile* profile) : DOMUIThemeSource(profile) { } + + void SendResponse(int request_id, RefCountedBytes* data) { + result_data_ = data ? data : new RefCountedBytes(); + result_request_id_ = request_id; + } + + int result_request_id_; + RefCountedBytes* result_data_; +}; + +// A mock profile +class MockProfile : public TestingProfile { + public: + ThemeProvider* GetThemeProvider() { return new BrowserThemeProvider(); } +}; + + +TEST(DOMUISources, ThemeSourceMimeTypes) { + MockProfile* profile = new MockProfile(); + DOMUIThemeSource* theme_source = new DOMUIThemeSource(profile); + + EXPECT_EQ(theme_source->GetMimeType("css/newtab.css"), "text/css"); + EXPECT_EQ(theme_source->GetMimeType("css/newtab.css?foo"), "text/css"); + EXPECT_EQ(theme_source->GetMimeType("WRONGURL"), "image/png"); +} + +TEST(DOMUISources, ThemeSourceImages) { + MockProfile* profile = new MockProfile(); + MockThemeSource* theme_source = new MockThemeSource(profile); + + // Our test data. + ThemeProvider* tp = profile->GetThemeProvider(); + SkBitmap* image = tp->GetBitmapNamed(IDR_THEME_FRAME); + std::vector<unsigned char> png_bytes; + PNGEncoder::EncodeBGRASkBitmap(*image, false, &png_bytes); + RefCountedBytes* image_data = new RefCountedBytes(png_bytes); + + theme_source->StartDataRequest("theme_frame", 1); + EXPECT_EQ(theme_source->result_request_id_, 1); + EXPECT_EQ(theme_source->result_data_, image_data); + + theme_source->StartDataRequest("theme_toolbar", 2); + EXPECT_EQ(theme_source->result_request_id_, 2); + EXPECT_NE(theme_source->result_data_, image_data); +} + +TEST(DOMUISources, ThemeSourceCSS) { + MockProfile* profile = new MockProfile(); + MockThemeSource* theme_source = new MockThemeSource(profile); + + // Generating the test data for the NTP CSS would just involve copying the + // method, or being super brittle and hard-coding the result (requiring + // an update to the unittest every time the CSS template changes), so we + // just check for a successful request. + theme_source->StartDataRequest("css/newtab.css", 1); + EXPECT_EQ(theme_source->result_request_id_, 1); + EXPECT_NE(theme_source->result_data_, new RefCountedBytes()); + + theme_source->StartDataRequest("css/newtab.css?pipe", 3); + EXPECT_EQ(theme_source->result_request_id_, 3); + EXPECT_NE(theme_source->result_data_, new RefCountedBytes()); + + // Check that we send NULL back when we can't find what we're looking for. + theme_source->StartDataRequest("css/WRONGURL", 7); + EXPECT_EQ(theme_source->result_request_id_, 7); + EXPECT_EQ(theme_source->result_data_, new RefCountedBytes()); +} diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc index f76c711..f64d0ff 100644 --- a/chrome/browser/dom_ui/new_tab_ui.cc +++ b/chrome/browser/dom_ui/new_tab_ui.cc @@ -1172,11 +1172,27 @@ NewTabUI::NewTabUI(TabContents* contents) html_source)); } } + + // Listen for theme installation. + NotificationService::current()->AddObserver(this, + NotificationType::THEME_INSTALLED, NotificationService::AllSources()); } NewTabUI::~NewTabUI() { + // Remove theme observer. + NotificationService::current()->RemoveObserver(this, + NotificationType::THEME_INSTALLED, NotificationService::AllSources()); +} + +void NewTabUI::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (NotificationType::THEME_INSTALLED == type) { + CallJavascriptFunction(L"themeChanged"); + } } + // static void NewTabUI::RegisterUserPrefs(PrefService* prefs) { MostVisitedHandler::RegisterUserPrefs(prefs); diff --git a/chrome/browser/dom_ui/new_tab_ui.h b/chrome/browser/dom_ui/new_tab_ui.h index 8e3b560..f233b0f 100644 --- a/chrome/browser/dom_ui/new_tab_ui.h +++ b/chrome/browser/dom_ui/new_tab_ui.h @@ -6,13 +6,15 @@ #define CHROME_BROWSER_DOM_UI_NEW_TAB_UI_H_ #include "chrome/browser/dom_ui/dom_ui.h" +#include "chrome/common/notification_observer.h" class GURL; class PrefService; class Profile; // The TabContents used for the New Tab page. -class NewTabUI : public DOMUI { +class NewTabUI : public DOMUI, + public NotificationObserver { public: explicit NewTabUI(TabContents* manager); ~NewTabUI(); @@ -20,6 +22,10 @@ class NewTabUI : public DOMUI { static void RegisterUserPrefs(PrefService* prefs); private: + void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + // The message id that should be displayed in this NewTabUIContents // instance's motd area. int motd_message_id_; diff --git a/chrome/browser/resources/new_tab.html b/chrome/browser/resources/new_tab.html index 271bc35..455cdb2 100644 --- a/chrome/browser/resources/new_tab.html +++ b/chrome/browser/resources/new_tab.html @@ -130,10 +130,12 @@ logEvent('log start'); <meta charset="utf-8"> <title jscontent="title"></title> <style> +html { + height:100%; +} body { background-color:white; margin:0px; - background-image:url(chrome-ui://theme/theme_newtab_background); background-repeat:repeat-x; } html[firstview='true'] #main { @@ -157,7 +159,6 @@ form { margin-bottom:30px; } .section-title { - color:#000; line-height:19pt; font-size:110%; font-weight:bold; @@ -223,7 +224,6 @@ a.thumbnail { padding:15px; margin:12px; } - .recent-bookmark { display:block; background-repeat:no-repeat; @@ -298,12 +298,6 @@ html[dir='rtl'] #managesearcheslink { -webkit-border-radius:5px 5px; margin-bottom:10px; } -#searches { - background-color:#e1ecfe; -} -#recentlyBookmarked { - background-color:#e1ecfe; -} html[dir='rtl'] #recentlyBookmarkedContainer { text-align:right; } @@ -358,6 +352,7 @@ html[dir='rtl'] #searches input { pointer-events: none; /* Disable clicks */ } </style> +<link id="themecss" rel="stylesheet" href="chrome://theme/css/newtab.css" /> </head> <body onload="logEvent('body onload fired');" jsvalues=".style.fontFamily:fontfamily;.style.fontSize:fontsize"> @@ -455,7 +450,7 @@ document.addEventListener('DOMContentLoaded', handleDOMContentLoaded); <div id='searches-entries'></div> </div> - <div id="recentlyBookmarked" class="sidebar" style="display:none"> + <div id="recentlyBookmarked" class="sidebar themed" style="display:none"> <span class="section-title" jscontent="bookmarks"></span> <div id="recentlyBookmarkedContainer"></div> </div> @@ -958,6 +953,10 @@ function restoreThumbnails() { chrome.send('clearMostVisitedURLsBlacklist'); } +function themeChanged() { + $('themecss').href = 'chrome://theme/css/newtab.css?' + Date.now(); +} + function viewLog() { var lines = []; var start = log[0][1]; @@ -987,7 +986,7 @@ setTimeout(function(){document.getElementById('main').className = 'visible'}, </script> <img id="small-cross-image" style="display: none; vertical-align:middle;" alt="X" - src="../../app/theme/ntp_x_icon_small.png"/> + src="chrome://theme/newtab_remove_icon"/> </body> <style> @@ -1001,16 +1000,16 @@ setTimeout(function(){document.getElementById('main').className = 'visible'}, height: 81px; left: 60px; top: 47px; - background: url('../../app/theme/ntp_x_icon.png'); + background: url(chrome://theme/newtab_remove_thumbnail); } .edit-mode div.edit-cross:hover { - background: url('../../app/theme/ntp_x_icon_hover.png'); + background: url(chrome://theme/newtab_remove_thumbnail_hover); } .edit-mode div.edit-cross:active { - background: url('../../app/theme/ntp_x_icon_active.png'); + background: url(chrome://theme/newtab_remove_thumbnail_active); } .recent-window-container { - background: url('../../app/theme/closed_window.png'); + background: url(chrome://theme/newtab_closed_window); background-repeat: no-repeat; } html[dir='rtl'] .recent-window-container { diff --git a/chrome/browser/resources/new_tab_theme.css b/chrome/browser/resources/new_tab_theme.css new file mode 100644 index 0000000..0c28c46 --- /dev/null +++ b/chrome/browser/resources/new_tab_theme.css @@ -0,0 +1,11 @@ +body { + background-image:url(chrome://theme/theme_ntp_background?$1); + background-position:bottom; + color: $2; +} +a { + color: $3; +} +.sidebar.themed { + background-color: $4; +}
\ No newline at end of file diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 7634269..becaa93 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -2695,6 +2695,7 @@ 'browser/cocoa/toolbar_view_unittest.mm', 'browser/command_updater_unittest.cc', 'browser/debugger/devtools_manager_unittest.cc', + 'browser/dom_ui/dom_ui_theme_source_unittest.cc', 'browser/dom_ui/dom_ui_unittest.cc', 'browser/download/download_manager_unittest.cc', 'browser/download/download_request_manager_unittest.cc', diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj index f18b051..f161020 100644 --- a/chrome/test/unit/unittests.vcproj +++ b/chrome/test/unit/unittests.vcproj @@ -496,6 +496,10 @@ > </File> <File + RelativePath="..\..\browser\dom_ui\dom_ui_theme_source_unittest.cc" + > + </File> + <File RelativePath="..\..\browser\dom_ui\dom_ui_unittest.cc" > </File> |