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.
5 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
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/instant_service.h"
13 #include "chrome/browser/search/instant_service_factory.h"
14 #include "chrome/browser/search/search.h"
15 #include "chrome/browser/ui/browser_navigator.h"
16 #include "chrome/browser/ui/search/search_tab_helper.h"
20 // Returns true if the underlying page supports Instant search.
21 bool PageSupportsInstantSearch(content::WebContents
* contents
) {
22 // Search results page supports Instant search.
23 return SearchTabHelper::FromWebContents(contents
)->IsSearchResultsPage();
28 InstantSearchPrerenderer::InstantSearchPrerenderer(Profile
* profile
,
34 InstantSearchPrerenderer::~InstantSearchPrerenderer() {
35 if (prerender_handle_
)
36 prerender_handle_
->OnCancel();
40 InstantSearchPrerenderer
* InstantSearchPrerenderer::GetForProfile(
43 InstantService
* instant_service
=
44 InstantServiceFactory::GetForProfile(profile
);
45 return instant_service
? instant_service
->instant_search_prerenderer() : NULL
;
48 void InstantSearchPrerenderer::Init(
49 const content::SessionStorageNamespaceMap
& session_storage_namespace_map
,
50 const gfx::Size
& size
) {
51 // TODO(kmadhusu): Enable Instant for Incognito profile.
52 if (profile_
->IsOffTheRecord())
55 // Only cancel the old prerender after starting the new one, so if the URLs
56 // are the same, the underlying prerender will be reused.
57 scoped_ptr
<prerender::PrerenderHandle
> old_prerender_handle(
58 prerender_handle_
.release());
59 prerender::PrerenderManager
* prerender_manager
=
60 prerender::PrerenderManagerFactory::GetForProfile(profile_
);
61 if (prerender_manager
) {
62 content::SessionStorageNamespace
* session_storage_namespace
= NULL
;
63 content::SessionStorageNamespaceMap::const_iterator it
=
64 session_storage_namespace_map
.find(std::string());
65 if (it
!= session_storage_namespace_map
.end())
66 session_storage_namespace
= it
->second
.get();
68 prerender_handle_
.reset(prerender_manager
->AddPrerenderForInstant(
69 prerender_url_
, session_storage_namespace
, size
));
71 if (old_prerender_handle
)
72 old_prerender_handle
->OnCancel();
75 void InstantSearchPrerenderer::Cancel() {
76 if (!prerender_handle_
)
79 last_instant_suggestion_
= InstantSuggestion();
80 prerender_handle_
->OnCancel();
81 prerender_handle_
.reset();
84 void InstantSearchPrerenderer::Prerender(const InstantSuggestion
& suggestion
) {
85 if (!prerender_handle_
)
88 if (last_instant_suggestion_
.text
== suggestion
.text
)
91 if (last_instant_suggestion_
.text
.empty() &&
92 !prerender_handle_
->IsFinishedLoading())
95 if (!prerender_contents())
98 last_instant_suggestion_
= suggestion
;
99 SearchTabHelper::FromWebContents(prerender_contents())->
100 SetSuggestionToPrefetch(suggestion
);
103 void InstantSearchPrerenderer::Commit(const base::string16
& query
) {
104 DCHECK(prerender_handle_
);
105 DCHECK(prerender_contents());
106 SearchTabHelper::FromWebContents(prerender_contents())->Submit(query
);
109 bool InstantSearchPrerenderer::CanCommitQuery(
110 content::WebContents
* source
,
111 const base::string16
& query
) const {
112 if (!source
|| query
.empty() || !prerender_handle_
||
113 !prerender_handle_
->IsFinishedLoading() ||
114 !prerender_contents() || !QueryMatchesPrefetch(query
)) {
118 // InstantSearchPrerenderer can commit query to the prerendered page only if
119 // the underlying |source| page doesn't support Instant search.
120 return !PageSupportsInstantSearch(source
);
123 bool InstantSearchPrerenderer::UsePrerenderedPage(
125 chrome::NavigateParams
* params
) {
126 base::string16 search_terms
=
127 chrome::ExtractSearchTermsFromURL(profile_
, url
);
128 prerender::PrerenderManager
* prerender_manager
=
129 prerender::PrerenderManagerFactory::GetForProfile(profile_
);
130 if (search_terms
.empty() || !params
->target_contents
||
131 !prerender_contents() || !prerender_manager
||
132 !QueryMatchesPrefetch(search_terms
)) {
137 bool success
= prerender_manager
->MaybeUsePrerenderedPage(
138 prerender_contents()->GetURL(), params
);
139 prerender_handle_
.reset();
143 bool InstantSearchPrerenderer::IsAllowed(const AutocompleteMatch
& match
,
144 content::WebContents
* source
) const {
145 return source
&& AutocompleteMatch::IsSearchType(match
.type
) &&
146 !PageSupportsInstantSearch(source
);
149 content::WebContents
* InstantSearchPrerenderer::prerender_contents() const {
150 return (prerender_handle_
&& prerender_handle_
->contents()) ?
151 prerender_handle_
->contents()->prerender_contents() : NULL
;
154 bool InstantSearchPrerenderer::QueryMatchesPrefetch(
155 const base::string16
& query
) const {
156 if (chrome::ShouldReuseInstantSearchBasePage())
158 return last_instant_suggestion_
.text
== query
;