133b9d1a8e5b769a823c482d2f65139f8cf7b662
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / search / search_tab_helper.cc
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/search/search_tab_helper.h"
6
7 #include <set>
8
9 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/string_util.h"
13 #include "build/build_config.h"
14 #include "chrome/browser/history/most_visited_tiles_experiment.h"
15 #include "chrome/browser/history/top_sites.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/search/instant_service.h"
18 #include "chrome/browser/search/instant_service_factory.h"
19 #include "chrome/browser/search/search.h"
20 #include "chrome/browser/signin/signin_manager.h"
21 #include "chrome/browser/signin/signin_manager_factory.h"
22 #include "chrome/browser/ui/app_list/app_list_util.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_finder.h"
25 #include "chrome/browser/ui/browser_navigator.h"
26 #include "chrome/browser/ui/browser_window.h"
27 #include "chrome/browser/ui/omnibox/location_bar.h"
28 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
29 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
30 #include "chrome/browser/ui/omnibox/omnibox_view.h"
31 #include "chrome/browser/ui/search/search_ipc_router_policy_impl.h"
32 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
33 #include "chrome/browser/ui/tabs/tab_strip_model.h"
34 #include "chrome/browser/ui/tabs/tab_strip_model_utils.h"
35 #include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
36 #include "chrome/common/url_constants.h"
37 #include "content/public/browser/navigation_controller.h"
38 #include "content/public/browser/navigation_details.h"
39 #include "content/public/browser/navigation_entry.h"
40 #include "content/public/browser/navigation_type.h"
41 #include "content/public/browser/render_process_host.h"
42 #include "content/public/browser/user_metrics.h"
43 #include "content/public/browser/web_contents.h"
44 #include "content/public/browser/web_contents_view.h"
45 #include "content/public/common/page_transition_types.h"
46 #include "content/public/common/referrer.h"
47 #include "grit/generated_resources.h"
48 #include "net/base/net_errors.h"
49 #include "ui/base/l10n/l10n_util.h"
50 #include "url/gurl.h"
51
52 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SearchTabHelper);
53
54 namespace {
55
56 // For reporting Cacheable NTP navigations.
57 enum CacheableNTPLoad {
58   CACHEABLE_NTP_LOAD_FAILED = 0,
59   CACHEABLE_NTP_LOAD_SUCCEEDED = 1,
60   CACHEABLE_NTP_LOAD_MAX = 2
61 };
62
63 void RecordCacheableNTPLoadHistogram(bool succeeded) {
64   UMA_HISTOGRAM_ENUMERATION("InstantExtended.CacheableNTPLoad",
65                             succeeded ? CACHEABLE_NTP_LOAD_SUCCEEDED :
66                                 CACHEABLE_NTP_LOAD_FAILED,
67                             CACHEABLE_NTP_LOAD_MAX);
68 }
69
70 bool IsCacheableNTP(const content::WebContents* contents) {
71   const content::NavigationEntry* entry =
72       contents->GetController().GetLastCommittedEntry();
73   return chrome::NavEntryIsInstantNTP(contents, entry) &&
74       entry->GetURL() != GURL(chrome::kChromeSearchLocalNtpUrl);
75 }
76
77 bool IsNTP(const content::WebContents* contents) {
78   // We can't use WebContents::GetURL() because that uses the active entry,
79   // whereas we want the visible entry.
80   const content::NavigationEntry* entry =
81       contents->GetController().GetVisibleEntry();
82   if (entry && entry->GetVirtualURL() == GURL(chrome::kChromeUINewTabURL))
83     return true;
84
85   return chrome::IsInstantNTP(contents);
86 }
87
88 bool IsSearchResults(const content::WebContents* contents) {
89   return !chrome::GetSearchTerms(contents).empty();
90 }
91
92 bool IsLocal(const content::WebContents* contents) {
93   if (!contents)
94     return false;
95   const content::NavigationEntry* entry =
96       contents->GetController().GetVisibleEntry();
97   return entry && entry->GetURL() == GURL(chrome::kChromeSearchLocalNtpUrl);
98 }
99
100 // Returns true if |contents| are rendered inside an Instant process.
101 bool InInstantProcess(Profile* profile,
102                       const content::WebContents* contents) {
103   if (!profile || !contents)
104     return false;
105
106   InstantService* instant_service =
107       InstantServiceFactory::GetForProfile(profile);
108   return instant_service &&
109       instant_service->IsInstantProcess(
110           contents->GetRenderProcessHost()->GetID());
111 }
112
113 // Updates the location bar to reflect |contents| Instant support state.
114 void UpdateLocationBar(content::WebContents* contents) {
115 // iOS and Android don't use the Instant framework.
116 #if !defined(OS_IOS) && !defined(OS_ANDROID)
117   if (!contents)
118     return;
119
120   Browser* browser = chrome::FindBrowserWithWebContents(contents);
121   if (!browser)
122     return;
123   browser->OnWebContentsInstantSupportDisabled(contents);
124 #endif
125 }
126
127 // Called when an NTP finishes loading. If the load start time was noted,
128 // calculates and logs the total load time.
129 void RecordNewTabLoadTime(content::WebContents* contents) {
130   CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents);
131   if (core_tab_helper->new_tab_start_time().is_null())
132     return;
133
134   base::TimeDelta duration =
135       base::TimeTicks::Now() - core_tab_helper->new_tab_start_time();
136   UMA_HISTOGRAM_TIMES("Tab.NewTabOnload", duration);
137   core_tab_helper->set_new_tab_start_time(base::TimeTicks());
138 }
139
140 }  // namespace
141
142 SearchTabHelper::SearchTabHelper(content::WebContents* web_contents)
143     : WebContentsObserver(web_contents),
144       is_search_enabled_(chrome::IsInstantExtendedAPIEnabled()),
145       user_input_in_progress_(false),
146       web_contents_(web_contents),
147       ipc_router_(web_contents, this,
148                   make_scoped_ptr(new SearchIPCRouterPolicyImpl(web_contents))
149                       .PassAs<SearchIPCRouter::Policy>()),
150       instant_service_(NULL) {
151   if (!is_search_enabled_)
152     return;
153
154   instant_service_ =
155       InstantServiceFactory::GetForProfile(
156           Profile::FromBrowserContext(web_contents_->GetBrowserContext()));
157   if (instant_service_)
158     instant_service_->AddObserver(this);
159 }
160
161 SearchTabHelper::~SearchTabHelper() {
162   if (instant_service_)
163     instant_service_->RemoveObserver(this);
164 }
165
166 void SearchTabHelper::InitForPreloadedNTP() {
167   UpdateMode(true, true);
168 }
169
170 void SearchTabHelper::OmniboxEditModelChanged(bool user_input_in_progress,
171                                               bool cancelling) {
172   if (!is_search_enabled_)
173     return;
174
175   user_input_in_progress_ = user_input_in_progress;
176   if (!user_input_in_progress && !cancelling)
177     return;
178
179   UpdateMode(false, false);
180 }
181
182 void SearchTabHelper::NavigationEntryUpdated() {
183   if (!is_search_enabled_)
184     return;
185
186   UpdateMode(false, false);
187 }
188
189 void SearchTabHelper::InstantSupportChanged(bool instant_support) {
190   if (!is_search_enabled_)
191     return;
192
193   InstantSupportState new_state = instant_support ? INSTANT_SUPPORT_YES :
194       INSTANT_SUPPORT_NO;
195
196   model_.SetInstantSupportState(new_state);
197
198   content::NavigationEntry* entry =
199       web_contents_->GetController().GetVisibleEntry();
200   if (entry) {
201     chrome::SetInstantSupportStateInNavigationEntry(new_state, entry);
202     if (!instant_support)
203       UpdateLocationBar(web_contents_);
204   }
205 }
206
207 bool SearchTabHelper::SupportsInstant() const {
208   return model_.instant_support() == INSTANT_SUPPORT_YES;
209 }
210
211 void SearchTabHelper::SetSuggestionToPrefetch(
212     const InstantSuggestion& suggestion) {
213   ipc_router_.SetSuggestionToPrefetch(suggestion);
214 }
215
216 void SearchTabHelper::Submit(const base::string16& text) {
217   ipc_router_.Submit(text);
218 }
219
220 void SearchTabHelper::OnTabActivated() {
221   ipc_router_.OnTabActivated();
222 }
223
224 void SearchTabHelper::OnTabDeactivated() {
225   ipc_router_.OnTabDeactivated();
226 }
227
228 void SearchTabHelper::ToggleVoiceSearch() {
229   ipc_router_.ToggleVoiceSearch();
230 }
231
232 bool SearchTabHelper::IsSearchResultsPage() {
233   return model_.mode().is_origin_search();
234 }
235
236 void SearchTabHelper::RenderViewCreated(
237     content::RenderViewHost* render_view_host) {
238   ipc_router_.SetPromoInformation(IsAppLauncherEnabled());
239 }
240
241 void SearchTabHelper::DidStartNavigationToPendingEntry(
242     const GURL& url,
243     content::NavigationController::ReloadType /* reload_type */) {
244   if (chrome::IsNTPURL(url, profile())) {
245     // Set the title on any pending entry corresponding to the NTP. This
246     // prevents any flickering of the tab title.
247     content::NavigationEntry* entry =
248         web_contents_->GetController().GetPendingEntry();
249     if (entry)
250       entry->SetTitle(l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
251   }
252 }
253
254 void SearchTabHelper::DidNavigateMainFrame(
255     const content::LoadCommittedDetails& details,
256     const content::FrameNavigateParams& params) {
257   if (IsCacheableNTP(web_contents_)) {
258     if (details.http_status_code == 204 || details.http_status_code >= 400) {
259       RedirectToLocalNTP();
260       RecordCacheableNTPLoadHistogram(false);
261       return;
262     }
263     RecordCacheableNTPLoadHistogram(true);
264   }
265
266   // Always set the title on the new tab page to be the one from our UI
267   // resources. Normally, we set the title when we begin a NTP load, but it can
268   // get reset in several places (like when you press Reload). This check
269   // ensures that the title is properly set to the string defined by the Chrome
270   // UI language (rather than the server language) in all cases.
271   //
272   // We only override the title when it's nonempty to allow the page to set the
273   // title if it really wants. An empty title means to use the default. There's
274   // also a race condition between this code and the page's SetTitle call which
275   // this rule avoids.
276   content::NavigationEntry* entry =
277       web_contents_->GetController().GetLastCommittedEntry();
278   if (entry && entry->GetTitle().empty() &&
279       (entry->GetVirtualURL() == GURL(chrome::kChromeUINewTabURL) ||
280        chrome::NavEntryIsInstantNTP(web_contents_, entry))) {
281     entry->SetTitle(l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
282   }
283 }
284
285 void SearchTabHelper::DidFailProvisionalLoad(
286     int64 /* frame_id */,
287     const base::string16& /* frame_unique_name */,
288     bool is_main_frame,
289     const GURL& validated_url,
290     int error_code,
291     const base::string16& /* error_description */,
292     content::RenderViewHost* /* render_view_host */) {
293   // If error_code is ERR_ABORTED means that the user has canceled this
294   // navigation so it shouldn't be redirected.
295   if (is_main_frame &&
296       error_code != net::ERR_ABORTED &&
297       validated_url != GURL(chrome::kChromeSearchLocalNtpUrl) &&
298       chrome::IsNTPURL(validated_url, profile())) {
299     RedirectToLocalNTP();
300     RecordCacheableNTPLoadHistogram(false);
301   }
302 }
303
304 void SearchTabHelper::DidFinishLoad(
305     int64 /* frame_id */,
306     const GURL&  /* validated_url */,
307     bool is_main_frame,
308     content::RenderViewHost* /* render_view_host */) {
309   if (is_main_frame) {
310     if (chrome::IsInstantNTP(web_contents_))
311       RecordNewTabLoadTime(web_contents_);
312
313     DetermineIfPageSupportsInstant();
314   }
315 }
316
317 void SearchTabHelper::NavigationEntryCommitted(
318     const content::LoadCommittedDetails& load_details) {
319   if (!is_search_enabled_)
320     return;
321
322   if (!load_details.is_main_frame)
323     return;
324
325   if (chrome::ShouldAssignURLToInstantRenderer(web_contents_->GetURL(),
326                                                profile())) {
327     InstantService* instant_service =
328         InstantServiceFactory::GetForProfile(profile());
329     ipc_router_.SetOmniboxStartMargin(instant_service->omnibox_start_margin());
330     ipc_router_.SetDisplayInstantResults();
331   }
332
333   UpdateMode(true, false);
334
335   content::NavigationEntry* entry =
336       web_contents_->GetController().GetVisibleEntry();
337   DCHECK(entry);
338
339   // Already determined the instant support state for this page, do not reset
340   // the instant support state.
341   //
342   // When we get a navigation entry committed event, there seem to be two ways
343   // to tell whether the navigation was "in-page". Ideally, when
344   // LoadCommittedDetails::is_in_page is true, we should have
345   // LoadCommittedDetails::type to be NAVIGATION_TYPE_IN_PAGE. Unfortunately,
346   // they are different in some cases. To workaround this bug, we are checking
347   // (is_in_page || type == NAVIGATION_TYPE_IN_PAGE). Please refer to
348   // crbug.com/251330 for more details.
349   if (load_details.is_in_page ||
350       load_details.type == content::NAVIGATION_TYPE_IN_PAGE) {
351     // When an "in-page" navigation happens, we will not receive a
352     // DidFinishLoad() event. Therefore, we will not determine the Instant
353     // support for the navigated page. So, copy over the Instant support from
354     // the previous entry. If the page does not support Instant, update the
355     // location bar from here to turn off search terms replacement.
356     chrome::SetInstantSupportStateInNavigationEntry(model_.instant_support(),
357                                                     entry);
358     if (model_.instant_support() == INSTANT_SUPPORT_NO)
359       UpdateLocationBar(web_contents_);
360     return;
361   }
362
363   model_.SetInstantSupportState(INSTANT_SUPPORT_UNKNOWN);
364   model_.SetVoiceSearchSupported(false);
365   chrome::SetInstantSupportStateInNavigationEntry(model_.instant_support(),
366                                                   entry);
367 }
368
369 void SearchTabHelper::OnInstantSupportDetermined(bool supports_instant) {
370   InstantSupportChanged(supports_instant);
371 }
372
373 void SearchTabHelper::OnSetVoiceSearchSupport(bool supports_voice_search) {
374   model_.SetVoiceSearchSupported(supports_voice_search);
375 }
376
377 void SearchTabHelper::ThemeInfoChanged(const ThemeBackgroundInfo& theme_info) {
378   ipc_router_.SendThemeBackgroundInfo(theme_info);
379 }
380
381 void SearchTabHelper::MostVisitedItemsChanged(
382     const std::vector<InstantMostVisitedItem>& items) {
383   std::vector<InstantMostVisitedItem> items_copy(items);
384   MaybeRemoveMostVisitedItems(&items_copy);
385   ipc_router_.SendMostVisitedItems(items_copy);
386 }
387
388 void SearchTabHelper::OmniboxStartMarginChanged(int omnibox_start_margin) {
389   ipc_router_.SetOmniboxStartMargin(omnibox_start_margin);
390 }
391
392 void SearchTabHelper::MaybeRemoveMostVisitedItems(
393     std::vector<InstantMostVisitedItem>* items) {
394 // The code below uses APIs not available on Android and the experiment should
395 // not run there.
396 #if !defined(OS_ANDROID)
397   if (!history::MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled())
398     return;
399
400   Profile* profile =
401       Profile::FromBrowserContext(web_contents_->GetBrowserContext());
402   if (!profile)
403     return;
404
405   Browser* browser = chrome::FindBrowserWithProfile(profile,
406                                                     chrome::GetActiveDesktop());
407   if (!browser)
408     return;
409
410   TabStripModel* tab_strip_model = browser->tab_strip_model();
411   history::TopSites* top_sites = profile->GetTopSites();
412   if (!tab_strip_model || !top_sites) {
413     NOTREACHED();
414     return;
415   }
416
417   std::set<std::string> open_urls;
418   chrome::GetOpenUrls(*tab_strip_model, *top_sites, &open_urls);
419   history::MostVisitedTilesExperiment::RemoveItemsMatchingOpenTabs(
420       open_urls, items);
421 #endif
422 }
423
424 void SearchTabHelper::FocusOmnibox(OmniboxFocusState state) {
425 // iOS and Android don't use the Instant framework.
426 #if !defined(OS_IOS) && !defined(OS_ANDROID)
427   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
428   if (!browser)
429     return;
430
431   OmniboxView* omnibox = browser->window()->GetLocationBar()->GetOmniboxView();
432   // Do not add a default case in the switch block for the following reasons:
433   // (1) Explicitly handle the new states. If new states are added in the
434   // OmniboxFocusState, the compiler will warn the developer to handle the new
435   // states.
436   // (2) An attacker may control the renderer and sends the browser process a
437   // malformed IPC. This function responds to the invalid |state| values by
438   // doing nothing instead of crashing the browser process (intentional no-op).
439   switch (state) {
440     case OMNIBOX_FOCUS_VISIBLE:
441       omnibox->SetFocus();
442       omnibox->model()->SetCaretVisibility(true);
443       break;
444     case OMNIBOX_FOCUS_INVISIBLE:
445       omnibox->SetFocus();
446       omnibox->model()->SetCaretVisibility(false);
447       // If the user clicked on the fakebox, any text already in the omnibox
448       // should get cleared when they start typing. Selecting all the existing
449       // text is a convenient way to accomplish this. It also gives a slight
450       // visual cue to users who really understand selection state about what
451       // will happen if they start typing.
452       omnibox->SelectAll(false);
453       omnibox->ShowImeIfNeeded();
454       break;
455     case OMNIBOX_FOCUS_NONE:
456       // Remove focus only if the popup is closed. This will prevent someone
457       // from changing the omnibox value and closing the popup without user
458       // interaction.
459       if (!omnibox->model()->popup_model()->IsOpen())
460         web_contents()->GetView()->Focus();
461       break;
462   }
463 #endif
464 }
465
466 void SearchTabHelper::NavigateToURL(const GURL& url,
467                                     WindowOpenDisposition disposition,
468                                     bool is_most_visited_item_url) {
469 // iOS and Android don't use the Instant framework.
470 #if !defined(OS_IOS) && !defined(OS_ANDROID)
471   // TODO(kmadhusu): Remove chrome::FindBrowser...() function call from here.
472   // Create a SearchTabHelperDelegate interface and have the Browser object
473   // implement that interface to provide the necessary functionality.
474   Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
475   Profile* profile =
476       Profile::FromBrowserContext(web_contents_->GetBrowserContext());
477   if (!browser || !profile)
478     return;
479
480   if (is_most_visited_item_url) {
481     content::RecordAction(
482         base::UserMetricsAction("InstantExtended.MostVisitedClicked"));
483   }
484
485   chrome::NavigateParams params(browser, url,
486                                 content::PAGE_TRANSITION_AUTO_BOOKMARK);
487   params.referrer = content::Referrer();
488   params.source_contents = web_contents_;
489   params.disposition = disposition;
490   params.is_renderer_initiated = false;
491   params.initiating_profile = profile;
492   chrome::Navigate(&params);
493 #endif
494 }
495
496 void SearchTabHelper::OnDeleteMostVisitedItem(const GURL& url) {
497   DCHECK(!url.is_empty());
498   if (instant_service_)
499     instant_service_->DeleteMostVisitedItem(url);
500 }
501
502 void SearchTabHelper::OnUndoMostVisitedDeletion(const GURL& url) {
503   DCHECK(!url.is_empty());
504   if (instant_service_)
505     instant_service_->UndoMostVisitedDeletion(url);
506 }
507
508 void SearchTabHelper::OnUndoAllMostVisitedDeletions() {
509   if (instant_service_)
510     instant_service_->UndoAllMostVisitedDeletions();
511 }
512
513 void SearchTabHelper::OnLogEvent(NTPLoggingEventType event) {
514   NTPUserDataLogger::GetOrCreateFromWebContents(
515       web_contents())->LogEvent(event);
516 }
517
518 void SearchTabHelper::OnLogImpression(int position,
519                                       const base::string16& provider) {
520   NTPUserDataLogger::GetOrCreateFromWebContents(
521       web_contents())->LogImpression(position, provider);
522 }
523
524 void SearchTabHelper::PasteIntoOmnibox(const base::string16& text) {
525 // iOS and Android don't use the Instant framework.
526 #if !defined(OS_IOS) && !defined(OS_ANDROID)
527   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
528   if (!browser)
529     return;
530
531   OmniboxView* omnibox = browser->window()->GetLocationBar()->GetOmniboxView();
532   // The first case is for right click to paste, where the text is retrieved
533   // from the clipboard already sanitized. The second case is needed to handle
534   // drag-and-drop value and it has to be sanitazed before setting it into the
535   // omnibox.
536   base::string16 text_to_paste = text.empty() ? omnibox->GetClipboardText() :
537       omnibox->SanitizeTextForPaste(text);
538
539   if (text_to_paste.empty())
540     return;
541
542   if (!omnibox->model()->has_focus())
543     omnibox->SetFocus();
544
545   omnibox->OnBeforePossibleChange();
546   omnibox->model()->OnPaste();
547   omnibox->SetUserText(text_to_paste);
548   omnibox->OnAfterPossibleChange();
549 #endif
550 }
551
552 void SearchTabHelper::OnChromeIdentityCheck(const base::string16& identity) {
553   SigninManagerBase* manager = SigninManagerFactory::GetForProfile(profile());
554   if (manager) {
555     const base::string16 username =
556         base::UTF8ToUTF16(manager->GetAuthenticatedUsername());
557     ipc_router_.SendChromeIdentityCheckResult(identity,
558                                               identity == username);
559   }
560 }
561
562 void SearchTabHelper::UpdateMode(bool update_origin, bool is_preloaded_ntp) {
563   SearchMode::Type type = SearchMode::MODE_DEFAULT;
564   SearchMode::Origin origin = SearchMode::ORIGIN_DEFAULT;
565   if (IsNTP(web_contents_) || is_preloaded_ntp) {
566     type = SearchMode::MODE_NTP;
567     origin = SearchMode::ORIGIN_NTP;
568   } else if (IsSearchResults(web_contents_)) {
569     type = SearchMode::MODE_SEARCH_RESULTS;
570     origin = SearchMode::ORIGIN_SEARCH;
571   }
572   if (!update_origin)
573     origin = model_.mode().origin;
574   if (user_input_in_progress_)
575     type = SearchMode::MODE_SEARCH_SUGGESTIONS;
576   model_.SetMode(SearchMode(type, origin));
577 }
578
579 void SearchTabHelper::DetermineIfPageSupportsInstant() {
580   if (!InInstantProcess(profile(), web_contents_)) {
581     // The page is not in the Instant process. This page does not support
582     // instant. If we send an IPC message to a page that is not in the Instant
583     // process, it will never receive it and will never respond. Therefore,
584     // return immediately.
585     InstantSupportChanged(false);
586   } else if (IsLocal(web_contents_)) {
587     // Local pages always support Instant.
588     InstantSupportChanged(true);
589   } else {
590     ipc_router_.DetermineIfPageSupportsInstant();
591   }
592 }
593
594 Profile* SearchTabHelper::profile() const {
595   return Profile::FromBrowserContext(web_contents_->GetBrowserContext());
596 }
597
598 void SearchTabHelper::RedirectToLocalNTP() {
599   // Extra parentheses to declare a variable.
600   content::NavigationController::LoadURLParams load_params(
601       (GURL(chrome::kChromeSearchLocalNtpUrl)));
602   load_params.referrer = content::Referrer();
603   load_params.transition_type = content::PAGE_TRANSITION_SERVER_REDIRECT;
604   // Don't push a history entry.
605   load_params.should_replace_current_entry = true;
606   web_contents_->GetController().LoadURLWithParams(load_params);
607 }