| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/search/search_tab_helper.h" |
| |
| #include <set> |
| |
| #include "base/memory/scoped_ptr.h" |
| #include "base/metrics/histogram.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/string_util.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/search/instant_service.h" |
| #include "chrome/browser/search/instant_service_factory.h" |
| #include "chrome/browser/search/search.h" |
| #include "chrome/browser/signin/signin_manager_factory.h" |
| #include "chrome/browser/sync/profile_sync_service.h" |
| #include "chrome/browser/sync/profile_sync_service_factory.h" |
| #include "chrome/browser/ui/app_list/app_list_util.h" |
| #include "chrome/browser/ui/browser_navigator.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/location_bar/location_bar.h" |
| #include "chrome/browser/ui/omnibox/omnibox_edit_model.h" |
| #include "chrome/browser/ui/omnibox/omnibox_popup_model.h" |
| #include "chrome/browser/ui/omnibox/omnibox_view.h" |
| #include "chrome/browser/ui/search/instant_search_prerenderer.h" |
| #include "chrome/browser/ui/search/search_ipc_router_policy_impl.h" |
| #include "chrome/browser/ui/search/search_tab_helper_delegate.h" |
| #include "chrome/browser/ui/tab_contents/core_tab_helper.h" |
| #include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "components/google/core/browser/google_util.h" |
| #include "components/search/search.h" |
| #include "components/signin/core/browser/signin_manager.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/navigation_details.h" |
| #include "content/public/browser/navigation_entry.h" |
| #include "content/public/browser/navigation_type.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/notification_source.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/user_metrics.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/referrer.h" |
| #include "net/base/net_errors.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/page_transition_types.h" |
| #include "url/gurl.h" |
| |
| DEFINE_WEB_CONTENTS_USER_DATA_KEY(SearchTabHelper); |
| |
| namespace { |
| |
| // For reporting Cacheable NTP navigations. |
| enum CacheableNTPLoad { |
| CACHEABLE_NTP_LOAD_FAILED = 0, |
| CACHEABLE_NTP_LOAD_SUCCEEDED = 1, |
| CACHEABLE_NTP_LOAD_MAX = 2 |
| }; |
| |
| void RecordCacheableNTPLoadHistogram(bool succeeded) { |
| UMA_HISTOGRAM_ENUMERATION("InstantExtended.CacheableNTPLoad", |
| succeeded ? CACHEABLE_NTP_LOAD_SUCCEEDED : |
| CACHEABLE_NTP_LOAD_FAILED, |
| CACHEABLE_NTP_LOAD_MAX); |
| } |
| |
| bool IsCacheableNTP(const content::WebContents* contents) { |
| const content::NavigationEntry* entry = |
| contents->GetController().GetLastCommittedEntry(); |
| return chrome::NavEntryIsInstantNTP(contents, entry) && |
| entry->GetURL() != GURL(chrome::kChromeSearchLocalNtpUrl); |
| } |
| |
| bool IsNTP(const content::WebContents* contents) { |
| // We can't use WebContents::GetURL() because that uses the active entry, |
| // whereas we want the visible entry. |
| const content::NavigationEntry* entry = |
| contents->GetController().GetVisibleEntry(); |
| if (entry && entry->GetVirtualURL() == GURL(chrome::kChromeUINewTabURL)) |
| return true; |
| |
| return chrome::IsInstantNTP(contents); |
| } |
| |
| bool IsSearchResults(const content::WebContents* contents) { |
| return !chrome::GetSearchTerms(contents).empty(); |
| } |
| |
| bool IsLocal(const content::WebContents* contents) { |
| if (!contents) |
| return false; |
| const content::NavigationEntry* entry = |
| contents->GetController().GetVisibleEntry(); |
| return entry && entry->GetURL() == GURL(chrome::kChromeSearchLocalNtpUrl); |
| } |
| |
| // Returns true if |contents| are rendered inside an Instant process. |
| bool InInstantProcess(Profile* profile, |
| const content::WebContents* contents) { |
| if (!profile || !contents) |
| return false; |
| |
| InstantService* instant_service = |
| InstantServiceFactory::GetForProfile(profile); |
| return instant_service && |
| instant_service->IsInstantProcess( |
| contents->GetRenderProcessHost()->GetID()); |
| } |
| |
| // Called when an NTP finishes loading. If the load start time was noted, |
| // calculates and logs the total load time. |
| void RecordNewTabLoadTime(content::WebContents* contents) { |
| CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents); |
| if (core_tab_helper->new_tab_start_time().is_null()) |
| return; |
| |
| base::TimeDelta duration = |
| base::TimeTicks::Now() - core_tab_helper->new_tab_start_time(); |
| if (IsCacheableNTP(contents)) { |
| if (google_util::IsGoogleDomainUrl( |
| contents->GetController().GetLastCommittedEntry()->GetURL(), |
| google_util::ALLOW_SUBDOMAIN, |
| google_util::DISALLOW_NON_STANDARD_PORTS)) { |
| UMA_HISTOGRAM_TIMES("Tab.NewTabOnload.Google", duration); |
| } else { |
| UMA_HISTOGRAM_TIMES("Tab.NewTabOnload.Other", duration); |
| } |
| } else { |
| UMA_HISTOGRAM_TIMES("Tab.NewTabOnload.Local", duration); |
| } |
| core_tab_helper->set_new_tab_start_time(base::TimeTicks()); |
| } |
| |
| // Returns true if the user is signed in and full history sync is enabled, |
| // and false otherwise. |
| bool IsHistorySyncEnabled(Profile* profile) { |
| ProfileSyncService* sync = |
| ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile); |
| return sync && |
| sync->SyncActive() && |
| sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES); |
| } |
| |
| bool OmniboxHasFocus(OmniboxView* omnibox) { |
| return omnibox && omnibox->model()->has_focus(); |
| } |
| |
| } // namespace |
| |
| SearchTabHelper::SearchTabHelper(content::WebContents* web_contents) |
| : WebContentsObserver(web_contents), |
| is_search_enabled_(chrome::IsInstantExtendedAPIEnabled()), |
| web_contents_(web_contents), |
| ipc_router_(web_contents, |
| this, |
| make_scoped_ptr(new SearchIPCRouterPolicyImpl(web_contents))), |
| instant_service_(NULL), |
| delegate_(NULL), |
| omnibox_has_focus_fn_(&OmniboxHasFocus) { |
| if (!is_search_enabled_) |
| return; |
| |
| instant_service_ = |
| InstantServiceFactory::GetForProfile( |
| Profile::FromBrowserContext(web_contents_->GetBrowserContext())); |
| if (instant_service_) |
| instant_service_->AddObserver(this); |
| } |
| |
| SearchTabHelper::~SearchTabHelper() { |
| if (instant_service_) |
| instant_service_->RemoveObserver(this); |
| } |
| |
| void SearchTabHelper::InitForPreloadedNTP() { |
| UpdateMode(true, true); |
| } |
| |
| void SearchTabHelper::OmniboxInputStateChanged() { |
| if (!is_search_enabled_) |
| return; |
| |
| UpdateMode(false, false); |
| } |
| |
| void SearchTabHelper::OmniboxFocusChanged(OmniboxFocusState state, |
| OmniboxFocusChangeReason reason) { |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_OMNIBOX_FOCUS_CHANGED, |
| content::Source<SearchTabHelper>(this), |
| content::NotificationService::NoDetails()); |
| |
| ipc_router_.OmniboxFocusChanged(state, reason); |
| |
| // Don't send oninputstart/oninputend updates in response to focus changes |
| // if there's a navigation in progress. This prevents Chrome from sending |
| // a spurious oninputend when the user accepts a match in the omnibox. |
| if (web_contents_->GetController().GetPendingEntry() == NULL) { |
| ipc_router_.SetInputInProgress(IsInputInProgress()); |
| |
| InstantSearchPrerenderer* prerenderer = |
| InstantSearchPrerenderer::GetForProfile(profile()); |
| if (!prerenderer || !chrome::ShouldPrerenderInstantUrlOnOmniboxFocus()) |
| return; |
| |
| if (state == OMNIBOX_FOCUS_NONE) { |
| prerenderer->Cancel(); |
| return; |
| } |
| |
| if (!IsSearchResultsPage()) { |
| prerenderer->Init( |
| web_contents_->GetController().GetSessionStorageNamespaceMap(), |
| web_contents_->GetContainerBounds().size()); |
| } |
| } |
| } |
| |
| void SearchTabHelper::NavigationEntryUpdated() { |
| if (!is_search_enabled_) |
| return; |
| |
| UpdateMode(false, false); |
| } |
| |
| void SearchTabHelper::InstantSupportChanged(bool instant_support) { |
| if (!is_search_enabled_) |
| return; |
| |
| InstantSupportState new_state = instant_support ? INSTANT_SUPPORT_YES : |
| INSTANT_SUPPORT_NO; |
| |
| model_.SetInstantSupportState(new_state); |
| |
| content::NavigationEntry* entry = |
| web_contents_->GetController().GetLastCommittedEntry(); |
| if (entry) { |
| chrome::SetInstantSupportStateInNavigationEntry(new_state, entry); |
| if (delegate_ && !instant_support) |
| delegate_->OnWebContentsInstantSupportDisabled(web_contents_); |
| } |
| } |
| |
| bool SearchTabHelper::SupportsInstant() const { |
| return model_.instant_support() == INSTANT_SUPPORT_YES; |
| } |
| |
| void SearchTabHelper::SetSuggestionToPrefetch( |
| const InstantSuggestion& suggestion) { |
| ipc_router_.SetSuggestionToPrefetch(suggestion); |
| } |
| |
| void SearchTabHelper::Submit(const base::string16& text) { |
| ipc_router_.Submit(text); |
| } |
| |
| void SearchTabHelper::OnTabActivated() { |
| ipc_router_.OnTabActivated(); |
| |
| OmniboxView* omnibox_view = GetOmniboxView(); |
| if (chrome::ShouldPrerenderInstantUrlOnOmniboxFocus() && |
| omnibox_has_focus_fn_(omnibox_view)) { |
| InstantSearchPrerenderer* prerenderer = |
| InstantSearchPrerenderer::GetForProfile(profile()); |
| if (prerenderer && !IsSearchResultsPage()) { |
| prerenderer->Init( |
| web_contents_->GetController().GetSessionStorageNamespaceMap(), |
| web_contents_->GetContainerBounds().size()); |
| } |
| } |
| } |
| |
| void SearchTabHelper::OnTabDeactivated() { |
| ipc_router_.OnTabDeactivated(); |
| } |
| |
| void SearchTabHelper::ToggleVoiceSearch() { |
| ipc_router_.ToggleVoiceSearch(); |
| } |
| |
| bool SearchTabHelper::IsSearchResultsPage() { |
| return model_.mode().is_origin_search(); |
| } |
| |
| void SearchTabHelper::RenderViewCreated( |
| content::RenderViewHost* render_view_host) { |
| ipc_router_.SetPromoInformation(IsAppLauncherEnabled()); |
| } |
| |
| void SearchTabHelper::DidStartNavigationToPendingEntry( |
| const GURL& url, |
| content::NavigationController::ReloadType /* reload_type */) { |
| if (chrome::IsNTPURL(url, profile())) { |
| // Set the title on any pending entry corresponding to the NTP. This |
| // prevents any flickering of the tab title. |
| content::NavigationEntry* entry = |
| web_contents_->GetController().GetPendingEntry(); |
| if (entry) |
| entry->SetTitle(l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE)); |
| } |
| } |
| |
| void SearchTabHelper::DidNavigateMainFrame( |
| const content::LoadCommittedDetails& details, |
| const content::FrameNavigateParams& params) { |
| if (IsCacheableNTP(web_contents_)) { |
| if (details.http_status_code == 204 || details.http_status_code >= 400) { |
| RedirectToLocalNTP(); |
| RecordCacheableNTPLoadHistogram(false); |
| return; |
| } |
| RecordCacheableNTPLoadHistogram(true); |
| } |
| |
| // Always set the title on the new tab page to be the one from our UI |
| // resources. Normally, we set the title when we begin a NTP load, but it can |
| // get reset in several places (like when you press Reload). This check |
| // ensures that the title is properly set to the string defined by the Chrome |
| // UI language (rather than the server language) in all cases. |
| // |
| // We only override the title when it's nonempty to allow the page to set the |
| // title if it really wants. An empty title means to use the default. There's |
| // also a race condition between this code and the page's SetTitle call which |
| // this rule avoids. |
| content::NavigationEntry* entry = |
| web_contents_->GetController().GetLastCommittedEntry(); |
| if (entry && entry->GetTitle().empty() && |
| (entry->GetVirtualURL() == GURL(chrome::kChromeUINewTabURL) || |
| chrome::NavEntryIsInstantNTP(web_contents_, entry))) { |
| entry->SetTitle(l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE)); |
| } |
| } |
| |
| void SearchTabHelper::DidFailProvisionalLoad( |
| content::RenderFrameHost* render_frame_host, |
| const GURL& validated_url, |
| int error_code, |
| const base::string16& /* error_description */) { |
| // If error_code is ERR_ABORTED means that the user has canceled this |
| // navigation so it shouldn't be redirected. |
| if (!render_frame_host->GetParent() && error_code != net::ERR_ABORTED && |
| validated_url != GURL(chrome::kChromeSearchLocalNtpUrl) && |
| chrome::IsNTPURL(validated_url, profile())) { |
| RedirectToLocalNTP(); |
| RecordCacheableNTPLoadHistogram(false); |
| } |
| } |
| |
| void SearchTabHelper::DidFinishLoad(content::RenderFrameHost* render_frame_host, |
| const GURL& /* validated_url */) { |
| if (!render_frame_host->GetParent()) { |
| if (chrome::IsInstantNTP(web_contents_)) |
| RecordNewTabLoadTime(web_contents_); |
| |
| DetermineIfPageSupportsInstant(); |
| } |
| } |
| |
| void SearchTabHelper::NavigationEntryCommitted( |
| const content::LoadCommittedDetails& load_details) { |
| if (!is_search_enabled_) |
| return; |
| |
| if (!load_details.is_main_frame) |
| return; |
| |
| if (chrome::ShouldAssignURLToInstantRenderer(web_contents_->GetURL(), |
| profile())) { |
| InstantService* instant_service = |
| InstantServiceFactory::GetForProfile(profile()); |
| ipc_router_.SetOmniboxStartMargin(instant_service->omnibox_start_margin()); |
| ipc_router_.SetDisplayInstantResults(); |
| } |
| |
| UpdateMode(true, false); |
| |
| content::NavigationEntry* entry = |
| web_contents_->GetController().GetVisibleEntry(); |
| DCHECK(entry); |
| |
| // Already determined the instant support state for this page, do not reset |
| // the instant support state. |
| // |
| // When we get a navigation entry committed event, there seem to be two ways |
| // to tell whether the navigation was "in-page". Ideally, when |
| // LoadCommittedDetails::is_in_page is true, we should have |
| // LoadCommittedDetails::type to be NAVIGATION_TYPE_IN_PAGE. Unfortunately, |
| // they are different in some cases. To workaround this bug, we are checking |
| // (is_in_page || type == NAVIGATION_TYPE_IN_PAGE). Please refer to |
| // crbug.com/251330 for more details. |
| if (load_details.is_in_page || |
| load_details.type == content::NAVIGATION_TYPE_IN_PAGE) { |
| // When an "in-page" navigation happens, we will not receive a |
| // DidFinishLoad() event. Therefore, we will not determine the Instant |
| // support for the navigated page. So, copy over the Instant support from |
| // the previous entry. If the page does not support Instant, update the |
| // location bar from here to turn off search terms replacement. |
| chrome::SetInstantSupportStateInNavigationEntry(model_.instant_support(), |
| entry); |
| if (delegate_ && model_.instant_support() == INSTANT_SUPPORT_NO) |
| delegate_->OnWebContentsInstantSupportDisabled(web_contents_); |
| return; |
| } |
| |
| model_.SetInstantSupportState(INSTANT_SUPPORT_UNKNOWN); |
| model_.SetVoiceSearchSupported(false); |
| chrome::SetInstantSupportStateInNavigationEntry(model_.instant_support(), |
| entry); |
| |
| if (InInstantProcess(profile(), web_contents_)) |
| ipc_router_.OnNavigationEntryCommitted(); |
| } |
| |
| void SearchTabHelper::OnInstantSupportDetermined(bool supports_instant) { |
| InstantSupportChanged(supports_instant); |
| } |
| |
| void SearchTabHelper::OnSetVoiceSearchSupport(bool supports_voice_search) { |
| model_.SetVoiceSearchSupported(supports_voice_search); |
| } |
| |
| void SearchTabHelper::ThemeInfoChanged(const ThemeBackgroundInfo& theme_info) { |
| ipc_router_.SendThemeBackgroundInfo(theme_info); |
| } |
| |
| void SearchTabHelper::MostVisitedItemsChanged( |
| const std::vector<InstantMostVisitedItem>& items) { |
| ipc_router_.SendMostVisitedItems(items); |
| } |
| |
| void SearchTabHelper::OmniboxStartMarginChanged(int omnibox_start_margin) { |
| ipc_router_.SetOmniboxStartMargin(omnibox_start_margin); |
| } |
| |
| void SearchTabHelper::FocusOmnibox(OmniboxFocusState state) { |
| // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef. |
| #if !defined(OS_ANDROID) |
| OmniboxView* omnibox = GetOmniboxView(); |
| if (!omnibox) |
| return; |
| |
| // Do not add a default case in the switch block for the following reasons: |
| // (1) Explicitly handle the new states. If new states are added in the |
| // OmniboxFocusState, the compiler will warn the developer to handle the new |
| // states. |
| // (2) An attacker may control the renderer and sends the browser process a |
| // malformed IPC. This function responds to the invalid |state| values by |
| // doing nothing instead of crashing the browser process (intentional no-op). |
| switch (state) { |
| case OMNIBOX_FOCUS_VISIBLE: |
| omnibox->SetFocus(); |
| omnibox->model()->SetCaretVisibility(true); |
| break; |
| case OMNIBOX_FOCUS_INVISIBLE: |
| omnibox->SetFocus(); |
| omnibox->model()->SetCaretVisibility(false); |
| // If the user clicked on the fakebox, any text already in the omnibox |
| // should get cleared when they start typing. Selecting all the existing |
| // text is a convenient way to accomplish this. It also gives a slight |
| // visual cue to users who really understand selection state about what |
| // will happen if they start typing. |
| omnibox->SelectAll(false); |
| omnibox->ShowImeIfNeeded(); |
| break; |
| case OMNIBOX_FOCUS_NONE: |
| // Remove focus only if the popup is closed. This will prevent someone |
| // from changing the omnibox value and closing the popup without user |
| // interaction. |
| if (!omnibox->model()->popup_model()->IsOpen()) |
| web_contents()->Focus(); |
| break; |
| } |
| #endif |
| } |
| |
| void SearchTabHelper::NavigateToURL(const GURL& url, |
| WindowOpenDisposition disposition, |
| bool is_most_visited_item_url) { |
| if (is_most_visited_item_url) { |
| content::RecordAction( |
| base::UserMetricsAction("InstantExtended.MostVisitedClicked")); |
| } |
| |
| if (delegate_) |
| delegate_->NavigateOnThumbnailClick(url, disposition, web_contents_); |
| } |
| |
| void SearchTabHelper::OnDeleteMostVisitedItem(const GURL& url) { |
| DCHECK(!url.is_empty()); |
| if (instant_service_) |
| instant_service_->DeleteMostVisitedItem(url); |
| } |
| |
| void SearchTabHelper::OnUndoMostVisitedDeletion(const GURL& url) { |
| DCHECK(!url.is_empty()); |
| if (instant_service_) |
| instant_service_->UndoMostVisitedDeletion(url); |
| } |
| |
| void SearchTabHelper::OnUndoAllMostVisitedDeletions() { |
| if (instant_service_) |
| instant_service_->UndoAllMostVisitedDeletions(); |
| } |
| |
| void SearchTabHelper::OnLogEvent(NTPLoggingEventType event) { |
| // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef. |
| #if !defined(OS_ANDROID) |
| NTPUserDataLogger::GetOrCreateFromWebContents( |
| web_contents())->LogEvent(event); |
| #endif |
| } |
| |
| void SearchTabHelper::OnLogMostVisitedImpression( |
| int position, const base::string16& provider) { |
| // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef. |
| #if !defined(OS_ANDROID) |
| NTPUserDataLogger::GetOrCreateFromWebContents( |
| web_contents())->LogMostVisitedImpression(position, provider); |
| #endif |
| } |
| |
| void SearchTabHelper::OnLogMostVisitedNavigation( |
| int position, const base::string16& provider) { |
| // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef. |
| #if !defined(OS_ANDROID) |
| NTPUserDataLogger::GetOrCreateFromWebContents( |
| web_contents())->LogMostVisitedNavigation(position, provider); |
| #endif |
| } |
| |
| void SearchTabHelper::PasteIntoOmnibox(const base::string16& text) { |
| // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef. |
| #if !defined(OS_ANDROID) |
| OmniboxView* omnibox = GetOmniboxView(); |
| if (!omnibox) |
| return; |
| // The first case is for right click to paste, where the text is retrieved |
| // from the clipboard already sanitized. The second case is needed to handle |
| // drag-and-drop value and it has to be sanitazed before setting it into the |
| // omnibox. |
| base::string16 text_to_paste = text.empty() ? omnibox->GetClipboardText() : |
| omnibox->SanitizeTextForPaste(text); |
| |
| if (text_to_paste.empty()) |
| return; |
| |
| if (!omnibox->model()->has_focus()) |
| omnibox->SetFocus(); |
| |
| omnibox->OnBeforePossibleChange(); |
| omnibox->model()->OnPaste(); |
| omnibox->SetUserText(text_to_paste); |
| omnibox->OnAfterPossibleChange(); |
| #endif |
| } |
| |
| void SearchTabHelper::OnChromeIdentityCheck(const base::string16& identity) { |
| SigninManagerBase* manager = SigninManagerFactory::GetForProfile(profile()); |
| if (manager) { |
| const base::string16 username = |
| base::UTF8ToUTF16(manager->GetAuthenticatedUsername()); |
| // The identity check only passes if the user is syncing their history. |
| // TODO(beaudoin): Change this function name and related APIs now that it's |
| // checking both the identity and the user's sync state. |
| bool matches = IsHistorySyncEnabled(profile()) && identity == username; |
| ipc_router_.SendChromeIdentityCheckResult(identity, matches); |
| } |
| } |
| |
| void SearchTabHelper::UpdateMode(bool update_origin, bool is_preloaded_ntp) { |
| SearchMode::Type type = SearchMode::MODE_DEFAULT; |
| SearchMode::Origin origin = SearchMode::ORIGIN_DEFAULT; |
| if (IsNTP(web_contents_) || is_preloaded_ntp) { |
| type = SearchMode::MODE_NTP; |
| origin = SearchMode::ORIGIN_NTP; |
| } else if (IsSearchResults(web_contents_)) { |
| type = SearchMode::MODE_SEARCH_RESULTS; |
| origin = SearchMode::ORIGIN_SEARCH; |
| } |
| if (!update_origin) |
| origin = model_.mode().origin; |
| |
| OmniboxView* omnibox = GetOmniboxView(); |
| if (omnibox && omnibox->model()->user_input_in_progress()) |
| type = SearchMode::MODE_SEARCH_SUGGESTIONS; |
| |
| SearchMode old_mode(model_.mode()); |
| model_.SetMode(SearchMode(type, origin)); |
| if (old_mode.is_ntp() != model_.mode().is_ntp()) { |
| ipc_router_.SetInputInProgress(IsInputInProgress()); |
| } |
| } |
| |
| void SearchTabHelper::DetermineIfPageSupportsInstant() { |
| if (!InInstantProcess(profile(), web_contents_)) { |
| // The page is not in the Instant process. This page does not support |
| // instant. If we send an IPC message to a page that is not in the Instant |
| // process, it will never receive it and will never respond. Therefore, |
| // return immediately. |
| InstantSupportChanged(false); |
| } else if (IsLocal(web_contents_)) { |
| // Local pages always support Instant. |
| InstantSupportChanged(true); |
| } else { |
| ipc_router_.DetermineIfPageSupportsInstant(); |
| } |
| } |
| |
| Profile* SearchTabHelper::profile() const { |
| return Profile::FromBrowserContext(web_contents_->GetBrowserContext()); |
| } |
| |
| void SearchTabHelper::RedirectToLocalNTP() { |
| // Extra parentheses to declare a variable. |
| content::NavigationController::LoadURLParams load_params( |
| (GURL(chrome::kChromeSearchLocalNtpUrl))); |
| load_params.referrer = content::Referrer(); |
| load_params.transition_type = ui::PAGE_TRANSITION_SERVER_REDIRECT; |
| // Don't push a history entry. |
| load_params.should_replace_current_entry = true; |
| web_contents_->GetController().LoadURLWithParams(load_params); |
| } |
| |
| bool SearchTabHelper::IsInputInProgress() const { |
| OmniboxView* omnibox = GetOmniboxView(); |
| return !model_.mode().is_ntp() && omnibox && |
| omnibox->model()->focus_state() == OMNIBOX_FOCUS_VISIBLE; |
| } |
| |
| OmniboxView* SearchTabHelper::GetOmniboxView() const { |
| return delegate_ ? delegate_->GetOmniboxView() : NULL; |
| } |