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 550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
561 // url_db can be NULL if it hasn't finished initializing (or failed to | 561 // url_db can be NULL if it hasn't finished initializing (or failed to |
562 // initialize). In this case all we can do is fall back on the second | 562 // initialize). In this case all we can do is fall back on the second |
563 // pass. | 563 // pass. |
564 // | 564 // |
565 // TODO(pkasting): We should just block here until this loads. Any time | 565 // TODO(pkasting): We should just block here until this loads. Any time |
566 // someone unloads the history backend, we'll get inconsistent inline | 566 // someone unloads the history backend, we'll get inconsistent inline |
567 // autocomplete behavior here. | 567 // autocomplete behavior here. |
568 if (url_db) { | 568 if (url_db) { |
569 DoAutocomplete(NULL, url_db, params.get()); | 569 DoAutocomplete(NULL, url_db, params.get()); |
570 matches_.clear(); | 570 matches_.clear(); |
571 PromoteMatchIfNecessary(*params); | 571 PromoteMatchesIfNecessary(*params); |
572 // NOTE: We don't reset |params| here since at least the |promote_type| | 572 // NOTE: We don't reset |params| here since at least the |promote_type| |
573 // field on it will be read by the second pass -- see comments in | 573 // field on it will be read by the second pass -- see comments in |
574 // DoAutocomplete(). | 574 // DoAutocomplete(). |
575 } | 575 } |
576 | 576 |
577 // Pass 2: Ask the history service to call us back on the history thread, | 577 // Pass 2: Ask the history service to call us back on the history thread, |
578 // where we can read the full on-disk DB. | 578 // where we can read the full on-disk DB. |
579 if (input.want_asynchronous_matches()) { | 579 if (input.want_asynchronous_matches()) { |
580 done_ = false; | 580 done_ = false; |
581 params_ = params.release(); // This object will be destroyed in | 581 params_ = params.release(); // This object will be destroyed in |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
759 SortAndDedupMatches(¶ms->matches); | 759 SortAndDedupMatches(¶ms->matches); |
760 | 760 |
761 // Try to create a shorter suggestion from the best match. | 761 // Try to create a shorter suggestion from the best match. |
762 // We consider the what you typed match eligible for display when it's | 762 // We consider the what you typed match eligible for display when it's |
763 // navigable and there's a reasonable chance the user intended to do | 763 // navigable and there's a reasonable chance the user intended to do |
764 // something other than search. We use a variety of heuristics to determine | 764 // something other than search. We use a variety of heuristics to determine |
765 // this, e.g. whether the user explicitly typed a scheme, or if omnibox | 765 // this, e.g. whether the user explicitly typed a scheme, or if omnibox |
766 // searching has been disabled by policy. In the cases where we've parsed as | 766 // searching has been disabled by policy. In the cases where we've parsed as |
767 // UNKNOWN, we'll still show an accidental search infobar if need be. | 767 // UNKNOWN, we'll still show an accidental search infobar if need be. |
768 VisitClassifier classifier(this, params->input, db); | 768 VisitClassifier classifier(this, params->input, db); |
769 bool have_what_you_typed_match = | 769 params->have_what_you_typed_match = |
770 (params->input.type() != metrics::OmniboxInputType::QUERY) && | 770 (params->input.type() != metrics::OmniboxInputType::QUERY) && |
771 ((params->input.type() != metrics::OmniboxInputType::UNKNOWN) || | 771 ((params->input.type() != metrics::OmniboxInputType::UNKNOWN) || |
772 (classifier.type() == VisitClassifier::UNVISITED_INTRANET) || | 772 (classifier.type() == VisitClassifier::UNVISITED_INTRANET) || |
773 !params->trim_http || | 773 !params->trim_http || |
774 (AutocompleteInput::NumNonHostComponents(params->input.parts()) > 0) || | 774 (AutocompleteInput::NumNonHostComponents(params->input.parts()) > 0) || |
775 !params->default_search_provider); | 775 !params->default_search_provider); |
776 const bool have_shorter_suggestion_suitable_for_inline_autocomplete = | 776 const bool have_shorter_suggestion_suitable_for_inline_autocomplete = |
777 PromoteOrCreateShorterSuggestion(db, have_what_you_typed_match, params); | 777 PromoteOrCreateShorterSuggestion(db, params); |
778 | 778 |
779 // Check whether what the user typed appears in history. | 779 // Check whether what the user typed appears in history. |
780 const bool can_check_history_for_exact_match = | 780 const bool can_check_history_for_exact_match = |
781 // Checking what_you_typed_match.is_history_what_you_typed_match tells us | 781 // Checking what_you_typed_match.is_history_what_you_typed_match tells us |
782 // whether SuggestExactInput() succeeded in constructing a valid match. | 782 // whether SuggestExactInput() succeeded in constructing a valid match. |
783 params->what_you_typed_match.is_history_what_you_typed_match && | 783 params->what_you_typed_match.is_history_what_you_typed_match && |
784 // Additionally, in the case where the user has typed "foo.com" and | 784 // Additionally, in the case where the user has typed "foo.com" and |
785 // visited (but not typed) "foo/", and the input is "foo", the first pass | 785 // visited (but not typed) "foo/", and the input is "foo", the first pass |
786 // will fall into the FRONT_HISTORY_MATCH case for "foo.com" but the | 786 // will fall into the FRONT_HISTORY_MATCH case for "foo.com" but the |
787 // second pass can suggest the exact input as a better URL. Since we need | 787 // second pass can suggest the exact input as a better URL. Since we need |
788 // both passes to agree, and since during the first pass there's no way to | 788 // both passes to agree, and since during the first pass there's no way to |
789 // know about "foo/", ensure that if the promote type was set to | 789 // know about "foo/", ensure that if the promote type was set to |
790 // FRONT_HISTORY_MATCH during the first pass, the second pass will not | 790 // FRONT_HISTORY_MATCH during the first pass, the second pass will not |
791 // consider the exact suggestion to be in history and therefore will not | 791 // consider the exact suggestion to be in history and therefore will not |
792 // suggest the exact input as a better match. (Note that during the first | 792 // suggest the exact input as a better match. (Note that during the first |
793 // pass, this conditional will always succeed since |promote_type| is | 793 // pass, this conditional will always succeed since |promote_type| is |
794 // initialized to NEITHER.) | 794 // initialized to NEITHER.) |
795 (params->promote_type != HistoryURLProviderParams::FRONT_HISTORY_MATCH); | 795 (params->promote_type != HistoryURLProviderParams::FRONT_HISTORY_MATCH); |
796 params->exact_suggestion_is_in_history = can_check_history_for_exact_match && | 796 params->exact_suggestion_is_in_history = can_check_history_for_exact_match && |
797 FixupExactSuggestion(db, classifier, params); | 797 FixupExactSuggestion(db, classifier, params); |
798 | 798 |
799 // If we succeeded in fixing up the exact match based on the user's history, | 799 // If we succeeded in fixing up the exact match based on the user's history, |
800 // we should treat it as the best match regardless of input type. If not, | 800 // we should treat it as the best match regardless of input type. If not, |
801 // then we check whether there's an inline autocompletion we can create from | 801 // then we check whether there's an inline autocompletion we can create from |
802 // this input, so we can promote that as the best match. | 802 // this input, so we can promote that as the best match. |
803 if (params->exact_suggestion_is_in_history) { | 803 if (params->exact_suggestion_is_in_history) { |
804 params->promote_type = HistoryURLProviderParams::WHAT_YOU_TYPED_MATCH; | 804 params->promote_type = HistoryURLProviderParams::WHAT_YOU_TYPED_MATCH; |
805 } else if (!params->prevent_inline_autocomplete && !params->matches.empty() && | 805 } else if (!params->matches.empty() && |
806 (have_shorter_suggestion_suitable_for_inline_autocomplete || | 806 (have_shorter_suggestion_suitable_for_inline_autocomplete || |
807 CanPromoteMatchForInlineAutocomplete(params->matches[0]))) { | 807 CanPromoteMatchForInlineAutocomplete(params->matches[0]))) { |
| 808 // Note that we promote this inline-autocompleted match even when |
| 809 // params->prevent_inline_autocomplete is true. This is safe because in |
| 810 // this case the match will be marked as "not allowed to be default", and |
| 811 // a non-inlined match that is "allowed to be default" will be reordered |
| 812 // above it by the controller/AutocompleteResult. We ensure there is such |
| 813 // a match in two ways: |
| 814 // * If params->have_what_you_typed_match is true, we force the |
| 815 // what-you-typed match to be added in this case. See comments in |
| 816 // PromoteMatchesIfNecessary(). |
| 817 // * Otherwise, we should have some sort of QUERY or UNKNOWN input that |
| 818 // the SearchProvider will provide a defaultable WYT match for. |
808 params->promote_type = HistoryURLProviderParams::FRONT_HISTORY_MATCH; | 819 params->promote_type = HistoryURLProviderParams::FRONT_HISTORY_MATCH; |
809 } else { | 820 } else { |
810 // Failed to promote any URLs. Use the What You Typed match, if we have it. | 821 // Failed to promote any URLs. Use the What You Typed match, if we have it. |
811 params->promote_type = have_what_you_typed_match ? | 822 params->promote_type = params->have_what_you_typed_match ? |
812 HistoryURLProviderParams::WHAT_YOU_TYPED_MATCH : | 823 HistoryURLProviderParams::WHAT_YOU_TYPED_MATCH : |
813 HistoryURLProviderParams::NEITHER; | 824 HistoryURLProviderParams::NEITHER; |
814 } | 825 } |
815 | 826 |
816 const size_t max_results = | 827 const size_t max_results = |
817 kMaxMatches + (params->exact_suggestion_is_in_history ? 1 : 0); | 828 kMaxMatches + (params->exact_suggestion_is_in_history ? 1 : 0); |
818 if (backend) { | 829 if (backend) { |
819 // Remove redirects and trim list to size. We want to provide up to | 830 // Remove redirects and trim list to size. We want to provide up to |
820 // kMaxMatches results plus the What You Typed result, if it was added to | 831 // kMaxMatches results plus the What You Typed result, if it was added to |
821 // params->matches above. | 832 // params->matches above. |
822 CullRedirects(backend, ¶ms->matches, max_results); | 833 CullRedirects(backend, ¶ms->matches, max_results); |
823 } else if (params->matches.size() > max_results) { | 834 } else if (params->matches.size() > max_results) { |
824 // Simply trim the list to size. | 835 // Simply trim the list to size. |
825 params->matches.resize(max_results); | 836 params->matches.resize(max_results); |
826 } | 837 } |
827 } | 838 } |
828 | 839 |
829 void HistoryURLProvider::PromoteMatchIfNecessary( | 840 void HistoryURLProvider::PromoteMatchesIfNecessary( |
830 const HistoryURLProviderParams& params) { | 841 const HistoryURLProviderParams& params) { |
831 if (params.promote_type == HistoryURLProviderParams::NEITHER) | 842 if (params.promote_type == HistoryURLProviderParams::NEITHER) |
832 return; | 843 return; |
833 matches_.push_back( | 844 if (params.promote_type == HistoryURLProviderParams::FRONT_HISTORY_MATCH) { |
834 (params.promote_type == HistoryURLProviderParams::WHAT_YOU_TYPED_MATCH) ? | 845 matches_.push_back( |
835 params.what_you_typed_match : | 846 HistoryMatchToACMatch(params, 0, INLINE_AUTOCOMPLETE, |
836 HistoryMatchToACMatch(params, 0, INLINE_AUTOCOMPLETE, | 847 CalculateRelevance(INLINE_AUTOCOMPLETE, 0))); |
837 CalculateRelevance(INLINE_AUTOCOMPLETE, 0))); | 848 } |
| 849 // There are two cases where we need to add the what-you-typed-match: |
| 850 // * If params.promote_type is WHAT_YOU_TYPED_MATCH, we're being explicitly |
| 851 // directed to. |
| 852 // * If params.have_what_you_typed_match is true, then params.promote_type |
| 853 // can't be NEITHER (see code near the end of DoAutocomplete()), so if |
| 854 // it's not WHAT_YOU_TYPED_MATCH, it must be FRONT_HISTORY_MATCH, and |
| 855 // we'll have promoted the history match above. If |
| 856 // params.prevent_inline_autocomplete is also true, then this match |
| 857 // will be marked "not allowed to be default", and we need to add the |
| 858 // what-you-typed match to ensure there's a legal default match for the |
| 859 // controller/AutocompleteResult to promote. (If |
| 860 // params.have_what_you_typed_match is false, the SearchProvider should |
| 861 // take care of adding this defaultable match.) |
| 862 if ((params.promote_type == HistoryURLProviderParams::WHAT_YOU_TYPED_MATCH) || |
| 863 (params.prevent_inline_autocomplete && |
| 864 params.have_what_you_typed_match)) { |
| 865 matches_.push_back(params.what_you_typed_match); |
| 866 } |
838 } | 867 } |
839 | 868 |
840 void HistoryURLProvider::QueryComplete( | 869 void HistoryURLProvider::QueryComplete( |
841 HistoryURLProviderParams* params_gets_deleted) { | 870 HistoryURLProviderParams* params_gets_deleted) { |
842 // Ensure |params_gets_deleted| gets deleted on exit. | 871 // Ensure |params_gets_deleted| gets deleted on exit. |
843 scoped_ptr<HistoryURLProviderParams> params(params_gets_deleted); | 872 scoped_ptr<HistoryURLProviderParams> params(params_gets_deleted); |
844 | 873 |
845 // If the user hasn't already started another query, clear our member pointer | 874 // If the user hasn't already started another query, clear our member pointer |
846 // so we can't write into deleted memory. | 875 // so we can't write into deleted memory. |
847 if (params_ == params_gets_deleted) | 876 if (params_ == params_gets_deleted) |
848 params_ = NULL; | 877 params_ = NULL; |
849 | 878 |
850 // Don't send responses for queries that have been canceled. | 879 // Don't send responses for queries that have been canceled. |
851 if (params->cancel_flag.IsSet()) | 880 if (params->cancel_flag.IsSet()) |
852 return; // Already set done_ when we canceled, no need to set it again. | 881 return; // Already set done_ when we canceled, no need to set it again. |
853 | 882 |
854 // Don't modify |matches_| if the query failed, since it might have a default | 883 // Don't modify |matches_| if the query failed, since it might have a default |
855 // match in it, whereas |params->matches| will be empty. | 884 // match in it, whereas |params->matches| will be empty. |
856 if (!params->failed) { | 885 if (!params->failed) { |
857 matches_.clear(); | 886 matches_.clear(); |
858 PromoteMatchIfNecessary(*params); | 887 PromoteMatchesIfNecessary(*params); |
859 | 888 |
860 // Determine relevance of highest scoring match, if any. | 889 // Determine relevance of highest scoring match, if any. |
861 int relevance = matches_.empty() ? | 890 int relevance = matches_.empty() ? |
862 CalculateRelevance(NORMAL, | 891 CalculateRelevance(NORMAL, |
863 static_cast<int>(params->matches.size() - 1)) : | 892 static_cast<int>(params->matches.size() - 1)) : |
864 matches_[0].relevance; | 893 matches_[0].relevance; |
865 | 894 |
866 // Convert the history matches to autocomplete matches. If we promoted the | 895 // Convert the history matches to autocomplete matches. If we promoted the |
867 // first match, skip over it. | 896 // first match, skip over it. |
868 const size_t first_match = | 897 const size_t first_match = |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
949 const size_t registry_length = | 978 const size_t registry_length = |
950 net::registry_controlled_domains::GetRegistryLength( | 979 net::registry_controlled_domains::GetRegistryLength( |
951 host, | 980 host, |
952 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, | 981 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, |
953 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); | 982 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); |
954 return registry_length == 0 && db->IsTypedHost(host); | 983 return registry_length == 0 && db->IsTypedHost(host); |
955 } | 984 } |
956 | 985 |
957 bool HistoryURLProvider::PromoteOrCreateShorterSuggestion( | 986 bool HistoryURLProvider::PromoteOrCreateShorterSuggestion( |
958 history::URLDatabase* db, | 987 history::URLDatabase* db, |
959 bool have_what_you_typed_match, | |
960 HistoryURLProviderParams* params) { | 988 HistoryURLProviderParams* params) { |
961 if (params->matches.empty()) | 989 if (params->matches.empty()) |
962 return false; // No matches, nothing to do. | 990 return false; // No matches, nothing to do. |
963 | 991 |
964 // Determine the base URL from which to search, and whether that URL could | 992 // Determine the base URL from which to search, and whether that URL could |
965 // itself be added as a match. We can add the base iff it's not "effectively | 993 // itself be added as a match. We can add the base iff it's not "effectively |
966 // the same" as any "what you typed" match. | 994 // the same" as any "what you typed" match. |
967 const history::HistoryMatch& match = params->matches[0]; | 995 const history::HistoryMatch& match = params->matches[0]; |
968 GURL search_base = ConvertToHostOnly(match, params->input.text()); | 996 GURL search_base = ConvertToHostOnly(match, params->input.text()); |
969 bool can_add_search_base_to_matches = !have_what_you_typed_match; | 997 bool can_add_search_base_to_matches = !params->have_what_you_typed_match; |
970 if (search_base.is_empty()) { | 998 if (search_base.is_empty()) { |
971 // Search from what the user typed when we couldn't reduce the best match | 999 // Search from what the user typed when we couldn't reduce the best match |
972 // to a host. Careful: use a substring of |match| here, rather than the | 1000 // to a host. Careful: use a substring of |match| here, rather than the |
973 // first match in |params|, because they might have different prefixes. If | 1001 // first match in |params|, because they might have different prefixes. If |
974 // the user typed "google.com", params->what_you_typed_match will hold | 1002 // the user typed "google.com", params->what_you_typed_match will hold |
975 // "http://google.com/", but |match| might begin with | 1003 // "http://google.com/", but |match| might begin with |
976 // "http://www.google.com/". | 1004 // "http://www.google.com/". |
977 // TODO: this should be cleaned up, and is probably incorrect for IDN. | 1005 // TODO: this should be cleaned up, and is probably incorrect for IDN. |
978 std::string new_match = match.url_info.url().possibly_invalid_spec(). | 1006 std::string new_match = match.url_info.url().possibly_invalid_spec(). |
979 substr(0, match.input_location + params->input.text().length()); | 1007 substr(0, match.input_location + params->input.text().length()); |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1153 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, | 1181 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, |
1154 match.contents.length(), ACMatchClassification::URL, | 1182 match.contents.length(), ACMatchClassification::URL, |
1155 &match.contents_class); | 1183 &match.contents_class); |
1156 } | 1184 } |
1157 match.description = info.title(); | 1185 match.description = info.title(); |
1158 match.description_class = | 1186 match.description_class = |
1159 ClassifyDescription(params.input.text(), match.description); | 1187 ClassifyDescription(params.input.text(), match.description); |
1160 RecordAdditionalInfoFromUrlRow(info, &match); | 1188 RecordAdditionalInfoFromUrlRow(info, &match); |
1161 return match; | 1189 return match; |
1162 } | 1190 } |
OLD | NEW |