1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/webui/ntp_resource_cache.h"
6
7#include <algorithm>
8#include <vector>
9
10#include "base/command_line.h"
11#include "base/file_util.h"
12#include "base/memory/ref_counted_memory.h"
13#include "base/string16.h"
14#include "base/string_number_conversions.h"
15#include "base/time.h"
16#include "base/utf_string_conversions.h"
17#include "base/values.h"
18#include "chrome/browser/google/google_util.h"
19#include "chrome/browser/metrics/user_metrics.h"
20#include "chrome/browser/prefs/pref_service.h"
21#include "chrome/browser/profiles/profile.h"
22#include "chrome/browser/themes/theme_service.h"
23#include "chrome/browser/themes/theme_service_factory.h"
24#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
25#include "chrome/browser/ui/webui/shown_sections_handler.h"
26#include "chrome/browser/web_resource/promo_resource_service.h"
27#include "chrome/common/chrome_switches.h"
28#include "chrome/common/extensions/extension.h"
29#include "chrome/common/extensions/extension_constants.h"
30#include "chrome/common/jstemplate_builder.h"
31#include "chrome/common/pref_names.h"
32#include "chrome/common/url_constants.h"
33#include "content/browser/browser_thread.h"
34#include "content/common/notification_service.h"
35#include "content/common/notification_type.h"
36#include "grit/browser_resources.h"
37#include "grit/chromium_strings.h"
38#include "grit/generated_resources.h"
39#include "grit/locale_settings.h"
40#include "grit/theme_resources.h"
41#include "ui/base/animation/animation.h"
42#include "ui/base/l10n/l10n_util.h"
43#include "ui/base/resource/resource_bundle.h"
44#include "ui/base/theme_provider.h"
45#include "ui/gfx/color_utils.h"
46
47#if defined(OS_WIN) || defined(TOOLKIT_VIEWS)
48#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
49#elif defined(OS_MACOSX)
50#include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
51#elif defined(OS_POSIX)
52#include "chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk.h"
53#endif
54
55using base::Time;
56
57namespace {
58
59// The URL for the the Learn More page shown on incognito new tab.
60const char kLearnMoreIncognitoUrl[] =
61#if defined(OS_CHROMEOS)
62    "https://www.google.com/support/chromeos/bin/answer.py?answer=95464";
63#else
64    "https://www.google.com/support/chrome/bin/answer.py?answer=95464";
65#endif
66
67// The URL for the Learn More page shown on guest session new tab.
68const char kLearnMoreGuestSessionUrl[] =
69    "https://www.google.com/support/chromeos/bin/answer.py?answer=1057090";
70
71// The URL for bookmark sync service help.
72const char kSyncServiceHelpUrl[] =
73    "https://www.google.com/support/chrome/bin/answer.py?answer=165139";
74
75// The URL to be loaded to display Help.
76const char kHelpContentUrl[] =
77    "https://www.google.com/support/chrome/";
78
79string16 GetUrlWithLang(const GURL& url) {
80  return ASCIIToUTF16(google_util::AppendGoogleLocaleParam(url).spec());
81}
82
83std::string SkColorToRGBAString(SkColor color) {
84  // We convert the alpha using DoubleToString because StringPrintf will use
85  // locale specific formatters (e.g., use , instead of . in German).
86  return StringPrintf("rgba(%d,%d,%d,%s)", SkColorGetR(color),
87      SkColorGetG(color), SkColorGetB(color),
88      base::DoubleToString(SkColorGetA(color) / 255.0).c_str());
89}
90
91// Get the CSS string for the background position on the new tab page for the
92// states when the bar is attached or detached.
93std::string GetNewTabBackgroundCSS(const ui::ThemeProvider* theme_provider,
94                                   bool bar_attached) {
95  int alignment;
96  theme_provider->GetDisplayProperty(
97      ThemeService::NTP_BACKGROUND_ALIGNMENT, &alignment);
98
99  // TODO(glen): This is a quick workaround to hide the notused.png image when
100  // no image is provided - we don't have time right now to figure out why
101  // this is painting as white.
102  // http://crbug.com/17593
103  if (!theme_provider->HasCustomImage(IDR_THEME_NTP_BACKGROUND)) {
104    return "-64px";
105  }
106
107  if (bar_attached)
108    return ThemeService::AlignmentToString(alignment);
109
110  // The bar is detached, so we must offset the background by the bar size
111  // if it's a top-aligned bar.
112#if defined(OS_WIN) || defined(TOOLKIT_VIEWS)
113  int offset = BookmarkBarView::kNewtabBarHeight;
114#elif defined(OS_MACOSX)
115  int offset = bookmarks::kNTPBookmarkBarHeight;
116#elif defined(OS_POSIX)
117  int offset = BookmarkBarGtk::kBookmarkBarNTPHeight;
118#else
119  int offset = 0;
120#endif
121
122  if (alignment & ThemeService::ALIGN_TOP) {
123    if (alignment & ThemeService::ALIGN_LEFT)
124      return "0% " + base::IntToString(-offset) + "px";
125    else if (alignment & ThemeService::ALIGN_RIGHT)
126      return "100% " + base::IntToString(-offset) + "px";
127    return "center " + base::IntToString(-offset) + "px";
128  }
129  return ThemeService::AlignmentToString(alignment);
130}
131
132// How the background image on the new tab page should be tiled (see tiling
133// masks in theme_service.h).
134std::string GetNewTabBackgroundTilingCSS(
135    const ui::ThemeProvider* theme_provider) {
136  int repeat_mode;
137  theme_provider->GetDisplayProperty(
138      ThemeService::NTP_BACKGROUND_TILING, &repeat_mode);
139  return ThemeService::TilingToString(repeat_mode);
140}
141
142// Is the current time within a given date range?
143bool InDateRange(double begin, double end) {
144  Time start_time = Time::FromDoubleT(begin);
145  Time end_time = Time::FromDoubleT(end);
146  return start_time < Time::Now() && end_time > Time::Now();
147}
148
149}  // namespace
150
151NTPResourceCache::NTPResourceCache(Profile* profile) : profile_(profile) {
152  registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
153                 NotificationService::AllSources());
154  registrar_.Add(this, NotificationType::PROMO_RESOURCE_STATE_CHANGED,
155                 NotificationService::AllSources());
156
157  // Watch for pref changes that cause us to need to invalidate the HTML cache.
158  pref_change_registrar_.Init(profile_->GetPrefs());
159  pref_change_registrar_.Add(prefs::kShowBookmarkBar, this);
160  pref_change_registrar_.Add(prefs::kEnableBookmarkBar, this);
161  pref_change_registrar_.Add(prefs::kNTPShownSections, this);
162}
163
164NTPResourceCache::~NTPResourceCache() {}
165
166RefCountedBytes* NTPResourceCache::GetNewTabHTML(bool is_incognito) {
167  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
168  if (is_incognito) {
169    if (!new_tab_incognito_html_.get())
170      CreateNewTabIncognitoHTML();
171  } else {
172    if (!new_tab_html_.get())
173      CreateNewTabHTML();
174  }
175  return is_incognito ? new_tab_incognito_html_.get()
176                      : new_tab_html_.get();
177}
178
179RefCountedBytes* NTPResourceCache::GetNewTabCSS(bool is_incognito) {
180  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
181  if (is_incognito) {
182    if (!new_tab_incognito_css_.get())
183      CreateNewTabIncognitoCSS();
184  } else {
185    if (!new_tab_css_.get())
186      CreateNewTabCSS();
187  }
188  return is_incognito ? new_tab_incognito_css_.get()
189                      : new_tab_css_.get();
190}
191
192void NTPResourceCache::Observe(NotificationType type,
193    const NotificationSource& source, const NotificationDetails& details) {
194  // Invalidate the cache.
195  if (NotificationType::BROWSER_THEME_CHANGED == type ||
196      NotificationType::PROMO_RESOURCE_STATE_CHANGED == type) {
197    new_tab_incognito_html_ = NULL;
198    new_tab_html_ = NULL;
199    new_tab_incognito_css_ = NULL;
200    new_tab_css_ = NULL;
201  } else if (NotificationType::PREF_CHANGED == type) {
202    std::string* pref_name = Details<std::string>(details).ptr();
203    if (*pref_name == prefs::kShowBookmarkBar ||
204        *pref_name == prefs::kEnableBookmarkBar ||
205        *pref_name == prefs::kHomePageIsNewTabPage ||
206        *pref_name == prefs::kNTPShownSections) {
207      new_tab_incognito_html_ = NULL;
208      new_tab_html_ = NULL;
209    } else {
210      NOTREACHED();
211    }
212  } else {
213    NOTREACHED();
214  }
215}
216
217void NTPResourceCache::CreateNewTabIncognitoHTML() {
218  DictionaryValue localized_strings;
219  localized_strings.SetString("title",
220      l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
221  int new_tab_message_ids = IDS_NEW_TAB_OTR_MESSAGE;
222  int new_tab_html_idr = IDR_INCOGNITO_TAB_HTML;
223  const char* new_tab_link = kLearnMoreIncognitoUrl;
224  // TODO(altimofeev): consider implementation without 'if def' usage.
225#if defined(OS_CHROMEOS)
226  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession)) {
227    new_tab_message_ids = IDS_NEW_TAB_GUEST_SESSION_MESSAGE;
228    new_tab_html_idr = IDR_GUEST_SESSION_TAB_HTML;
229    new_tab_link = kLearnMoreGuestSessionUrl;
230  }
231#endif
232  localized_strings.SetString("content",
233      l10n_util::GetStringFUTF16(new_tab_message_ids,
234                                 GetUrlWithLang(GURL(new_tab_link))));
235  localized_strings.SetString("extensionsmessage",
236      l10n_util::GetStringFUTF16(IDS_NEW_TAB_OTR_EXTENSIONS_MESSAGE,
237                                 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
238                                 ASCIIToUTF16(chrome::kChromeUIExtensionsURL)));
239  bool bookmark_bar_attached = profile_->GetPrefs()->GetBoolean(
240      prefs::kShowBookmarkBar);
241  localized_strings.SetString("bookmarkbarattached",
242      bookmark_bar_attached ? "true" : "false");
243
244  ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
245
246  static const base::StringPiece incognito_tab_html(
247      ResourceBundle::GetSharedInstance().GetRawDataResource(
248          new_tab_html_idr));
249
250  std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
251      incognito_tab_html, &localized_strings);
252
253  new_tab_incognito_html_ = new RefCountedBytes;
254  new_tab_incognito_html_->data.resize(full_html.size());
255  std::copy(full_html.begin(), full_html.end(),
256            new_tab_incognito_html_->data.begin());
257}
258
259void NTPResourceCache::CreateNewTabHTML() {
260  // Show the profile name in the title and most visited labels if the current
261  // profile is not the default.
262  string16 apps = l10n_util::GetStringUTF16(IDS_NEW_TAB_APPS);
263  string16 title = l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
264  string16 most_visited = l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED);
265  DictionaryValue localized_strings;
266  localized_strings.SetString("bookmarkbarattached",
267      profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) ?
268      "true" : "false");
269  localized_strings.SetString("hasattribution",
270      ThemeServiceFactory::GetForProfile(profile_)->HasCustomImage(
271          IDR_THEME_NTP_ATTRIBUTION) ?
272      "true" : "false");
273  localized_strings.SetString("apps", apps);
274  localized_strings.SetString("title", title);
275  localized_strings.SetString("mostvisited", most_visited);
276  localized_strings.SetString("restorethumbnails",
277      l10n_util::GetStringUTF16(IDS_NEW_TAB_RESTORE_THUMBNAILS_LINK));
278  localized_strings.SetString("recentlyclosed",
279      l10n_util::GetStringUTF16(IDS_NEW_TAB_RECENTLY_CLOSED));
280  localized_strings.SetString("closedwindowsingle",
281      l10n_util::GetStringUTF16(IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_SINGLE));
282  localized_strings.SetString("foreignsessions",
283      l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_SESSIONS));
284  localized_strings.SetString("closedwindowmultiple",
285      l10n_util::GetStringUTF16(IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE));
286  localized_strings.SetString("attributionintro",
287      l10n_util::GetStringUTF16(IDS_NEW_TAB_ATTRIBUTION_INTRO));
288  localized_strings.SetString("thumbnailremovednotification",
289      l10n_util::GetStringUTF16(IDS_NEW_TAB_THUMBNAIL_REMOVED_NOTIFICATION));
290  localized_strings.SetString("undothumbnailremove",
291      l10n_util::GetStringUTF16(IDS_NEW_TAB_UNDO_THUMBNAIL_REMOVE));
292  localized_strings.SetString("removethumbnailtooltip",
293      l10n_util::GetStringUTF16(IDS_NEW_TAB_REMOVE_THUMBNAIL_TOOLTIP));
294  localized_strings.SetString("pinthumbnailtooltip",
295      l10n_util::GetStringUTF16(IDS_NEW_TAB_PIN_THUMBNAIL_TOOLTIP));
296  localized_strings.SetString("unpinthumbnailtooltip",
297      l10n_util::GetStringUTF16(IDS_NEW_TAB_UNPIN_THUMBNAIL_TOOLTIP));
298  localized_strings.SetString("showhidethumbnailtooltip",
299      l10n_util::GetStringUTF16(IDS_NEW_TAB_SHOW_HIDE_THUMBNAIL_TOOLTIP));
300  localized_strings.SetString("showhidelisttooltip",
301      l10n_util::GetStringUTF16(IDS_NEW_TAB_SHOW_HIDE_LIST_TOOLTIP));
302  localized_strings.SetString("pagedisplaytooltip",
303      l10n_util::GetStringUTF16(IDS_NEW_TAB_PAGE_DISPLAY_TOOLTIP));
304  localized_strings.SetString("closefirstrunnotification",
305      l10n_util::GetStringUTF16(IDS_NEW_TAB_CLOSE_FIRST_RUN_NOTIFICATION));
306  localized_strings.SetString("close", l10n_util::GetStringUTF16(IDS_CLOSE));
307  localized_strings.SetString("history",
308      l10n_util::GetStringUTF16(IDS_NEW_TAB_HISTORY));
309  localized_strings.SetString("downloads",
310      l10n_util::GetStringUTF16(IDS_NEW_TAB_DOWNLOADS));
311  localized_strings.SetString("help",
312      l10n_util::GetStringUTF16(IDS_NEW_TAB_HELP));
313  localized_strings.SetString("helpurl",
314      GetUrlWithLang(GURL(kHelpContentUrl)));
315  localized_strings.SetString("appsettings",
316      l10n_util::GetStringUTF16(IDS_NEW_TAB_APP_SETTINGS));
317  localized_strings.SetString("appuninstall",
318      l10n_util::GetStringUTF16(IDS_NEW_TAB_APP_UNINSTALL));
319  localized_strings.SetString("appoptions",
320      l10n_util::GetStringUTF16(IDS_NEW_TAB_APP_OPTIONS));
321  localized_strings.SetString("appcreateshortcut",
322      l10n_util::GetStringUTF16(IDS_NEW_TAB_APP_CREATE_SHORTCUT));
323  localized_strings.SetString("applaunchtypepinned",
324      l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_PINNED));
325  localized_strings.SetString("applaunchtyperegular",
326      l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_REGULAR));
327  localized_strings.SetString("applaunchtypewindow",
328      l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_WINDOW));
329  localized_strings.SetString("applaunchtypefullscreen",
330      l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_FULLSCREEN));
331  localized_strings.SetString("web_store_title",
332      l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE));
333  localized_strings.SetString("web_store_url",
334      GetUrlWithLang(GURL(Extension::ChromeStoreLaunchURL())));
335  localized_strings.SetString("syncpromotext",
336      l10n_util::GetStringUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL));
337#if defined(OS_CHROMEOS)
338  localized_strings.SetString("expandMenu",
339      l10n_util::GetStringUTF16(IDS_NEW_TAB_CLOSE_MENU_EXPAND));
340#endif
341
342  // Don't initiate the sync related message passing with the page if the sync
343  // code is not present.
344  if (profile_->GetProfileSyncService())
345    localized_strings.SetString("syncispresent", "true");
346  else
347    localized_strings.SetString("syncispresent", "false");
348
349  ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
350
351  // Control fade and resize animations.
352  std::string anim =
353      ui::Animation::ShouldRenderRichAnimation() ? "true" : "false";
354  localized_strings.SetString("anim", anim);
355
356  // Pass the shown_sections pref early so that we can prevent flicker.
357  const int shown_sections = ShownSectionsHandler::GetShownSections(
358      profile_->GetPrefs());
359  localized_strings.SetInteger("shown_sections", shown_sections);
360
361  // If the user has preferences for a start and end time for a custom logo,
362  // and the time now is between these two times, show the custom logo.
363  if (profile_->GetPrefs()->FindPreference(prefs::kNTPCustomLogoStart) &&
364      profile_->GetPrefs()->FindPreference(prefs::kNTPCustomLogoEnd)) {
365    localized_strings.SetString("customlogo",
366        InDateRange(profile_->GetPrefs()->GetDouble(prefs::kNTPCustomLogoStart),
367                    profile_->GetPrefs()->GetDouble(prefs::kNTPCustomLogoEnd)) ?
368        "true" : "false");
369  } else {
370    localized_strings.SetString("customlogo", "false");
371  }
372
373  // If the user has preferences for a start and end time for a promo from
374  // the server, and this promo string exists, set the localized string.
375  if (profile_->GetPrefs()->FindPreference(prefs::kNTPPromoStart) &&
376      profile_->GetPrefs()->FindPreference(prefs::kNTPPromoEnd) &&
377      profile_->GetPrefs()->FindPreference(prefs::kNTPPromoLine) &&
378      PromoResourceServiceUtil::CanShowPromo(profile_)) {
379    localized_strings.SetString("serverpromo",
380        InDateRange(profile_->GetPrefs()->GetDouble(prefs::kNTPPromoStart),
381                    profile_->GetPrefs()->GetDouble(prefs::kNTPPromoEnd)) ?
382                    profile_->GetPrefs()->GetString(prefs::kNTPPromoLine) :
383                                                    std::string());
384    UserMetrics::RecordAction(UserMetricsAction("NTPPromoShown"));
385  }
386
387  // Load the new tab page appropriate for this build
388  // Note that some builds (eg. TOUCHUI) don't make use of everything we
389  // do here (all of the template data, etc.), but we keep the back end
390  // consistent across builds, supporting the union of all NTP front-ends
391  // for simplicity.
392  std::string full_html;
393  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNewTabPage4)) {
394    base::StringPiece new_tab_html(ResourceBundle::GetSharedInstance().
395        GetRawDataResource(IDR_NEW_TAB_4_HTML));
396    full_html = jstemplate_builder::GetI18nTemplateHtml(new_tab_html,
397                                                        &localized_strings);
398  } else {
399    base::StringPiece new_tab_html(ResourceBundle::GetSharedInstance().
400        GetRawDataResource(IDR_NEW_TAB_HTML));
401
402    // Inject the template data into the HTML so that it is available before any
403    // layout is needed.
404    std::string json_html;
405    jstemplate_builder::AppendJsonHtml(&localized_strings, &json_html);
406
407    static const base::StringPiece template_data_placeholder(
408        "<!-- template data placeholder -->");
409    size_t pos = new_tab_html.find(template_data_placeholder);
410
411    if (pos != base::StringPiece::npos) {
412      full_html.assign(new_tab_html.data(), pos);
413      full_html.append(json_html);
414      size_t after_offset = pos + template_data_placeholder.size();
415      full_html.append(new_tab_html.data() + after_offset,
416                       new_tab_html.size() - after_offset);
417    } else {
418      NOTREACHED();
419      full_html.assign(new_tab_html.data(), new_tab_html.size());
420    }
421  }
422
423  new_tab_html_ = new RefCountedBytes;
424  new_tab_html_->data.resize(full_html.size());
425  std::copy(full_html.begin(), full_html.end(), new_tab_html_->data.begin());
426}
427
428void NTPResourceCache::CreateNewTabIncognitoCSS() {
429  ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
430  DCHECK(tp);
431
432  // Get our theme colors
433  SkColor color_background =
434      tp->GetColor(ThemeService::COLOR_NTP_BACKGROUND);
435
436  // Generate the replacements.
437  std::vector<std::string> subst;
438
439  // Cache-buster for background.
440  subst.push_back(
441      profile_->GetPrefs()->GetString(prefs::kCurrentThemeID));  // $1
442
443  // Colors.
444  subst.push_back(SkColorToRGBAString(color_background));  // $2
445  subst.push_back(GetNewTabBackgroundCSS(tp, false));  // $3
446  subst.push_back(GetNewTabBackgroundCSS(tp, true));  // $4
447  subst.push_back(GetNewTabBackgroundTilingCSS(tp));  // $5
448
449  // Get our template.
450  static const base::StringPiece new_tab_theme_css(
451      ResourceBundle::GetSharedInstance().GetRawDataResource(
452      IDR_NEW_INCOGNITO_TAB_THEME_CSS));
453
454  // Create the string from our template and the replacements.
455  std::string full_css = ReplaceStringPlaceholders(
456      new_tab_theme_css, subst, NULL);
457
458  new_tab_incognito_css_ = new RefCountedBytes;
459  new_tab_incognito_css_->data.resize(full_css.size());
460  std::copy(full_css.begin(), full_css.end(),
461            new_tab_incognito_css_->data.begin());
462}
463
464void NTPResourceCache::CreateNewTabCSS() {
465  ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
466  DCHECK(tp);
467
468  // Get our theme colors
469  SkColor color_background =
470      tp->GetColor(ThemeService::COLOR_NTP_BACKGROUND);
471  SkColor color_text = tp->GetColor(ThemeService::COLOR_NTP_TEXT);
472  SkColor color_link = tp->GetColor(ThemeService::COLOR_NTP_LINK);
473  SkColor color_link_underline =
474      tp->GetColor(ThemeService::COLOR_NTP_LINK_UNDERLINE);
475
476  SkColor color_section =
477      tp->GetColor(ThemeService::COLOR_NTP_SECTION);
478  SkColor color_section_text =
479      tp->GetColor(ThemeService::COLOR_NTP_SECTION_TEXT);
480  SkColor color_section_link =
481      tp->GetColor(ThemeService::COLOR_NTP_SECTION_LINK);
482  SkColor color_section_link_underline =
483      tp->GetColor(ThemeService::COLOR_NTP_SECTION_LINK_UNDERLINE);
484  SkColor color_section_header_text =
485      tp->GetColor(ThemeService::COLOR_NTP_SECTION_HEADER_TEXT);
486  SkColor color_section_header_text_hover =
487      tp->GetColor(ThemeService::COLOR_NTP_SECTION_HEADER_TEXT_HOVER);
488  SkColor color_section_header_rule =
489      tp->GetColor(ThemeService::COLOR_NTP_SECTION_HEADER_RULE);
490  SkColor color_section_header_rule_light =
491      tp->GetColor(ThemeService::COLOR_NTP_SECTION_HEADER_RULE_LIGHT);
492  SkColor color_text_light =
493      tp->GetColor(ThemeService::COLOR_NTP_TEXT_LIGHT);
494
495  SkColor color_header =
496      tp->GetColor(ThemeService::COLOR_NTP_HEADER);
497  // Generate a lighter color for the header gradients.
498  color_utils::HSL header_lighter;
499  color_utils::SkColorToHSL(color_header, &header_lighter);
500  header_lighter.l += (1 - header_lighter.l) * 0.33;
501  SkColor color_header_gradient_light =
502      color_utils::HSLToSkColor(header_lighter, SkColorGetA(color_header));
503
504  // Generate section border color from the header color. See
505  // BookmarkBarView::Paint for how we do this for the bookmark bar
506  // borders.
507  SkColor color_section_border =
508      SkColorSetARGB(80,
509                     SkColorGetR(color_header),
510                     SkColorGetG(color_header),
511                     SkColorGetB(color_header));
512
513  // Generate the replacements.
514  std::vector<std::string> subst;
515  // A second list of replacements, each of which must be in $$x format,
516  // where x is a digit from 1-9.
517  std::vector<std::string> subst2;
518  std::vector<std::string> subst3;
519
520  // Cache-buster for background.
521  subst.push_back(
522      profile_->GetPrefs()->GetString(prefs::kCurrentThemeID));  // $1
523
524  // Colors.
525  subst.push_back(SkColorToRGBAString(color_background));  // $2
526  subst.push_back(GetNewTabBackgroundCSS(tp, false));  // $3
527  subst.push_back(GetNewTabBackgroundCSS(tp, true));  // $4
528  subst.push_back(GetNewTabBackgroundTilingCSS(tp));  // $5
529  subst.push_back(SkColorToRGBAString(color_header));  // $6
530  subst.push_back(SkColorToRGBAString(color_header_gradient_light));  // $7
531  subst.push_back(SkColorToRGBAString(color_text));  // $8
532  subst.push_back(SkColorToRGBAString(color_link));  // $9
533
534  subst2.push_back(SkColorToRGBAString(color_section));  // $$1
535  subst2.push_back(SkColorToRGBAString(color_section_border));  // $$2
536  subst2.push_back(SkColorToRGBAString(color_section_text));  // $$3
537  subst2.push_back(SkColorToRGBAString(color_section_link));  // $$4
538  subst2.push_back(SkColorToRGBAString(color_link_underline));  // $$5
539  subst2.push_back(SkColorToRGBAString(color_section_link_underline));  // $$6
540  subst2.push_back(SkColorToRGBAString(color_section_header_text)); // $$7
541  subst2.push_back(SkColorToRGBAString(
542      color_section_header_text_hover)); // $$8
543  subst2.push_back(SkColorToRGBAString(color_section_header_rule));  // $$9
544
545  subst3.push_back(SkColorToRGBAString(
546      color_section_header_rule_light));  // $$$1
547  subst3.push_back(SkColorToRGBAString(
548      SkColorSetA(color_section_header_rule, 0)));  // $$$2
549  subst3.push_back(SkColorToRGBAString(color_text_light));  // $$$3
550
551  // Get our template.
552  int ntp_css_resource_id =
553      CommandLine::ForCurrentProcess()->HasSwitch(switches::kNewTabPage4) ?
554          IDR_NEW_TAB_4_THEME_CSS : IDR_NEW_TAB_THEME_CSS;
555  static const base::StringPiece new_tab_theme_css(
556      ResourceBundle::GetSharedInstance().GetRawDataResource(
557          ntp_css_resource_id));
558
559  // Create the string from our template and the replacements.
560  std::string css_string;
561  css_string = ReplaceStringPlaceholders(new_tab_theme_css, subst, NULL);
562  css_string = ReplaceStringPlaceholders(css_string, subst2, NULL);
563  css_string = ReplaceStringPlaceholders(css_string, subst3, NULL);
564
565  new_tab_css_ = new RefCountedBytes;
566  new_tab_css_->data.resize(css_string.size());
567  std::copy(css_string.begin(), css_string.end(),
568            new_tab_css_->data.begin());
569}
570