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 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 const AutocompleteMatch& what_you_typed_match, | 410 const AutocompleteMatch& what_you_typed_match, |
411 const std::string& languages, | 411 const std::string& languages, |
412 TemplateURL* default_search_provider, | 412 TemplateURL* default_search_provider, |
413 const SearchTermsData& search_terms_data) | 413 const SearchTermsData& search_terms_data) |
414 : message_loop(base::MessageLoop::current()), | 414 : message_loop(base::MessageLoop::current()), |
415 input(input), | 415 input(input), |
416 prevent_inline_autocomplete(input.prevent_inline_autocomplete()), | 416 prevent_inline_autocomplete(input.prevent_inline_autocomplete()), |
417 trim_http(trim_http), | 417 trim_http(trim_http), |
418 what_you_typed_match(what_you_typed_match), | 418 what_you_typed_match(what_you_typed_match), |
419 failed(false), | 419 failed(false), |
| 420 exact_suggestion(0), |
| 421 promote_type(NEITHER), |
420 languages(languages), | 422 languages(languages), |
421 dont_suggest_exact_input(false), | |
422 default_search_provider(default_search_provider ? | 423 default_search_provider(default_search_provider ? |
423 new TemplateURL(default_search_provider->profile(), | 424 new TemplateURL(default_search_provider->profile(), |
424 default_search_provider->data()) : NULL), | 425 default_search_provider->data()) : NULL), |
425 search_terms_data(new SearchTermsDataSnapshot(search_terms_data)) { | 426 search_terms_data(new SearchTermsDataSnapshot(search_terms_data)) { |
426 } | 427 } |
427 | 428 |
428 HistoryURLProviderParams::~HistoryURLProviderParams() { | 429 HistoryURLProviderParams::~HistoryURLProviderParams() { |
429 } | 430 } |
430 | 431 |
431 HistoryURLProvider::HistoryURLProvider(AutocompleteProviderListener* listener, | 432 HistoryURLProvider::HistoryURLProvider(AutocompleteProviderListener* listener, |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
521 history::URLDatabase* url_db = history_service->InMemoryDatabase(); | 522 history::URLDatabase* url_db = history_service->InMemoryDatabase(); |
522 // url_db can be NULL if it hasn't finished initializing (or failed to | 523 // url_db can be NULL if it hasn't finished initializing (or failed to |
523 // initialize). In this case all we can do is fall back on the second | 524 // initialize). In this case all we can do is fall back on the second |
524 // pass. | 525 // pass. |
525 // | 526 // |
526 // TODO(pkasting): We should just block here until this loads. Any time | 527 // TODO(pkasting): We should just block here until this loads. Any time |
527 // someone unloads the history backend, we'll get inconsistent inline | 528 // someone unloads the history backend, we'll get inconsistent inline |
528 // autocomplete behavior here. | 529 // autocomplete behavior here. |
529 if (url_db) { | 530 if (url_db) { |
530 DoAutocomplete(NULL, url_db, params.get()); | 531 DoAutocomplete(NULL, url_db, params.get()); |
531 // params->matches now has the matches we should expose to the provider. | 532 PromoteMatchIfNecessary(*params); |
532 // Pass 2 expects a "clean slate" set of matches. | |
533 matches_.clear(); | |
534 matches_.swap(params->matches); | |
535 UpdateStarredStateOfMatches(); | 533 UpdateStarredStateOfMatches(); |
536 // Reset the WYT match in |params| so that both passes get the same input | 534 // Reset the WYT match in |params| so that both passes get the same input |
537 // state, since DoAutocomplete() may have modified it. | 535 // state, since DoAutocomplete() may have modified it. |
538 params->what_you_typed_match = what_you_typed_match; | 536 params->what_you_typed_match = what_you_typed_match; |
539 } | 537 } |
540 | 538 |
541 // Pass 2: Ask the history service to call us back on the history thread, | 539 // Pass 2: Ask the history service to call us back on the history thread, |
542 // where we can read the full on-disk DB. | 540 // where we can read the full on-disk DB. |
543 if (input.want_asynchronous_matches()) { | 541 if (input.want_asynchronous_matches()) { |
544 done_ = false; | 542 done_ = false; |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
683 description_matches, offsets, description_word_starts, 0, | 681 description_matches, offsets, description_word_starts, 0, |
684 std::string::npos); | 682 std::string::npos); |
685 return SpansFromTermMatch( | 683 return SpansFromTermMatch( |
686 description_matches, clean_description.length(), false); | 684 description_matches, clean_description.length(), false); |
687 } | 685 } |
688 | 686 |
689 void HistoryURLProvider::DoAutocomplete(history::HistoryBackend* backend, | 687 void HistoryURLProvider::DoAutocomplete(history::HistoryBackend* backend, |
690 history::URLDatabase* db, | 688 history::URLDatabase* db, |
691 HistoryURLProviderParams* params) { | 689 HistoryURLProviderParams* params) { |
692 // Get the matching URLs from the DB. | 690 // Get the matching URLs from the DB. |
| 691 params->matches.clear(); |
693 history::URLRows url_matches; | 692 history::URLRows url_matches; |
694 history::HistoryMatches history_matches; | |
695 | |
696 const URLPrefixes& prefixes = URLPrefix::GetURLPrefixes(); | 693 const URLPrefixes& prefixes = URLPrefix::GetURLPrefixes(); |
697 for (URLPrefixes::const_iterator i(prefixes.begin()); i != prefixes.end(); | 694 for (URLPrefixes::const_iterator i(prefixes.begin()); i != prefixes.end(); |
698 ++i) { | 695 ++i) { |
699 if (params->cancel_flag.IsSet()) | 696 if (params->cancel_flag.IsSet()) |
700 return; // Canceled in the middle of a query, give up. | 697 return; // Canceled in the middle of a query, give up. |
701 | 698 |
702 // We only need kMaxMatches results in the end, but before we get there we | 699 // We only need kMaxMatches results in the end, but before we get there we |
703 // need to promote lower-quality matches that are prefixes of higher-quality | 700 // need to promote lower-quality matches that are prefixes of higher-quality |
704 // matches, and remove lower-quality redirects. So we ask for more results | 701 // matches, and remove lower-quality redirects. So we ask for more results |
705 // than we need, of every prefix type, in hopes this will give us far more | 702 // than we need, of every prefix type, in hopes this will give us far more |
706 // than enough to work with. CullRedirects() will then reduce the list to | 703 // than enough to work with. CullRedirects() will then reduce the list to |
707 // the best kMaxMatches results. | 704 // the best kMaxMatches results. |
708 db->AutocompleteForPrefix( | 705 db->AutocompleteForPrefix( |
709 base::UTF16ToUTF8(i->prefix + params->input.text()), kMaxMatches * 2, | 706 base::UTF16ToUTF8(i->prefix + params->input.text()), kMaxMatches * 2, |
710 !backend, &url_matches); | 707 !backend, &url_matches); |
711 for (history::URLRows::const_iterator j(url_matches.begin()); | 708 for (history::URLRows::const_iterator j(url_matches.begin()); |
712 j != url_matches.end(); ++j) { | 709 j != url_matches.end(); ++j) { |
713 const URLPrefix* best_prefix = URLPrefix::BestURLPrefix( | 710 const URLPrefix* best_prefix = URLPrefix::BestURLPrefix( |
714 base::UTF8ToUTF16(j->url().spec()), base::string16()); | 711 base::UTF8ToUTF16(j->url().spec()), base::string16()); |
715 DCHECK(best_prefix); | 712 DCHECK(best_prefix); |
716 history_matches.push_back(history::HistoryMatch( | 713 params->matches.push_back(history::HistoryMatch( |
717 *j, i->prefix.length(), !i->num_components, | 714 *j, i->prefix.length(), !i->num_components, |
718 i->num_components >= best_prefix->num_components)); | 715 i->num_components >= best_prefix->num_components)); |
719 } | 716 } |
720 } | 717 } |
721 | 718 |
722 // Create sorted list of suggestions. | 719 // Create sorted list of suggestions. |
723 CullPoorMatches(*params, &history_matches); | 720 CullPoorMatches(params); |
724 SortAndDedupMatches(&history_matches); | 721 SortAndDedupMatches(¶ms->matches); |
725 | 722 |
726 // Try to create a shorter suggestion from the best match. | 723 // Try to create a shorter suggestion from the best match. |
727 // We allow the what you typed match to be displayed when there's a reasonable | 724 // We allow the what you typed match to be displayed when there's a reasonable |
728 // chance the user actually cares: | 725 // chance the user actually cares: |
729 // * Their input can be opened as a URL, and | 726 // * Their input can be opened as a URL, and |
730 // * We parsed the input as a URL, or it starts with an explicit "http:" or | 727 // * We parsed the input as a URL, or it starts with an explicit "http:" or |
731 // "https:". | 728 // "https:". |
732 // Otherwise, this is just low-quality noise. In the cases where we've parsed | 729 // Otherwise, this is just low-quality noise. In the cases where we've parsed |
733 // as UNKNOWN, we'll still show an accidental search infobar if need be. | 730 // as UNKNOWN, we'll still show an accidental search infobar if need be. |
734 VisitClassifier classifier(this, params->input, db); | 731 VisitClassifier classifier(this, params->input, db); |
735 bool have_what_you_typed_match = | 732 bool have_what_you_typed_match = |
736 (params->input.type() != metrics::OmniboxInputType::QUERY) && | 733 (params->input.type() != metrics::OmniboxInputType::QUERY) && |
737 ((params->input.type() != metrics::OmniboxInputType::UNKNOWN) || | 734 ((params->input.type() != metrics::OmniboxInputType::UNKNOWN) || |
738 (classifier.type() == VisitClassifier::UNVISITED_INTRANET) || | 735 (classifier.type() == VisitClassifier::UNVISITED_INTRANET) || |
739 !params->trim_http || | 736 !params->trim_http || |
740 (AutocompleteInput::NumNonHostComponents(params->input.parts()) > 0)); | 737 (AutocompleteInput::NumNonHostComponents(params->input.parts()) > 0)); |
741 PromoteOrCreateShorterSuggestion(db, *params, have_what_you_typed_match, | 738 PromoteOrCreateShorterSuggestion(db, have_what_you_typed_match, params); |
742 &history_matches); | |
743 | 739 |
744 // Try to promote a match as an exact/inline autocomplete match. This also | 740 // Try to promote a match as an exact/inline autocomplete match. |
745 // moves it to the front of |history_matches|, so skip over it when | 741 // Checking what_you_typed_match.is_history_what_you_typed_match tells us |
746 // converting the rest of the matches. | 742 // whether SuggestExactInput() succeeded in constructing a valid match. |
747 size_t first_match = 1; | 743 // We need to avoid suggesting the exact input when the first pass promoted |
748 size_t exact_suggestion = 0; | 744 // the first history match; see comments below. |
749 // Checking params->what_you_typed_match.is_history_what_you_typed_match tells | |
750 // us whether SuggestExactInput() succeeded in constructing a valid match. | |
751 if (params->what_you_typed_match.is_history_what_you_typed_match && | 745 if (params->what_you_typed_match.is_history_what_you_typed_match && |
752 (!backend || !params->dont_suggest_exact_input) && | 746 (!backend || |
753 FixupExactSuggestion(db, classifier, params, &history_matches)) { | 747 (params->promote_type != |
| 748 HistoryURLProviderParams::FRONT_HISTORY_MATCH)) && |
| 749 FixupExactSuggestion(db, classifier, params)) { |
754 // Got an exact match for the user's input. Treat it as the best match | 750 // Got an exact match for the user's input. Treat it as the best match |
755 // regardless of the input type. | 751 // regardless of the input type. |
756 exact_suggestion = 1; | 752 params->exact_suggestion = 1; |
757 params->matches.push_back(params->what_you_typed_match); | 753 params->promote_type = HistoryURLProviderParams::WHAT_YOU_TYPED_MATCH; |
758 } else if (params->prevent_inline_autocomplete || | 754 } else { |
759 history_matches.empty() || | 755 params->exact_suggestion = 0; |
760 !PromoteMatchForInlineAutocomplete(history_matches.front(), params)) { | 756 if (!params->prevent_inline_autocomplete && !params->matches.empty() && |
761 // Failed to promote any URLs for inline autocompletion. Use the What You | 757 CanPromoteMatchForInlineAutocomplete(params->matches[0])) { |
762 // Typed match, if we have it. | 758 params->promote_type = HistoryURLProviderParams::FRONT_HISTORY_MATCH; |
763 first_match = 0; | 759 // In the case where the user has typed "foo.com" and visited (but not |
764 if (have_what_you_typed_match) | 760 // typed) "foo/", and the input is "foo", we can reach here for "foo.com" |
765 params->matches.push_back(params->what_you_typed_match); | 761 // during the first pass but have the second pass suggest the exact input |
| 762 // as a better URL. Since we need both passes to agree, and since during |
| 763 // the first pass there's no way to know about "foo/", setting the promote |
| 764 // type to FRONT_HISTORY_MATCH here should prevent the second pass from |
| 765 // suggesting the exact input as a better match (just above). |
| 766 } else if (have_what_you_typed_match) { |
| 767 // Failed to promote any URLs for inline autocompletion. Use the What You |
| 768 // Typed match, if we have it. |
| 769 params->promote_type = HistoryURLProviderParams::WHAT_YOU_TYPED_MATCH; |
| 770 } else { |
| 771 params->promote_type = HistoryURLProviderParams::NEITHER; |
| 772 } |
766 } | 773 } |
767 | 774 |
768 // This is the end of the synchronous pass. | 775 if (backend && cull_redirects_) { |
769 if (!backend) | |
770 return; | |
771 | |
772 // Determine relevancy of highest scoring match, if any. | |
773 int relevance = -1; | |
774 for (ACMatches::const_iterator it = params->matches.begin(); | |
775 it != params->matches.end(); ++it) { | |
776 relevance = std::max(relevance, it->relevance); | |
777 } | |
778 | |
779 if (cull_redirects_) { | |
780 // Remove redirects and trim list to size. We want to provide up to | 776 // Remove redirects and trim list to size. We want to provide up to |
781 // kMaxMatches results plus the What You Typed result, if it was added to | 777 // kMaxMatches results plus the What You Typed result, if it was added to |
782 // |history_matches| above. | 778 // params->matches above. |
783 CullRedirects(backend, &history_matches, kMaxMatches + exact_suggestion); | 779 CullRedirects(backend, ¶ms->matches, |
784 } else { | 780 kMaxMatches + params->exact_suggestion); |
| 781 } else if (params->matches.size() > kMaxMatches + params->exact_suggestion) { |
785 // Simply trim the list to size. | 782 // Simply trim the list to size. |
786 if (history_matches.size() > kMaxMatches + exact_suggestion) | 783 params->matches.resize(kMaxMatches + params->exact_suggestion); |
787 history_matches.resize(kMaxMatches + exact_suggestion); | |
788 } | |
789 | |
790 // Convert the history matches to autocomplete matches. | |
791 for (size_t i = first_match; i < history_matches.size(); ++i) { | |
792 const history::HistoryMatch& match = history_matches[i]; | |
793 DCHECK(!have_what_you_typed_match || | |
794 (match.url_info.url() != | |
795 GURL(params->matches.front().destination_url))); | |
796 // If we've assigned a score already, all later matches score one | |
797 // less than the previous match. | |
798 relevance = (relevance > 0) ? | |
799 (relevance - 1) : | |
800 CalculateRelevance(NORMAL, | |
801 static_cast<int>(history_matches.size() - 1 - i)); | |
802 AutocompleteMatch ac_match = HistoryMatchToACMatch(*params, match, | |
803 NORMAL, relevance); | |
804 // The experimental scoring must not change the top result's score. | |
805 if (!params->matches.empty()) { | |
806 relevance = CalculateRelevanceScoreUsingScoringParams(match, relevance, | |
807 scoring_params_); | |
808 ac_match.relevance = relevance; | |
809 } | |
810 params->matches.push_back(ac_match); | |
811 } | 784 } |
812 } | 785 } |
813 | 786 |
| 787 void HistoryURLProvider::PromoteMatchIfNecessary( |
| 788 const HistoryURLProviderParams& params) { |
| 789 matches_.clear(); |
| 790 if (params.promote_type == HistoryURLProviderParams::NEITHER) |
| 791 return; |
| 792 matches_.push_back( |
| 793 (params.promote_type == HistoryURLProviderParams::WHAT_YOU_TYPED_MATCH) ? |
| 794 params.what_you_typed_match : |
| 795 HistoryMatchToACMatch(params, 0, INLINE_AUTOCOMPLETE, |
| 796 CalculateRelevance(INLINE_AUTOCOMPLETE, 0))); |
| 797 } |
| 798 |
814 void HistoryURLProvider::QueryComplete( | 799 void HistoryURLProvider::QueryComplete( |
815 HistoryURLProviderParams* params_gets_deleted) { | 800 HistoryURLProviderParams* params_gets_deleted) { |
816 // Ensure |params_gets_deleted| gets deleted on exit. | 801 // Ensure |params_gets_deleted| gets deleted on exit. |
817 scoped_ptr<HistoryURLProviderParams> params(params_gets_deleted); | 802 scoped_ptr<HistoryURLProviderParams> params(params_gets_deleted); |
818 | 803 |
819 // If the user hasn't already started another query, clear our member pointer | 804 // If the user hasn't already started another query, clear our member pointer |
820 // so we can't write into deleted memory. | 805 // so we can't write into deleted memory. |
821 if (params_ == params_gets_deleted) | 806 if (params_ == params_gets_deleted) |
822 params_ = NULL; | 807 params_ = NULL; |
823 | 808 |
824 // Don't send responses for queries that have been canceled. | 809 // Don't send responses for queries that have been canceled. |
825 if (params->cancel_flag.IsSet()) | 810 if (params->cancel_flag.IsSet()) |
826 return; // Already set done_ when we canceled, no need to set it again. | 811 return; // Already set done_ when we canceled, no need to set it again. |
827 | 812 |
828 // Don't modify |matches_| if the query failed, since it might have a default | 813 // Don't modify |matches_| if the query failed, since it might have a default |
829 // match in it, whereas |params->matches| will be empty. | 814 // match in it, whereas |params->matches| will be empty. |
830 if (!params->failed) { | 815 if (!params->failed) { |
831 matches_.swap(params->matches); | 816 PromoteMatchIfNecessary(*params); |
| 817 |
| 818 // If we promoted the first match, skip over it when converting the rest of |
| 819 // the matches. |
| 820 const size_t first_match = |
| 821 (params->promote_type == |
| 822 HistoryURLProviderParams::FRONT_HISTORY_MATCH) ? |
| 823 1 : params->exact_suggestion; |
| 824 |
| 825 // Determine relevance of highest scoring match, if any. |
| 826 int relevance = matches_.empty() ? |
| 827 CalculateRelevance( |
| 828 NORMAL, |
| 829 static_cast<int>(params->matches.size() - 1 - first_match)) : |
| 830 matches_[0].relevance; |
| 831 |
| 832 // Convert the history matches to autocomplete matches. |
| 833 for (size_t i = first_match; i < params->matches.size(); ++i) { |
| 834 // All matches score one less than the previous match. |
| 835 --relevance; |
| 836 // The experimental scoring must not change the top result's score. |
| 837 if (!matches_.empty()) { |
| 838 relevance = CalculateRelevanceScoreUsingScoringParams( |
| 839 params->matches[i], relevance, scoring_params_); |
| 840 } |
| 841 matches_.push_back(HistoryMatchToACMatch(*params, i, NORMAL, relevance)); |
| 842 } |
| 843 |
832 UpdateStarredStateOfMatches(); | 844 UpdateStarredStateOfMatches(); |
833 } | 845 } |
834 | 846 |
835 done_ = true; | 847 done_ = true; |
836 listener_->OnProviderUpdate(true); | 848 listener_->OnProviderUpdate(true); |
837 } | 849 } |
838 | 850 |
839 bool HistoryURLProvider::FixupExactSuggestion( | 851 bool HistoryURLProvider::FixupExactSuggestion( |
840 history::URLDatabase* db, | 852 history::URLDatabase* db, |
841 const VisitClassifier& classifier, | 853 const VisitClassifier& classifier, |
842 HistoryURLProviderParams* params, | 854 HistoryURLProviderParams* params) const { |
843 history::HistoryMatches* matches) const { | |
844 DCHECK(matches != NULL); | |
845 | |
846 MatchType type = INLINE_AUTOCOMPLETE; | 855 MatchType type = INLINE_AUTOCOMPLETE; |
847 switch (classifier.type()) { | 856 switch (classifier.type()) { |
848 case VisitClassifier::INVALID: | 857 case VisitClassifier::INVALID: |
849 return false; | 858 return false; |
850 case VisitClassifier::UNVISITED_INTRANET: | 859 case VisitClassifier::UNVISITED_INTRANET: |
851 type = UNVISITED_INTRANET; | 860 type = UNVISITED_INTRANET; |
852 break; | 861 break; |
853 default: | 862 default: |
854 DCHECK_EQ(VisitClassifier::VISITED, classifier.type()); | 863 DCHECK_EQ(VisitClassifier::VISITED, classifier.type()); |
855 // We have data for this match, use it. | 864 // We have data for this match, use it. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
898 return false; | 907 return false; |
899 } | 908 } |
900 | 909 |
901 params->what_you_typed_match.relevance = CalculateRelevance(type, 0); | 910 params->what_you_typed_match.relevance = CalculateRelevance(type, 0); |
902 | 911 |
903 // If there are any other matches, then don't promote this match here, in | 912 // If there are any other matches, then don't promote this match here, in |
904 // hopes the caller will be able to inline autocomplete a better suggestion. | 913 // hopes the caller will be able to inline autocomplete a better suggestion. |
905 // DoAutocomplete() will fall back on this match if inline autocompletion | 914 // DoAutocomplete() will fall back on this match if inline autocompletion |
906 // fails. This matches how we react to never-visited URL inputs in the non- | 915 // fails. This matches how we react to never-visited URL inputs in the non- |
907 // intranet case. | 916 // intranet case. |
908 if (type == UNVISITED_INTRANET && !matches->empty()) | 917 if (type == UNVISITED_INTRANET && !params->matches.empty()) |
909 return false; | 918 return false; |
910 | 919 |
911 // Put it on the front of the HistoryMatches for redirect culling. | 920 // Put it on the front of the HistoryMatches for redirect culling. |
912 CreateOrPromoteMatch(classifier.url_row(), base::string16::npos, false, | 921 CreateOrPromoteMatch(classifier.url_row(), base::string16::npos, false, |
913 matches, true, true); | 922 ¶ms->matches, true, true); |
914 return true; | 923 return true; |
915 } | 924 } |
916 | 925 |
917 bool HistoryURLProvider::CanFindIntranetURL( | 926 bool HistoryURLProvider::CanFindIntranetURL( |
918 history::URLDatabase* db, | 927 history::URLDatabase* db, |
919 const AutocompleteInput& input) const { | 928 const AutocompleteInput& input) const { |
920 // Normally passing the first two conditions below ought to guarantee the | 929 // Normally passing the first two conditions below ought to guarantee the |
921 // third condition, but because FixupUserInput() can run and modify the | 930 // third condition, but because FixupUserInput() can run and modify the |
922 // input's text and parts between Parse() and here, it seems better to be | 931 // input's text and parts between Parse() and here, it seems better to be |
923 // paranoid and check. | 932 // paranoid and check. |
924 if ((input.type() != metrics::OmniboxInputType::UNKNOWN) || | 933 if ((input.type() != metrics::OmniboxInputType::UNKNOWN) || |
925 !LowerCaseEqualsASCII(input.scheme(), url::kHttpScheme) || | 934 !LowerCaseEqualsASCII(input.scheme(), url::kHttpScheme) || |
926 !input.parts().host.is_nonempty()) | 935 !input.parts().host.is_nonempty()) |
927 return false; | 936 return false; |
928 const std::string host(base::UTF16ToUTF8( | 937 const std::string host(base::UTF16ToUTF8( |
929 input.text().substr(input.parts().host.begin, input.parts().host.len))); | 938 input.text().substr(input.parts().host.begin, input.parts().host.len))); |
930 const size_t registry_length = | 939 const size_t registry_length = |
931 net::registry_controlled_domains::GetRegistryLength( | 940 net::registry_controlled_domains::GetRegistryLength( |
932 host, | 941 host, |
933 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, | 942 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, |
934 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); | 943 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); |
935 return registry_length == 0 && db->IsTypedHost(host); | 944 return registry_length == 0 && db->IsTypedHost(host); |
936 } | 945 } |
937 | 946 |
938 bool HistoryURLProvider::PromoteMatchForInlineAutocomplete( | |
939 const history::HistoryMatch& match, | |
940 HistoryURLProviderParams* params) { | |
941 if (!CanPromoteMatchForInlineAutocomplete(match)) | |
942 return false; | |
943 | |
944 // In the case where the user has typed "foo.com" and visited (but not typed) | |
945 // "foo/", and the input is "foo", we can reach here for "foo.com" during the | |
946 // first pass but have the second pass suggest the exact input as a better | |
947 // URL. Since we need both passes to agree, and since during the first pass | |
948 // there's no way to know about "foo/", make reaching this point prevent any | |
949 // future pass from suggesting the exact input as a better match. | |
950 params->dont_suggest_exact_input = true; | |
951 params->matches.push_back(HistoryMatchToACMatch( | |
952 *params, match, INLINE_AUTOCOMPLETE, | |
953 CalculateRelevance(INLINE_AUTOCOMPLETE, 0))); | |
954 return true; | |
955 } | |
956 | |
957 void HistoryURLProvider::PromoteOrCreateShorterSuggestion( | 947 void HistoryURLProvider::PromoteOrCreateShorterSuggestion( |
958 history::URLDatabase* db, | 948 history::URLDatabase* db, |
959 const HistoryURLProviderParams& params, | |
960 bool have_what_you_typed_match, | 949 bool have_what_you_typed_match, |
961 history::HistoryMatches* matches) { | 950 HistoryURLProviderParams* params) { |
962 if (matches->empty()) | 951 if (params->matches.empty()) |
963 return; // No matches, nothing to do. | 952 return; // No matches, nothing to do. |
964 | 953 |
965 // Determine the base URL from which to search, and whether that URL could | 954 // Determine the base URL from which to search, and whether that URL could |
966 // itself be added as a match. We can add the base iff it's not "effectively | 955 // itself be added as a match. We can add the base iff it's not "effectively |
967 // the same" as any "what you typed" match. | 956 // the same" as any "what you typed" match. |
968 const history::HistoryMatch& match = matches->front(); | 957 const history::HistoryMatch& match = params->matches[0]; |
969 GURL search_base = ConvertToHostOnly(match, params.input.text()); | 958 GURL search_base = ConvertToHostOnly(match, params->input.text()); |
970 bool can_add_search_base_to_matches = !have_what_you_typed_match; | 959 bool can_add_search_base_to_matches = !have_what_you_typed_match; |
971 if (search_base.is_empty()) { | 960 if (search_base.is_empty()) { |
972 // Search from what the user typed when we couldn't reduce the best match | 961 // Search from what the user typed when we couldn't reduce the best match |
973 // to a host. Careful: use a substring of |match| here, rather than the | 962 // to a host. Careful: use a substring of |match| here, rather than the |
974 // first match in |params|, because they might have different prefixes. If | 963 // first match in |params|, because they might have different prefixes. If |
975 // the user typed "google.com", params->what_you_typed_match will hold | 964 // the user typed "google.com", params->what_you_typed_match will hold |
976 // "http://google.com/", but |match| might begin with | 965 // "http://google.com/", but |match| might begin with |
977 // "http://www.google.com/". | 966 // "http://www.google.com/". |
978 // TODO: this should be cleaned up, and is probably incorrect for IDN. | 967 // TODO: this should be cleaned up, and is probably incorrect for IDN. |
979 std::string new_match = match.url_info.url().possibly_invalid_spec(). | 968 std::string new_match = match.url_info.url().possibly_invalid_spec(). |
980 substr(0, match.input_location + params.input.text().length()); | 969 substr(0, match.input_location + params->input.text().length()); |
981 search_base = GURL(new_match); | 970 search_base = GURL(new_match); |
982 if (search_base.is_empty()) | 971 if (search_base.is_empty()) |
983 return; // Can't construct a valid URL from which to start a search. | 972 return; // Can't construct a valid URL from which to start a search. |
984 } else if (!can_add_search_base_to_matches) { | 973 } else if (!can_add_search_base_to_matches) { |
985 can_add_search_base_to_matches = | 974 can_add_search_base_to_matches = |
986 (search_base != params.what_you_typed_match.destination_url); | 975 (search_base != params->what_you_typed_match.destination_url); |
987 } | 976 } |
988 if (search_base == match.url_info.url()) | 977 if (search_base == match.url_info.url()) |
989 return; // Couldn't shorten |match|, so no range of URLs to search over. | 978 return; // Couldn't shorten |match|, so no range of URLs to search over. |
990 | 979 |
991 // Search the DB for short URLs between our base and |match|. | 980 // Search the DB for short URLs between our base and |match|. |
992 history::URLRow info(search_base); | 981 history::URLRow info(search_base); |
993 bool promote = true; | 982 bool promote = true; |
994 // A short URL is only worth suggesting if it's been visited at least a third | 983 // A short URL is only worth suggesting if it's been visited at least a third |
995 // as often as the longer URL. | 984 // as often as the longer URL. |
996 const int min_visit_count = ((match.url_info.visit_count() - 1) / 3) + 1; | 985 const int min_visit_count = ((match.url_info.visit_count() - 1) / 3) + 1; |
(...skipping 13 matching lines...) Expand all Loading... |
1010 // Try to get info on the search base itself. Promote it to the top if the | 999 // Try to get info on the search base itself. Promote it to the top if the |
1011 // original best match isn't good enough to autocomplete. | 1000 // original best match isn't good enough to autocomplete. |
1012 db->GetRowForURL(search_base, &info); | 1001 db->GetRowForURL(search_base, &info); |
1013 promote = match.url_info.typed_count() <= 1; | 1002 promote = match.url_info.typed_count() <= 1; |
1014 } | 1003 } |
1015 | 1004 |
1016 // Promote or add the desired URL to the list of matches. | 1005 // Promote or add the desired URL to the list of matches. |
1017 bool ensure_can_inline = | 1006 bool ensure_can_inline = |
1018 promote && CanPromoteMatchForInlineAutocomplete(match); | 1007 promote && CanPromoteMatchForInlineAutocomplete(match); |
1019 ensure_can_inline &= CreateOrPromoteMatch(info, match.input_location, | 1008 ensure_can_inline &= CreateOrPromoteMatch(info, match.input_location, |
1020 match.match_in_scheme, matches, create_shorter_match_, promote); | 1009 match.match_in_scheme, ¶ms->matches, create_shorter_match_, promote); |
1021 if (ensure_can_inline) | 1010 if (ensure_can_inline) |
1022 matches->front().promoted = true; | 1011 params->matches[0].promoted = true; |
1023 } | 1012 } |
1024 | 1013 |
1025 void HistoryURLProvider::CullPoorMatches( | 1014 void HistoryURLProvider::CullPoorMatches( |
1026 const HistoryURLProviderParams& params, | 1015 HistoryURLProviderParams* params) const { |
1027 history::HistoryMatches* matches) const { | |
1028 const base::Time& threshold(history::AutocompleteAgeThreshold()); | 1016 const base::Time& threshold(history::AutocompleteAgeThreshold()); |
1029 for (history::HistoryMatches::iterator i(matches->begin()); | 1017 for (history::HistoryMatches::iterator i(params->matches.begin()); |
1030 i != matches->end(); ) { | 1018 i != params->matches.end(); ) { |
1031 if (RowQualifiesAsSignificant(i->url_info, threshold) && | 1019 if (RowQualifiesAsSignificant(i->url_info, threshold) && |
1032 !(params.default_search_provider && | 1020 (!params->default_search_provider || |
1033 params.default_search_provider->IsSearchURL( | 1021 !params->default_search_provider->IsSearchURL( |
1034 i->url_info.url(), *params.search_terms_data.get()))) { | 1022 i->url_info.url(), *params->search_terms_data))) { |
1035 ++i; | 1023 ++i; |
1036 } else { | 1024 } else { |
1037 i = matches->erase(i); | 1025 i = params->matches.erase(i); |
1038 } | 1026 } |
1039 } | 1027 } |
1040 } | 1028 } |
1041 | 1029 |
1042 void HistoryURLProvider::CullRedirects(history::HistoryBackend* backend, | 1030 void HistoryURLProvider::CullRedirects(history::HistoryBackend* backend, |
1043 history::HistoryMatches* matches, | 1031 history::HistoryMatches* matches, |
1044 size_t max_results) const { | 1032 size_t max_results) const { |
1045 for (size_t source = 0; | 1033 for (size_t source = 0; |
1046 (source < matches->size()) && (source < max_results); ) { | 1034 (source < matches->size()) && (source < max_results); ) { |
1047 const GURL& url = (*matches)[source].url_info.url(); | 1035 const GURL& url = (*matches)[source].url_info.url(); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1094 // need to shift it to the right and remember that so we can return it. | 1082 // need to shift it to the right and remember that so we can return it. |
1095 next = matches->erase(next); | 1083 next = matches->erase(next); |
1096 if (static_cast<size_t>(next - matches->begin()) < next_index) | 1084 if (static_cast<size_t>(next - matches->begin()) < next_index) |
1097 --next_index; | 1085 --next_index; |
1098 } | 1086 } |
1099 return next_index; | 1087 return next_index; |
1100 } | 1088 } |
1101 | 1089 |
1102 AutocompleteMatch HistoryURLProvider::HistoryMatchToACMatch( | 1090 AutocompleteMatch HistoryURLProvider::HistoryMatchToACMatch( |
1103 const HistoryURLProviderParams& params, | 1091 const HistoryURLProviderParams& params, |
1104 const history::HistoryMatch& history_match, | 1092 size_t match_number, |
1105 MatchType match_type, | 1093 MatchType match_type, |
1106 int relevance) { | 1094 int relevance) { |
| 1095 // The FormattedStringWithEquivalentMeaning() call below requires callers to |
| 1096 // be on the UI thread. |
| 1097 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI) || |
| 1098 !content::BrowserThread::IsThreadInitialized(content::BrowserThread::UI)); |
| 1099 |
| 1100 const history::HistoryMatch& history_match = params.matches[match_number]; |
1107 const history::URLRow& info = history_match.url_info; | 1101 const history::URLRow& info = history_match.url_info; |
1108 AutocompleteMatch match(this, relevance, | 1102 AutocompleteMatch match(this, relevance, |
1109 !!info.visit_count(), AutocompleteMatchType::HISTORY_URL); | 1103 !!info.visit_count(), AutocompleteMatchType::HISTORY_URL); |
1110 match.typed_count = info.typed_count(); | 1104 match.typed_count = info.typed_count(); |
1111 match.destination_url = info.url(); | 1105 match.destination_url = info.url(); |
1112 DCHECK(match.destination_url.is_valid()); | 1106 DCHECK(match.destination_url.is_valid()); |
1113 size_t inline_autocomplete_offset = | 1107 size_t inline_autocomplete_offset = |
1114 history_match.input_location + params.input.text().length(); | 1108 history_match.input_location + params.input.text().length(); |
1115 std::string languages = (match_type == WHAT_YOU_TYPED) ? | 1109 std::string languages = (match_type == WHAT_YOU_TYPED) ? |
1116 std::string() : params.languages; | 1110 std::string() : params.languages; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1148 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, | 1142 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, |
1149 match.contents.length(), ACMatchClassification::URL, | 1143 match.contents.length(), ACMatchClassification::URL, |
1150 &match.contents_class); | 1144 &match.contents_class); |
1151 } | 1145 } |
1152 match.description = info.title(); | 1146 match.description = info.title(); |
1153 match.description_class = | 1147 match.description_class = |
1154 ClassifyDescription(params.input.text(), match.description); | 1148 ClassifyDescription(params.input.text(), match.description); |
1155 RecordAdditionalInfoFromUrlRow(info, &match); | 1149 RecordAdditionalInfoFromUrlRow(info, &match); |
1156 return match; | 1150 return match; |
1157 } | 1151 } |
OLD | NEW |