| 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" | 
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 220 | 220 | 
| 221   instant_finalized_ = | 221   instant_finalized_ = | 
| 222       (input.matches_requested() != AutocompleteInput::ALL_MATCHES); | 222       (input.matches_requested() != AutocompleteInput::ALL_MATCHES); | 
| 223 | 223 | 
| 224   // Can't return search/suggest results for bogus input or without a profile. | 224   // Can't return search/suggest results for bogus input or without a profile. | 
| 225   if (!profile_ || (input.type() == AutocompleteInput::INVALID)) { | 225   if (!profile_ || (input.type() == AutocompleteInput::INVALID)) { | 
| 226     Stop(false); | 226     Stop(false); | 
| 227     return; | 227     return; | 
| 228   } | 228   } | 
| 229 | 229 | 
| 230   keyword_input_text_.clear(); | 230   keyword_input_ = input; | 
| 231   const TemplateURL* keyword_provider = | 231   const TemplateURL* keyword_provider = | 
| 232       KeywordProvider::GetSubstitutingTemplateURLForInput(profile_, input, | 232       KeywordProvider::GetSubstitutingTemplateURLForInput(model, | 
| 233                                                           &keyword_input_text_); | 233                                                           &keyword_input_); | 
| 234   if (keyword_input_text_.empty()) | 234   if (keyword_provider == NULL) | 
|  | 235     keyword_input_.Clear(); | 
|  | 236   else if (keyword_input_.text().empty()) | 
| 235     keyword_provider = NULL; | 237     keyword_provider = NULL; | 
| 236 | 238 | 
| 237   const TemplateURL* default_provider = model->GetDefaultSearchProvider(); | 239   const TemplateURL* default_provider = model->GetDefaultSearchProvider(); | 
| 238   if (default_provider && !default_provider->SupportsReplacement()) | 240   if (default_provider && !default_provider->SupportsReplacement()) | 
| 239     default_provider = NULL; | 241     default_provider = NULL; | 
| 240 | 242 | 
| 241   if (keyword_provider == default_provider) | 243   if (keyword_provider == default_provider) | 
| 242     default_provider = NULL;  // No use in querying the same provider twice. | 244     default_provider = NULL;  // No use in querying the same provider twice. | 
| 243 | 245 | 
| 244   if (!default_provider && !keyword_provider) { | 246   if (!default_provider && !keyword_provider) { | 
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 323     return a.relevance() > b.relevance(); | 325     return a.relevance() > b.relevance(); | 
| 324   } | 326   } | 
| 325 }; | 327 }; | 
| 326 | 328 | 
| 327 void SearchProvider::Run() { | 329 void SearchProvider::Run() { | 
| 328   // Start a new request with the current input. | 330   // Start a new request with the current input. | 
| 329   suggest_results_pending_ = 0; | 331   suggest_results_pending_ = 0; | 
| 330   time_suggest_request_sent_ = base::TimeTicks::Now(); | 332   time_suggest_request_sent_ = base::TimeTicks::Now(); | 
| 331 | 333 | 
| 332   default_fetcher_.reset(CreateSuggestFetcher(kDefaultProviderURLFetcherID, | 334   default_fetcher_.reset(CreateSuggestFetcher(kDefaultProviderURLFetcherID, | 
| 333       providers_.GetDefaultProviderURL(), input_.text())); | 335       providers_.GetDefaultProviderURL(), input_)); | 
| 334   keyword_fetcher_.reset(CreateSuggestFetcher(kKeywordProviderURLFetcherID, | 336   keyword_fetcher_.reset(CreateSuggestFetcher(kKeywordProviderURLFetcherID, | 
| 335       providers_.GetKeywordProviderURL(), keyword_input_text_)); | 337       providers_.GetKeywordProviderURL(), keyword_input_)); | 
| 336 | 338 | 
| 337   // Both the above can fail if the providers have been modified or deleted | 339   // Both the above can fail if the providers have been modified or deleted | 
| 338   // since the query began. | 340   // since the query began. | 
| 339   if (suggest_results_pending_ == 0) { | 341   if (suggest_results_pending_ == 0) { | 
| 340     UpdateDone(); | 342     UpdateDone(); | 
| 341     // We only need to update the listener if we're actually done. | 343     // We only need to update the listener if we're actually done. | 
| 342     if (done_) | 344     if (done_) | 
| 343       listener_->OnProviderUpdate(false); | 345       listener_->OnProviderUpdate(false); | 
| 344   } | 346   } | 
| 345 } | 347 } | 
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 467   // database. | 469   // database. | 
| 468   int num_matches = kMaxMatches * 5; | 470   int num_matches = kMaxMatches * 5; | 
| 469   const TemplateURL* default_url = providers_.GetDefaultProviderURL(); | 471   const TemplateURL* default_url = providers_.GetDefaultProviderURL(); | 
| 470   if (default_url) { | 472   if (default_url) { | 
| 471     url_db->GetMostRecentKeywordSearchTerms(default_url->id(), input_.text(), | 473     url_db->GetMostRecentKeywordSearchTerms(default_url->id(), input_.text(), | 
| 472         num_matches, &default_history_results_); | 474         num_matches, &default_history_results_); | 
| 473   } | 475   } | 
| 474   const TemplateURL* keyword_url = providers_.GetKeywordProviderURL(); | 476   const TemplateURL* keyword_url = providers_.GetKeywordProviderURL(); | 
| 475   if (keyword_url) { | 477   if (keyword_url) { | 
| 476     url_db->GetMostRecentKeywordSearchTerms(keyword_url->id(), | 478     url_db->GetMostRecentKeywordSearchTerms(keyword_url->id(), | 
| 477         keyword_input_text_, num_matches, &keyword_history_results_); | 479         keyword_input_.text(), num_matches, &keyword_history_results_); | 
| 478   } | 480   } | 
| 479 } | 481 } | 
| 480 | 482 | 
| 481 void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) { | 483 void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) { | 
| 482   if (!IsQuerySuitableForSuggest()) { | 484   if (!IsQuerySuitableForSuggest()) { | 
| 483     StopSuggest(); | 485     StopSuggest(); | 
| 484     ClearResults(); | 486     ClearResults(); | 
| 485     return; | 487     return; | 
| 486   } | 488   } | 
| 487 | 489 | 
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 588   keyword_suggest_results_.clear(); | 590   keyword_suggest_results_.clear(); | 
| 589   default_suggest_results_.clear(); | 591   default_suggest_results_.clear(); | 
| 590   keyword_navigation_results_.clear(); | 592   keyword_navigation_results_.clear(); | 
| 591   default_navigation_results_.clear(); | 593   default_navigation_results_.clear(); | 
| 592   has_suggested_relevance_ = false; | 594   has_suggested_relevance_ = false; | 
| 593   verbatim_relevance_ = -1; | 595   verbatim_relevance_ = -1; | 
| 594   have_suggest_results_ = false; | 596   have_suggest_results_ = false; | 
| 595 } | 597 } | 
| 596 | 598 | 
| 597 void SearchProvider::RemoveStaleResults() { | 599 void SearchProvider::RemoveStaleResults() { | 
| 598   // Keyword provider results should match |keyword_input_text_|, unless | 600   // Keyword provider results should match |keyword_input_.text()|, unless | 
| 599   // the input was just changed to non-keyword mode; in that case, compare | 601   // the input was just changed to non-keyword mode; in that case, compare | 
| 600   // against |input_.text()|. | 602   // against |input_.text()|. | 
| 601   const string16& keyword_input = | 603   const string16& keyword_input = | 
| 602       !keyword_input_text_.empty() ? keyword_input_text_ : input_.text(); | 604       !keyword_input_.text().empty() ? keyword_input_.text() : input_.text(); | 
| 603   RemoveStaleSuggestResults(&keyword_suggest_results_, keyword_input); | 605   RemoveStaleSuggestResults(&keyword_suggest_results_, keyword_input); | 
| 604   RemoveStaleSuggestResults(&default_suggest_results_, input_.text()); | 606   RemoveStaleSuggestResults(&default_suggest_results_, input_.text()); | 
| 605   RemoveStaleNavigationResults(&keyword_navigation_results_, keyword_input); | 607   RemoveStaleNavigationResults(&keyword_navigation_results_, keyword_input); | 
| 606   RemoveStaleNavigationResults(&default_navigation_results_, input_.text()); | 608   RemoveStaleNavigationResults(&default_navigation_results_, input_.text()); | 
| 607 } | 609 } | 
| 608 | 610 | 
| 609 // static | 611 // static | 
| 610 void SearchProvider::RemoveStaleSuggestResults(SuggestResults* list, | 612 void SearchProvider::RemoveStaleSuggestResults(SuggestResults* list, | 
| 611                                                const string16& input) { | 613                                                const string16& input) { | 
| 612   for (SuggestResults::iterator i = list->begin(); i < list->end();) | 614   for (SuggestResults::iterator i = list->begin(); i < list->end();) | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
| 643                                                         bool is_keyword) { | 645                                                         bool is_keyword) { | 
| 644   for (size_t i = 0; i < list->size(); ++i) { | 646   for (size_t i = 0; i < list->size(); ++i) { | 
| 645     (*list)[i].set_relevance(CalculateRelevanceForNavigation(is_keyword) + | 647     (*list)[i].set_relevance(CalculateRelevanceForNavigation(is_keyword) + | 
| 646                              (list->size() - i - 1)); | 648                              (list->size() - i - 1)); | 
| 647   } | 649   } | 
| 648 } | 650 } | 
| 649 | 651 | 
| 650 net::URLFetcher* SearchProvider::CreateSuggestFetcher( | 652 net::URLFetcher* SearchProvider::CreateSuggestFetcher( | 
| 651     int id, | 653     int id, | 
| 652     const TemplateURL* template_url, | 654     const TemplateURL* template_url, | 
| 653     const string16& text) { | 655     const AutocompleteInput& input) { | 
| 654   if (!template_url || template_url->suggestions_url().empty()) | 656   if (!template_url || template_url->suggestions_url().empty()) | 
| 655     return NULL; | 657     return NULL; | 
| 656 | 658 | 
| 657   // Bail if the suggestion URL is invalid with the given replacements. | 659   // Bail if the suggestion URL is invalid with the given replacements. | 
| 658   TemplateURLRef::SearchTermsArgs search_term_args(text); | 660   TemplateURLRef::SearchTermsArgs search_term_args(input.text()); | 
| 659   search_term_args.cursor_position = input_.cursor_position(); | 661   search_term_args.cursor_position = input.cursor_position(); | 
| 660   GURL suggest_url(template_url->suggestions_url_ref().ReplaceSearchTerms( | 662   GURL suggest_url(template_url->suggestions_url_ref().ReplaceSearchTerms( | 
| 661       search_term_args)); | 663       search_term_args)); | 
| 662   if (!suggest_url.is_valid()) | 664   if (!suggest_url.is_valid()) | 
| 663     return NULL; | 665     return NULL; | 
| 664 | 666 | 
| 665   suggest_results_pending_++; | 667   suggest_results_pending_++; | 
| 666   LogOmniboxSuggestRequest(REQUEST_SENT); | 668   LogOmniboxSuggestRequest(REQUEST_SENT); | 
| 667 | 669 | 
| 668   net::URLFetcher* fetcher = | 670   net::URLFetcher* fetcher = | 
| 669       net::URLFetcher::Create(id, suggest_url, net::URLFetcher::GET, this); | 671       net::URLFetcher::Create(id, suggest_url, net::URLFetcher::GET, this); | 
| 670   fetcher->SetRequestContext(profile_->GetRequestContext()); | 672   fetcher->SetRequestContext(profile_->GetRequestContext()); | 
| 671   fetcher->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES); | 673   fetcher->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES); | 
| 672   // Add Chrome experiment state to the request headers. | 674   // Add Chrome experiment state to the request headers. | 
| 673   net::HttpRequestHeaders headers; | 675   net::HttpRequestHeaders headers; | 
| 674   chrome_variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( | 676   chrome_variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( | 
| 675       fetcher->GetOriginalURL(), profile_->IsOffTheRecord(), false, &headers); | 677       fetcher->GetOriginalURL(), profile_->IsOffTheRecord(), false, &headers); | 
| 676   fetcher->SetExtraRequestHeaders(headers.ToString()); | 678   fetcher->SetExtraRequestHeaders(headers.ToString()); | 
| 677   fetcher->Start(); | 679   fetcher->Start(); | 
| 678   return fetcher; | 680   return fetcher; | 
| 679 } | 681 } | 
| 680 | 682 | 
| 681 bool SearchProvider::ParseSuggestResults(Value* root_val, bool is_keyword) { | 683 bool SearchProvider::ParseSuggestResults(Value* root_val, bool is_keyword) { | 
| 682   // TODO(pkasting): Fix |have_suggest_results_|; see http://crbug.com/130631 | 684   // TODO(pkasting): Fix |have_suggest_results_|; see http://crbug.com/130631 | 
| 683   have_suggest_results_ = false; | 685   have_suggest_results_ = false; | 
| 684 | 686 | 
| 685   string16 query; | 687   string16 query; | 
| 686   ListValue* root_list = NULL; | 688   ListValue* root_list = NULL; | 
| 687   ListValue* results = NULL; | 689   ListValue* results = NULL; | 
| 688   const string16& input_text = is_keyword ? keyword_input_text_ : input_.text(); | 690   const string16& input_text = | 
|  | 691       is_keyword ? keyword_input_.text() : input_.text(); | 
| 689   if (!root_val->GetAsList(&root_list) || !root_list->GetString(0, &query) || | 692   if (!root_val->GetAsList(&root_list) || !root_list->GetString(0, &query) || | 
| 690       (query != input_text) || !root_list->GetList(1, &results)) | 693       (query != input_text) || !root_list->GetList(1, &results)) | 
| 691     return false; | 694     return false; | 
| 692 | 695 | 
| 693   // 3rd element: Description list. | 696   // 3rd element: Description list. | 
| 694   ListValue* descriptions = NULL; | 697   ListValue* descriptions = NULL; | 
| 695   root_list->GetList(2, &descriptions); | 698   root_list->GetList(2, &descriptions); | 
| 696 | 699 | 
| 697   // 4th element: Disregard the query URL list for now. | 700   // 4th element: Disregard the query URL list for now. | 
| 698 | 701 | 
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 943 | 946 | 
| 944 void SearchProvider::AddHistoryResultsToMap(const HistoryResults& results, | 947 void SearchProvider::AddHistoryResultsToMap(const HistoryResults& results, | 
| 945                                             bool is_keyword, | 948                                             bool is_keyword, | 
| 946                                             int did_not_accept_suggestion, | 949                                             int did_not_accept_suggestion, | 
| 947                                             MatchMap* map) { | 950                                             MatchMap* map) { | 
| 948   if (results.empty()) | 951   if (results.empty()) | 
| 949     return; | 952     return; | 
| 950 | 953 | 
| 951   bool prevent_inline_autocomplete = input_.prevent_inline_autocomplete() || | 954   bool prevent_inline_autocomplete = input_.prevent_inline_autocomplete() || | 
| 952       (input_.type() == AutocompleteInput::URL); | 955       (input_.type() == AutocompleteInput::URL); | 
| 953   const string16& input_text = is_keyword ? keyword_input_text_ : input_.text(); | 956   const string16& input_text = | 
|  | 957       is_keyword ? keyword_input_.text() : input_.text(); | 
| 954   bool input_multiple_words = HasMultipleWords(input_text); | 958   bool input_multiple_words = HasMultipleWords(input_text); | 
| 955 | 959 | 
| 956   SuggestResults scored_results; | 960   SuggestResults scored_results; | 
| 957   if (!prevent_inline_autocomplete && input_multiple_words) { | 961   if (!prevent_inline_autocomplete && input_multiple_words) { | 
| 958     // ScoreHistoryResults() allows autocompletion of multi-word, 1-visit | 962     // ScoreHistoryResults() allows autocompletion of multi-word, 1-visit | 
| 959     // queries if the input also has multiple words.  But if we were already | 963     // queries if the input also has multiple words.  But if we were already | 
| 960     // autocompleting a multi-word, multi-visit query, and the current input is | 964     // autocompleting a multi-word, multi-visit query, and the current input is | 
| 961     // still a prefix of it, then changing the autocompletion suddenly feels | 965     // still a prefix of it, then changing the autocompletion suddenly feels | 
| 962     // wrong.  To detect this case, first score as if only one word has been | 966     // wrong.  To detect this case, first score as if only one word has been | 
| 963     // typed, then check for a best result that is an autocompleted, multi-word | 967     // typed, then check for a best result that is an autocompleted, multi-word | 
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1036       i->set_relevance(last_relevance - 1); | 1040       i->set_relevance(last_relevance - 1); | 
| 1037     last_relevance = i->relevance(); | 1041     last_relevance = i->relevance(); | 
| 1038   } | 1042   } | 
| 1039 | 1043 | 
| 1040   return scored_results; | 1044   return scored_results; | 
| 1041 } | 1045 } | 
| 1042 | 1046 | 
| 1043 void SearchProvider::AddSuggestResultsToMap(const SuggestResults& results, | 1047 void SearchProvider::AddSuggestResultsToMap(const SuggestResults& results, | 
| 1044                                             bool is_keyword, | 1048                                             bool is_keyword, | 
| 1045                                             MatchMap* map) { | 1049                                             MatchMap* map) { | 
| 1046   const string16& input_text = is_keyword ? keyword_input_text_ : input_.text(); | 1050   const string16& input_text = | 
|  | 1051       is_keyword ? keyword_input_.text() : input_.text(); | 
| 1047   for (size_t i = 0; i < results.size(); ++i) { | 1052   for (size_t i = 0; i < results.size(); ++i) { | 
| 1048     AddMatchToMap(results[i].suggestion(), input_text, results[i].relevance(), | 1053     AddMatchToMap(results[i].suggestion(), input_text, results[i].relevance(), | 
| 1049                   AutocompleteMatch::SEARCH_SUGGEST, i, is_keyword, map); | 1054                   AutocompleteMatch::SEARCH_SUGGEST, i, is_keyword, map); | 
| 1050   } | 1055   } | 
| 1051 } | 1056 } | 
| 1052 | 1057 | 
| 1053 int SearchProvider::GetVerbatimRelevance() const { | 1058 int SearchProvider::GetVerbatimRelevance() const { | 
| 1054   // Use the suggested verbatim relevance score if it is non-negative (valid), | 1059   // Use the suggested verbatim relevance score if it is non-negative (valid), | 
| 1055   // if inline autocomplete isn't prevented (always show verbatim on backspace), | 1060   // if inline autocomplete isn't prevented (always show verbatim on backspace), | 
| 1056   // and if it won't suppress verbatim, leaving no default provider matches. | 1061   // and if it won't suppress verbatim, leaving no default provider matches. | 
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1234   // results sorted by recency, this means we'll pick the most recent such | 1239   // results sorted by recency, this means we'll pick the most recent such | 
| 1235   // result even if the precision of our relevance score is too low to | 1240   // result even if the precision of our relevance score is too low to | 
| 1236   // distinguish the two. | 1241   // distinguish the two. | 
| 1237   if (!i.second && (match.relevance > i.first->second.relevance)) | 1242   if (!i.second && (match.relevance > i.first->second.relevance)) | 
| 1238     i.first->second = match; | 1243     i.first->second = match; | 
| 1239 } | 1244 } | 
| 1240 | 1245 | 
| 1241 AutocompleteMatch SearchProvider::NavigationToMatch( | 1246 AutocompleteMatch SearchProvider::NavigationToMatch( | 
| 1242     const NavigationResult& navigation, | 1247     const NavigationResult& navigation, | 
| 1243     bool is_keyword) { | 1248     bool is_keyword) { | 
| 1244   const string16& input = is_keyword ? keyword_input_text_ : input_.text(); | 1249   const string16& input = is_keyword ? keyword_input_.text() : input_.text(); | 
| 1245   AutocompleteMatch match(this, navigation.relevance(), false, | 1250   AutocompleteMatch match(this, navigation.relevance(), false, | 
| 1246                           AutocompleteMatch::NAVSUGGEST); | 1251                           AutocompleteMatch::NAVSUGGEST); | 
| 1247   match.destination_url = navigation.url(); | 1252   match.destination_url = navigation.url(); | 
| 1248 | 1253 | 
| 1249   // First look for the user's input inside the fill_into_edit as it would be | 1254   // First look for the user's input inside the fill_into_edit as it would be | 
| 1250   // without trimming the scheme, so we can find matches at the beginning of the | 1255   // without trimming the scheme, so we can find matches at the beginning of the | 
| 1251   // scheme. | 1256   // scheme. | 
| 1252   const string16 untrimmed_fill_into_edit( | 1257   const string16 untrimmed_fill_into_edit( | 
| 1253       AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(), | 1258       AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(), | 
| 1254           StringForURLDisplay(navigation.url(), true, false))); | 1259           StringForURLDisplay(navigation.url(), true, false))); | 
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1301 } | 1306 } | 
| 1302 | 1307 | 
| 1303 void SearchProvider::UpdateDone() { | 1308 void SearchProvider::UpdateDone() { | 
| 1304   // We're done when the timer isn't running, there are no suggest queries | 1309   // We're done when the timer isn't running, there are no suggest queries | 
| 1305   // pending, and we're not waiting on instant. | 1310   // pending, and we're not waiting on instant. | 
| 1306   done_ = (!timer_.IsRunning() && (suggest_results_pending_ == 0) && | 1311   done_ = (!timer_.IsRunning() && (suggest_results_pending_ == 0) && | 
| 1307            (instant_finalized_ || | 1312            (instant_finalized_ || | 
| 1308             (!chrome::BrowserInstantController::IsInstantEnabled(profile_) && | 1313             (!chrome::BrowserInstantController::IsInstantEnabled(profile_) && | 
| 1309              !chrome::search::IsInstantExtendedAPIEnabled(profile_)))); | 1314              !chrome::search::IsInstantExtendedAPIEnabled(profile_)))); | 
| 1310 } | 1315 } | 
| OLD | NEW | 
|---|