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 const FixupReturn fixup_return(FixupUserInput(input)); |
| 450 if (!fixup_return.first) |
| 451 return; |
| 452 url::Parsed parts; |
| 453 URLFixerUpper::SegmentURL(fixup_return.second, &parts); |
| 454 AutocompleteInput fixed_up_input(input); |
| 455 fixed_up_input.UpdateText(fixup_return.second, 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 |