// Copyright 2013 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/instant_search_prerenderer.h" #include "chrome/browser/prerender/prerender_handle.h" #include "chrome/browser/prerender/prerender_manager.h" #include "chrome/browser/prerender/prerender_manager_factory.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/ui/browser_navigator.h" #include "chrome/browser/ui/search/search_tab_helper.h" #include "components/omnibox/autocomplete_match.h" namespace { // Returns true if the underlying page supports Instant search. bool PageSupportsInstantSearch(content::WebContents* contents) { // Search results page supports Instant search. return SearchTabHelper::FromWebContents(contents)->IsSearchResultsPage(); } } // namespace InstantSearchPrerenderer::InstantSearchPrerenderer(Profile* profile, const GURL& url) : profile_(profile), prerender_url_(url) { } InstantSearchPrerenderer::~InstantSearchPrerenderer() { if (prerender_handle_) prerender_handle_->OnCancel(); } // static InstantSearchPrerenderer* InstantSearchPrerenderer::GetForProfile( Profile* profile) { DCHECK(profile); InstantService* instant_service = InstantServiceFactory::GetForProfile(profile); return instant_service ? instant_service->instant_search_prerenderer() : NULL; } void InstantSearchPrerenderer::Init( content::SessionStorageNamespace* session_storage_namespace, const gfx::Size& size) { // TODO(kmadhusu): Enable Instant for Incognito profile. if (profile_->IsOffTheRecord()) return; // Only cancel the old prerender after starting the new one, so if the URLs // are the same, the underlying prerender will be reused. scoped_ptr old_prerender_handle( prerender_handle_.release()); prerender::PrerenderManager* prerender_manager = prerender::PrerenderManagerFactory::GetForProfile(profile_); if (prerender_manager) { prerender_handle_.reset(prerender_manager->AddPrerenderForInstant( prerender_url_, session_storage_namespace, size)); } if (old_prerender_handle) old_prerender_handle->OnCancel(); } void InstantSearchPrerenderer::Cancel() { if (!prerender_handle_) return; last_instant_suggestion_ = InstantSuggestion(); prerender_handle_->OnCancel(); prerender_handle_.reset(); } void InstantSearchPrerenderer::Prerender(const InstantSuggestion& suggestion) { if (!prerender_handle_) return; if (last_instant_suggestion_.text == suggestion.text) return; if (last_instant_suggestion_.text.empty() && !prerender_handle_->IsFinishedLoading()) return; if (!prerender_contents()) return; last_instant_suggestion_ = suggestion; SearchTabHelper::FromWebContents(prerender_contents())-> SetSuggestionToPrefetch(suggestion); } void InstantSearchPrerenderer::Commit( const base::string16& query, const EmbeddedSearchRequestParams& params) { DCHECK(prerender_handle_); DCHECK(prerender_contents()); SearchTabHelper::FromWebContents(prerender_contents())->Submit(query, params); } bool InstantSearchPrerenderer::CanCommitQuery( content::WebContents* source, const base::string16& query) const { if (!source || query.empty() || !prerender_handle_ || !prerender_handle_->IsFinishedLoading() || !prerender_contents() || !QueryMatchesPrefetch(query)) { return false; } // InstantSearchPrerenderer can commit query to the prerendered page only if // the underlying |source| page doesn't support Instant search. return !PageSupportsInstantSearch(source); } bool InstantSearchPrerenderer::UsePrerenderedPage( const GURL& url, chrome::NavigateParams* params) { base::string16 search_terms = chrome::ExtractSearchTermsFromURL(profile_, url); prerender::PrerenderManager* prerender_manager = prerender::PrerenderManagerFactory::GetForProfile(profile_); if (search_terms.empty() || !params->target_contents || !prerender_contents() || !prerender_manager || !QueryMatchesPrefetch(search_terms) || params->disposition != CURRENT_TAB) { Cancel(); return false; } // Do not use prerendered page for renderer initiated search requests. if (params->is_renderer_initiated && params->transition == ui::PAGE_TRANSITION_LINK) { Cancel(); return false; } bool success = prerender_manager->MaybeUsePrerenderedPage( prerender_contents()->GetURL(), params); prerender_handle_.reset(); return success; } bool InstantSearchPrerenderer::IsAllowed(const AutocompleteMatch& match, content::WebContents* source) const { return source && AutocompleteMatch::IsSearchType(match.type) && !PageSupportsInstantSearch(source); } content::WebContents* InstantSearchPrerenderer::prerender_contents() const { return (prerender_handle_ && prerender_handle_->contents()) ? prerender_handle_->contents()->prerender_contents() : NULL; } bool InstantSearchPrerenderer::QueryMatchesPrefetch( const base::string16& query) const { if (chrome::ShouldReuseInstantSearchBasePage()) return true; return last_instant_suggestion_.text == query; }