Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: chrome/browser/autocomplete/zero_suggest_provider.cc

Issue 10832256: Experimental AutocompleteProvider for zerosuggest. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Address comments. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/autocomplete/zero_suggest_provider.h"
6
7 #include "base/callback.h"
8 #include "base/json/json_string_value_serializer.h"
9 #include "base/string16.h"
10 #include "base/string_util.h"
11 #include "base/time.h"
12 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/autocomplete/autocomplete_input.h"
14 #include "chrome/browser/autocomplete/autocomplete_match.h"
15 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/search_engines/template_url_service.h"
18 #include "chrome/browser/search_engines/template_url_service_factory.h"
19 #include "chrome/common/url_constants.h"
20 #include "googleurl/src/gurl.h"
21 #include "net/base/load_flags.h"
22 #include "net/http/http_response_headers.h"
23 #include "net/url_request/url_fetcher.h"
24 #include "net/url_request/url_request_status.h"
25
26 ZeroSuggestProvider::ZeroSuggestProvider(
27 AutocompleteProviderListener* listener,
28 Profile* profile,
29 const std::string& url_prefix)
30 : AutocompleteProvider(listener, profile, "ZeroSuggest"),
31 url_prefix_(url_prefix),
32 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)) {
33 }
34
35 void ZeroSuggestProvider::Start(const AutocompleteInput& input,
36 bool /*minimal_changes*/) {
37 UpdateMatches(input.text());
38 }
39
40 void ZeroSuggestProvider::StartZeroSuggest(const GURL& url,
41 const string16& user_text) {
42 DCHECK(url.is_valid());
43 // Do not query non-http URLs. There will be no useful suggestions for https
44 // or chrome URLs.
45 if (!url.is_valid() || url.scheme() != chrome::kHttpScheme)
Peter Kasting 2012/08/15 21:52:44 Nit: Remove "!url.is_valid() ||", since we should
Jered 2012/08/15 23:13:00 Done.
46 return;
47 matches_.clear();
48 done_ = false;
49 user_text_ = user_text;
50 current_query_ = url.spec();
51 current_query_text_ = ASCIIToUTF16(url.spec());
52 // TODO(jered): Consider adding locally-sourced zero-suggestions here too.
53 // These may be useful on the NTP or more relevant to the user than server
54 // suggestions, if based on local browsing history.
55 Run();
56 }
57
58 void ZeroSuggestProvider::Stop(bool clear_cached_results) {
59 fetcher_.reset();
60 done_ = true;
61 if (clear_cached_results) {
62 results_.clear();
63 current_query_.clear();
64 current_query_text_.clear();
65 }
66 }
67
68 void ZeroSuggestProvider::OnURLFetchComplete(const net::URLFetcher* source) {
69 std::string json_data;
70 source->GetResponseAsString(&json_data);
71 const bool request_succeeded =
72 source->GetStatus().is_success() && source->GetResponseCode() == 200;
73
74 bool results_updated = false;
75 if (request_succeeded) {
76 JSONStringValueSerializer deserializer(json_data);
77 deserializer.set_allow_trailing_comma(true);
78 scoped_ptr<Value> data(deserializer.Deserialize(NULL, NULL));
79 results_updated = data.get() && ParseSuggestResults(data.get());
80 }
81 done_ = true;
82
83 ConvertResultsToAutocompleteMatches();
84 if (results_updated)
85 listener_->OnProviderUpdate(results_updated);
86 }
87
88 ZeroSuggestProvider::~ZeroSuggestProvider() {
89 }
90
91 void ZeroSuggestProvider::Run() {
92 const int kFetcherID = 1;
93 fetcher_.reset(
94 net::URLFetcher::Create(kFetcherID,
95 GURL(url_prefix_ + current_query_),
96 net::URLFetcher::GET, this));
97 fetcher_->SetRequestContext(profile_->GetRequestContext());
98 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
99 fetcher_->Start();
100 }
101
102 void ZeroSuggestProvider::UpdateMatches(const string16& user_text) {
103 user_text_ = user_text;
104 const size_t prev_num_matches = matches_.size();
105 ConvertResultsToAutocompleteMatches();
106 if (matches_.size() != prev_num_matches)
107 listener_->OnProviderUpdate(true);
108 }
109
110 bool ZeroSuggestProvider::ParseSuggestResults(Value* root_val) {
111 std::string query;
112 ListValue* root_list = NULL;
113 ListValue* results = NULL;
114 if (!root_val->GetAsList(&root_list) || !root_list->GetString(0, &query) ||
115 (query != current_query_) || !root_list->GetList(1, &results))
116 return false;
117
118 results_.clear();
119 ListValue* one_result = NULL;
120 for (size_t index = 0; results->GetList(index, &one_result); ++index) {
121 string16 result;
122 one_result->GetString(0, &result);
123 if (result.empty())
124 continue;
125 results_.push_back(result);
126 }
127
128 return true;
129 }
130
131 void ZeroSuggestProvider::ConvertResultsToAutocompleteMatches() {
132 const TemplateURL* search_provider =
133 template_url_service_->GetDefaultSearchProvider();
134 // Fail if we can't set the clickthrough URL for query suggestions.
135 if (search_provider == NULL || !search_provider->SupportsReplacement())
136 return;
137 matches_.clear();
138 // Do not add anything if there are no results for this URL.
139 if (results_.empty())
140 return;
141 AddMatchForCurrentURL();
142 for (size_t i = 0; i < results_.size(); ++i)
143 AddMatchForResult(search_provider, i, results_[i]);
144 }
145
146 // TODO(jered): Rip this out once the first match is decoupled from the current
147 // typing in the omnibox.
148 void ZeroSuggestProvider::AddMatchForCurrentURL() {
149 // If the user has typed something besides the current url, they probably
150 // don't intend to refresh it.
151 const bool user_text_is_url = user_text_ == current_query_text_;
152 if (user_text_.empty() || user_text_is_url) {
153 // The placeholder suggestion for the current URL has high relevance so
154 // that it is in the first suggestion slot and inline autocompleted. It
155 // gets dropped as soon as the user types something.
Peter Kasting 2012/08/15 21:52:44 Nit: Since the zerosuggest provider is the only th
Jered 2012/08/15 23:13:00 It seems existing providers (e.g. SearchProvider)
Peter Kasting 2012/08/16 00:24:41 I'm not really sure what you're saying here. The
156 const int kPlaceholderRelevance = 2000;
157 AutocompleteMatch match(this, kPlaceholderRelevance, false,
158 AutocompleteMatch::NAVSUGGEST);
159 match.destination_url = GURL(current_query_);
160 match.contents = current_query_text_;
161 if (!user_text_is_url) {
162 match.fill_into_edit = current_query_text_;
163 match.inline_autocomplete_offset = 0;
164 }
165 AutocompleteMatch::ClassifyLocationInString(0, current_query_.size(),
166 match.contents.length(), ACMatchClassification::URL,
167 &match.contents_class);
168 matches_.push_back(match);
169 }
170 }
171
172 void ZeroSuggestProvider::AddMatchForResult(
173 const TemplateURL* search_provider,
174 size_t result_index,
175 const string16& result) {
176 // TODO(jered): Rip out user_text_is_url logic when AddMatchForCurrentURL
177 // goes away.
178 const bool user_text_is_url = user_text_ == current_query_text_;
179 const bool kCaseInsensitve = false;
180 if (!user_text_.empty() && !user_text_is_url &&
181 !StartsWith(result, user_text_, kCaseInsensitve))
182 // This suggestion isn't relevant for the current prefix.
183 return;
184 // This bogus relevance puts suggestions below the placeholder from
185 // AddMatchForCurrentURL(), but very low after the user starts typing so that
186 // zero-suggestions go away after there are other suggestions.
187 // TODO(jered): Use real scores from the suggestion server.
188 const int suggestion_relevance =
189 (user_text_.empty() || user_text_is_url) ? 1999 : 100;
Peter Kasting 2012/08/15 21:52:44 The suggestions we add should not have the same re
Jered 2012/08/15 23:13:00 Done.
190 AutocompleteMatch match(this, suggestion_relevance, false,
191 AutocompleteMatch::SEARCH_SUGGEST);
192 match.contents = result;
193 match.fill_into_edit = result;
194 if (!user_text_is_url && user_text_ != result)
195 match.inline_autocomplete_offset = user_text_.length();
196
197 // Build a URL for this query using the default search provider.
198 const TemplateURLRef& search_url = search_provider->url_ref();
199 DCHECK(search_url.SupportsReplacement());
200 match.search_terms_args.reset(
201 new TemplateURLRef::SearchTermsArgs(result));
202 match.search_terms_args->original_query = string16();
203 match.search_terms_args->accepted_suggestion = result_index;
204 match.destination_url =
205 GURL(search_url.ReplaceSearchTerms(*match.search_terms_args.get()));
206
207 if (user_text_.empty() || user_text_is_url || user_text_ == result) {
208 match.contents_class.push_back(
209 ACMatchClassification(0, ACMatchClassification::NONE));
210 } else {
211 // Style to look like normal search suggestions.
212 match.contents_class.push_back(
213 ACMatchClassification(0, ACMatchClassification::DIM));
214 match.contents_class.push_back(
215 ACMatchClassification(user_text_.length(), ACMatchClassification::NONE));
216 }
217 match.transition = content::PAGE_TRANSITION_GENERATED;
218
219 matches_.push_back(match);
220 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698