instant_search_prerenderer.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
1// Copyright 2013 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/instant_search_prerenderer.h"
6
7#include "chrome/browser/autocomplete/autocomplete_match.h"
8#include "chrome/browser/prerender/prerender_handle.h"
9#include "chrome/browser/prerender/prerender_manager.h"
10#include "chrome/browser/prerender/prerender_manager_factory.h"
11#include "chrome/browser/profiles/profile.h"
12#include "chrome/browser/search/search.h"
13#include "chrome/browser/ui/browser_navigator.h"
14#include "chrome/browser/ui/search/search_tab_helper.h"
15
16namespace {
17
18// Returns true if the underlying page supports Instant search.
19bool PageSupportsInstantSearch(content::WebContents* contents) {
20  DCHECK(contents);
21  // Search results page supports Instant search.
22  return SearchTabHelper::FromWebContents(contents)->IsSearchResultsPage();
23}
24
25}  // namespace
26
27InstantSearchPrerenderer::InstantSearchPrerenderer(Profile* profile,
28                                                   const GURL& url)
29    : profile_(profile),
30      prerender_url_(url) {
31}
32
33InstantSearchPrerenderer::~InstantSearchPrerenderer() {
34  if (prerender_handle_)
35    prerender_handle_->OnCancel();
36}
37
38void InstantSearchPrerenderer::Init(
39    const content::SessionStorageNamespaceMap& session_storage_namespace_map,
40    const gfx::Size& size) {
41  // TODO(kmadhusu): Enable Instant for Incognito profile.
42  if (profile_->IsOffTheRecord())
43    return;
44
45  // Only cancel the old prerender after starting the new one, so if the URLs
46  // are the same, the underlying prerender will be reused.
47  scoped_ptr<prerender::PrerenderHandle> old_prerender_handle(
48      prerender_handle_.release());
49  prerender::PrerenderManager* prerender_manager =
50      prerender::PrerenderManagerFactory::GetForProfile(profile_);
51  if (prerender_manager) {
52    content::SessionStorageNamespace* session_storage_namespace = NULL;
53    content::SessionStorageNamespaceMap::const_iterator it =
54        session_storage_namespace_map.find(std::string());
55    if (it != session_storage_namespace_map.end())
56      session_storage_namespace = it->second.get();
57
58    prerender_handle_.reset(prerender_manager->AddPrerenderForInstant(
59        prerender_url_, session_storage_namespace, size));
60  }
61  if (old_prerender_handle)
62    old_prerender_handle->OnCancel();
63}
64
65void InstantSearchPrerenderer::Cancel() {
66  if (!prerender_handle_)
67    return;
68
69  last_instant_suggestion_ = InstantSuggestion();
70  prerender_handle_->OnCancel();
71  prerender_handle_.reset();
72}
73
74void InstantSearchPrerenderer::Prerender(const InstantSuggestion& suggestion) {
75  if (!prerender_handle_)
76    return;
77
78  if (last_instant_suggestion_.text == suggestion.text)
79    return;
80
81  if (last_instant_suggestion_.text.empty() &&
82      !prerender_handle_->IsFinishedLoading())
83    return;
84
85  if (!prerender_contents())
86    return;
87
88  last_instant_suggestion_ = suggestion;
89  SearchTabHelper::FromWebContents(prerender_contents())->
90      SetSuggestionToPrefetch(suggestion);
91}
92
93void InstantSearchPrerenderer::Commit(const string16& query) {
94  DCHECK(prerender_handle_);
95  DCHECK(prerender_contents());
96  SearchTabHelper::FromWebContents(prerender_contents())->Submit(query);
97}
98
99bool InstantSearchPrerenderer::CanCommitQuery(content::WebContents* source,
100                                              const string16& query) const {
101  if (!source || query.empty())
102    return false;
103
104  if (last_instant_suggestion_.text != query)
105    return false;
106
107  if (!prerender_handle_ || !prerender_contents())
108    return false;
109
110  // InstantSearchPrerenderer can commit query to the prerendered page only if
111  // the underlying |source| page doesn't support Instant search.
112  return !PageSupportsInstantSearch(source);
113}
114
115bool InstantSearchPrerenderer::UsePrerenderedPage(
116    const GURL& url,
117    chrome::NavigateParams* params) {
118  string16 search_terms = chrome::GetSearchTermsFromURL(profile_, url);
119  prerender::PrerenderManager* prerender_manager =
120      prerender::PrerenderManagerFactory::GetForProfile(profile_);
121  if (search_terms.empty() ||
122      !params->target_contents ||
123      last_instant_suggestion_.text != search_terms ||
124      !prerender_contents() ||
125      !prerender_manager) {
126    Cancel();
127    return false;
128  }
129
130  bool success = prerender_manager->MaybeUsePrerenderedPage(
131      prerender_contents()->GetURL(), params);
132  prerender_handle_.reset();
133  return success;
134}
135
136bool InstantSearchPrerenderer::IsAllowed(const AutocompleteMatch& match,
137                                         content::WebContents* source) const {
138  return AutocompleteMatch::IsSearchType(match.type) &&
139      !PageSupportsInstantSearch(source);
140}
141
142content::WebContents* InstantSearchPrerenderer::prerender_contents() const {
143  return (prerender_handle_ && prerender_handle_->contents()) ?
144      prerender_handle_->contents()->prerender_contents() : NULL;
145}
146