OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/autocomplete/zero_suggest_provider.h" | 5 #include "chrome/browser/autocomplete/zero_suggest_provider.h" |
6 | 6 |
7 #include "base/callback.h" | 7 #include "base/callback.h" |
8 #include "base/i18n/case_conversion.h" | 8 #include "base/i18n/case_conversion.h" |
9 #include "base/json/json_string_value_serializer.h" | 9 #include "base/json/json_string_value_serializer.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/prefs/pref_service.h" | 11 #include "base/prefs/pref_service.h" |
12 #include "base/strings/string16.h" | 12 #include "base/strings/string16.h" |
13 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
14 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
15 #include "base/time/time.h" | 15 #include "base/time/time.h" |
16 #include "chrome/browser/autocomplete/autocomplete_classifier.h" | 16 #include "chrome/browser/autocomplete/autocomplete_classifier.h" |
17 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" | 17 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" |
18 #include "chrome/browser/autocomplete/autocomplete_input.h" | 18 #include "chrome/browser/autocomplete/autocomplete_input.h" |
19 #include "chrome/browser/autocomplete/autocomplete_match.h" | 19 #include "chrome/browser/autocomplete/autocomplete_match.h" |
20 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h" | 20 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h" |
21 #include "chrome/browser/autocomplete/base_search_provider.h" | |
msw
2014/02/03 22:53:14
nit: remove redundant includes like this.
Maria
2014/02/04 03:16:39
Done.
| |
21 #include "chrome/browser/autocomplete/history_url_provider.h" | 22 #include "chrome/browser/autocomplete/history_url_provider.h" |
22 #include "chrome/browser/autocomplete/search_provider.h" | 23 #include "chrome/browser/autocomplete/search_provider.h" |
23 #include "chrome/browser/autocomplete/url_prefix.h" | 24 #include "chrome/browser/autocomplete/url_prefix.h" |
24 #include "chrome/browser/history/history_types.h" | 25 #include "chrome/browser/history/history_types.h" |
25 #include "chrome/browser/history/top_sites.h" | 26 #include "chrome/browser/history/top_sites.h" |
26 #include "chrome/browser/metrics/variations/variations_http_header_provider.h" | 27 #include "chrome/browser/metrics/variations/variations_http_header_provider.h" |
27 #include "chrome/browser/omnibox/omnibox_field_trial.h" | 28 #include "chrome/browser/omnibox/omnibox_field_trial.h" |
28 #include "chrome/browser/profiles/profile.h" | 29 #include "chrome/browser/profiles/profile.h" |
29 #include "chrome/browser/search/search.h" | 30 #include "chrome/browser/search/search.h" |
30 #include "chrome/browser/search_engines/template_url_service.h" | 31 #include "chrome/browser/search_engines/template_url_service.h" |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
176 done_ = false; | 177 done_ = false; |
177 // TODO(jered): Consider adding locally-sourced zero-suggestions here too. | 178 // TODO(jered): Consider adding locally-sourced zero-suggestions here too. |
178 // These may be useful on the NTP or more relevant to the user than server | 179 // These may be useful on the NTP or more relevant to the user than server |
179 // suggestions, if based on local browsing history. | 180 // suggestions, if based on local browsing history. |
180 Run(suggest_url); | 181 Run(suggest_url); |
181 } | 182 } |
182 | 183 |
183 ZeroSuggestProvider::ZeroSuggestProvider( | 184 ZeroSuggestProvider::ZeroSuggestProvider( |
184 AutocompleteProviderListener* listener, | 185 AutocompleteProviderListener* listener, |
185 Profile* profile) | 186 Profile* profile) |
186 : AutocompleteProvider(listener, profile, | 187 : BaseSearchProvider(listener, |
187 AutocompleteProvider::TYPE_ZERO_SUGGEST), | 188 profile, |
msw
2014/02/03 22:53:14
nit: this can be wrapped on the line above.
Maria
2014/02/04 03:16:39
Done.
| |
189 AutocompleteProvider::TYPE_ZERO_SUGGEST), | |
188 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)), | 190 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)), |
189 have_pending_request_(false), | 191 have_pending_request_(false), |
190 verbatim_relevance_(kDefaultVerbatimZeroSuggestRelevance), | 192 verbatim_relevance_(kDefaultVerbatimZeroSuggestRelevance), |
191 field_trial_triggered_(false), | 193 field_trial_triggered_(false), |
192 field_trial_triggered_in_session_(false), | 194 field_trial_triggered_in_session_(false), |
193 weak_ptr_factory_(this) { | 195 weak_ptr_factory_(this) { |
194 } | 196 } |
195 | 197 |
196 ZeroSuggestProvider::~ZeroSuggestProvider() { | 198 ZeroSuggestProvider::~ZeroSuggestProvider() { |
197 } | 199 } |
198 | 200 |
199 void ZeroSuggestProvider::FillResults( | 201 void ZeroSuggestProvider::FillResults( |
200 const base::Value& root_val, | 202 const base::Value& root_val, |
msw
2014/02/03 22:53:14
nit: wrap this on the line above; indent others to
Maria
2014/02/04 03:16:39
Done.
| |
201 int* verbatim_relevance, | 203 int* verbatim_relevance, |
202 SearchProvider::SuggestResults* suggest_results, | 204 SuggestResults* suggest_results, |
203 SearchProvider::NavigationResults* navigation_results) { | 205 NavigationResults* navigation_results) { |
204 base::string16 query; | 206 base::string16 query; |
205 const base::ListValue* root_list = NULL; | 207 const base::ListValue* root_list = NULL; |
206 const base::ListValue* results = NULL; | 208 const base::ListValue* results = NULL; |
207 const base::ListValue* relevances = NULL; | 209 const base::ListValue* relevances = NULL; |
208 // The response includes the query, which should be empty for ZeroSuggest | 210 // The response includes the query, which should be empty for ZeroSuggest |
209 // responses. | 211 // responses. |
210 if (!root_val.GetAsList(&root_list) || !root_list->GetString(0, &query) || | 212 if (!root_val.GetAsList(&root_list) || !root_list->GetString(0, &query) || |
211 (!query.empty()) || !root_list->GetList(1, &results)) | 213 (!query.empty()) || !root_list->GetList(1, &results)) |
212 return; | 214 return; |
213 | 215 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
260 // Apply valid suggested relevance scores; discard invalid lists. | 262 // Apply valid suggested relevance scores; discard invalid lists. |
261 if (relevances != NULL && !relevances->GetInteger(index, &relevance)) | 263 if (relevances != NULL && !relevances->GetInteger(index, &relevance)) |
262 relevances = NULL; | 264 relevances = NULL; |
263 if (types && types->GetString(index, &type) && (type == "NAVIGATION")) { | 265 if (types && types->GetString(index, &type) && (type == "NAVIGATION")) { |
264 // Do not blindly trust the URL coming from the server to be valid. | 266 // Do not blindly trust the URL coming from the server to be valid. |
265 GURL url(URLFixerUpper::FixupURL( | 267 GURL url(URLFixerUpper::FixupURL( |
266 base::UTF16ToUTF8(result), std::string())); | 268 base::UTF16ToUTF8(result), std::string())); |
267 if (url.is_valid()) { | 269 if (url.is_valid()) { |
268 if (descriptions != NULL) | 270 if (descriptions != NULL) |
269 descriptions->GetString(index, &title); | 271 descriptions->GetString(index, &title); |
270 navigation_results->push_back(SearchProvider::NavigationResult( | 272 navigation_results->push_back(NavigationResult( |
271 *this, url, title, false, relevance, relevances != NULL, | 273 *this, url, title, false, relevance, relevances != NULL, |
272 current_query_string16, languages)); | 274 current_query_string16, languages)); |
273 } | 275 } |
274 } else { | 276 } else { |
275 suggest_results->push_back(SearchProvider::SuggestResult( | 277 suggest_results->push_back(SuggestResult( |
276 result, AutocompleteMatchType::SEARCH_SUGGEST, result, | 278 result, AutocompleteMatchType::SEARCH_SUGGEST, result, |
277 base::string16(), std::string(), std::string(), false, relevance, | 279 base::string16(), std::string(), std::string(), false, relevance, |
278 relevances != NULL, false, current_query_string16)); | 280 relevances != NULL, false, current_query_string16)); |
279 } | 281 } |
280 } | 282 } |
281 } | 283 } |
282 | 284 |
283 void ZeroSuggestProvider::AddSuggestResultsToMap( | 285 void ZeroSuggestProvider::AddSuggestResultsToMap( |
284 const SearchProvider::SuggestResults& results, | 286 const SuggestResults& results, |
285 const TemplateURL* template_url, | 287 const TemplateURL* template_url, |
286 SearchProvider::MatchMap* map) { | 288 MatchMap* map) { |
287 for (size_t i = 0; i < results.size(); ++i) { | 289 for (size_t i = 0; i < results.size(); ++i) { |
288 AddMatchToMap(results[i].relevance(), AutocompleteMatchType::SEARCH_SUGGEST, | 290 AddMatchToMap(results[i].relevance(), AutocompleteMatchType::SEARCH_SUGGEST, |
289 template_url, results[i].suggestion(), i, map); | 291 template_url, results[i].suggestion(), i, map); |
290 } | 292 } |
291 } | 293 } |
292 | 294 |
293 void ZeroSuggestProvider::AddMatchToMap(int relevance, | 295 void ZeroSuggestProvider::AddMatchToMap(int relevance, |
294 AutocompleteMatch::Type type, | 296 AutocompleteMatch::Type type, |
295 const TemplateURL* template_url, | 297 const TemplateURL* template_url, |
296 const base::string16& query_string, | 298 const base::string16& query_string, |
297 int accepted_suggestion, | 299 int accepted_suggestion, |
298 SearchProvider::MatchMap* map) { | 300 MatchMap* map) { |
299 // Pass in query_string as the input_text to avoid bolding. | 301 // Pass in query_string as the input_text to avoid bolding. |
300 SearchProvider::SuggestResult suggestion( | 302 SuggestResult suggestion( |
301 query_string, type, query_string, base::string16(), std::string(), | 303 query_string, type, query_string, base::string16(), std::string(), |
302 std::string(), false, relevance, true, false, query_string); | 304 std::string(), false, relevance, true, false, query_string); |
303 // TODO(samarth|melevin): use the actual omnibox margin here as well instead | 305 // TODO(samarth|melevin): use the actual omnibox margin here as well instead |
304 // of passing in -1. | 306 // of passing in -1. |
305 AutocompleteMatch match = SearchProvider::CreateSearchSuggestion( | 307 AutocompleteMatch match = SearchProvider::CreateSearchSuggestion( |
306 this, AutocompleteInput(), query_string, suggestion, template_url, | 308 this, AutocompleteInput(), query_string, suggestion, template_url, |
307 accepted_suggestion, -1, true); | 309 accepted_suggestion, -1, true); |
308 if (!match.destination_url.is_valid()) | 310 if (!match.destination_url.is_valid()) |
309 return; | 311 return; |
310 | 312 |
311 // Try to add |match| to |map|. If a match for |query_string| is already in | 313 // Try to add |match| to |map|. If a match for |query_string| is already in |
312 // |map|, replace it if |match| is more relevant. | 314 // |map|, replace it if |match| is more relevant. |
313 // NOTE: Keep this ToLower() call in sync with url_database.cc. | 315 // NOTE: Keep this ToLower() call in sync with url_database.cc. |
314 SearchProvider::MatchKey match_key( | 316 MatchKey match_key( |
315 std::make_pair(base::i18n::ToLower(query_string), std::string())); | 317 std::make_pair(base::i18n::ToLower(query_string), std::string())); |
316 const std::pair<SearchProvider::MatchMap::iterator, bool> i(map->insert( | 318 const std::pair<MatchMap::iterator, bool> i(map->insert( |
317 std::make_pair(match_key, match))); | 319 std::make_pair(match_key, match))); |
318 // NOTE: We purposefully do a direct relevance comparison here instead of | 320 // NOTE: We purposefully do a direct relevance comparison here instead of |
319 // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added | 321 // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added |
320 // first" rather than "items alphabetically first" when the scores are equal. | 322 // first" rather than "items alphabetically first" when the scores are equal. |
321 // The only case this matters is when a user has results with the same score | 323 // The only case this matters is when a user has results with the same score |
322 // that differ only by capitalization; because the history system returns | 324 // that differ only by capitalization; because the history system returns |
323 // results sorted by recency, this means we'll pick the most recent such | 325 // results sorted by recency, this means we'll pick the most recent such |
324 // result even if the precision of our relevance score is too low to | 326 // result even if the precision of our relevance score is too low to |
325 // distinguish the two. | 327 // distinguish the two. |
326 if (!i.second && (match.relevance > i.first->second.relevance)) | 328 if (!i.second && (match.relevance > i.first->second.relevance)) |
327 i.first->second = match; | 329 i.first->second = match; |
328 } | 330 } |
329 | 331 |
330 AutocompleteMatch ZeroSuggestProvider::NavigationToMatch( | 332 AutocompleteMatch ZeroSuggestProvider::NavigationToMatch( |
331 const SearchProvider::NavigationResult& navigation) { | 333 const NavigationResult& navigation) { |
332 AutocompleteMatch match(this, navigation.relevance(), false, | 334 AutocompleteMatch match(this, navigation.relevance(), false, |
333 AutocompleteMatchType::NAVSUGGEST); | 335 AutocompleteMatchType::NAVSUGGEST); |
334 match.destination_url = navigation.url(); | 336 match.destination_url = navigation.url(); |
335 | 337 |
336 // Zero suggest results should always omit protocols and never appear bold. | 338 // Zero suggest results should always omit protocols and never appear bold. |
337 const std::string languages( | 339 const std::string languages( |
338 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); | 340 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); |
339 match.contents = net::FormatUrl(navigation.url(), languages, | 341 match.contents = net::FormatUrl(navigation.url(), languages, |
340 net::kFormatUrlOmitAll, net::UnescapeRule::SPACES, NULL, NULL, NULL); | 342 net::kFormatUrlOmitAll, net::UnescapeRule::SPACES, NULL, NULL, NULL); |
341 match.fill_into_edit += | 343 match.fill_into_edit += |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
378 ts->GetMostVisitedURLs( | 380 ts->GetMostVisitedURLs( |
379 base::Bind(&ZeroSuggestProvider::OnMostVisitedUrlsAvailable, | 381 base::Bind(&ZeroSuggestProvider::OnMostVisitedUrlsAvailable, |
380 weak_ptr_factory_.GetWeakPtr()), false); | 382 weak_ptr_factory_.GetWeakPtr()), false); |
381 } | 383 } |
382 } | 384 } |
383 have_pending_request_ = true; | 385 have_pending_request_ = true; |
384 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_SENT); | 386 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_SENT); |
385 } | 387 } |
386 | 388 |
387 void ZeroSuggestProvider::ParseSuggestResults(const base::Value& root_val) { | 389 void ZeroSuggestProvider::ParseSuggestResults(const base::Value& root_val) { |
388 SearchProvider::SuggestResults suggest_results; | 390 SuggestResults suggest_results; |
389 FillResults(root_val, &verbatim_relevance_, | 391 FillResults(root_val, &verbatim_relevance_, |
390 &suggest_results, &navigation_results_); | 392 &suggest_results, &navigation_results_); |
391 | 393 |
392 query_matches_map_.clear(); | 394 query_matches_map_.clear(); |
393 AddSuggestResultsToMap(suggest_results, | 395 AddSuggestResultsToMap(suggest_results, |
394 template_url_service_->GetDefaultSearchProvider(), | 396 template_url_service_->GetDefaultSearchProvider(), |
395 &query_matches_map_); | 397 &query_matches_map_); |
396 } | 398 } |
397 | 399 |
398 void ZeroSuggestProvider::OnMostVisitedUrlsAvailable( | 400 void ZeroSuggestProvider::OnMostVisitedUrlsAvailable( |
(...skipping 27 matching lines...) Expand all Loading... | |
426 UMA_HISTOGRAM_COUNTS( | 428 UMA_HISTOGRAM_COUNTS( |
427 "Omnibox.ZeroSuggest.MostVisitedResultsCounterfactual", | 429 "Omnibox.ZeroSuggest.MostVisitedResultsCounterfactual", |
428 most_visited_urls_.size()); | 430 most_visited_urls_.size()); |
429 } | 431 } |
430 const base::string16 current_query_string16( | 432 const base::string16 current_query_string16( |
431 base::ASCIIToUTF16(current_query_)); | 433 base::ASCIIToUTF16(current_query_)); |
432 const std::string languages( | 434 const std::string languages( |
433 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); | 435 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); |
434 for (size_t i = 0; i < most_visited_urls_.size(); i++) { | 436 for (size_t i = 0; i < most_visited_urls_.size(); i++) { |
435 const history::MostVisitedURL& url = most_visited_urls_[i]; | 437 const history::MostVisitedURL& url = most_visited_urls_[i]; |
436 SearchProvider::NavigationResult nav( | 438 NavigationResult nav(*this, url.url, url.title, false, relevance, true, |
437 *this, url.url, url.title, false, relevance, true, | |
438 current_query_string16, languages); | 439 current_query_string16, languages); |
439 matches_.push_back(NavigationToMatch(nav)); | 440 matches_.push_back(NavigationToMatch(nav)); |
440 --relevance; | 441 --relevance; |
441 } | 442 } |
442 return; | 443 return; |
443 } | 444 } |
444 | 445 |
445 if (num_results == 0) | 446 if (num_results == 0) |
446 return; | 447 return; |
447 | 448 |
448 // TODO(jered): Rip this out once the first match is decoupled from the | 449 // TODO(jered): Rip this out once the first match is decoupled from the |
449 // current typing in the omnibox. | 450 // current typing in the omnibox. |
450 matches_.push_back(current_url_match_); | 451 matches_.push_back(current_url_match_); |
451 | 452 |
452 for (SearchProvider::MatchMap::const_iterator it(query_matches_map_.begin()); | 453 for (MatchMap::const_iterator it(query_matches_map_.begin()); |
453 it != query_matches_map_.end(); ++it) | 454 it != query_matches_map_.end(); ++it) |
454 matches_.push_back(it->second); | 455 matches_.push_back(it->second); |
455 | 456 |
456 for (SearchProvider::NavigationResults::const_iterator it( | 457 for (NavigationResults::const_iterator it(navigation_results_.begin()); |
457 navigation_results_.begin()); it != navigation_results_.end(); ++it) | 458 it != navigation_results_.end(); ++it) |
msw
2014/02/03 22:53:14
nit: indent one more space.
Maria
2014/02/04 03:16:39
Done.
| |
458 matches_.push_back(NavigationToMatch(*it)); | 459 matches_.push_back(NavigationToMatch(*it)); |
459 } | 460 } |
460 | 461 |
461 AutocompleteMatch ZeroSuggestProvider::MatchForCurrentURL() { | 462 AutocompleteMatch ZeroSuggestProvider::MatchForCurrentURL() { |
462 AutocompleteInput input(permanent_text_, base::string16::npos, base::string16( ), | 463 AutocompleteInput input(permanent_text_, base::string16::npos, base::string16( ), |
463 GURL(current_query_), current_page_classification_, | 464 GURL(current_query_), current_page_classification_, |
464 false, false, true, AutocompleteInput::ALL_MATCHES); | 465 false, false, true, AutocompleteInput::ALL_MATCHES); |
465 | 466 |
466 AutocompleteMatch match; | 467 AutocompleteMatch match; |
467 AutocompleteClassifierFactory::GetForProfile(profile_)->Classify( | 468 AutocompleteClassifierFactory::GetForProfile(profile_)->Classify( |
468 permanent_text_, false, true, &match, NULL); | 469 permanent_text_, false, true, &match, NULL); |
469 match.is_history_what_you_typed_match = false; | 470 match.is_history_what_you_typed_match = false; |
470 match.allowed_to_be_default_match = true; | 471 match.allowed_to_be_default_match = true; |
471 | 472 |
472 // The placeholder suggestion for the current URL has high relevance so | 473 // The placeholder suggestion for the current URL has high relevance so |
473 // that it is in the first suggestion slot and inline autocompleted. It | 474 // that it is in the first suggestion slot and inline autocompleted. It |
474 // gets dropped as soon as the user types something. | 475 // gets dropped as soon as the user types something. |
475 match.relevance = verbatim_relevance_; | 476 match.relevance = verbatim_relevance_; |
476 | 477 |
477 return match; | 478 return match; |
478 } | 479 } |
OLD | NEW |