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