Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 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/search_provider.h" | 5 #include "chrome/browser/autocomplete/search_provider.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 | 9 |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/i18n/break_iterator.h" | 11 #include "base/i18n/break_iterator.h" |
| 12 #include "base/i18n/case_conversion.h" | 12 #include "base/i18n/case_conversion.h" |
| 13 #include "base/i18n/icu_string_conversions.h" | 13 #include "base/i18n/icu_string_conversions.h" |
| 14 #include "base/json/json_string_value_serializer.h" | 14 #include "base/json/json_string_value_serializer.h" |
| 15 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
| 16 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" |
| 17 #include "base/prefs/pref_service.h" | 17 #include "base/prefs/pref_service.h" |
| 18 #include "base/strings/string16.h" | 18 #include "base/strings/string16.h" |
| 19 #include "base/strings/string_util.h" | 19 #include "base/strings/string_util.h" |
| 20 #include "base/strings/utf_string_conversions.h" | 20 #include "base/strings/utf_string_conversions.h" |
| 21 #include "chrome/browser/autocomplete/autocomplete_classifier.h" | 21 #include "chrome/browser/autocomplete/autocomplete_classifier.h" |
| 22 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" | 22 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" |
| 23 #include "chrome/browser/autocomplete/autocomplete_match.h" | 23 #include "chrome/browser/autocomplete/autocomplete_match.h" |
| 24 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h" | 24 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h" |
| 25 #include "chrome/browser/autocomplete/autocomplete_result.h" | 25 #include "chrome/browser/autocomplete/autocomplete_result.h" |
| 26 #include "chrome/browser/autocomplete/base_search_provider.h" | |
| 26 #include "chrome/browser/autocomplete/keyword_provider.h" | 27 #include "chrome/browser/autocomplete/keyword_provider.h" |
| 27 #include "chrome/browser/autocomplete/url_prefix.h" | 28 #include "chrome/browser/autocomplete/url_prefix.h" |
| 28 #include "chrome/browser/google/google_util.h" | 29 #include "chrome/browser/google/google_util.h" |
| 29 #include "chrome/browser/history/history_service.h" | 30 #include "chrome/browser/history/history_service.h" |
| 30 #include "chrome/browser/history/history_service_factory.h" | 31 #include "chrome/browser/history/history_service_factory.h" |
| 31 #include "chrome/browser/history/in_memory_database.h" | 32 #include "chrome/browser/history/in_memory_database.h" |
| 32 #include "chrome/browser/metrics/variations/variations_http_header_provider.h" | 33 #include "chrome/browser/metrics/variations/variations_http_header_provider.h" |
| 33 #include "chrome/browser/omnibox/omnibox_field_trial.h" | 34 #include "chrome/browser/omnibox/omnibox_field_trial.h" |
| 34 #include "chrome/browser/profiles/profile.h" | 35 #include "chrome/browser/profiles/profile.h" |
| 35 #include "chrome/browser/search/search.h" | 36 #include "chrome/browser/search/search.h" |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 DCHECK(source == deletion_fetcher_.get()); | 169 DCHECK(source == deletion_fetcher_.get()); |
| 169 callback_.Run( | 170 callback_.Run( |
| 170 source->GetStatus().is_success() && (source->GetResponseCode() == 200), | 171 source->GetStatus().is_success() && (source->GetResponseCode() == 200), |
| 171 this); | 172 this); |
| 172 }; | 173 }; |
| 173 | 174 |
| 174 | 175 |
| 175 // SearchProvider::Providers -------------------------------------------------- | 176 // SearchProvider::Providers -------------------------------------------------- |
| 176 | 177 |
| 177 SearchProvider::Providers::Providers(TemplateURLService* template_url_service) | 178 SearchProvider::Providers::Providers(TemplateURLService* template_url_service) |
| 178 : template_url_service_(template_url_service) { | 179 : template_url_service_(template_url_service) {} |
| 179 } | |
| 180 | 180 |
| 181 const TemplateURL* SearchProvider::Providers::GetDefaultProviderURL() const { | 181 const TemplateURL* SearchProvider::Providers::GetDefaultProviderURL() const { |
| 182 return default_provider_.empty() ? NULL : | 182 return default_provider_.empty() ? NULL : |
| 183 template_url_service_->GetTemplateURLForKeyword(default_provider_); | 183 template_url_service_->GetTemplateURLForKeyword(default_provider_); |
| 184 } | 184 } |
| 185 | 185 |
| 186 const TemplateURL* SearchProvider::Providers::GetKeywordProviderURL() const { | 186 const TemplateURL* SearchProvider::Providers::GetKeywordProviderURL() |
|
H Fung
2014/01/30 02:35:33
I'm not sure why you changed this since it had fit
Maria
2014/01/30 02:47:02
Done.
| |
| 187 const { | |
| 187 return keyword_provider_.empty() ? NULL : | 188 return keyword_provider_.empty() ? NULL : |
| 188 template_url_service_->GetTemplateURLForKeyword(keyword_provider_); | 189 template_url_service_->GetTemplateURLForKeyword(keyword_provider_); |
| 189 } | 190 } |
| 190 | 191 |
| 191 | 192 |
| 192 // SearchProvider::Result ----------------------------------------------------- | |
| 193 | |
| 194 SearchProvider::Result::Result(bool from_keyword_provider, | |
| 195 int relevance, | |
| 196 bool relevance_from_server) | |
| 197 : from_keyword_provider_(from_keyword_provider), | |
| 198 relevance_(relevance), | |
| 199 relevance_from_server_(relevance_from_server) { | |
| 200 } | |
| 201 | |
| 202 SearchProvider::Result::~Result() { | |
| 203 } | |
| 204 | |
| 205 | |
| 206 // SearchProvider::SuggestResult ---------------------------------------------- | |
| 207 | |
| 208 SearchProvider::SuggestResult::SuggestResult( | |
| 209 const base::string16& suggestion, | |
| 210 AutocompleteMatchType::Type type, | |
| 211 const base::string16& match_contents, | |
| 212 const base::string16& annotation, | |
| 213 const std::string& suggest_query_params, | |
| 214 const std::string& deletion_url, | |
| 215 bool from_keyword_provider, | |
| 216 int relevance, | |
| 217 bool relevance_from_server, | |
| 218 bool should_prefetch, | |
| 219 const base::string16& input_text) | |
| 220 : Result(from_keyword_provider, relevance, relevance_from_server), | |
| 221 suggestion_(suggestion), | |
| 222 type_(type), | |
| 223 annotation_(annotation), | |
| 224 suggest_query_params_(suggest_query_params), | |
| 225 deletion_url_(deletion_url), | |
| 226 should_prefetch_(should_prefetch) { | |
| 227 match_contents_ = match_contents; | |
| 228 DCHECK(!match_contents_.empty()); | |
| 229 ClassifyMatchContents(true, input_text); | |
| 230 } | |
| 231 | |
| 232 SearchProvider::SuggestResult::~SuggestResult() { | |
| 233 } | |
| 234 | |
| 235 void SearchProvider::SuggestResult::ClassifyMatchContents( | |
| 236 const bool allow_bolding_all, | |
| 237 const base::string16& input_text) { | |
| 238 size_t input_position = match_contents_.find(input_text); | |
| 239 if (!allow_bolding_all && (input_position == base::string16::npos)) { | |
| 240 // Bail if the code below to update the bolding would bold the whole | |
| 241 // string. Note that the string may already be entirely bolded; if | |
| 242 // so, leave it as is. | |
| 243 return; | |
| 244 } | |
| 245 match_contents_class_.clear(); | |
| 246 // We do intra-string highlighting for suggestions - the suggested segment | |
| 247 // will be highlighted, e.g. for input_text = "you" the suggestion may be | |
| 248 // "youtube", so we'll bold the "tube" section: you*tube*. | |
| 249 if (input_text != match_contents_) { | |
| 250 if (input_position == base::string16::npos) { | |
| 251 // The input text is not a substring of the query string, e.g. input | |
| 252 // text is "slasdot" and the query string is "slashdot", so we bold the | |
| 253 // whole thing. | |
| 254 match_contents_class_.push_back(ACMatchClassification( | |
| 255 0, ACMatchClassification::MATCH)); | |
| 256 } else { | |
| 257 // We don't iterate over the string here annotating all matches because | |
| 258 // it looks odd to have every occurrence of a substring that may be as | |
| 259 // short as a single character highlighted in a query suggestion result, | |
| 260 // e.g. for input text "s" and query string "southwest airlines", it | |
| 261 // looks odd if both the first and last s are highlighted. | |
| 262 if (input_position != 0) { | |
| 263 match_contents_class_.push_back(ACMatchClassification( | |
| 264 0, ACMatchClassification::MATCH)); | |
| 265 } | |
| 266 match_contents_class_.push_back( | |
| 267 ACMatchClassification(input_position, ACMatchClassification::NONE)); | |
| 268 size_t next_fragment_position = input_position + input_text.length(); | |
| 269 if (next_fragment_position < match_contents_.length()) { | |
| 270 match_contents_class_.push_back(ACMatchClassification( | |
| 271 next_fragment_position, ACMatchClassification::MATCH)); | |
| 272 } | |
| 273 } | |
| 274 } else { | |
| 275 // Otherwise, match_contents_ is a verbatim (what-you-typed) match, either | |
| 276 // for the default provider or a keyword search provider. | |
| 277 match_contents_class_.push_back(ACMatchClassification( | |
| 278 0, ACMatchClassification::NONE)); | |
| 279 } | |
| 280 } | |
| 281 | |
| 282 bool SearchProvider::SuggestResult::IsInlineable( | |
| 283 const base::string16& input) const { | |
| 284 return StartsWith(suggestion_, input, false); | |
| 285 } | |
| 286 | |
| 287 int SearchProvider::SuggestResult::CalculateRelevance( | |
| 288 const AutocompleteInput& input, | |
| 289 bool keyword_provider_requested) const { | |
| 290 if (!from_keyword_provider_ && keyword_provider_requested) | |
| 291 return 100; | |
| 292 return ((input.type() == AutocompleteInput::URL) ? 300 : 600); | |
| 293 } | |
| 294 | |
| 295 | |
| 296 // SearchProvider::NavigationResult ------------------------------------------- | |
| 297 | |
| 298 SearchProvider::NavigationResult::NavigationResult( | |
| 299 const AutocompleteProvider& provider, | |
| 300 const GURL& url, | |
| 301 const base::string16& description, | |
| 302 bool from_keyword_provider, | |
| 303 int relevance, | |
| 304 bool relevance_from_server, | |
| 305 const base::string16& input_text, | |
| 306 const std::string& languages) | |
| 307 : Result(from_keyword_provider, relevance, relevance_from_server), | |
| 308 url_(url), | |
| 309 formatted_url_(AutocompleteInput::FormattedStringWithEquivalentMeaning( | |
| 310 url, provider.StringForURLDisplay(url, true, false))), | |
| 311 description_(description) { | |
| 312 DCHECK(url_.is_valid()); | |
| 313 CalculateAndClassifyMatchContents(true, input_text, languages); | |
| 314 } | |
| 315 | |
| 316 SearchProvider::NavigationResult::~NavigationResult() { | |
| 317 } | |
| 318 | |
| 319 void SearchProvider::NavigationResult::CalculateAndClassifyMatchContents( | |
| 320 const bool allow_bolding_nothing, | |
| 321 const base::string16& input_text, | |
| 322 const std::string& languages) { | |
| 323 // First look for the user's input inside the formatted url as it would be | |
| 324 // without trimming the scheme, so we can find matches at the beginning of the | |
| 325 // scheme. | |
| 326 const URLPrefix* prefix = | |
| 327 URLPrefix::BestURLPrefix(formatted_url_, input_text); | |
| 328 size_t match_start = (prefix == NULL) ? | |
| 329 formatted_url_.find(input_text) : prefix->prefix.length(); | |
| 330 bool trim_http = !AutocompleteInput::HasHTTPScheme(input_text) && | |
| 331 (!prefix || (match_start != 0)); | |
| 332 const net::FormatUrlTypes format_types = | |
| 333 net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP); | |
| 334 | |
| 335 base::string16 match_contents = net::FormatUrl(url_, languages, format_types, | |
| 336 net::UnescapeRule::SPACES, NULL, NULL, &match_start); | |
| 337 // If the first match in the untrimmed string was inside a scheme that we | |
| 338 // trimmed, look for a subsequent match. | |
| 339 if (match_start == base::string16::npos) | |
| 340 match_start = match_contents.find(input_text); | |
| 341 // Update |match_contents_| and |match_contents_class_| if it's allowed. | |
| 342 if (allow_bolding_nothing || (match_start != base::string16::npos)) { | |
| 343 match_contents_ = match_contents; | |
| 344 // Safe if |match_start| is npos; also safe if the input is longer than the | |
| 345 // remaining contents after |match_start|. | |
| 346 AutocompleteMatch::ClassifyLocationInString(match_start, | |
| 347 input_text.length(), match_contents_.length(), | |
| 348 ACMatchClassification::URL, &match_contents_class_); | |
| 349 } | |
| 350 } | |
| 351 | |
| 352 bool SearchProvider::NavigationResult::IsInlineable( | |
| 353 const base::string16& input) const { | |
| 354 return URLPrefix::BestURLPrefix(formatted_url_, input) != NULL; | |
| 355 } | |
| 356 | |
| 357 int SearchProvider::NavigationResult::CalculateRelevance( | |
| 358 const AutocompleteInput& input, | |
| 359 bool keyword_provider_requested) const { | |
| 360 return (from_keyword_provider_ || !keyword_provider_requested) ? 800 : 150; | |
| 361 } | |
| 362 | |
| 363 | |
| 364 // SearchProvider::CompareScoredResults --------------------------------------- | 193 // SearchProvider::CompareScoredResults --------------------------------------- |
| 365 | 194 |
| 366 class SearchProvider::CompareScoredResults { | 195 class SearchProvider::CompareScoredResults { |
| 367 public: | 196 public: |
| 368 bool operator()(const Result& a, const Result& b) { | 197 bool operator()(const Result& a, const Result& b) { |
| 369 // Sort in descending relevance order. | 198 // Sort in descending relevance order. |
| 370 return a.relevance() > b.relevance(); | 199 return a.relevance() > b.relevance(); |
| 371 } | 200 } |
| 372 }; | 201 }; |
| 373 | 202 |
| 374 | 203 |
| 375 // SearchProvider::Results ---------------------------------------------------- | |
| 376 | |
| 377 SearchProvider::Results::Results() : verbatim_relevance(-1) { | |
| 378 } | |
| 379 | |
| 380 SearchProvider::Results::~Results() { | |
| 381 } | |
| 382 | |
| 383 void SearchProvider::Results::Clear() { | |
| 384 suggest_results.clear(); | |
| 385 navigation_results.clear(); | |
| 386 verbatim_relevance = -1; | |
| 387 metadata.clear(); | |
| 388 } | |
| 389 | |
| 390 bool SearchProvider::Results::HasServerProvidedScores() const { | |
| 391 if (verbatim_relevance >= 0) | |
| 392 return true; | |
| 393 | |
| 394 // Right now either all results of one type will be server-scored or they will | |
| 395 // all be locally scored, but in case we change this later, we'll just check | |
| 396 // them all. | |
| 397 for (SuggestResults::const_iterator i(suggest_results.begin()); | |
| 398 i != suggest_results.end(); ++i) { | |
| 399 if (i->relevance_from_server()) | |
| 400 return true; | |
| 401 } | |
| 402 for (NavigationResults::const_iterator i(navigation_results.begin()); | |
| 403 i != navigation_results.end(); ++i) { | |
| 404 if (i->relevance_from_server()) | |
| 405 return true; | |
| 406 } | |
| 407 | |
| 408 return false; | |
| 409 } | |
| 410 | |
| 411 | |
| 412 // SearchProvider ------------------------------------------------------------- | 204 // SearchProvider ------------------------------------------------------------- |
| 413 | 205 |
| 414 // static | 206 // static |
| 415 const int SearchProvider::kDefaultProviderURLFetcherID = 1; | 207 const int SearchProvider::kDefaultProviderURLFetcherID = 1; |
| 416 const int SearchProvider::kKeywordProviderURLFetcherID = 2; | 208 const int SearchProvider::kKeywordProviderURLFetcherID = 2; |
| 417 const int SearchProvider::kDeletionURLFetcherID = 3; | 209 const int SearchProvider::kDeletionURLFetcherID = 3; |
| 418 int SearchProvider::kMinimumTimeBetweenSuggestQueriesMs = 100; | 210 int SearchProvider::kMinimumTimeBetweenSuggestQueriesMs = 100; |
| 419 const char SearchProvider::kRelevanceFromServerKey[] = "relevance_from_server"; | 211 const char SearchProvider::kRelevanceFromServerKey[] = "relevance_from_server"; |
| 420 const char SearchProvider::kShouldPrefetchKey[] = "should_prefetch"; | 212 const char SearchProvider::kShouldPrefetchKey[] = "should_prefetch"; |
| 421 const char SearchProvider::kSuggestMetadataKey[] = "suggest_metadata"; | 213 const char SearchProvider::kSuggestMetadataKey[] = "suggest_metadata"; |
| 422 const char SearchProvider::kDeletionUrlKey[] = "deletion_url"; | 214 const char SearchProvider::kDeletionUrlKey[] = "deletion_url"; |
| 423 const char SearchProvider::kTrue[] = "true"; | 215 const char SearchProvider::kTrue[] = "true"; |
| 424 const char SearchProvider::kFalse[] = "false"; | 216 const char SearchProvider::kFalse[] = "false"; |
| 425 | 217 |
| 426 SearchProvider::SearchProvider(AutocompleteProviderListener* listener, | 218 SearchProvider::SearchProvider(AutocompleteProviderListener* listener, |
| 427 Profile* profile) | 219 Profile* profile) |
| 428 : AutocompleteProvider(listener, profile, | 220 : BaseSearchProvider(listener, profile, AutocompleteProvider::TYPE_SEARCH), |
| 429 AutocompleteProvider::TYPE_SEARCH), | |
| 430 providers_(TemplateURLServiceFactory::GetForProfile(profile)), | 221 providers_(TemplateURLServiceFactory::GetForProfile(profile)), |
| 431 suggest_results_pending_(0), | 222 suggest_results_pending_(0), |
| 432 field_trial_triggered_(false), | 223 field_trial_triggered_(false), |
| 433 field_trial_triggered_in_session_(false) { | 224 field_trial_triggered_in_session_(false) { |
| 434 } | 225 } |
| 435 | 226 |
| 436 // static | 227 // static |
| 437 AutocompleteMatch SearchProvider::CreateSearchSuggestion( | 228 AutocompleteMatch SearchProvider::CreateSearchSuggestion( |
| 438 AutocompleteProvider* autocomplete_provider, | 229 AutocompleteProvider* autocomplete_provider, |
| 439 const AutocompleteInput& input, | 230 const AutocompleteInput& input, |
| (...skipping 1648 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2088 if (!OmniboxFieldTrial::InZeroSuggestFieldTrial() || | 1879 if (!OmniboxFieldTrial::InZeroSuggestFieldTrial() || |
| 2089 service == NULL || | 1880 service == NULL || |
| 2090 !service->IsSyncEnabledAndLoggedIn() || | 1881 !service->IsSyncEnabledAndLoggedIn() || |
| 2091 !sync_prefs.GetPreferredDataTypes(syncer::UserTypes()).Has( | 1882 !sync_prefs.GetPreferredDataTypes(syncer::UserTypes()).Has( |
| 2092 syncer::PROXY_TABS) || | 1883 syncer::PROXY_TABS) || |
| 2093 service->GetEncryptedDataTypes().Has(syncer::SESSIONS)) | 1884 service->GetEncryptedDataTypes().Has(syncer::SESSIONS)) |
| 2094 return false; | 1885 return false; |
| 2095 | 1886 |
| 2096 return true; | 1887 return true; |
| 2097 } | 1888 } |
| OLD | NEW |