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