| 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/history_url_provider.h" | 5 #include "chrome/browser/autocomplete/history_url_provider.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 // history DB without re-querying. However, we'd still have to go back to | 401 // history DB without re-querying. However, we'd still have to go back to |
| 402 // the history thread to mark these up properly, and if pass 2 is currently | 402 // the history thread to mark these up properly, and if pass 2 is currently |
| 403 // running, we'd need to wait for it to return to the main thread before | 403 // running, we'd need to wait for it to return to the main thread before |
| 404 // doing this (we can't just write new data for it to read due to thread | 404 // doing this (we can't just write new data for it to read due to thread |
| 405 // safety issues). At that point it's just as fast, and easier, to simply | 405 // safety issues). At that point it's just as fast, and easier, to simply |
| 406 // re-run the query from scratch and ignore |minimal_changes|. | 406 // re-run the query from scratch and ignore |minimal_changes|. |
| 407 | 407 |
| 408 // Cancel any in-progress query. | 408 // Cancel any in-progress query. |
| 409 Stop(false); | 409 Stop(false); |
| 410 | 410 |
| 411 RunAutocompletePasses(input, true); | 411 matches_.clear(); |
| 412 |
| 413 if ((input.type() == AutocompleteInput::INVALID) || |
| 414 (input.type() == AutocompleteInput::FORCED_QUERY)) |
| 415 return; |
| 416 |
| 417 // Create a match for exactly what the user typed. This will only be used as |
| 418 // a fallback in case we can't get the history service or URL DB; otherwise, |
| 419 // we'll run this again in DoAutocomplete() and use that result instead. |
| 420 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()); |
| 421 // Don't do this for queries -- while we can sometimes mark up a match for |
| 422 // this, it's not what the user wants, and just adds noise. |
| 423 if (input.type() != AutocompleteInput::QUERY) { |
| 424 AutocompleteMatch what_you_typed(SuggestExactInput( |
| 425 input.text(), input.canonicalized_url(), trim_http)); |
| 426 what_you_typed.relevance = CalculateRelevance(WHAT_YOU_TYPED, 0); |
| 427 matches_.push_back(what_you_typed); |
| 428 } |
| 429 |
| 430 // We'll need the history service to run both passes, so try to obtain it. |
| 431 if (!profile_) |
| 432 return; |
| 433 HistoryService* const history_service = |
| 434 HistoryServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); |
| 435 if (!history_service) |
| 436 return; |
| 437 |
| 438 // Get the default search provider and search terms data now since we have to |
| 439 // retrieve these on the UI thread, and the second pass runs on the history |
| 440 // thread. |template_url_service| can be NULL when testing. |
| 441 TemplateURLService* template_url_service = |
| 442 TemplateURLServiceFactory::GetForProfile(profile_); |
| 443 TemplateURL* default_search_provider = template_url_service ? |
| 444 template_url_service->GetDefaultSearchProvider() : NULL; |
| 445 UIThreadSearchTermsData data(profile_); |
| 446 |
| 447 // Do some fixup on the user input before matching against it, so we provide |
| 448 // good results for local file paths, input with spaces, etc. |
| 449 base::string16 fixed_up_input_text(FixupUserInput(input, false)); |
| 450 if (fixed_up_input_text.empty()) |
| 451 return; |
| 452 url::Parsed parts; |
| 453 URLFixerUpper::SegmentURL(fixed_up_input_text, &parts); |
| 454 AutocompleteInput fixed_up_input(input); |
| 455 fixed_up_input.UpdateText(fixed_up_input_text, base::string16::npos, parts); |
| 456 |
| 457 // Create the data structure for the autocomplete passes. We'll save this off |
| 458 // onto the |params_| member for later deletion below if we need to run pass |
| 459 // 2. |
| 460 scoped_ptr<HistoryURLProviderParams> params( |
| 461 new HistoryURLProviderParams( |
| 462 fixed_up_input, trim_http, |
| 463 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), |
| 464 default_search_provider, data)); |
| 465 // Note that we use the non-fixed-up input here, since fixup may strip |
| 466 // trailing whitespace. |
| 467 params->prevent_inline_autocomplete = PreventInlineAutocomplete(input); |
| 468 |
| 469 // Pass 1: Get the in-memory URL database, and use it to find and promote |
| 470 // the inline autocomplete match, if any. |
| 471 history::URLDatabase* url_db = history_service->InMemoryDatabase(); |
| 472 // url_db can be NULL if it hasn't finished initializing (or failed to |
| 473 // initialize). In this case all we can do is fall back on the second |
| 474 // pass. |
| 475 // |
| 476 // TODO(pkasting): We should just block here until this loads. Any time |
| 477 // someone unloads the history backend, we'll get inconsistent inline |
| 478 // autocomplete behavior here. |
| 479 if (url_db) { |
| 480 DoAutocomplete(NULL, url_db, params.get()); |
| 481 // params->matches now has the matches we should expose to the provider. |
| 482 // Pass 2 expects a "clean slate" set of matches. |
| 483 matches_.clear(); |
| 484 matches_.swap(params->matches); |
| 485 UpdateStarredStateOfMatches(); |
| 486 } |
| 487 |
| 488 // Pass 2: Ask the history service to call us back on the history thread, |
| 489 // where we can read the full on-disk DB. |
| 490 if (search_url_database_ && input.want_asynchronous_matches()) { |
| 491 done_ = false; |
| 492 params_ = params.release(); // This object will be destroyed in |
| 493 // QueryComplete() once we're done with it. |
| 494 history_service->ScheduleAutocomplete(this, params_); |
| 495 } |
| 412 } | 496 } |
| 413 | 497 |
| 414 void HistoryURLProvider::Stop(bool clear_cached_results) { | 498 void HistoryURLProvider::Stop(bool clear_cached_results) { |
| 415 done_ = true; | 499 done_ = true; |
| 416 | 500 |
| 417 if (params_) | 501 if (params_) |
| 418 params_->cancel_flag.Set(); | 502 params_->cancel_flag.Set(); |
| 419 } | 503 } |
| 420 | 504 |
| 421 AutocompleteMatch HistoryURLProvider::SuggestExactInput( | 505 AutocompleteMatch HistoryURLProvider::SuggestExactInput( |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 681 | 765 |
| 682 case WHAT_YOU_TYPED: | 766 case WHAT_YOU_TYPED: |
| 683 return kScoreForWhatYouTypedResult; | 767 return kScoreForWhatYouTypedResult; |
| 684 | 768 |
| 685 default: // NORMAL | 769 default: // NORMAL |
| 686 return kBaseScoreForNonInlineableResult + | 770 return kBaseScoreForNonInlineableResult + |
| 687 static_cast<int>(match_number); | 771 static_cast<int>(match_number); |
| 688 } | 772 } |
| 689 } | 773 } |
| 690 | 774 |
| 691 void HistoryURLProvider::RunAutocompletePasses( | |
| 692 const AutocompleteInput& input, | |
| 693 bool fixup_input_and_run_pass_1) { | |
| 694 matches_.clear(); | |
| 695 | |
| 696 if ((input.type() == AutocompleteInput::INVALID) || | |
| 697 (input.type() == AutocompleteInput::FORCED_QUERY)) | |
| 698 return; | |
| 699 | |
| 700 // Create a match for exactly what the user typed. This will only be used as | |
| 701 // a fallback in case we can't get the history service or URL DB; otherwise, | |
| 702 // we'll run this again in DoAutocomplete() and use that result instead. | |
| 703 const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()); | |
| 704 // Don't do this for queries -- while we can sometimes mark up a match for | |
| 705 // this, it's not what the user wants, and just adds noise. | |
| 706 if (input.type() != AutocompleteInput::QUERY) { | |
| 707 AutocompleteMatch what_you_typed(SuggestExactInput( | |
| 708 input.text(), input.canonicalized_url(), trim_http)); | |
| 709 what_you_typed.relevance = CalculateRelevance(WHAT_YOU_TYPED, 0); | |
| 710 matches_.push_back(what_you_typed); | |
| 711 } | |
| 712 | |
| 713 // We'll need the history service to run both passes, so try to obtain it. | |
| 714 if (!profile_) | |
| 715 return; | |
| 716 HistoryService* const history_service = | |
| 717 HistoryServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); | |
| 718 if (!history_service) | |
| 719 return; | |
| 720 | |
| 721 // Get the default search provider and search terms data now since we have to | |
| 722 // retrieve these on the UI thread, and the second pass runs on the history | |
| 723 // thread. |template_url_service| can be NULL when testing. | |
| 724 TemplateURLService* template_url_service = | |
| 725 TemplateURLServiceFactory::GetForProfile(profile_); | |
| 726 TemplateURL* default_search_provider = template_url_service ? | |
| 727 template_url_service->GetDefaultSearchProvider() : NULL; | |
| 728 UIThreadSearchTermsData data(profile_); | |
| 729 | |
| 730 // Create the data structure for the autocomplete passes. We'll save this off | |
| 731 // onto the |params_| member for later deletion below if we need to run pass | |
| 732 // 2. | |
| 733 scoped_ptr<HistoryURLProviderParams> params( | |
| 734 new HistoryURLProviderParams( | |
| 735 input, trim_http, | |
| 736 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), | |
| 737 default_search_provider, data)); | |
| 738 | |
| 739 params->prevent_inline_autocomplete = | |
| 740 PreventInlineAutocomplete(input); | |
| 741 | |
| 742 if (fixup_input_and_run_pass_1) { | |
| 743 // Do some fixup on the user input before matching against it, so we provide | |
| 744 // good results for local file paths, input with spaces, etc. | |
| 745 if (!FixupUserInput(¶ms->input)) | |
| 746 return; | |
| 747 | |
| 748 // Pass 1: Get the in-memory URL database, and use it to find and promote | |
| 749 // the inline autocomplete match, if any. | |
| 750 history::URLDatabase* url_db = history_service->InMemoryDatabase(); | |
| 751 // url_db can be NULL if it hasn't finished initializing (or failed to | |
| 752 // initialize). In this case all we can do is fall back on the second | |
| 753 // pass. | |
| 754 // | |
| 755 // TODO(pkasting): We should just block here until this loads. Any time | |
| 756 // someone unloads the history backend, we'll get inconsistent inline | |
| 757 // autocomplete behavior here. | |
| 758 if (url_db) { | |
| 759 DoAutocomplete(NULL, url_db, params.get()); | |
| 760 // params->matches now has the matches we should expose to the provider. | |
| 761 // Pass 2 expects a "clean slate" set of matches. | |
| 762 matches_.clear(); | |
| 763 matches_.swap(params->matches); | |
| 764 UpdateStarredStateOfMatches(); | |
| 765 } | |
| 766 } | |
| 767 | |
| 768 // Pass 2: Ask the history service to call us back on the history thread, | |
| 769 // where we can read the full on-disk DB. | |
| 770 if (search_url_database_ && input.want_asynchronous_matches()) { | |
| 771 done_ = false; | |
| 772 params_ = params.release(); // This object will be destroyed in | |
| 773 // QueryComplete() once we're done with it. | |
| 774 history_service->ScheduleAutocomplete(this, params_); | |
| 775 } | |
| 776 } | |
| 777 | |
| 778 bool HistoryURLProvider::FixupExactSuggestion( | 775 bool HistoryURLProvider::FixupExactSuggestion( |
| 779 history::URLDatabase* db, | 776 history::URLDatabase* db, |
| 780 const AutocompleteInput& input, | 777 const AutocompleteInput& input, |
| 781 const VisitClassifier& classifier, | 778 const VisitClassifier& classifier, |
| 782 AutocompleteMatch* match, | 779 AutocompleteMatch* match, |
| 783 history::HistoryMatches* matches) const { | 780 history::HistoryMatches* matches) const { |
| 784 DCHECK(match != NULL); | 781 DCHECK(match != NULL); |
| 785 DCHECK(matches != NULL); | 782 DCHECK(matches != NULL); |
| 786 | 783 |
| 787 MatchType type = INLINE_AUTOCOMPLETE; | 784 MatchType type = INLINE_AUTOCOMPLETE; |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1158 // If HistoryURL retrieves any matches (and hence we reach this code), we | 1155 // If HistoryURL retrieves any matches (and hence we reach this code), we |
| 1159 // are guaranteed that the beginning of input_text must be a word break. | 1156 // are guaranteed that the beginning of input_text must be a word break. |
| 1160 history::WordStarts offsets(1, 0u); | 1157 history::WordStarts offsets(1, 0u); |
| 1161 description_matches = | 1158 description_matches = |
| 1162 history::ScoredHistoryMatch::FilterTermMatchesByWordStarts( | 1159 history::ScoredHistoryMatch::FilterTermMatchesByWordStarts( |
| 1163 description_matches, offsets, description_word_starts, 0, | 1160 description_matches, offsets, description_word_starts, 0, |
| 1164 std::string::npos); | 1161 std::string::npos); |
| 1165 return SpansFromTermMatch( | 1162 return SpansFromTermMatch( |
| 1166 description_matches, clean_description.length(), false); | 1163 description_matches, clean_description.length(), false); |
| 1167 } | 1164 } |
| OLD | NEW |