// 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/autocomplete/autocomplete_match.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" 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( const content::SessionStorageNamespaceMap& session_storage_namespace_map, 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) { content::SessionStorageNamespace* session_storage_namespace = NULL; content::SessionStorageNamespaceMap::const_iterator it = session_storage_namespace_map.find(std::string()); if (it != session_storage_namespace_map.end()) session_storage_namespace = it->second.get(); 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 string16& query) { DCHECK(prerender_handle_); DCHECK(prerender_contents()); SearchTabHelper::FromWebContents(prerender_contents())->Submit(query); } bool InstantSearchPrerenderer::CanCommitQuery(content::WebContents* source, const string16& query) const { if (!source || query.empty()) return false; if (last_instant_suggestion_.text != query) return false; if (!prerender_handle_ || !prerender_contents()) 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) { string16 search_terms = chrome::GetSearchTermsFromURL(profile_, url); prerender::PrerenderManager* prerender_manager = prerender::PrerenderManagerFactory::GetForProfile(profile_); if (search_terms.empty() || !params->target_contents || last_instant_suggestion_.text != search_terms || !prerender_contents() || !prerender_manager) { 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; }