summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/l10n_util.cc24
-rw-r--r--app/l10n_util.h10
-rw-r--r--base/string_util.cc85
-rw-r--r--base/string_util.h25
-rw-r--r--base/string_util_unittest.cc43
-rw-r--r--chrome/app/generated_resources.grd4
-rw-r--r--chrome/app/theme/ntp_background.pngbin1885 -> 144 bytes
-rw-r--r--chrome/app/theme/theme_resources.grd7
-rw-r--r--chrome/browser/browser_resources.grd1
-rw-r--r--chrome/browser/browser_theme_provider.cc81
-rw-r--r--chrome/browser/browser_theme_provider.h4
-rw-r--r--chrome/browser/dom_ui/dom_ui_theme_source.cc125
-rw-r--r--chrome/browser/dom_ui/dom_ui_theme_source.h14
-rw-r--r--chrome/browser/dom_ui/dom_ui_theme_source_unittest.cc84
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.cc16
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.h8
-rw-r--r--chrome/browser/resources/new_tab.html29
-rw-r--r--chrome/browser/resources/new_tab_theme.css11
-rw-r--r--chrome/chrome.gyp1
-rw-r--r--chrome/test/unit/unittests.vcproj4
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
index fb75b9f..490e723 100644
--- a/chrome/app/theme/ntp_background.png
+++ b/chrome/app/theme/ntp_background.png
Binary files differ
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>