blob: e0e051aaf06141dbbf4eb526a26d8fc93c686c1c [file] [log] [blame]
// 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<prerender::PrerenderHandle> 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;
}