new_tab_ui.cc revision 868fa2fe829687343ffae624259930155e16dbd8
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/rtl.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/metrics_handler.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/favicon_webui_handler.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/foreign_session_handler.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/most_visited_handler.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/ntp_resource_cache.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_notification_types.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "components/user_prefs/pref_registry_syncable.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/render_process_host.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/url_data_source.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_ui.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/browser_resources.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/new_tab_page_handler.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/new_tab_page_sync_handler.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/ntp_login_handler.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/android/bookmarks_handler.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/android/context_menu_handler.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/android/new_tab_page_ready_handler.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/android/promo_handler.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(ENABLE_THEMES)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/webui/theme_handler.h"
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(USE_ASH)
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/host_desktop.h"
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::RenderViewHost;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebUIController;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The amount of time there must be no painting for us to consider painting
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// finished.  Observed times are in the ~1200ms range on Windows.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTimeoutMs = 2000;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Strings sent to the page via jstemplates used to set the direction of the
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HTML document based on locale.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kRTLHtmlTextDirection[] = "rtl";
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kLTRHtmlTextDirection[] = "ltr";
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<std::set<const WebUIController*> > g_live_new_tabs;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NewTabUI
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NewTabUI::NewTabUI(content::WebUI* web_ui)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : WebUIController(web_ui),
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      showing_sync_bubble_(false) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_live_new_tabs.Pointer()->insert(this);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui->OverrideTitle(l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We count all link clicks as AUTO_BOOKMARK, so that site can be ranked more
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // highly. Note this means we're including clicks on not only most visited
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thumbnails, but also clicks on recently bookmarked.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui->SetLinkTransitionType(content::PAGE_TRANSITION_AUTO_BOOKMARK);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetProfile()->IsOffTheRecord()) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new browser_sync::ForeignSessionHandler());
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new MostVisitedHandler());
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new RecentlyClosedTabsHandler());
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new MetricsHandler());
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new NewTabPageHandler());
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (NewTabUI::IsDiscoveryInNTPEnabled())
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      web_ui->AddMessageHandler(new SuggestionsHandler());
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Android doesn't have a sync promo/username on NTP.
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    web_ui->AddMessageHandler(new NewTabPageSyncHandler());
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ShouldShowApps()) {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ExtensionService* service = GetProfile()->GetExtensionService();
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We might not have an ExtensionService (on ChromeOS when not logged in
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // for example).
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (service)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        web_ui->AddMessageHandler(new AppLauncherHandler(service));
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new FaviconWebUIHandler());
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These handlers are specific to the Android NTP page.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui->AddMessageHandler(new BookmarksHandler());
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui->AddMessageHandler(new ContextMenuHandler());
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui->AddMessageHandler(new NewTabPageReadyHandler());
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetProfile()->IsOffTheRecord())
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new PromoHandler());
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Android uses native UI for sync setup.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NTPLoginHandler::ShouldShow(GetProfile()))
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new NTPLoginHandler());
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(ENABLE_THEMES)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The theme handler can require some CPU, so do it after hooking up the most
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // visited handler. This allows the DB query for the new tab thumbs to happen
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // earlier.
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  web_ui->AddMessageHandler(new ThemeHandler());
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<NewTabHTMLSource> html_source(new NewTabHTMLSource(
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetProfile()->GetOriginalProfile()));
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These two resources should be loaded only if suggestions NTP is enabled.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  html_source->AddResource("suggestions_page.css", "text/css",
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NewTabUI::IsDiscoveryInNTPEnabled() ? IDR_SUGGESTIONS_PAGE_CSS : 0);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NewTabUI::IsDiscoveryInNTPEnabled()) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    html_source->AddResource("suggestions_page.js", "application/javascript",
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDR_SUGGESTIONS_PAGE_JS);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // content::URLDataSource assumes the ownership of the html_source.
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  content::URLDataSource::Add(GetProfile(), html_source.release());
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_change_registrar_.Init(GetProfile()->GetPrefs());
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pref_change_registrar_.Add(prefs::kShowBookmarkBar,
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             base::Bind(&NewTabUI::OnShowBookmarkBarChanged,
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        base::Unretained(this)));
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NewTabUI::~NewTabUI() {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_live_new_tabs.Pointer()->erase(this);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The timer callback.  If enough time has elapsed since the last paint
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// message, we say we're done painting; otherwise, we keep waiting.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::PaintTimeout() {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The amount of time there must be no painting for us to consider painting
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // finished.  Observed times are in the ~1200ms range on Windows.
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks now = base::TimeTicks::Now();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((now - last_paint_) >= base::TimeDelta::FromMilliseconds(kTimeoutMs)) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Painting has quieted down.  Log this as the full time to run.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta load_time = last_paint_ - start_;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int load_time_ms = static_cast<int>(load_time.InMilliseconds());
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::NotificationService::current()->Notify(
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        chrome::NOTIFICATION_INITIAL_NEW_TAB_UI_LOAD,
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::Source<Profile>(GetProfile()),
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::Details<int>(&load_time_ms));
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("NewTabUI load", load_time);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Not enough quiet time has elapsed.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Some more paints must've occurred since we set the timeout.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait some more.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kTimeoutMs), this,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 &NewTabUI::PaintTimeout);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::StartTimingPaint(RenderViewHost* render_view_host) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  start_ = base::TimeTicks::Now();
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_paint_ = start_;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationSource source =
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<content::RenderWidgetHost>(render_view_host);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!registrar_.IsRegistered(this,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          source)) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    registrar_.Add(
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this,
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        source);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kTimeoutMs), this,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               &NewTabUI::PaintTimeout);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::RenderViewCreated(RenderViewHost* render_view_host) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartTimingPaint(render_view_host);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::RenderViewReused(RenderViewHost* render_view_host) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartTimingPaint(render_view_host);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::Observe(int type,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const content::NotificationSource& source,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const content::NotificationDetails& details) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_paint_ = base::TimeTicks::Now();
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CHECK(false) << "Unexpected notification: " << type;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NewTabUI::OnShowBookmarkBarChanged() {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringValue attached(
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetProfile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) ?
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "true" : "false");
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->CallJavascriptFunction("ntp.setBookmarkBarAttached", attached);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void NewTabUI::RegisterUserPrefs(user_prefs::PrefRegistrySyncable* registry) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID)
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AppLauncherHandler::RegisterUserPrefs(registry);
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NewTabPageHandler::RegisterUserPrefs(registry);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NewTabUI::IsDiscoveryInNTPEnabled())
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SuggestionsHandler::RegisterUserPrefs(registry);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MostVisitedHandler::RegisterUserPrefs(registry);
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  browser_sync::ForeignSessionHandler::RegisterUserPrefs(registry);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NewTabUI::ShouldShowApps() {
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Ash shows apps in app list thus should not show apps page in NTP4.
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Android does not have apps.
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_ANDROID)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#elif defined(USE_ASH)
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return chrome::GetActiveDesktop() != chrome::HOST_DESKTOP_TYPE_ASH;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NewTabUI::IsDiscoveryInNTPEnabled() {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(beaudoin): The flag was removed during a clean-up pass. We leave that
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // here to easily enable it back when we will explore this option again.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::SetUrlTitleAndDirection(DictionaryValue* dictionary,
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const string16& title,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const GURL& gurl) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary->SetString("url", gurl.spec());
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool using_url_as_the_title = false;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 title_to_set(title);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (title_to_set.empty()) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    using_url_as_the_title = true;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    title_to_set = UTF8ToUTF16(gurl.spec());
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We set the "dir" attribute of the title, so that in RTL locales, a LTR
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // title is rendered left-to-right and truncated from the right. For example,
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the title of http://msdn.microsoft.com/en-us/default.aspx is "MSDN:
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Microsoft developer network". In RTL locales, in the [New Tab] page, if
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the "dir" of this title is not specified, it takes Chrome UI's
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // directionality. So the title will be truncated as "soft developer
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // network". Setting the "dir" attribute as "ltr" renders the truncated title
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // as "MSDN: Microsoft D...". As another example, the title of
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://yahoo.com is "Yahoo!". In RTL locales, in the [New Tab] page, the
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // title will be rendered as "!Yahoo" if its "dir" attribute is not set to
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "ltr".
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string direction;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!using_url_as_the_title &&
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::i18n::IsRTL() &&
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::i18n::StringContainsStrongRTLChars(title)) {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    direction = kRTLHtmlTextDirection;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    direction = kLTRHtmlTextDirection;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary->SetString("title", title_to_set);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary->SetString("direction", direction);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NewTabUI* NewTabUI::FromWebUIController(WebUIController* ui) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_live_new_tabs.Pointer()->count(ui))
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<NewTabUI*>(ui);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Profile* NewTabUI::GetProfile() const {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Profile::FromWebUI(web_ui());
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NewTabHTMLSource
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NewTabUI::NewTabHTMLSource::NewTabHTMLSource(Profile* profile)
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : profile_(profile) {
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string NewTabUI::NewTabHTMLSource::GetSource() const {
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return chrome::kChromeUINewTabHost;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NewTabUI::NewTabHTMLSource::StartDataRequest(
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& path,
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int render_process_id,
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int render_view_id,
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const content::URLDataSource::GotDataCallback& callback) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<std::string, std::pair<std::string, int> >::iterator it =
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resource_map_.find(path);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != resource_map_.end()) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedStaticMemory> resource_bytes(
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        it->second.second ?
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                it->second.second) :
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            new base::RefCountedStaticMemory);
335868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callback.Run(resource_bytes.get());
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!path.empty() && path[0] != '#') {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // A path under new-tab was requested; it's likely a bad relative
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URL from the new tab page, but in any case it's an error.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(dtrainor): Can remove this #if check once we update the
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // accessibility script to no longer try to access urls like
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // '?2314124523523'.
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See http://crbug.com/150252.
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << path << " should not have been requested on the NTP";
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    callback.Run(NULL);
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content::RenderProcessHost* render_host =
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      content::RenderProcessHost::FromID(render_process_id);
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool is_incognito = render_host->GetBrowserContext()->IsOffTheRecord();
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::RefCountedMemory> html_bytes(
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NTPResourceCacheFactory::GetForProfile(profile_)->
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetNewTabHTML(is_incognito));
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  callback.Run(html_bytes.get());
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string NewTabUI::NewTabHTMLSource::GetMimeType(const std::string& resource)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<std::string, std::pair<std::string, int> >::const_iterator it =
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resource_map_.find(resource);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != resource_map_.end())
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return it->second.first;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return "text/html";
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NewTabUI::NewTabHTMLSource::ShouldReplaceExistingSource() const {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NewTabUI::NewTabHTMLSource::ShouldAddContentSecurityPolicy() const {
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::NewTabHTMLSource::AddResource(const char* resource,
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const char* mime_type,
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             int resource_id) {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(resource);
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(mime_type);
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resource_map_[std::string(resource)] =
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::make_pair(std::string(mime_type), resource_id);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NewTabUI::NewTabHTMLSource::~NewTabHTMLSource() {}
391