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: 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 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 112 RecentlyClosedTabsHandler::~RecentlyClosedTabsHandler() { 113 if (tab_restore_service_) 114 tab_restore_service_->RemoveObserver(this); 115 } 116 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 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 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 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: 175 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 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 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 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: 217 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 231 void NewTabPageSetHomePageHandler::RegisterMessages() { 232 web_ui_->RegisterMessageCallback("setHomePage", NewCallback( 233 this, &NewTabPageSetHomePageHandler::HandleSetHomePage)); 234 } 235 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: 255 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 269 void NewTabPageClosePromoHandler::RegisterMessages() { 270 web_ui_->RegisterMessageCallback("closePromo", NewCallback( 271 this, &NewTabPageClosePromoHandler::HandleClosePromo)); 272 } 273 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 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 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. 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 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 } 386 void NewTabUI::RenderViewCreated(RenderViewHost* render_view_host) { 387 StartTimingPaint(render_view_host); 388 } 389 390 void NewTabUI::RenderViewReused(RenderViewHost* render_view_host) { 391 StartTimingPaint(render_view_host); 392 } 393 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 428 void NewTabUI::InitializeCSSCaches() { 429 Profile* profile = GetProfile(); 430 ThemeSource* theme = new ThemeSource(profile); 431 profile->GetChromeURLDataManager()->AddDataSource(theme); 432 } 433 434 // static 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 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 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 463 bool NewTabUI::FirstRunDisabled() { 464 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 465 return command_line->HasSwitch(switches::kDisableNewTabFirstRun); 466 } 467 468 // static 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 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 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 574 NewTabUI::NewTabHTMLSource::NewTabHTMLSource(Profile* profile) 575 : DataSource(chrome::kChromeUINewTabHost, MessageLoop::current()), 576 profile_(profile) { 577 } 578 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 599 std::string NewTabUI::NewTabHTMLSource::GetMimeType(const std::string&) const { 600 return "text/html"; 601 } 602 603 bool NewTabUI::NewTabHTMLSource::ShouldReplaceExistingSource() const { 604 return false; 605 } 606