• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "build/build_config.h"
6 
7 #include "chrome/browser/ui/webui/new_tab_ui.h"
8 
9 #include <set>
10 
11 #include "base/callback.h"
12 #include "base/command_line.h"
13 #include "base/i18n/rtl.h"
14 #include "base/memory/singleton.h"
15 #include "base/metrics/histogram.h"
16 #include "base/string_number_conversions.h"
17 #include "base/threading/thread.h"
18 #include "base/utf_string_conversions.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/sessions/session_types.h"
23 #include "chrome/browser/sessions/tab_restore_service.h"
24 #include "chrome/browser/sessions/tab_restore_service_delegate.h"
25 #include "chrome/browser/sessions/tab_restore_service_observer.h"
26 #include "chrome/browser/sync/profile_sync_service.h"
27 #include "chrome/browser/themes/theme_service.h"
28 #include "chrome/browser/themes/theme_service_factory.h"
29 #include "chrome/browser/ui/browser.h"
30 #include "chrome/browser/ui/webui/app_launcher_handler.h"
31 #include "chrome/browser/ui/webui/foreign_session_handler.h"
32 #include "chrome/browser/ui/webui/most_visited_handler.h"
33 #include "chrome/browser/ui/webui/new_tab_page_sync_handler.h"
34 #include "chrome/browser/ui/webui/ntp_login_handler.h"
35 #include "chrome/browser/ui/webui/ntp_resource_cache.h"
36 #include "chrome/browser/ui/webui/shown_sections_handler.h"
37 #include "chrome/browser/ui/webui/theme_source.h"
38 #include "chrome/browser/ui/webui/value_helper.h"
39 #include "chrome/common/chrome_switches.h"
40 #include "chrome/common/extensions/extension.h"
41 #include "chrome/common/pref_names.h"
42 #include "chrome/common/url_constants.h"
43 #include "content/browser/browser_thread.h"
44 #include "content/browser/renderer_host/render_view_host.h"
45 #include "content/browser/tab_contents/tab_contents.h"
46 #include "content/common/notification_service.h"
47 #include "grit/generated_resources.h"
48 #include "grit/theme_resources.h"
49 #include "ui/base/l10n/l10n_util.h"
50 
51 namespace {
52 
53 // The number of recent bookmarks we show.
54 const int kRecentBookmarks = 9;
55 
56 // The number of search URLs to show.
57 const int kSearchURLs = 3;
58 
59 // The amount of time there must be no painting for us to consider painting
60 // finished.  Observed times are in the ~1200ms range on Windows.
61 const int kTimeoutMs = 2000;
62 
63 // Strings sent to the page via jstemplates used to set the direction of the
64 // HTML document based on locale.
65 const char kRTLHtmlTextDirection[] = "rtl";
66 const char kDefaultHtmlTextDirection[] = "ltr";
67 
68 ///////////////////////////////////////////////////////////////////////////////
69 // RecentlyClosedTabsHandler
70 
71 class RecentlyClosedTabsHandler : public WebUIMessageHandler,
72                                   public TabRestoreServiceObserver {
73  public:
RecentlyClosedTabsHandler()74   RecentlyClosedTabsHandler() : tab_restore_service_(NULL) {}
75   virtual ~RecentlyClosedTabsHandler();
76 
77   // WebUIMessageHandler implementation.
78   virtual void RegisterMessages();
79 
80   // Callback for the "reopenTab" message. Rewrites the history of the
81   // currently displayed tab to be the one in TabRestoreService with a
82   // history of a session passed in through the content pointer.
83   void HandleReopenTab(const ListValue* args);
84 
85   // Callback for the "getRecentlyClosedTabs" message.
86   void HandleGetRecentlyClosedTabs(const ListValue* args);
87 
88   // Observer callback for TabRestoreServiceObserver. Sends data on
89   // recently closed tabs to the javascript side of this page to
90   // display to the user.
91   virtual void TabRestoreServiceChanged(TabRestoreService* service);
92 
93   // Observer callback to notice when our associated TabRestoreService
94   // is destroyed.
95   virtual void TabRestoreServiceDestroyed(TabRestoreService* service);
96 
97  private:
98   // TabRestoreService that we are observing.
99   TabRestoreService* tab_restore_service_;
100 
101   DISALLOW_COPY_AND_ASSIGN(RecentlyClosedTabsHandler);
102 };
103 
RegisterMessages()104 void RecentlyClosedTabsHandler::RegisterMessages() {
105   web_ui_->RegisterMessageCallback("getRecentlyClosedTabs",
106       NewCallback(this,
107                   &RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs));
108   web_ui_->RegisterMessageCallback("reopenTab",
109       NewCallback(this, &RecentlyClosedTabsHandler::HandleReopenTab));
110 }
111 
~RecentlyClosedTabsHandler()112 RecentlyClosedTabsHandler::~RecentlyClosedTabsHandler() {
113   if (tab_restore_service_)
114     tab_restore_service_->RemoveObserver(this);
115 }
116 
HandleReopenTab(const ListValue * args)117 void RecentlyClosedTabsHandler::HandleReopenTab(const ListValue* args) {
118   TabRestoreServiceDelegate* delegate =
119       TabRestoreServiceDelegate::FindDelegateForController(
120       &web_ui_->tab_contents()->controller(), NULL);
121   if (!delegate)
122     return;
123 
124   int session_to_restore;
125   if (ExtractIntegerValue(args, &session_to_restore))
126     tab_restore_service_->RestoreEntryById(delegate, session_to_restore, true);
127   // The current tab has been nuked at this point; don't touch any member
128   // variables.
129 }
130 
HandleGetRecentlyClosedTabs(const ListValue * args)131 void RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs(
132     const ListValue* args) {
133   if (!tab_restore_service_) {
134     tab_restore_service_ = web_ui_->GetProfile()->GetTabRestoreService();
135 
136     // GetTabRestoreService() can return NULL (i.e., when in Off the
137     // Record mode)
138     if (tab_restore_service_) {
139       // This does nothing if the tabs have already been loaded or they
140       // shouldn't be loaded.
141       tab_restore_service_->LoadTabsFromLastSession();
142 
143       tab_restore_service_->AddObserver(this);
144     }
145   }
146 
147   if (tab_restore_service_)
148     TabRestoreServiceChanged(tab_restore_service_);
149 }
150 
TabRestoreServiceChanged(TabRestoreService * service)151 void RecentlyClosedTabsHandler::TabRestoreServiceChanged(
152     TabRestoreService* service) {
153   ListValue list_value;
154   NewTabUI::AddRecentlyClosedEntries(service->entries(), &list_value);
155 
156   web_ui_->CallJavascriptFunction("recentlyClosedTabs", list_value);
157 }
158 
TabRestoreServiceDestroyed(TabRestoreService * service)159 void RecentlyClosedTabsHandler::TabRestoreServiceDestroyed(
160     TabRestoreService* service) {
161   tab_restore_service_ = NULL;
162 }
163 
164 ///////////////////////////////////////////////////////////////////////////////
165 // MetricsHandler
166 
167 // Let the page contents record UMA actions. Only use when you can't do it from
168 // C++. For example, we currently use it to let the NTP log the postion of the
169 // Most Visited or Bookmark the user clicked on, as we don't get that
170 // information through RequestOpenURL. You will need to update the metrics
171 // dashboard with the action names you use, as our processor won't catch that
172 // information (treat it as RecordComputedMetrics)
173 class MetricsHandler : public WebUIMessageHandler {
174  public:
MetricsHandler()175   MetricsHandler() {}
~MetricsHandler()176   virtual ~MetricsHandler() {}
177 
178   // WebUIMessageHandler implementation.
179   virtual void RegisterMessages();
180 
181   // Callback which records a user action.
182   void HandleMetrics(const ListValue* args);
183 
184   // Callback for the "logEventTime" message.
185   void HandleLogEventTime(const ListValue* args);
186 
187  private:
188 
189   DISALLOW_COPY_AND_ASSIGN(MetricsHandler);
190 };
191 
RegisterMessages()192 void MetricsHandler::RegisterMessages() {
193   web_ui_->RegisterMessageCallback("metrics",
194       NewCallback(this, &MetricsHandler::HandleMetrics));
195 
196   web_ui_->RegisterMessageCallback("logEventTime",
197       NewCallback(this, &MetricsHandler::HandleLogEventTime));
198 }
199 
HandleMetrics(const ListValue * args)200 void MetricsHandler::HandleMetrics(const ListValue* args) {
201   std::string string_action = UTF16ToUTF8(ExtractStringValue(args));
202   UserMetrics::RecordComputedAction(string_action, web_ui_->GetProfile());
203 }
204 
HandleLogEventTime(const ListValue * args)205 void MetricsHandler::HandleLogEventTime(const ListValue* args) {
206   std::string event_name = UTF16ToUTF8(ExtractStringValue(args));
207   web_ui_->tab_contents()->LogNewTabTime(event_name);
208 }
209 
210 ///////////////////////////////////////////////////////////////////////////////
211 // NewTabPageSetHomePageHandler
212 
213 // Sets the new tab page as home page when user clicks on "make this my home
214 // page" link.
215 class NewTabPageSetHomePageHandler : public WebUIMessageHandler {
216  public:
NewTabPageSetHomePageHandler()217   NewTabPageSetHomePageHandler() {}
~NewTabPageSetHomePageHandler()218   virtual ~NewTabPageSetHomePageHandler() {}
219 
220   // WebUIMessageHandler implementation.
221   virtual void RegisterMessages();
222 
223   // Callback for "setHomePage".
224   void HandleSetHomePage(const ListValue* args);
225 
226  private:
227 
228   DISALLOW_COPY_AND_ASSIGN(NewTabPageSetHomePageHandler);
229 };
230 
RegisterMessages()231 void NewTabPageSetHomePageHandler::RegisterMessages() {
232   web_ui_->RegisterMessageCallback("setHomePage", NewCallback(
233       this, &NewTabPageSetHomePageHandler::HandleSetHomePage));
234 }
235 
HandleSetHomePage(const ListValue * args)236 void NewTabPageSetHomePageHandler::HandleSetHomePage(
237     const ListValue* args) {
238   web_ui_->GetProfile()->GetPrefs()->SetBoolean(prefs::kHomePageIsNewTabPage,
239                                                 true);
240   ListValue list_value;
241   list_value.Append(new StringValue(
242       l10n_util::GetStringUTF16(IDS_NEW_TAB_HOME_PAGE_SET_NOTIFICATION)));
243   list_value.Append(new StringValue(
244       l10n_util::GetStringUTF16(IDS_NEW_TAB_HOME_PAGE_HIDE_NOTIFICATION)));
245   web_ui_->CallJavascriptFunction("onHomePageSet", list_value);
246 }
247 
248 ///////////////////////////////////////////////////////////////////////////////
249 // NewTabPageClosePromoHandler
250 
251 // Turns off the promo line permanently when it has been explicitly closed by
252 // the user.
253 class NewTabPageClosePromoHandler : public WebUIMessageHandler {
254  public:
NewTabPageClosePromoHandler()255   NewTabPageClosePromoHandler() {}
~NewTabPageClosePromoHandler()256   virtual ~NewTabPageClosePromoHandler() {}
257 
258   // WebUIMessageHandler implementation.
259   virtual void RegisterMessages();
260 
261   // Callback for "closePromo".
262   void HandleClosePromo(const ListValue* args);
263 
264  private:
265 
266   DISALLOW_COPY_AND_ASSIGN(NewTabPageClosePromoHandler);
267 };
268 
RegisterMessages()269 void NewTabPageClosePromoHandler::RegisterMessages() {
270   web_ui_->RegisterMessageCallback("closePromo", NewCallback(
271       this, &NewTabPageClosePromoHandler::HandleClosePromo));
272 }
273 
HandleClosePromo(const ListValue * args)274 void NewTabPageClosePromoHandler::HandleClosePromo(
275     const ListValue* args) {
276   web_ui_->GetProfile()->GetPrefs()->SetBoolean(prefs::kNTPPromoClosed, true);
277   NotificationService* service = NotificationService::current();
278   service->Notify(NotificationType::PROMO_RESOURCE_STATE_CHANGED,
279                   Source<NewTabPageClosePromoHandler>(this),
280                   NotificationService::NoDetails());
281 }
282 
283 }  // namespace
284 
285 ///////////////////////////////////////////////////////////////////////////////
286 // NewTabUI
287 
NewTabUI(TabContents * contents)288 NewTabUI::NewTabUI(TabContents* contents)
289     : WebUI(contents) {
290   // Override some options on the Web UI.
291   hide_favicon_ = true;
292 
293   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kNewTabPage4))
294     force_bookmark_bar_visible_ = true;
295 
296   focus_location_bar_by_default_ = true;
297   should_hide_url_ = true;
298   overridden_title_ = l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
299 
300   // We count all link clicks as AUTO_BOOKMARK, so that site can be ranked more
301   // highly. Note this means we're including clicks on not only most visited
302   // thumbnails, but also clicks on recently bookmarked.
303   link_transition_type_ = PageTransition::AUTO_BOOKMARK;
304 
305   if (NewTabUI::FirstRunDisabled())
306     NewTabHTMLSource::set_first_run(false);
307 
308   static bool first_view = true;
309   if (first_view) {
310     first_view = false;
311   }
312 
313   if (!GetProfile()->IsOffTheRecord()) {
314     PrefService* pref_service = GetProfile()->GetPrefs();
315     AddMessageHandler((new NTPLoginHandler())->Attach(this));
316     AddMessageHandler((new ShownSectionsHandler(pref_service))->Attach(this));
317     AddMessageHandler((new browser_sync::ForeignSessionHandler())->
318       Attach(this));
319     AddMessageHandler((new MostVisitedHandler())->Attach(this));
320     AddMessageHandler((new RecentlyClosedTabsHandler())->Attach(this));
321     AddMessageHandler((new MetricsHandler())->Attach(this));
322     if (GetProfile()->IsSyncAccessible())
323       AddMessageHandler((new NewTabPageSyncHandler())->Attach(this));
324     ExtensionService* service = GetProfile()->GetExtensionService();
325     // We might not have an ExtensionService (on ChromeOS when not logged in
326     // for example).
327     if (service)
328       AddMessageHandler((new AppLauncherHandler(service))->Attach(this));
329 
330     AddMessageHandler((new NewTabPageSetHomePageHandler())->Attach(this));
331     AddMessageHandler((new NewTabPageClosePromoHandler())->Attach(this));
332   }
333 
334   // Initializing the CSS and HTML can require some CPU, so do it after
335   // we've hooked up the most visited handler.  This allows the DB query
336   // for the new tab thumbs to happen earlier.
337   InitializeCSSCaches();
338   NewTabHTMLSource* html_source =
339       new NewTabHTMLSource(GetProfile()->GetOriginalProfile());
340   contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
341 
342   // Listen for theme installation.
343   registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
344                  NotificationService::AllSources());
345   // Listen for bookmark bar visibility changes.
346   registrar_.Add(this, NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
347                  NotificationService::AllSources());
348 }
349 
~NewTabUI()350 NewTabUI::~NewTabUI() {
351 }
352 
353 // The timer callback.  If enough time has elapsed since the last paint
354 // message, we say we're done painting; otherwise, we keep waiting.
PaintTimeout()355 void NewTabUI::PaintTimeout() {
356   // The amount of time there must be no painting for us to consider painting
357   // finished.  Observed times are in the ~1200ms range on Windows.
358   base::TimeTicks now = base::TimeTicks::Now();
359   if ((now - last_paint_) >= base::TimeDelta::FromMilliseconds(kTimeoutMs)) {
360     // Painting has quieted down.  Log this as the full time to run.
361     base::TimeDelta load_time = last_paint_ - start_;
362     int load_time_ms = static_cast<int>(load_time.InMilliseconds());
363     NotificationService::current()->Notify(
364         NotificationType::INITIAL_NEW_TAB_UI_LOAD,
365         NotificationService::AllSources(),
366         Details<int>(&load_time_ms));
367     UMA_HISTOGRAM_TIMES("NewTabUI load", load_time);
368   } else {
369     // Not enough quiet time has elapsed.
370     // Some more paints must've occurred since we set the timeout.
371     // Wait some more.
372     timer_.Start(base::TimeDelta::FromMilliseconds(kTimeoutMs), this,
373                  &NewTabUI::PaintTimeout);
374   }
375 }
376 
StartTimingPaint(RenderViewHost * render_view_host)377 void NewTabUI::StartTimingPaint(RenderViewHost* render_view_host) {
378   start_ = base::TimeTicks::Now();
379   last_paint_ = start_;
380   registrar_.Add(this, NotificationType::RENDER_WIDGET_HOST_DID_PAINT,
381       Source<RenderWidgetHost>(render_view_host));
382   timer_.Start(base::TimeDelta::FromMilliseconds(kTimeoutMs), this,
383                &NewTabUI::PaintTimeout);
384 
385 }
RenderViewCreated(RenderViewHost * render_view_host)386 void NewTabUI::RenderViewCreated(RenderViewHost* render_view_host) {
387   StartTimingPaint(render_view_host);
388 }
389 
RenderViewReused(RenderViewHost * render_view_host)390 void NewTabUI::RenderViewReused(RenderViewHost* render_view_host) {
391   StartTimingPaint(render_view_host);
392 }
393 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)394 void NewTabUI::Observe(NotificationType type,
395                        const NotificationSource& source,
396                        const NotificationDetails& details) {
397   switch (type.value) {
398     case NotificationType::BROWSER_THEME_CHANGED: {
399       InitializeCSSCaches();
400       ListValue args;
401       args.Append(Value::CreateStringValue(
402           ThemeServiceFactory::GetForProfile(GetProfile())->HasCustomImage(
403               IDR_THEME_NTP_ATTRIBUTION) ?
404           "true" : "false"));
405       CallJavascriptFunction("themeChanged", args);
406       break;
407     }
408     case NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED: {
409       if (GetProfile()->GetPrefs()->IsManagedPreference(
410               prefs::kEnableBookmarkBar)) {
411         break;
412       }
413       if (GetProfile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar))
414         CallJavascriptFunction("bookmarkBarAttached");
415       else
416         CallJavascriptFunction("bookmarkBarDetached");
417       break;
418     }
419     case NotificationType::RENDER_WIDGET_HOST_DID_PAINT: {
420       last_paint_ = base::TimeTicks::Now();
421       break;
422     }
423     default:
424       CHECK(false) << "Unexpected notification: " << type.value;
425   }
426 }
427 
InitializeCSSCaches()428 void NewTabUI::InitializeCSSCaches() {
429   Profile* profile = GetProfile();
430   ThemeSource* theme = new ThemeSource(profile);
431   profile->GetChromeURLDataManager()->AddDataSource(theme);
432 }
433 
434 // static
RegisterUserPrefs(PrefService * prefs)435 void NewTabUI::RegisterUserPrefs(PrefService* prefs) {
436   prefs->RegisterIntegerPref(prefs::kNTPPrefVersion, 0);
437 
438   MostVisitedHandler::RegisterUserPrefs(prefs);
439   ShownSectionsHandler::RegisterUserPrefs(prefs);
440 
441   UpdateUserPrefsVersion(prefs);
442 }
443 
444 // static
UpdateUserPrefsVersion(PrefService * prefs)445 bool NewTabUI::UpdateUserPrefsVersion(PrefService* prefs) {
446   const int old_pref_version = prefs->GetInteger(prefs::kNTPPrefVersion);
447   if (old_pref_version != current_pref_version()) {
448     MigrateUserPrefs(prefs, old_pref_version, current_pref_version());
449     prefs->SetInteger(prefs::kNTPPrefVersion, current_pref_version());
450     return true;
451   }
452   return false;
453 }
454 
455 // static
MigrateUserPrefs(PrefService * prefs,int old_pref_version,int new_pref_version)456 void NewTabUI::MigrateUserPrefs(PrefService* prefs, int old_pref_version,
457                                 int new_pref_version) {
458   ShownSectionsHandler::MigrateUserPrefs(prefs, old_pref_version,
459                                          current_pref_version());
460 }
461 
462 // static
FirstRunDisabled()463 bool NewTabUI::FirstRunDisabled() {
464   const CommandLine* command_line = CommandLine::ForCurrentProcess();
465   return command_line->HasSwitch(switches::kDisableNewTabFirstRun);
466 }
467 
468 // static
SetURLTitleAndDirection(DictionaryValue * dictionary,const string16 & title,const GURL & gurl)469 void NewTabUI::SetURLTitleAndDirection(DictionaryValue* dictionary,
470                                        const string16& title,
471                                        const GURL& gurl) {
472   dictionary->SetString("url", gurl.spec());
473 
474   bool using_url_as_the_title = false;
475   string16 title_to_set(title);
476   if (title_to_set.empty()) {
477     using_url_as_the_title = true;
478     title_to_set = UTF8ToUTF16(gurl.spec());
479   }
480 
481   // We set the "dir" attribute of the title, so that in RTL locales, a LTR
482   // title is rendered left-to-right and truncated from the right. For example,
483   // the title of http://msdn.microsoft.com/en-us/default.aspx is "MSDN:
484   // Microsoft developer network". In RTL locales, in the [New Tab] page, if
485   // the "dir" of this title is not specified, it takes Chrome UI's
486   // directionality. So the title will be truncated as "soft developer
487   // network". Setting the "dir" attribute as "ltr" renders the truncated title
488   // as "MSDN: Microsoft D...". As another example, the title of
489   // http://yahoo.com is "Yahoo!". In RTL locales, in the [New Tab] page, the
490   // title will be rendered as "!Yahoo" if its "dir" attribute is not set to
491   // "ltr".
492   //
493   // Since the title can contain BiDi text, we need to mark the text as either
494   // RTL or LTR, depending on the characters in the string. If we use the URL
495   // as the title, we mark the title as LTR since URLs are always treated as
496   // left to right strings. Simply setting the title's "dir" attribute works
497   // fine for rendering and truncating the title. However, it does not work for
498   // entire title within a tooltip when the mouse is over the title link.. For
499   // example, without LRE-PDF pair, the title "Yahoo!" will be rendered as
500   // "!Yahoo" within the tooltip when the mouse is over the title link.
501   std::string direction = kDefaultHtmlTextDirection;
502   if (base::i18n::IsRTL()) {
503     if (using_url_as_the_title) {
504       base::i18n::WrapStringWithLTRFormatting(&title_to_set);
505     } else {
506       if (base::i18n::StringContainsStrongRTLChars(title)) {
507         base::i18n::WrapStringWithRTLFormatting(&title_to_set);
508         direction = kRTLHtmlTextDirection;
509       } else {
510         base::i18n::WrapStringWithLTRFormatting(&title_to_set);
511       }
512     }
513   }
514   dictionary->SetString("title", title_to_set);
515   dictionary->SetString("direction", direction);
516 }
517 
518 namespace {
519 
IsTabUnique(const DictionaryValue * tab,std::set<std::string> * unique_items)520 bool IsTabUnique(const DictionaryValue* tab,
521                  std::set<std::string>* unique_items) {
522   DCHECK(unique_items);
523   std::string title;
524   std::string url;
525   if (tab->GetString("title", &title) &&
526       tab->GetString("url", &url)) {
527     // TODO(viettrungluu): this isn't obviously reliable, since different
528     // combinations of titles/urls may conceivably yield the same string.
529     std::string unique_key = title + url;
530     if (unique_items->find(unique_key) != unique_items->end())
531       return false;
532     else
533       unique_items->insert(unique_key);
534   }
535   return true;
536 }
537 
538 }  // namespace
539 
540 // static
AddRecentlyClosedEntries(const TabRestoreService::Entries & entries,ListValue * entry_list_value)541 void NewTabUI::AddRecentlyClosedEntries(
542     const TabRestoreService::Entries& entries, ListValue* entry_list_value) {
543   const int max_count = 10;
544   int added_count = 0;
545   std::set<std::string> unique_items;
546   // We filter the list of recently closed to only show 'interesting' entries,
547   // where an interesting entry is either a closed window or a closed tab
548   // whose selected navigation is not the new tab ui.
549   for (TabRestoreService::Entries::const_iterator it = entries.begin();
550        it != entries.end() && added_count < max_count; ++it) {
551     TabRestoreService::Entry* entry = *it;
552     scoped_ptr<DictionaryValue> entry_dict(new DictionaryValue());
553     if ((entry->type == TabRestoreService::TAB &&
554          ValueHelper::TabToValue(
555              *static_cast<TabRestoreService::Tab*>(entry),
556              entry_dict.get()) &&
557          IsTabUnique(entry_dict.get(), &unique_items)) ||
558         (entry->type == TabRestoreService::WINDOW &&
559          ValueHelper::WindowToValue(
560              *static_cast<TabRestoreService::Window*>(entry),
561              entry_dict.get()))) {
562       entry_dict->SetInteger("sessionId", entry->id);
563       entry_list_value->Append(entry_dict.release());
564       added_count++;
565     }
566   }
567 }
568 
569 ///////////////////////////////////////////////////////////////////////////////
570 // NewTabHTMLSource
571 
572 bool NewTabUI::NewTabHTMLSource::first_run_ = true;
573 
NewTabHTMLSource(Profile * profile)574 NewTabUI::NewTabHTMLSource::NewTabHTMLSource(Profile* profile)
575     : DataSource(chrome::kChromeUINewTabHost, MessageLoop::current()),
576       profile_(profile) {
577 }
578 
StartDataRequest(const std::string & path,bool is_incognito,int request_id)579 void NewTabUI::NewTabHTMLSource::StartDataRequest(const std::string& path,
580                                                   bool is_incognito,
581                                                   int request_id) {
582   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
583 
584   if (AppLauncherHandler::HandlePing(profile_, path)) {
585     return;
586   } else if (!path.empty() && path[0] != '#') {
587     // A path under new-tab was requested; it's likely a bad relative
588     // URL from the new tab page, but in any case it's an error.
589     NOTREACHED();
590     return;
591   }
592 
593   scoped_refptr<RefCountedBytes> html_bytes(
594       profile_->GetNTPResourceCache()->GetNewTabHTML(is_incognito));
595 
596   SendResponse(request_id, html_bytes);
597 }
598 
GetMimeType(const std::string &) const599 std::string NewTabUI::NewTabHTMLSource::GetMimeType(const std::string&) const {
600   return "text/html";
601 }
602 
ShouldReplaceExistingSource() const603 bool NewTabUI::NewTabHTMLSource::ShouldReplaceExistingSource() const {
604   return false;
605 }
606