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 } 638