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