Chromium Code Reviews| 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/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 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 83 // static | 83 // static |
| 84 const int SearchProvider::kDefaultProviderURLFetcherID = 1; | 84 const int SearchProvider::kDefaultProviderURLFetcherID = 1; |
| 85 // static | 85 // static |
| 86 const int SearchProvider::kKeywordProviderURLFetcherID = 2; | 86 const int SearchProvider::kKeywordProviderURLFetcherID = 2; |
| 87 // static | 87 // static |
| 88 bool SearchProvider::query_suggest_immediately_ = false; | 88 bool SearchProvider::query_suggest_immediately_ = false; |
| 89 | 89 |
| 90 SearchProvider::SearchProvider(ACProviderListener* listener, Profile* profile) | 90 SearchProvider::SearchProvider(ACProviderListener* listener, Profile* profile) |
| 91 : AutocompleteProvider(listener, profile, "Search"), | 91 : AutocompleteProvider(listener, profile, "Search"), |
| 92 providers_(profile), | 92 providers_(profile), |
| 93 has_verbatim_relevance_(false), | |
| 94 verbatim_relevance_(0), | |
| 93 suggest_results_pending_(0), | 95 suggest_results_pending_(0), |
| 94 have_suggest_results_(false), | 96 have_suggest_results_(false), |
| 95 instant_finalized_(false) { | 97 instant_finalized_(false) { |
| 96 // We use GetSuggestNumberOfGroups() as the group ID to mean "not in field | 98 // We use GetSuggestNumberOfGroups() as the group ID to mean "not in field |
| 97 // trial." Field trial groups run from 0 to GetSuggestNumberOfGroups() - 1 | 99 // trial." Field trial groups run from 0 to GetSuggestNumberOfGroups() - 1 |
| 98 // (inclusive). | 100 // (inclusive). |
| 99 int suggest_field_trial_group_number = | 101 int suggest_field_trial_group_number = |
| 100 AutocompleteFieldTrial::GetSuggestNumberOfGroups(); | 102 AutocompleteFieldTrial::GetSuggestNumberOfGroups(); |
| 101 if (AutocompleteFieldTrial::InSuggestFieldTrial()) { | 103 if (AutocompleteFieldTrial::InSuggestFieldTrial()) { |
| 102 suggest_field_trial_group_number = | 104 suggest_field_trial_group_number = |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 140 for (ACMatches::iterator i = matches_.begin(); i != matches_.end();) { | 142 for (ACMatches::iterator i = matches_.begin(); i != matches_.end();) { |
| 141 if (((i->type == AutocompleteMatch::SEARCH_HISTORY) || | 143 if (((i->type == AutocompleteMatch::SEARCH_HISTORY) || |
| 142 (i->type == AutocompleteMatch::SEARCH_SUGGEST)) && | 144 (i->type == AutocompleteMatch::SEARCH_SUGGEST)) && |
| 143 (i->fill_into_edit == text)) { | 145 (i->fill_into_edit == text)) { |
| 144 i = matches_.erase(i); | 146 i = matches_.erase(i); |
| 145 } else { | 147 } else { |
| 146 ++i; | 148 ++i; |
| 147 } | 149 } |
| 148 } | 150 } |
| 149 | 151 |
| 152 // TODO(msw): Update this or ensure it's not removed in | |
| 153 // ConvertResultsToAutocompleteMatches? | |
| 150 // Add the new suggest result. We give it a rank higher than | 154 // Add the new suggest result. We give it a rank higher than |
| 151 // SEARCH_WHAT_YOU_TYPED so that it gets autocompleted. | 155 // SEARCH_WHAT_YOU_TYPED so that it gets autocompleted. |
| 152 int did_not_accept_default_suggestion = default_suggest_results_.empty() ? | 156 int did_not_accept_default_suggestion = default_suggest_results_.empty() ? |
| 153 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE : | 157 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE : |
| 154 TemplateURLRef::NO_SUGGESTION_CHOSEN; | 158 TemplateURLRef::NO_SUGGESTION_CHOSEN; |
| 155 MatchMap match_map; | 159 MatchMap match_map; |
| 156 AddMatchToMap(text, adjusted_input_text, | 160 AddMatchToMap(text, adjusted_input_text, |
| 157 CalculateRelevanceForWhatYouTyped() + 1, | 161 CalculateRelevanceForWhatYouTyped() + 1, |
| 158 AutocompleteMatch::SEARCH_SUGGEST, | 162 AutocompleteMatch::SEARCH_SUGGEST, |
| 159 did_not_accept_default_suggestion, false, | 163 did_not_accept_default_suggestion, false, |
| 160 input_.prevent_inline_autocomplete(), &match_map); | 164 input_.prevent_inline_autocomplete(), &match_map); |
| 161 DCHECK_EQ(1u, match_map.size()); | 165 DCHECK_EQ(1u, match_map.size()); |
| 162 matches_.push_back(match_map.begin()->second); | 166 matches_.push_back(match_map.begin()->second); |
| 163 | 167 |
| 164 listener_->OnProviderUpdate(true); | 168 listener_->OnProviderUpdate(true); |
| 165 } | 169 } |
| 166 | 170 |
| 167 void SearchProvider::Start(const AutocompleteInput& input, | 171 void SearchProvider::Start(const AutocompleteInput& input, |
| 168 bool minimal_changes) { | 172 bool minimal_changes) { |
| 169 matches_.clear(); | |
| 170 | |
| 171 instant_finalized_ = | 173 instant_finalized_ = |
| 172 (input.matches_requested() != AutocompleteInput::ALL_MATCHES); | 174 (input.matches_requested() != AutocompleteInput::ALL_MATCHES); |
| 173 | 175 |
| 174 // Can't return search/suggest results for bogus input or without a profile. | 176 // Can't return search/suggest results for bogus input or without a profile. |
| 175 if (!profile_ || (input.type() == AutocompleteInput::INVALID)) { | 177 if (!profile_ || (input.type() == AutocompleteInput::INVALID)) { |
| 176 Stop(); | 178 Stop(); |
| 177 return; | 179 return; |
| 178 } | 180 } |
| 179 | 181 |
| 180 keyword_input_text_.clear(); | 182 keyword_input_text_.clear(); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 227 return; | 229 return; |
| 228 } | 230 } |
| 229 | 231 |
| 230 input_ = input; | 232 input_ = input; |
| 231 | 233 |
| 232 DoHistoryQuery(minimal_changes); | 234 DoHistoryQuery(minimal_changes); |
| 233 StartOrStopSuggestQuery(minimal_changes); | 235 StartOrStopSuggestQuery(minimal_changes); |
| 234 ConvertResultsToAutocompleteMatches(); | 236 ConvertResultsToAutocompleteMatches(); |
| 235 } | 237 } |
| 236 | 238 |
| 239 SearchProvider::SuggestResult::SuggestResult(const string16& suggestion, | |
| 240 bool has_suggested_relevance, | |
| 241 int relevance) | |
| 242 : suggestion(suggestion), | |
| 243 has_suggested_relevance(has_suggested_relevance), | |
| 244 relevance(relevance) { | |
| 245 } | |
| 246 | |
| 247 SearchProvider::NavigationResult::NavigationResult( | |
| 248 const GURL& url, | |
| 249 const string16& site_name, | |
| 250 bool has_suggested_relevance, | |
| 251 int relevance) | |
| 252 : url(url), | |
| 253 site_name(site_name), | |
| 254 has_suggested_relevance(has_suggested_relevance), | |
| 255 relevance(relevance) { | |
| 256 } | |
| 257 | |
| 237 class SearchProvider::CompareScoredTerms { | 258 class SearchProvider::CompareScoredTerms { |
| 238 public: | 259 public: |
| 239 bool operator()(const ScoredTerm& a, const ScoredTerm& b) { | 260 bool operator()(const ScoredTerm& a, const ScoredTerm& b) { |
| 240 // Sort in descending relevance order. | 261 // Sort in descending relevance order. |
| 241 return a.second > b.second; | 262 return a.second > b.second; |
| 242 } | 263 } |
| 243 }; | 264 }; |
| 244 | 265 |
| 245 void SearchProvider::Run() { | 266 void SearchProvider::Run() { |
| 246 // Start a new request with the current input. | 267 // Start a new request with the current input. |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 257 providers_.keyword_provider()->suggestions_url_ref(), | 278 providers_.keyword_provider()->suggestions_url_ref(), |
| 258 keyword_input_text_)); | 279 keyword_input_text_)); |
| 259 } | 280 } |
| 260 // We should only get here if we have a suggest url for the keyword or default | 281 // We should only get here if we have a suggest url for the keyword or default |
| 261 // providers. | 282 // providers. |
| 262 DCHECK_GT(suggest_results_pending_, 0); | 283 DCHECK_GT(suggest_results_pending_, 0); |
| 263 } | 284 } |
| 264 | 285 |
| 265 void SearchProvider::Stop() { | 286 void SearchProvider::Stop() { |
| 266 StopSuggest(); | 287 StopSuggest(); |
| 288 ClearResults(); | |
| 267 done_ = true; | 289 done_ = true; |
| 268 default_provider_suggest_text_.clear(); | 290 default_provider_suggest_text_.clear(); |
| 269 } | 291 } |
| 270 | 292 |
| 271 void SearchProvider::OnURLFetchComplete(const content::URLFetcher* source) { | 293 void SearchProvider::OnURLFetchComplete(const content::URLFetcher* source) { |
| 272 DCHECK(!done_); | 294 DCHECK(!done_); |
| 273 suggest_results_pending_--; | 295 suggest_results_pending_--; |
| 274 DCHECK_GE(suggest_results_pending_, 0); // Should never go negative. | 296 DCHECK_GE(suggest_results_pending_, 0); // Should never go negative. |
| 275 const net::HttpResponseHeaders* const response_headers = | 297 const net::HttpResponseHeaders* const response_headers = |
| 276 source->GetResponseHeaders(); | 298 source->GetResponseHeaders(); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 349 keyword_input_text_, num_matches, &keyword_history_results_); | 371 keyword_input_text_, num_matches, &keyword_history_results_); |
| 350 } | 372 } |
| 351 } | 373 } |
| 352 | 374 |
| 353 void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) { | 375 void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) { |
| 354 // Don't send any queries to the server until some time has elapsed after | 376 // Don't send any queries to the server until some time has elapsed after |
| 355 // the last keypress, to avoid flooding the server with requests we are | 377 // the last keypress, to avoid flooding the server with requests we are |
| 356 // likely to end up throwing away anyway. | 378 // likely to end up throwing away anyway. |
| 357 const int kQueryDelayMs = 200; | 379 const int kQueryDelayMs = 200; |
| 358 | 380 |
| 381 // TODO(msw): Synchronously remove irrelevant inline autocomplete matches, | |
| 382 // update the remaining matches for the new input. | |
| 383 // Mark these matches from_previous = true? | |
| 384 for (ACMatches::iterator i = matches_.begin(); i != matches_.end();) { | |
| 385 if (i->contents.find(input_.text()) == string16::npos && | |
| 386 i->description.find(input_.text()) == string16::npos) { | |
| 387 i = matches_.erase(i); | |
| 388 } else { | |
| 389 if (i->inline_autocomplete_offset != string16::npos) { | |
|
Peter Kasting
2012/05/04 00:11:33
I wouldn't try to adjust the offsets directly, I'd
msw
2012/05/04 09:43:40
Done; but I still may need to update the results s
| |
| 390 if (StartsWith(i->fill_into_edit, input_.text(), false)) | |
| 391 i->inline_autocomplete_offset = input_.text().length(); | |
| 392 else | |
| 393 i->inline_autocomplete_offset = string16::npos; | |
| 394 } | |
| 395 // TODO(msw): Fixup navigational result highlighting/styling? | |
| 396 ++i; | |
| 397 } | |
| 398 } | |
| 399 | |
| 359 if (!IsQuerySuitableForSuggest()) { | 400 if (!IsQuerySuitableForSuggest()) { |
| 360 StopSuggest(); | 401 StopSuggest(); |
| 402 ClearResults(); | |
| 361 return; | 403 return; |
| 362 } | 404 } |
| 363 | 405 |
| 364 // For the minimal_changes case, if we finished the previous query and still | 406 // For the minimal_changes case, if we finished the previous query and still |
| 365 // have its results, or are allowed to keep running it, just do that, rather | 407 // have its results, or are allowed to keep running it, just do that, rather |
| 366 // than starting a new query. | 408 // than starting a new query. |
| 367 if (minimal_changes && | 409 if (minimal_changes && |
| 368 (have_suggest_results_ || | 410 (have_suggest_results_ || |
| 369 (!done_ && | 411 (!done_ && |
| 370 input_.matches_requested() == AutocompleteInput::ALL_MATCHES))) | 412 input_.matches_requested() == AutocompleteInput::ALL_MATCHES))) |
| 371 return; | 413 return; |
| 372 | 414 |
| 373 // We can't keep running any previous query, so halt it. | 415 // We can't keep running any previous query, so halt it. |
| 374 StopSuggest(); | 416 StopSuggest(); |
| 417 ClearResults(); | |
| 375 | 418 |
| 376 // We can't start a new query if we're only allowed synchronous results. | 419 // We can't start a new query if we're only allowed synchronous results. |
| 377 if (input_.matches_requested() != AutocompleteInput::ALL_MATCHES) | 420 if (input_.matches_requested() != AutocompleteInput::ALL_MATCHES) |
| 378 return; | 421 return; |
| 379 | 422 |
| 380 // We'll have at least one pending fetch. Set it to 1 now, but the value is | 423 // We'll have at least one pending fetch. Set it to 1 now, but the value is |
| 381 // correctly set in Run. As Run isn't invoked immediately we need to set this | 424 // correctly set in Run. As Run isn't invoked immediately we need to set this |
| 382 // now, else we won't think we're waiting on results from the server when we | 425 // now, else we won't think we're waiting on results from the server when we |
| 383 // really are. | 426 // really are. |
| 384 suggest_results_pending_ = 1; | 427 suggest_results_pending_ = 1; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 442 | 485 |
| 443 return true; | 486 return true; |
| 444 } | 487 } |
| 445 | 488 |
| 446 void SearchProvider::StopSuggest() { | 489 void SearchProvider::StopSuggest() { |
| 447 suggest_results_pending_ = 0; | 490 suggest_results_pending_ = 0; |
| 448 timer_.Stop(); | 491 timer_.Stop(); |
| 449 // Stop any in-progress URL fetches. | 492 // Stop any in-progress URL fetches. |
| 450 keyword_fetcher_.reset(); | 493 keyword_fetcher_.reset(); |
| 451 default_fetcher_.reset(); | 494 default_fetcher_.reset(); |
| 495 } | |
| 496 | |
| 497 void SearchProvider::ClearResults() { | |
| 452 keyword_suggest_results_.clear(); | 498 keyword_suggest_results_.clear(); |
| 453 default_suggest_results_.clear(); | 499 default_suggest_results_.clear(); |
| 454 keyword_navigation_results_.clear(); | 500 keyword_navigation_results_.clear(); |
| 455 default_navigation_results_.clear(); | 501 default_navigation_results_.clear(); |
| 456 have_suggest_results_ = false; | 502 have_suggest_results_ = false; |
| 457 } | 503 } |
| 458 | 504 |
| 459 content::URLFetcher* SearchProvider::CreateSuggestFetcher( | 505 content::URLFetcher* SearchProvider::CreateSuggestFetcher( |
| 460 int id, | 506 int id, |
| 461 const TemplateURLRef& suggestions_url, | 507 const TemplateURLRef& suggestions_url, |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 495 if (root_list->Get(2, &description_val) && | 541 if (root_list->Get(2, &description_val) && |
| 496 description_val->IsType(Value::TYPE_LIST)) | 542 description_val->IsType(Value::TYPE_LIST)) |
| 497 description_list = static_cast<ListValue*>(description_val); | 543 description_list = static_cast<ListValue*>(description_val); |
| 498 } | 544 } |
| 499 | 545 |
| 500 // We don't care about the query URL list (the fourth element in the | 546 // We don't care about the query URL list (the fourth element in the |
| 501 // response) for now. | 547 // response) for now. |
| 502 | 548 |
| 503 // Parse optional data in the results from the Suggest server if any. | 549 // Parse optional data in the results from the Suggest server if any. |
| 504 ListValue* type_list = NULL; | 550 ListValue* type_list = NULL; |
| 551 ListValue* relevance_list = NULL; | |
| 552 has_verbatim_relevance_ = false; | |
| 553 verbatim_relevance_ = 0; | |
| 505 // 5th argument: Optional key-value pairs. | 554 // 5th argument: Optional key-value pairs. |
| 506 // TODO: We may iterate the 5th+ arguments of the root_list if any other | 555 // TODO: We may iterate the 5th+ arguments of the root_list if any other |
| 507 // optional data are defined. | 556 // optional data are defined. |
| 508 if (root_list->GetSize() > 4) { | 557 if (root_list->GetSize() > 4) { |
| 509 Value* optional_val; | 558 Value* optional_val; |
| 510 if (root_list->Get(4, &optional_val) && | 559 if (root_list->Get(4, &optional_val) && |
| 511 optional_val->IsType(Value::TYPE_DICTIONARY)) { | 560 optional_val->IsType(Value::TYPE_DICTIONARY)) { |
| 512 DictionaryValue* dict_val = static_cast<DictionaryValue*>(optional_val); | 561 DictionaryValue* dict_val = static_cast<DictionaryValue*>(optional_val); |
| 513 | 562 |
| 514 // Parse Google Suggest specific type extension. | 563 // Parse Google Suggest specific type extension. |
| 515 const std::string kGoogleSuggestType("google:suggesttype"); | 564 const std::string kGoogleSuggestType("google:suggesttype"); |
| 516 if (dict_val->HasKey(kGoogleSuggestType)) | 565 if (dict_val->HasKey(kGoogleSuggestType)) |
| 517 dict_val->GetList(kGoogleSuggestType, &type_list); | 566 dict_val->GetList(kGoogleSuggestType, &type_list); |
| 567 | |
| 568 // Parse Google Suggest specific relevance extension. | |
| 569 const std::string kGoogleSuggestRelevance("google:suggestrelevance"); | |
| 570 if (dict_val->HasKey(kGoogleSuggestRelevance)) | |
| 571 dict_val->GetList(kGoogleSuggestRelevance, &relevance_list); | |
| 572 | |
| 573 // Parse Google Suggest specific verbatim relevance extension. | |
| 574 const std::string kGoogleVerbatimRelevance("google:verbatimrelevance"); | |
| 575 if (dict_val->GetInteger(kGoogleVerbatimRelevance, &verbatim_relevance_)) | |
| 576 has_verbatim_relevance_ = true; | |
| 518 } | 577 } |
| 519 } | 578 } |
| 520 | 579 |
| 521 ListValue* result_list = static_cast<ListValue*>(result_val); | 580 ListValue* result_list = static_cast<ListValue*>(result_val); |
| 522 for (size_t i = 0; i < result_list->GetSize(); ++i) { | 581 for (size_t i = 0; i < result_list->GetSize(); ++i) { |
| 523 Value* suggestion_val; | 582 Value* suggestion_val; |
| 524 string16 suggestion_str; | 583 string16 suggestion_str; |
| 525 if (!result_list->Get(i, &suggestion_val) || | 584 if (!result_list->Get(i, &suggestion_val) || |
| 526 !suggestion_val->GetAsString(&suggestion_str)) | 585 !suggestion_val->GetAsString(&suggestion_str)) |
| 527 return false; | 586 return false; |
| 528 | 587 |
| 529 // Google search may return empty suggestions for weird input characters, | 588 // Google search may return empty suggestions for weird input characters, |
| 530 // they make no sense at all and can cause problem in our code. | 589 // they make no sense at all and can cause problem in our code. |
| 531 // See http://crbug.com/56214 | 590 // See http://crbug.com/56214 |
| 532 if (!suggestion_str.length()) | 591 if (!suggestion_str.length()) |
| 533 continue; | 592 continue; |
| 534 | 593 |
| 594 bool has_suggested_relevance = false; | |
| 595 int relevance = 0; | |
| 596 if (relevance_list && relevance_list->GetInteger(i, &relevance)) | |
| 597 has_suggested_relevance = true; | |
| 598 | |
| 535 Value* type_val; | 599 Value* type_val; |
| 536 std::string type_str; | 600 std::string type_str; |
| 537 if (type_list && type_list->Get(i, &type_val) && | 601 if (type_list && type_list->Get(i, &type_val) && |
| 538 type_val->GetAsString(&type_str) && (type_str == "NAVIGATION")) { | 602 type_val->GetAsString(&type_str) && (type_str == "NAVIGATION")) { |
| 539 Value* site_val; | 603 Value* site_val; |
| 540 string16 site_name; | 604 string16 site_name; |
| 541 NavigationResults& navigation_results = | 605 NavigationResults& navigation_results = |
| 542 is_keyword ? keyword_navigation_results_ : | 606 is_keyword ? keyword_navigation_results_ : |
| 543 default_navigation_results_; | 607 default_navigation_results_; |
| 544 if ((navigation_results.size() < kMaxMatches) && | 608 if ((navigation_results.size() < kMaxMatches) && |
| 545 description_list && description_list->Get(i, &site_val) && | 609 description_list && description_list->Get(i, &site_val) && |
| 546 site_val->IsType(Value::TYPE_STRING) && | 610 site_val->IsType(Value::TYPE_STRING) && |
| 547 site_val->GetAsString(&site_name)) { | 611 site_val->GetAsString(&site_name)) { |
| 548 // We can't blindly trust the URL coming from the server to be valid. | 612 // We can't blindly trust the URL coming from the server to be valid. |
| 549 GURL result_url(URLFixerUpper::FixupURL(UTF16ToUTF8(suggestion_str), | 613 GURL result_url(URLFixerUpper::FixupURL(UTF16ToUTF8(suggestion_str), |
| 550 std::string())); | 614 std::string())); |
| 551 if (result_url.is_valid()) { | 615 if (result_url.is_valid()) { |
| 552 navigation_results.push_back(NavigationResult(result_url, site_name)); | 616 navigation_results.push_back(NavigationResult(result_url, site_name, |
| 617 has_suggested_relevance, | |
| 618 relevance)); | |
| 553 } | 619 } |
| 554 } | 620 } |
| 555 } else { | 621 } else { |
| 556 // TODO(kochi): Currently we treat a calculator result as a query, but it | 622 // TODO(kochi): Currently we treat a calculator result as a query, but it |
| 557 // is better to have better presentation for caluculator results. | 623 // is better to have better presentation for caluculator results. |
| 558 if (suggest_results->size() < kMaxMatches) | 624 if (suggest_results->size() < kMaxMatches) { |
| 559 suggest_results->push_back(suggestion_str); | 625 suggest_results->push_back(SuggestResult(suggestion_str, |
| 626 has_suggested_relevance, | |
| 627 relevance)); | |
| 628 } | |
| 560 } | 629 } |
| 561 } | 630 } |
| 562 | 631 |
| 563 return true; | 632 return true; |
| 564 } | 633 } |
| 565 | 634 |
| 566 void SearchProvider::ConvertResultsToAutocompleteMatches() { | 635 void SearchProvider::ConvertResultsToAutocompleteMatches() { |
| 567 // Convert all the results to matches and add them to a map, so we can keep | 636 // Convert all the results to matches and add them to a map, so we can keep |
| 568 // the most relevant match for each result. | 637 // the most relevant match for each result. |
| 569 MatchMap map; | 638 MatchMap map; |
| 570 const Time no_time; | 639 const Time no_time; |
| 571 int did_not_accept_keyword_suggestion = keyword_suggest_results_.empty() ? | 640 int did_not_accept_keyword_suggestion = keyword_suggest_results_.empty() ? |
| 572 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE : | 641 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE : |
| 573 TemplateURLRef::NO_SUGGESTION_CHOSEN; | 642 TemplateURLRef::NO_SUGGESTION_CHOSEN; |
| 574 // Keyword what you typed results are handled by the KeywordProvider. | 643 // Keyword what you typed results are handled by the KeywordProvider. |
| 575 | 644 |
| 576 int did_not_accept_default_suggestion = default_suggest_results_.empty() ? | 645 int did_not_accept_default_suggestion = default_suggest_results_.empty() ? |
| 577 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE : | 646 TemplateURLRef::NO_SUGGESTIONS_AVAILABLE : |
| 578 TemplateURLRef::NO_SUGGESTION_CHOSEN; | 647 TemplateURLRef::NO_SUGGESTION_CHOSEN; |
| 579 if (providers_.valid_default_provider()) { | 648 if (providers_.valid_default_provider()) { |
| 580 AddMatchToMap(input_.text(), input_.text(), | 649 int verbatim_relevance = CalculateRelevanceForWhatYouTyped(); |
| 581 CalculateRelevanceForWhatYouTyped(), | 650 if (verbatim_relevance > 0) { |
| 582 AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, | 651 AddMatchToMap(input_.text(), input_.text(), verbatim_relevance, |
| 583 did_not_accept_default_suggestion, false, | 652 AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, |
| 584 input_.prevent_inline_autocomplete(), &map); | 653 did_not_accept_default_suggestion, false, |
| 654 input_.prevent_inline_autocomplete(), &map); | |
| 655 } | |
| 656 // TODO(msw): Should verbatim_relevance affect and/or supress this result? | |
| 585 if (!default_provider_suggest_text_.empty()) { | 657 if (!default_provider_suggest_text_.empty()) { |
| 586 AddMatchToMap(input_.text() + default_provider_suggest_text_, | 658 AddMatchToMap(input_.text() + default_provider_suggest_text_, |
| 587 input_.text(), CalculateRelevanceForWhatYouTyped() + 1, | 659 input_.text(), CalculateRelevanceForWhatYouTyped() + 1, |
| 588 AutocompleteMatch::SEARCH_SUGGEST, | 660 AutocompleteMatch::SEARCH_SUGGEST, |
| 589 did_not_accept_default_suggestion, false, | 661 did_not_accept_default_suggestion, false, |
| 590 input_.prevent_inline_autocomplete(), &map); | 662 input_.prevent_inline_autocomplete(), &map); |
| 591 } | 663 } |
| 592 } | 664 } |
| 593 | 665 |
| 594 AddHistoryResultsToMap(keyword_history_results_, true, | 666 AddHistoryResultsToMap(keyword_history_results_, true, |
| 595 did_not_accept_keyword_suggestion, &map); | 667 did_not_accept_keyword_suggestion, &map); |
| 596 AddHistoryResultsToMap(default_history_results_, false, | 668 AddHistoryResultsToMap(default_history_results_, false, |
| 597 did_not_accept_default_suggestion, &map); | 669 did_not_accept_default_suggestion, &map); |
| 598 | 670 |
| 599 AddSuggestResultsToMap(keyword_suggest_results_, true, | 671 AddSuggestResultsToMap(keyword_suggest_results_, true, |
| 600 did_not_accept_keyword_suggestion, &map); | 672 did_not_accept_keyword_suggestion, &map); |
| 601 AddSuggestResultsToMap(default_suggest_results_, false, | 673 AddSuggestResultsToMap(default_suggest_results_, false, |
| 602 did_not_accept_default_suggestion, &map); | 674 did_not_accept_default_suggestion, &map); |
| 603 | 675 |
| 604 // Now add the most relevant matches from the map to |matches_|. | 676 // Now add the most relevant matches from the map to |matches_|. |
| 605 matches_.clear(); | 677 // TODO(msw): Clear the old matches now?? (only if there are new ones to add?) |
| 678 if (!map.empty()) | |
| 679 matches_.clear(); | |
| 680 // TODO(msw): Merge matches from_previous = true? | |
|
Peter Kasting
2012/05/04 00:11:33
So remember that if you merge previous matches, yo
msw
2012/05/04 09:43:40
Done.
| |
| 681 // (I think removing and re-adding any repeats should be okay...) | |
| 606 for (MatchMap::const_iterator i(map.begin()); i != map.end(); ++i) | 682 for (MatchMap::const_iterator i(map.begin()); i != map.end(); ++i) |
| 607 matches_.push_back(i->second); | 683 matches_.push_back(i->second); |
| 608 | 684 |
| 685 // TODO(msw): Need additional logic to preserve the navigational matches from | |
| 686 // StartOrStopSuggestQuery cleanup through the ClearResults calls? | |
| 609 AddNavigationResultsToMatches(keyword_navigation_results_, true); | 687 AddNavigationResultsToMatches(keyword_navigation_results_, true); |
| 610 AddNavigationResultsToMatches(default_navigation_results_, false); | 688 AddNavigationResultsToMatches(default_navigation_results_, false); |
| 611 | 689 |
| 690 // TODO(msw): Additional logic to only +1 if we have a what-you-typed? | |
|
Peter Kasting
2012/05/04 00:11:33
Yeah
msw
2012/05/04 09:43:40
Done.
| |
| 612 const size_t max_total_matches = kMaxMatches + 1; // 1 for "what you typed" | 691 const size_t max_total_matches = kMaxMatches + 1; // 1 for "what you typed" |
| 613 std::partial_sort(matches_.begin(), | 692 std::partial_sort(matches_.begin(), |
| 614 matches_.begin() + std::min(max_total_matches, matches_.size()), | 693 matches_.begin() + std::min(max_total_matches, matches_.size()), |
| 615 matches_.end(), &AutocompleteMatch::MoreRelevant); | 694 matches_.end(), &AutocompleteMatch::MoreRelevant); |
| 616 if (matches_.size() > max_total_matches) | 695 if (matches_.size() > max_total_matches) |
| 617 matches_.erase(matches_.begin() + max_total_matches, matches_.end()); | 696 matches_.erase(matches_.begin() + max_total_matches, matches_.end()); |
| 618 | 697 |
| 619 UpdateStarredStateOfMatches(); | 698 UpdateStarredStateOfMatches(); |
| 620 | 699 |
| 621 UpdateDone(); | 700 UpdateDone(); |
| 622 } | 701 } |
| 623 | 702 |
| 624 void SearchProvider::AddNavigationResultsToMatches( | 703 void SearchProvider::AddNavigationResultsToMatches( |
| 625 const NavigationResults& navigation_results, | 704 const NavigationResults& navigation_results, |
| 626 bool is_keyword) { | 705 bool is_keyword) { |
| 627 if (!navigation_results.empty()) { | 706 if (!navigation_results.empty()) { |
| 628 // TODO(kochi): http://b/1170574 We add only one results for navigational | 707 // TODO(kochi): http://b/1170574 We add only one results for navigational |
| 629 // suggestions. If we can get more useful information about the score, | 708 // suggestions. If we can get more useful information about the score, |
| 630 // consider adding more results. | 709 // consider adding more results. |
| 631 const size_t num_results = is_keyword ? | |
| 632 keyword_navigation_results_.size() : default_navigation_results_.size(); | |
| 633 matches_.push_back(NavigationToMatch(navigation_results.front(), | 710 matches_.push_back(NavigationToMatch(navigation_results.front(), |
| 634 CalculateRelevanceForNavigation(num_results, 0, is_keyword), | 711 CalculateRelevanceForNavigation(navigation_results, 0, is_keyword), |
| 635 is_keyword)); | 712 is_keyword)); |
| 636 } | 713 } |
| 637 } | 714 } |
| 638 | 715 |
| 639 void SearchProvider::AddHistoryResultsToMap(const HistoryResults& results, | 716 void SearchProvider::AddHistoryResultsToMap(const HistoryResults& results, |
| 640 bool is_keyword, | 717 bool is_keyword, |
| 641 int did_not_accept_suggestion, | 718 int did_not_accept_suggestion, |
| 642 MatchMap* map) { | 719 MatchMap* map) { |
| 643 if (results.empty()) | 720 if (results.empty()) |
| 644 return; | 721 return; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 734 | 811 |
| 735 return scored_terms; | 812 return scored_terms; |
| 736 } | 813 } |
| 737 | 814 |
| 738 void SearchProvider::AddSuggestResultsToMap( | 815 void SearchProvider::AddSuggestResultsToMap( |
| 739 const SuggestResults& suggest_results, | 816 const SuggestResults& suggest_results, |
| 740 bool is_keyword, | 817 bool is_keyword, |
| 741 int did_not_accept_suggestion, | 818 int did_not_accept_suggestion, |
| 742 MatchMap* map) { | 819 MatchMap* map) { |
| 743 for (size_t i = 0; i < suggest_results.size(); ++i) { | 820 for (size_t i = 0; i < suggest_results.size(); ++i) { |
| 744 AddMatchToMap(suggest_results[i], | 821 AddMatchToMap(suggest_results[i].suggestion, |
| 745 is_keyword ? keyword_input_text_ : input_.text(), | 822 is_keyword ? keyword_input_text_ : input_.text(), |
| 746 CalculateRelevanceForSuggestion(suggest_results.size(), i, | 823 CalculateRelevanceForSuggestion(suggest_results, i, |
| 747 is_keyword), | 824 is_keyword), |
| 748 AutocompleteMatch::SEARCH_SUGGEST, | 825 AutocompleteMatch::SEARCH_SUGGEST, |
| 749 static_cast<int>(i), is_keyword, | 826 static_cast<int>(i), is_keyword, |
| 750 input_.prevent_inline_autocomplete(), map); | 827 input_.prevent_inline_autocomplete(), map); |
| 751 } | 828 } |
| 752 } | 829 } |
| 753 | 830 |
| 754 int SearchProvider::CalculateRelevanceForWhatYouTyped() const { | 831 int SearchProvider::CalculateRelevanceForWhatYouTyped() const { |
| 832 // TODO(msw): Effect just the exact SEARCH_WHAT_YOU_TYPED match (line 624) or | |
| 833 // also inline-autocomplete from FinalizeInstantQuery and | |
| 834 // default_provider_suggest_text_??? | |
|
Peter Kasting
2012/05/04 00:11:33
It's not at all clear to me how instant is suppose
msw
2012/05/04 09:43:40
I have a TODO on the CR & in the CL, will e-mail/a
| |
| 835 | |
| 836 // TODO(msw): Do not demote on just_deleted_text_/prevent_inline_autocomplete? | |
|
Peter Kasting
2012/05/04 00:11:33
I think your code does this currently and is corre
msw
2012/05/04 09:43:40
Cool, thanks for the confirmation.
| |
| 837 if (has_verbatim_relevance_ && !input_.prevent_inline_autocomplete()) | |
| 838 return verbatim_relevance_; | |
| 839 | |
| 755 if (providers_.valid_keyword_provider()) | 840 if (providers_.valid_keyword_provider()) |
| 756 return 250; | 841 return 250; |
| 757 | 842 |
| 758 switch (input_.type()) { | 843 switch (input_.type()) { |
| 759 case AutocompleteInput::UNKNOWN: | 844 case AutocompleteInput::UNKNOWN: |
| 760 case AutocompleteInput::QUERY: | 845 case AutocompleteInput::QUERY: |
| 761 case AutocompleteInput::FORCED_QUERY: | 846 case AutocompleteInput::FORCED_QUERY: |
| 762 return 1300; | 847 return 1300; |
| 763 | 848 |
| 764 case AutocompleteInput::REQUESTED_URL: | 849 case AutocompleteInput::REQUESTED_URL: |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 801 // Don't let scores go below 0. Negative relevance scores are meaningful in | 886 // Don't let scores go below 0. Negative relevance scores are meaningful in |
| 802 // a different way. | 887 // a different way. |
| 803 int base_score; | 888 int base_score; |
| 804 if (is_primary_provider) | 889 if (is_primary_provider) |
| 805 base_score = (input_.type() == AutocompleteInput::URL) ? 750 : 1050; | 890 base_score = (input_.type() == AutocompleteInput::URL) ? 750 : 1050; |
| 806 else | 891 else |
| 807 base_score = 200; | 892 base_score = 200; |
| 808 return std::max(0, base_score - score_discount); | 893 return std::max(0, base_score - score_discount); |
| 809 } | 894 } |
| 810 | 895 |
| 811 int SearchProvider::CalculateRelevanceForSuggestion(size_t num_results, | 896 int SearchProvider::CalculateRelevanceForSuggestion( |
| 812 size_t result_number, | 897 const SuggestResults& results, |
| 813 bool is_keyword) const { | 898 size_t result_number, |
| 814 DCHECK(result_number < num_results); | 899 bool is_keyword) const { |
| 900 DCHECK(result_number < results.size()); | |
| 901 if (results[result_number].has_suggested_relevance) | |
| 902 return results[result_number].relevance; | |
| 903 | |
| 815 int base_score; | 904 int base_score; |
| 816 if (!providers_.is_primary_provider(is_keyword)) | 905 if (!providers_.is_primary_provider(is_keyword)) |
| 817 base_score = 100; | 906 base_score = 100; |
| 818 else | 907 else |
| 819 base_score = (input_.type() == AutocompleteInput::URL) ? 300 : 600; | 908 base_score = (input_.type() == AutocompleteInput::URL) ? 300 : 600; |
| 820 return base_score + | 909 return base_score + |
| 821 static_cast<int>(num_results - 1 - result_number); | 910 static_cast<int>(results.size() - 1 - result_number); |
| 822 } | 911 } |
| 823 | 912 |
| 824 int SearchProvider::CalculateRelevanceForNavigation(size_t num_results, | 913 int SearchProvider::CalculateRelevanceForNavigation( |
| 825 size_t result_number, | 914 const NavigationResults& results, |
| 826 bool is_keyword) const { | 915 size_t result_number, |
| 827 DCHECK(result_number < num_results); | 916 bool is_keyword) const { |
| 828 // TODO(kochi): http://b/784900 Use relevance score from the NavSuggest | 917 DCHECK(result_number < results.size()); |
| 829 // server if possible. | 918 if (results[result_number].has_suggested_relevance) |
| 919 return results[result_number].relevance; | |
| 920 | |
| 830 return (providers_.is_primary_provider(is_keyword) ? 800 : 150) + | 921 return (providers_.is_primary_provider(is_keyword) ? 800 : 150) + |
| 831 static_cast<int>(num_results - 1 - result_number); | 922 static_cast<int>(results.size() - 1 - result_number); |
| 832 } | 923 } |
| 833 | 924 |
| 834 void SearchProvider::AddMatchToMap(const string16& query_string, | 925 void SearchProvider::AddMatchToMap(const string16& query_string, |
| 835 const string16& input_text, | 926 const string16& input_text, |
| 836 int relevance, | 927 int relevance, |
| 837 AutocompleteMatch::Type type, | 928 AutocompleteMatch::Type type, |
| 838 int accepted_suggestion, | 929 int accepted_suggestion, |
| 839 bool is_keyword, | 930 bool is_keyword, |
| 840 bool prevent_inline_autocomplete, | 931 bool prevent_inline_autocomplete, |
| 841 MatchMap* map) { | 932 MatchMap* map) { |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 952 &match.description_class); | 1043 &match.description_class); |
| 953 | 1044 |
| 954 // When the user forced a query, we need to make sure all the fill_into_edit | 1045 // When the user forced a query, we need to make sure all the fill_into_edit |
| 955 // values preserve that property. Otherwise, if the user starts editing a | 1046 // values preserve that property. Otherwise, if the user starts editing a |
| 956 // suggestion, non-Search results will suddenly appear. | 1047 // suggestion, non-Search results will suddenly appear. |
| 957 if (input_.type() == AutocompleteInput::FORCED_QUERY) | 1048 if (input_.type() == AutocompleteInput::FORCED_QUERY) |
| 958 match.fill_into_edit.assign(ASCIIToUTF16("?")); | 1049 match.fill_into_edit.assign(ASCIIToUTF16("?")); |
| 959 match.fill_into_edit.append( | 1050 match.fill_into_edit.append( |
| 960 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url, | 1051 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url, |
| 961 match.contents)); | 1052 match.contents)); |
| 962 // TODO(pkasting): http://b/1112879 These should perhaps be | 1053 // TODO(pkasting|msw): http://b/1112879 These should perhaps be |
| 963 // inline-autocompletable? | 1054 // inline-autocompletable? |
| 964 | 1055 |
| 965 return match; | 1056 return match; |
| 966 } | 1057 } |
| 967 | 1058 |
| 968 void SearchProvider::UpdateDone() { | 1059 void SearchProvider::UpdateDone() { |
| 969 // We're done when there are no more suggest queries pending (this is set to 1 | 1060 // We're done when there are no more suggest queries pending (this is set to 1 |
| 970 // when the timer is started) and we're not waiting on instant. | 1061 // when the timer is started) and we're not waiting on instant. |
| 971 done_ = ((suggest_results_pending_ == 0) && | 1062 done_ = ((suggest_results_pending_ == 0) && |
| 972 (instant_finalized_ || !InstantController::IsEnabled(profile_))); | 1063 (instant_finalized_ || !InstantController::IsEnabled(profile_))); |
| 973 } | 1064 } |
| OLD | NEW |