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 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 DISALLOW_COPY_AND_ASSIGN(VisitClassifier); | 367 DISALLOW_COPY_AND_ASSIGN(VisitClassifier); |
368 }; | 368 }; |
369 | 369 |
370 HistoryURLProvider::VisitClassifier::VisitClassifier( | 370 HistoryURLProvider::VisitClassifier::VisitClassifier( |
371 HistoryURLProvider* provider, | 371 HistoryURLProvider* provider, |
372 const AutocompleteInput& input, | 372 const AutocompleteInput& input, |
373 history::URLDatabase* db) | 373 history::URLDatabase* db) |
374 : provider_(provider), | 374 : provider_(provider), |
375 db_(db), | 375 db_(db), |
376 type_(INVALID) { | 376 type_(INVALID) { |
| 377 if (!db_) |
| 378 return; |
| 379 |
377 const GURL& url = input.canonicalized_url(); | 380 const GURL& url = input.canonicalized_url(); |
378 // Detect email addresses. These cases will look like "http://user@site/", | 381 // Detect email addresses. These cases will look like "http://user@site/", |
379 // and because the history backend strips auth creds, we'll get a bogus exact | 382 // and because the history backend strips auth creds, we'll get a bogus exact |
380 // match below if the user has visited "site". | 383 // match below if the user has visited "site". |
381 if (!url.is_valid() || | 384 if (!url.is_valid() || |
382 ((input.type() == metrics::OmniboxInputType::UNKNOWN) && | 385 ((input.type() == metrics::OmniboxInputType::UNKNOWN) && |
383 input.parts().username.is_nonempty() && | 386 input.parts().username.is_nonempty() && |
384 !input.parts().password.is_nonempty() && | 387 !input.parts().password.is_nonempty() && |
385 !input.parts().path.is_nonempty())) | 388 !input.parts().path.is_nonempty())) |
386 return; | 389 return; |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 // url_db can be NULL if it hasn't finished initializing (or failed to | 519 // url_db can be NULL if it hasn't finished initializing (or failed to |
517 // initialize). In this case all we can do is fall back on the second | 520 // initialize). In this case all we can do is fall back on the second |
518 // pass. | 521 // pass. |
519 // | 522 // |
520 // TODO(pkasting): We should just block here until this loads. Any time | 523 // TODO(pkasting): We should just block here until this loads. Any time |
521 // someone unloads the history backend, we'll get inconsistent inline | 524 // someone unloads the history backend, we'll get inconsistent inline |
522 // autocomplete behavior here. | 525 // autocomplete behavior here. |
523 if (url_db) { | 526 if (url_db) { |
524 DoAutocomplete(NULL, url_db, params.get()); | 527 DoAutocomplete(NULL, url_db, params.get()); |
525 matches_.clear(); | 528 matches_.clear(); |
526 PromoteMatchIfNecessary(*params); | 529 PromoteMatchesIfNecessary(*params); |
527 UpdateStarredStateOfMatches(); | 530 UpdateStarredStateOfMatches(); |
528 // NOTE: We don't reset |params| here since at least the |promote_type| | 531 // NOTE: We don't reset |params| here since at least the |promote_type| |
529 // field on it will be read by the second pass -- see comments in | 532 // field on it will be read by the second pass -- see comments in |
530 // DoAutocomplete(). | 533 // DoAutocomplete(). |
531 } | 534 } |
532 | 535 |
533 // Pass 2: Ask the history service to call us back on the history thread, | 536 // Pass 2: Ask the history service to call us back on the history thread, |
534 // where we can read the full on-disk DB. | 537 // where we can read the full on-disk DB. |
535 if (input.want_asynchronous_matches()) { | 538 if (input.want_asynchronous_matches()) { |
536 done_ = false; | 539 done_ = false; |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
708 *j, i->prefix.length(), !i->num_components, | 711 *j, i->prefix.length(), !i->num_components, |
709 i->num_components >= best_prefix->num_components)); | 712 i->num_components >= best_prefix->num_components)); |
710 } | 713 } |
711 } | 714 } |
712 | 715 |
713 // Create sorted list of suggestions. | 716 // Create sorted list of suggestions. |
714 CullPoorMatches(params); | 717 CullPoorMatches(params); |
715 SortAndDedupMatches(¶ms->matches); | 718 SortAndDedupMatches(¶ms->matches); |
716 | 719 |
717 // Try to create a shorter suggestion from the best match. | 720 // Try to create a shorter suggestion from the best match. |
718 // We allow the what you typed match to be displayed when there's a reasonable | |
719 // chance the user actually cares: | |
720 // * Their input can be opened as a URL, and | |
721 // * We parsed the input as a URL, or it starts with an explicit "http:" or | |
722 // "https:". | |
723 // Otherwise, this is just low-quality noise. In the cases where we've parsed | |
724 // as UNKNOWN, we'll still show an accidental search infobar if need be. | |
725 VisitClassifier classifier(this, params->input, db); | 721 VisitClassifier classifier(this, params->input, db); |
726 bool have_what_you_typed_match = | 722 const bool have_what_you_typed_match = |
727 (params->input.type() != metrics::OmniboxInputType::QUERY) && | 723 HaveWhatYouTypedMatch(classifier, *params); |
728 ((params->input.type() != metrics::OmniboxInputType::UNKNOWN) || | |
729 (classifier.type() == VisitClassifier::UNVISITED_INTRANET) || | |
730 !params->trim_http || | |
731 (AutocompleteInput::NumNonHostComponents(params->input.parts()) > 0)); | |
732 const bool have_shorter_suggestion_suitable_for_inline_autocomplete = | 724 const bool have_shorter_suggestion_suitable_for_inline_autocomplete = |
733 PromoteOrCreateShorterSuggestion(db, have_what_you_typed_match, params); | 725 PromoteOrCreateShorterSuggestion(db, have_what_you_typed_match, params); |
734 | 726 |
735 // Check whether what the user typed appears in history. | 727 // Check whether what the user typed appears in history. |
736 const bool can_check_history_for_exact_match = | 728 const bool can_check_history_for_exact_match = |
737 // Checking what_you_typed_match.is_history_what_you_typed_match tells us | 729 // Checking what_you_typed_match.is_history_what_you_typed_match tells us |
738 // whether SuggestExactInput() succeeded in constructing a valid match. | 730 // whether SuggestExactInput() succeeded in constructing a valid match. |
739 params->what_you_typed_match.is_history_what_you_typed_match && | 731 params->what_you_typed_match.is_history_what_you_typed_match && |
740 // Additionally, in the case where the user has typed "foo.com" and | 732 // Additionally, in the case where the user has typed "foo.com" and |
741 // visited (but not typed) "foo/", and the input is "foo", the first pass | 733 // visited (but not typed) "foo/", and the input is "foo", the first pass |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
775 // Remove redirects and trim list to size. We want to provide up to | 767 // Remove redirects and trim list to size. We want to provide up to |
776 // kMaxMatches results plus the What You Typed result, if it was added to | 768 // kMaxMatches results plus the What You Typed result, if it was added to |
777 // params->matches above. | 769 // params->matches above. |
778 CullRedirects(backend, ¶ms->matches, max_results); | 770 CullRedirects(backend, ¶ms->matches, max_results); |
779 } else if (params->matches.size() > max_results) { | 771 } else if (params->matches.size() > max_results) { |
780 // Simply trim the list to size. | 772 // Simply trim the list to size. |
781 params->matches.resize(max_results); | 773 params->matches.resize(max_results); |
782 } | 774 } |
783 } | 775 } |
784 | 776 |
785 void HistoryURLProvider::PromoteMatchIfNecessary( | 777 void HistoryURLProvider::PromoteMatchesIfNecessary( |
786 const HistoryURLProviderParams& params) { | 778 const HistoryURLProviderParams& params) { |
787 if (params.promote_type == HistoryURLProviderParams::NEITHER) | 779 if (params.promote_type == HistoryURLProviderParams::FRONT_HISTORY_MATCH) { |
788 return; | 780 matches_.push_back(HistoryMatchToACMatch(params, 0, INLINE_AUTOCOMPLETE, |
789 matches_.push_back( | 781 CalculateRelevance(INLINE_AUTOCOMPLETE, 0))); |
790 (params.promote_type == HistoryURLProviderParams::WHAT_YOU_TYPED_MATCH) ? | 782 if (OmniboxFieldTrial::AddUWYTMatchEvenIfPromotedURLs()) { |
791 params.what_you_typed_match : | 783 HistoryService* const history_service = |
792 HistoryMatchToACMatch(params, 0, INLINE_AUTOCOMPLETE, | 784 HistoryServiceFactory::GetForProfile(profile_, |
793 CalculateRelevance(INLINE_AUTOCOMPLETE, 0))); | 785 Profile::EXPLICIT_ACCESS); |
| 786 if (history_service && |
| 787 HaveWhatYouTypedMatch(VisitClassifier( |
| 788 this, params.input, history_service->InMemoryDatabase()), |
| 789 params)) { |
| 790 matches_.push_back(params.what_you_typed_match); |
| 791 } |
| 792 } |
| 793 } else if (params.promote_type == |
| 794 HistoryURLProviderParams::WHAT_YOU_TYPED_MATCH) { |
| 795 matches_.push_back(params.what_you_typed_match); |
| 796 } |
794 } | 797 } |
795 | 798 |
796 void HistoryURLProvider::QueryComplete( | 799 void HistoryURLProvider::QueryComplete( |
797 HistoryURLProviderParams* params_gets_deleted) { | 800 HistoryURLProviderParams* params_gets_deleted) { |
798 // Ensure |params_gets_deleted| gets deleted on exit. | 801 // Ensure |params_gets_deleted| gets deleted on exit. |
799 scoped_ptr<HistoryURLProviderParams> params(params_gets_deleted); | 802 scoped_ptr<HistoryURLProviderParams> params(params_gets_deleted); |
800 | 803 |
801 // 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 |
802 // so we can't write into deleted memory. | 805 // so we can't write into deleted memory. |
803 if (params_ == params_gets_deleted) | 806 if (params_ == params_gets_deleted) |
804 params_ = NULL; | 807 params_ = NULL; |
805 | 808 |
806 // Don't send responses for queries that have been canceled. | 809 // Don't send responses for queries that have been canceled. |
807 if (params->cancel_flag.IsSet()) | 810 if (params->cancel_flag.IsSet()) |
808 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. |
809 | 812 |
810 // 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 |
811 // match in it, whereas |params->matches| will be empty. | 814 // match in it, whereas |params->matches| will be empty. |
812 if (!params->failed) { | 815 if (!params->failed) { |
813 matches_.clear(); | 816 matches_.clear(); |
814 PromoteMatchIfNecessary(*params); | 817 PromoteMatchesIfNecessary(*params); |
815 | 818 |
816 // Determine relevance of highest scoring match, if any. | 819 // Determine relevance of highest scoring match, if any. |
817 int relevance = matches_.empty() ? | 820 int relevance = matches_.empty() ? |
818 CalculateRelevance(NORMAL, | 821 CalculateRelevance(NORMAL, |
819 static_cast<int>(params->matches.size() - 1)) : | 822 static_cast<int>(params->matches.size() - 1)) : |
820 matches_[0].relevance; | 823 matches_[0].relevance; |
821 | 824 |
822 // Convert the history matches to autocomplete matches. If we promoted the | 825 // Convert the history matches to autocomplete matches. If we promoted the |
823 // first match, skip over it. | 826 // first match, skip over it. |
824 const size_t first_match = | 827 const size_t first_match = |
(...skipping 11 matching lines...) Expand all Loading... |
836 matches_.push_back(HistoryMatchToACMatch(*params, i, NORMAL, relevance)); | 839 matches_.push_back(HistoryMatchToACMatch(*params, i, NORMAL, relevance)); |
837 } | 840 } |
838 | 841 |
839 UpdateStarredStateOfMatches(); | 842 UpdateStarredStateOfMatches(); |
840 } | 843 } |
841 | 844 |
842 done_ = true; | 845 done_ = true; |
843 listener_->OnProviderUpdate(true); | 846 listener_->OnProviderUpdate(true); |
844 } | 847 } |
845 | 848 |
| 849 // static |
| 850 bool HistoryURLProvider::HaveWhatYouTypedMatch( |
| 851 const VisitClassifier& classifier, |
| 852 const HistoryURLProviderParams& params) { |
| 853 // We consider the what you typed match to be eligible to be displayed when |
| 854 // there's a reasonable chance the user actually cares: |
| 855 // * Their input can be opened as a URL, and |
| 856 // * We parsed the input as a URL, or it starts with an explicit "http:" or |
| 857 // "https:". |
| 858 // Otherwise, this is just low-quality noise. In the cases where we've parsed |
| 859 // as UNKNOWN, we'll still show an accidental search infobar if need be. |
| 860 return (params.input.type() != metrics::OmniboxInputType::QUERY) && |
| 861 ((params.input.type() != metrics::OmniboxInputType::UNKNOWN) || |
| 862 (classifier.type() == VisitClassifier::UNVISITED_INTRANET) || |
| 863 !params.trim_http || |
| 864 (AutocompleteInput::NumNonHostComponents(params.input.parts()) > 0)); |
| 865 } |
| 866 |
846 bool HistoryURLProvider::FixupExactSuggestion( | 867 bool HistoryURLProvider::FixupExactSuggestion( |
847 history::URLDatabase* db, | 868 history::URLDatabase* db, |
848 const VisitClassifier& classifier, | 869 const VisitClassifier& classifier, |
849 HistoryURLProviderParams* params) const { | 870 HistoryURLProviderParams* params) const { |
850 MatchType type = INLINE_AUTOCOMPLETE; | 871 MatchType type = INLINE_AUTOCOMPLETE; |
851 switch (classifier.type()) { | 872 switch (classifier.type()) { |
852 case VisitClassifier::INVALID: | 873 case VisitClassifier::INVALID: |
853 return false; | 874 return false; |
854 case VisitClassifier::UNVISITED_INTRANET: | 875 case VisitClassifier::UNVISITED_INTRANET: |
855 type = UNVISITED_INTRANET; | 876 type = UNVISITED_INTRANET; |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1137 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, | 1158 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, |
1138 match.contents.length(), ACMatchClassification::URL, | 1159 match.contents.length(), ACMatchClassification::URL, |
1139 &match.contents_class); | 1160 &match.contents_class); |
1140 } | 1161 } |
1141 match.description = info.title(); | 1162 match.description = info.title(); |
1142 match.description_class = | 1163 match.description_class = |
1143 ClassifyDescription(params.input.text(), match.description); | 1164 ClassifyDescription(params.input.text(), match.description); |
1144 RecordAdditionalInfoFromUrlRow(info, &match); | 1165 RecordAdditionalInfoFromUrlRow(info, &match); |
1145 return match; | 1166 return match; |
1146 } | 1167 } |
OLD | NEW |