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

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: Fix constant name. 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 // Do not query invalid or non-http URLs. The URL may be invalid if it is
43 // empty, which may happen on initial omnibox focus, and there will be no
44 // useful suggestions for https or chrome URLs.
45 if (!url.is_valid() || url.scheme() != chrome::kHttpScheme)
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 Run();
53 }
54
55 void ZeroSuggestProvider::Stop(bool clear_cached_results) {
56 fetcher_.reset();
57 done_ = true;
58 if (clear_cached_results) {
59 results_.clear();
60 current_query_.clear();
61 current_query_text_.clear();
62 }
63 }
64
65 void ZeroSuggestProvider::OnURLFetchComplete(const net::URLFetcher* source) {
66 std::string json_data;
67 source->GetResponseAsString(&json_data);
68 const bool request_succeeded =
69 source->GetStatus().is_success() && source->GetResponseCode() == 200;
70
71 bool results_updated = false;
72 if (request_succeeded) {
73 JSONStringValueSerializer deserializer(json_data);
74 deserializer.set_allow_trailing_comma(true);
75 scoped_ptr<Value> data(deserializer.Deserialize(NULL, NULL));
76 results_updated = data.get() && ParseSuggestResults(data.get());
77 }
78 done_ = true;
79
80 ConvertResultsToAutocompleteMatches();
81 if (results_updated)
82 listener_->OnProviderUpdate(results_updated);
83 }
84
85 ZeroSuggestProvider::~ZeroSuggestProvider() {
86 }
87
88 void ZeroSuggestProvider::Run() {
89 const int kFetcherID = 1;
90 fetcher_.reset(
91 net::URLFetcher::Create(kFetcherID,
92 GURL(url_prefix_ + current_query_),
93 net::URLFetcher::GET, this));
94 fetcher_->SetRequestContext(profile_->GetRequestContext());
95 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
96 fetcher_->Start();
97 }
98
99 void ZeroSuggestProvider::UpdateMatches(const string16& user_text) {
100 user_text_ = user_text;
101 const size_t prev_num_matches = matches_.size();
102 ConvertResultsToAutocompleteMatches();
103 if (matches_.size() != prev_num_matches)
104 listener_->OnProviderUpdate(true);
105 }
106
107 bool ZeroSuggestProvider::ParseSuggestResults(Value* root_val) {
108 std::string query;
109 ListValue* root_list = NULL;
110 ListValue* results = NULL;
111 if (!root_val->GetAsList(&root_list) || !root_list->GetString(0, &query) ||
112 (query != current_query_) || !root_list->GetList(1, &results))
113 return false;
114
115 results_.clear();
116 ListValue* one_result = NULL;
117 for (size_t index = 0; results->GetList(index, &one_result); ++index) {
118 string16 result;
119 one_result->GetString(0, &result);
120 if (result.empty())
121 continue;
122 results_.push_back(result);
123 }
124
125 return true;
126 }
127
128 void ZeroSuggestProvider::ConvertResultsToAutocompleteMatches() {
129 const TemplateURL* search_provider =
130 template_url_service_->GetDefaultSearchProvider();
131 // Fail if we can't set the clickthrough URL for query suggestions.
132 if (search_provider == NULL || !search_provider->SupportsReplacement())
133 return;
134 matches_.clear();
135 // Do not add anything if there are no results for this URL.
136 if (results_.empty())
137 return;
138 AddMatchForCurrentURL();
139 for (size_t i = 0; i < results_.size(); ++i)
140 AddMatchForResult(search_provider, i, results_[i]);
141 }
142
143 // TODO(jered): Rip this out once the first match is decoupled from the current
144 // typing in the omnibox.
145 void ZeroSuggestProvider::AddMatchForCurrentURL() {
146 // If the user has typed something besides the current url, they probably
147 // don't intend to refresh it.
148 const bool user_text_is_url = user_text_ == current_query_text_;
149 if (user_text_.empty() || user_text_is_url) {
150 // The placeholder suggestion for the current URL has high relevance so
151 // that it is in the first suggestion slot and inline autocompleted. It
152 // gets dropped as soon as the user types something.
153 const int kPlaceholderRelevance = 2000;
154 AutocompleteMatch match(this, kPlaceholderRelevance, false,
155 AutocompleteMatch::NAVSUGGEST);
156 match.destination_url = GURL(current_query_);
157 match.contents = current_query_text_;
158 if (!user_text_is_url) {
159 match.fill_into_edit = current_query_text_;
160 match.inline_autocomplete_offset = 0;
161 }
162 AutocompleteMatch::ClassifyLocationInString(0, current_query_.size(),
163 match.contents.length(), ACMatchClassification::URL,
164 &match.contents_class);
165 matches_.push_back(match);
166 }
167 }
168
169 void ZeroSuggestProvider::AddMatchForResult(
170 const TemplateURL* search_provider,
171 size_t result_index,
172 const string16& result) {
173 // TODO(jered): Rip out user_text_is_url logic when AddMatchForCurrentURL
174 // goes away.
175 const bool user_text_is_url = user_text_ == current_query_text_;
176 const bool kCaseInsensitve = false;
177 if (!user_text_.empty() && !user_text_is_url &&
178 !StartsWith(result, user_text_, kCaseInsensitve))
179 // This suggestion isn't relevant for the current prefix.
180 return;
181 // This bogus relevance puts suggestions below the placeholder from
182 // AddMatchForCurrentURL(), but very low after the user starts typing so that
183 // zero-suggestions go away after there are other suggestions.
184 // TODO(jered): Use real scores from the suggestion server.
185 const int suggestion_relevance =
186 (user_text_.empty() || user_text_is_url) ? 1999 : 100;
187 AutocompleteMatch match(this, suggestion_relevance, false,
188 AutocompleteMatch::SEARCH_SUGGEST);
189 match.contents = result;
190 match.fill_into_edit = result;
191 if (!user_text_is_url && user_text_ != result)
192 match.inline_autocomplete_offset = user_text_.length();
193
194 // Build a URL for this query using the default search provider.
195 const TemplateURLRef& search_url = search_provider->url_ref();
196 DCHECK(search_url.SupportsReplacement());
197 match.search_terms_args.reset(
198 new TemplateURLRef::SearchTermsArgs(result));
199 match.search_terms_args->original_query = string16();
200 match.search_terms_args->accepted_suggestion = result_index;
201 match.destination_url =
202 GURL(search_url.ReplaceSearchTerms(*match.search_terms_args.get()));
203
204 if (user_text_.empty() || user_text_is_url || user_text_ == result) {
205 match.contents_class.push_back(
206 ACMatchClassification(0, ACMatchClassification::NONE));
207 } else {
208 // Style to look like normal search suggestions.
209 match.contents_class.push_back(
210 ACMatchClassification(0, ACMatchClassification::DIM));
211 match.contents_class.push_back(
212 ACMatchClassification(user_text_.length(), ACMatchClassification::NONE));
213 }
214 match.transition = content::PAGE_TRANSITION_GENERATED;
215
216 matches_.push_back(match);
217 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698