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(¶ms);
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