new_tab_ui.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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"
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/metrics_handler.h"
185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/favicon_webui_handler.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/foreign_session_handler.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/most_visited_handler.h"
235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/ui/webui/ntp/new_tab_page_handler.h"
245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/ui/webui/ntp/new_tab_page_sync_handler.h"
255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/ui/webui/ntp/ntp_login_handler.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/ntp_resource_cache.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h"
289ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h"
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/ui/webui/ntp/suggestions_page_handler.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/render_process_host.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/url_data_source.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_ui.h"
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/browser/extension_system.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/browser_resources.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(ENABLE_THEMES)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/webui/theme_handler.h"
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(USE_ASH)
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/host_desktop.h"
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::RenderViewHost;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebUIController;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The amount of time there must be no painting for us to consider painting
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// finished.  Observed times are in the ~1200ms range on Windows.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTimeoutMs = 2000;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Strings sent to the page via jstemplates used to set the direction of the
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HTML document based on locale.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kRTLHtmlTextDirection[] = "rtl";
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kLTRHtmlTextDirection[] = "ltr";
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<std::set<const WebUIController*> > g_live_new_tabs;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const char* GetHtmlTextDirection(const base::string16& text) {
72d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (base::i18n::IsRTL() && base::i18n::StringContainsStrongRTLChars(text))
73d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return kRTLHtmlTextDirection;
74d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  else
75d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return kLTRHtmlTextDirection;
76d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
77d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NewTabUI
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NewTabUI::NewTabUI(content::WebUI* web_ui)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : WebUIController(web_ui),
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      WebContentsObserver(web_ui->GetWebContents()),
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      showing_sync_bubble_(false) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_live_new_tabs.Pointer()->insert(this);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui->OverrideTitle(l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We count all link clicks as AUTO_BOOKMARK, so that site can be ranked more
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // highly. Note this means we're including clicks on not only most visited
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thumbnails, but also clicks on recently bookmarked.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui->SetLinkTransitionType(content::PAGE_TRANSITION_AUTO_BOOKMARK);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  Profile* profile = GetProfile();
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!profile->IsOffTheRecord()) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new browser_sync::ForeignSessionHandler());
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    web_ui->AddMessageHandler(new MetricsHandler());
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new MostVisitedHandler());
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new RecentlyClosedTabsHandler());
101a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    web_ui->AddMessageHandler(new FaviconWebUIHandler());
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new NewTabPageHandler());
103558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    web_ui->AddMessageHandler(new CoreAppLauncherHandler());
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (NewTabUI::IsDiscoveryInNTPEnabled())
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      web_ui->AddMessageHandler(new SuggestionsHandler());
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    web_ui->AddMessageHandler(new NewTabPageSyncHandler());
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ExtensionService* service =
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        extensions::ExtensionSystem::Get(profile)->extension_service();
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // We might not have an ExtensionService (on ChromeOS when not logged in
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // for example).
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (service)
1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      web_ui->AddMessageHandler(new AppLauncherHandler(service));
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (NTPLoginHandler::ShouldShow(profile))
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui->AddMessageHandler(new NTPLoginHandler());
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(ENABLE_THEMES)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The theme handler can require some CPU, so do it after hooking up the most
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // visited handler. This allows the DB query for the new tab thumbs to happen
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // earlier.
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  web_ui->AddMessageHandler(new ThemeHandler());
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<NewTabHTMLSource> html_source(
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new NewTabHTMLSource(profile->GetOriginalProfile()));
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These two resources should be loaded only if suggestions NTP is enabled.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  html_source->AddResource("suggestions_page.css", "text/css",
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NewTabUI::IsDiscoveryInNTPEnabled() ? IDR_SUGGESTIONS_PAGE_CSS : 0);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NewTabUI::IsDiscoveryInNTPEnabled()) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    html_source->AddResource("suggestions_page.js", "application/javascript",
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDR_SUGGESTIONS_PAGE_JS);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // content::URLDataSource assumes the ownership of the html_source.
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  content::URLDataSource::Add(profile, html_source.release());
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  pref_change_registrar_.Init(profile->GetPrefs());
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pref_change_registrar_.Add(prefs::kShowBookmarkBar,
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             base::Bind(&NewTabUI::OnShowBookmarkBarChanged,
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        base::Unretained(this)));
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NewTabUI::~NewTabUI() {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_live_new_tabs.Pointer()->erase(this);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The timer callback.  If enough time has elapsed since the last paint
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// message, we say we're done painting; otherwise, we keep waiting.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::PaintTimeout() {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The amount of time there must be no painting for us to consider painting
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // finished.  Observed times are in the ~1200ms range on Windows.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks now = base::TimeTicks::Now();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((now - last_paint_) >= base::TimeDelta::FromMilliseconds(kTimeoutMs)) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Painting has quieted down.  Log this as the full time to run.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta load_time = last_paint_ - start_;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("NewTabUI load", load_time);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Not enough quiet time has elapsed.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Some more paints must've occurred since we set the timeout.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait some more.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kTimeoutMs), this,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 &NewTabUI::PaintTimeout);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::StartTimingPaint(RenderViewHost* render_view_host) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  start_ = base::TimeTicks::Now();
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_paint_ = start_;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationSource source =
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<content::RenderWidgetHost>(render_view_host);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!registrar_.IsRegistered(this,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          source)) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    registrar_.Add(
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        source);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kTimeoutMs), this,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               &NewTabUI::PaintTimeout);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::RenderViewCreated(RenderViewHost* render_view_host) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartTimingPaint(render_view_host);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::RenderViewReused(RenderViewHost* render_view_host) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartTimingPaint(render_view_host);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void NewTabUI::WasHidden() {
196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EmitNtpStatistics();
1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::Observe(int type,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const content::NotificationSource& source,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const content::NotificationDetails& details) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_paint_ = base::TimeTicks::Now();
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CHECK(false) << "Unexpected notification: " << type;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void NewTabUI::EmitNtpStatistics() {
213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  NTPUserDataLogger::GetOrCreateFromWebContents(
214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      web_contents())->EmitNtpStatistics();
2159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
2169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NewTabUI::OnShowBookmarkBarChanged() {
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::StringValue attached(
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetProfile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) ?
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "true" : "false");
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->CallJavascriptFunction("ntp.setBookmarkBarAttached", attached);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid NewTabUI::RegisterProfilePrefs(
2267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    user_prefs::PrefRegistrySyncable* registry) {
227a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  CoreAppLauncherHandler::RegisterProfilePrefs(registry);
2287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  NewTabPageHandler::RegisterProfilePrefs(registry);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NewTabUI::IsDiscoveryInNTPEnabled())
2307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SuggestionsHandler::RegisterProfilePrefs(registry);
2317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  MostVisitedHandler::RegisterProfilePrefs(registry);
2327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  browser_sync::ForeignSessionHandler::RegisterProfilePrefs(registry);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NewTabUI::ShouldShowApps() {
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Ash shows apps in app list thus should not show apps page in NTP4.
2385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#if defined(USE_ASH)
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return chrome::GetActiveDesktop() != chrome::HOST_DESKTOP_TYPE_ASH;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NewTabUI::IsDiscoveryInNTPEnabled() {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(beaudoin): The flag was removed during a clean-up pass. We leave that
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // here to easily enable it back when we will explore this option again.
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void NewTabUI::SetUrlTitleAndDirection(base::DictionaryValue* dictionary,
254a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                       const base::string16& title,
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const GURL& gurl) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary->SetString("url", gurl.spec());
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool using_url_as_the_title = false;
259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 title_to_set(title);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (title_to_set.empty()) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    using_url_as_the_title = true;
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    title_to_set = base::UTF8ToUTF16(gurl.spec());
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We set the "dir" attribute of the title, so that in RTL locales, a LTR
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // title is rendered left-to-right and truncated from the right. For example,
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the title of http://msdn.microsoft.com/en-us/default.aspx is "MSDN:
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Microsoft developer network". In RTL locales, in the [New Tab] page, if
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the "dir" of this title is not specified, it takes Chrome UI's
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // directionality. So the title will be truncated as "soft developer
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // network". Setting the "dir" attribute as "ltr" renders the truncated title
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // as "MSDN: Microsoft D...". As another example, the title of
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://yahoo.com is "Yahoo!". In RTL locales, in the [New Tab] page, the
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // title will be rendered as "!Yahoo" if its "dir" attribute is not set to
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "ltr".
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string direction;
277d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (using_url_as_the_title)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    direction = kLTRHtmlTextDirection;
279d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  else
280d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    direction = GetHtmlTextDirection(title);
281d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary->SetString("title", title_to_set);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary->SetString("direction", direction);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
287a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void NewTabUI::SetFullNameAndDirection(const base::string16& full_name,
288d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                       base::DictionaryValue* dictionary) {
289d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  dictionary->SetString("full_name", full_name);
290d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  dictionary->SetString("full_name_direction", GetHtmlTextDirection(full_name));
291d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
292d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
293d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// static
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NewTabUI* NewTabUI::FromWebUIController(WebUIController* ui) {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_live_new_tabs.Pointer()->count(ui))
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<NewTabUI*>(ui);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Profile* NewTabUI::GetProfile() const {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Profile::FromWebUI(web_ui());
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NewTabHTMLSource
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NewTabUI::NewTabHTMLSource::NewTabHTMLSource(Profile* profile)
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : profile_(profile) {
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string NewTabUI::NewTabHTMLSource::GetSource() const {
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return chrome::kChromeUINewTabHost;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NewTabUI::NewTabHTMLSource::StartDataRequest(
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& path,
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int render_process_id,
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int render_frame_id,
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const content::URLDataSource::GotDataCallback& callback) {
320e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<std::string, std::pair<std::string, int> >::iterator it =
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    resource_map_.find(path);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != resource_map_.end()) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedStaticMemory> resource_bytes(
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        it->second.second ?
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                it->second.second) :
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            new base::RefCountedStaticMemory);
330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callback.Run(resource_bytes.get());
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!path.empty() && path[0] != '#') {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // A path under new-tab was requested; it's likely a bad relative
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URL from the new tab page, but in any case it's an error.
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << path << " should not have been requested on the NTP";
338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    callback.Run(NULL);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content::RenderProcessHost* render_host =
343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      content::RenderProcessHost::FromID(render_process_id);
3443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  NTPResourceCache::WindowType win_type = NTPResourceCache::GetWindowType(
3453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      profile_, render_host);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::RefCountedMemory> html_bytes(
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NTPResourceCacheFactory::GetForProfile(profile_)->
3483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      GetNewTabHTML(win_type));
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  callback.Run(html_bytes.get());
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string NewTabUI::NewTabHTMLSource::GetMimeType(const std::string& resource)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<std::string, std::pair<std::string, int> >::const_iterator it =
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resource_map_.find(resource);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != resource_map_.end())
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return it->second.first;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return "text/html";
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NewTabUI::NewTabHTMLSource::ShouldReplaceExistingSource() const {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NewTabUI::NewTabHTMLSource::ShouldAddContentSecurityPolicy() const {
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabUI::NewTabHTMLSource::AddResource(const char* resource,
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const char* mime_type,
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             int resource_id) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(resource);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(mime_type);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resource_map_[std::string(resource)] =
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::make_pair(std::string(mime_type), resource_id);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NewTabUI::NewTabHTMLSource::~NewTabHTMLSource() {}
380