OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/autocomplete.h" | 5 #include "chrome/browser/autocomplete/autocomplete.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "app/l10n_util.h" | 9 #include "app/l10n_util.h" |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
(...skipping 530 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
541 // static | 541 // static |
542 const size_t AutocompleteResult::kMaxMatches = 6; | 542 const size_t AutocompleteResult::kMaxMatches = 6; |
543 | 543 |
544 void AutocompleteResult::Selection::Clear() { | 544 void AutocompleteResult::Selection::Clear() { |
545 destination_url = GURL(); | 545 destination_url = GURL(); |
546 provider_affinity = NULL; | 546 provider_affinity = NULL; |
547 is_history_what_you_typed_match = false; | 547 is_history_what_you_typed_match = false; |
548 } | 548 } |
549 | 549 |
550 AutocompleteResult::AutocompleteResult() { | 550 AutocompleteResult::AutocompleteResult() { |
551 // Reserve space for the max number of matches we'll show. The +1 accounts | 551 // Reserve space for the max number of matches we'll show. |
552 // for the history shortcut match as it isn't included in max_matches. | 552 matches_.reserve(kMaxMatches); |
553 matches_.reserve(kMaxMatches + 1); | |
554 | 553 |
555 // It's probably safe to do this in the initializer list, but there's little | 554 // It's probably safe to do this in the initializer list, but there's little |
556 // penalty to doing it here and it ensures our object is fully constructed | 555 // penalty to doing it here and it ensures our object is fully constructed |
557 // before calling member functions. | 556 // before calling member functions. |
558 default_match_ = end(); | 557 default_match_ = end(); |
559 } | 558 } |
560 | 559 |
561 AutocompleteResult::~AutocompleteResult() {} | 560 AutocompleteResult::~AutocompleteResult() {} |
562 | 561 |
563 void AutocompleteResult::CopyFrom(const AutocompleteResult& rhs) { | 562 void AutocompleteResult::CopyFrom(const AutocompleteResult& rhs) { |
(...skipping 28 matching lines...) Expand all Loading... | |
592 } | 591 } |
593 | 592 |
594 void AutocompleteResult::SortAndCull(const AutocompleteInput& input) { | 593 void AutocompleteResult::SortAndCull(const AutocompleteInput& input) { |
595 // Remove duplicates. | 594 // Remove duplicates. |
596 std::sort(matches_.begin(), matches_.end(), | 595 std::sort(matches_.begin(), matches_.end(), |
597 &AutocompleteMatch::DestinationSortFunc); | 596 &AutocompleteMatch::DestinationSortFunc); |
598 matches_.erase(std::unique(matches_.begin(), matches_.end(), | 597 matches_.erase(std::unique(matches_.begin(), matches_.end(), |
599 &AutocompleteMatch::DestinationsEqual), | 598 &AutocompleteMatch::DestinationsEqual), |
600 matches_.end()); | 599 matches_.end()); |
601 | 600 |
602 // Find the top |kMaxMatches| matches. | 601 // Sort the results. |
Peter Kasting
2011/01/20 00:08:33
Nit: I'd just combine the two comments into a sing
| |
603 if (matches_.size() > kMaxMatches) { | 602 const size_t num_matches = std::min(kMaxMatches, matches_.size()); |
604 std::partial_sort(matches_.begin(), matches_.begin() + kMaxMatches, | 603 std::partial_sort(matches_.begin(), matches_.begin() + num_matches, |
605 matches_.end(), &AutocompleteMatch::MoreRelevant); | 604 matches_.end(), &AutocompleteMatch::MoreRelevant); |
606 matches_.erase(matches_.begin() + kMaxMatches, matches_.end()); | 605 // Remove matches so that we have at most kMaxMatches. |
607 } | 606 matches_.resize(num_matches); |
608 | 607 |
609 // HistoryContentsProvider uses a negative relevance as a way to avoid | |
610 // starving out other provider matches, yet we may end up using this match. To | |
611 // make sure such matches are sorted correctly we search for all | |
612 // relevances < 0 and negate them. If we change our relevance algorithm to | |
613 // properly mix different providers' matches, this can go away. | |
614 for (ACMatches::iterator i = matches_.begin(); i != matches_.end(); ++i) { | |
615 if (i->relevance < 0) | |
616 i->relevance = -i->relevance; | |
617 } | |
618 | |
619 // Put the final result set in order. | |
620 std::sort(matches_.begin(), matches_.end(), &AutocompleteMatch::MoreRelevant); | |
621 default_match_ = begin(); | 608 default_match_ = begin(); |
622 | 609 |
623 // Set the alternate nav URL. | 610 // Set the alternate nav URL. |
624 alternate_nav_url_ = GURL(); | 611 alternate_nav_url_ = GURL(); |
625 if (((input.type() == AutocompleteInput::UNKNOWN) || | 612 if (((input.type() == AutocompleteInput::UNKNOWN) || |
626 (input.type() == AutocompleteInput::REQUESTED_URL)) && | 613 (input.type() == AutocompleteInput::REQUESTED_URL)) && |
627 (default_match_ != end()) && | 614 (default_match_ != end()) && |
628 (default_match_->transition != PageTransition::TYPED) && | 615 (default_match_->transition != PageTransition::TYPED) && |
629 (default_match_->transition != PageTransition::KEYWORD) && | 616 (default_match_->transition != PageTransition::KEYWORD) && |
630 (input.canonicalized_url() != default_match_->destination_url)) | 617 (input.canonicalized_url() != default_match_->destination_url)) |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
690 done_(true) { | 677 done_(true) { |
691 search_provider_ = new SearchProvider(this, profile); | 678 search_provider_ = new SearchProvider(this, profile); |
692 providers_.push_back(search_provider_); | 679 providers_.push_back(search_provider_); |
693 if (!CommandLine::ForCurrentProcess()->HasSwitch( | 680 if (!CommandLine::ForCurrentProcess()->HasSwitch( |
694 switches::kDisableHistoryQuickProvider)) | 681 switches::kDisableHistoryQuickProvider)) |
695 providers_.push_back(new HistoryQuickProvider(this, profile)); | 682 providers_.push_back(new HistoryQuickProvider(this, profile)); |
696 if (!CommandLine::ForCurrentProcess()->HasSwitch( | 683 if (!CommandLine::ForCurrentProcess()->HasSwitch( |
697 switches::kDisableHistoryURLProvider)) | 684 switches::kDisableHistoryURLProvider)) |
698 providers_.push_back(new HistoryURLProvider(this, profile)); | 685 providers_.push_back(new HistoryURLProvider(this, profile)); |
699 providers_.push_back(new KeywordProvider(this, profile)); | 686 providers_.push_back(new KeywordProvider(this, profile)); |
700 history_contents_provider_ = new HistoryContentsProvider(this, profile); | 687 providers_.push_back(new HistoryContentsProvider(this, profile)); |
701 providers_.push_back(history_contents_provider_); | |
702 for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) | 688 for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) |
703 (*i)->AddRef(); | 689 (*i)->AddRef(); |
704 } | 690 } |
705 | 691 |
706 AutocompleteController::~AutocompleteController() { | 692 AutocompleteController::~AutocompleteController() { |
707 // The providers may have tasks outstanding that hold refs to them. We need | 693 // The providers may have tasks outstanding that hold refs to them. We need |
708 // to ensure they won't call us back if they outlive us. (Practically, | 694 // to ensure they won't call us back if they outlive us. (Practically, |
709 // calling Stop() should also cancel those tasks and make it so that we hold | 695 // calling Stop() should also cancel those tasks and make it so that we hold |
710 // the only refs.) We also don't want to bother notifying anyone of our | 696 // the only refs.) We also don't want to bother notifying anyone of our |
711 // result changes here, because the notification observer is in the midst of | 697 // result changes here, because the notification observer is in the midst of |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
829 // Add all providers' matches. | 815 // Add all providers' matches. |
830 latest_result_.Reset(); | 816 latest_result_.Reset(); |
831 for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); | 817 for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); |
832 ++i) | 818 ++i) |
833 latest_result_.AppendMatches((*i)->matches()); | 819 latest_result_.AppendMatches((*i)->matches()); |
834 updated_latest_result_ = true; | 820 updated_latest_result_ = true; |
835 | 821 |
836 // Sort the matches and trim to a small number of "best" matches. | 822 // Sort the matches and trim to a small number of "best" matches. |
837 latest_result_.SortAndCull(input_); | 823 latest_result_.SortAndCull(input_); |
838 | 824 |
839 if (history_contents_provider_) | |
840 AddHistoryContentsShortcut(); | |
841 | |
842 #ifndef NDEBUG | 825 #ifndef NDEBUG |
843 latest_result_.Validate(); | 826 latest_result_.Validate(); |
844 #endif | 827 #endif |
845 | 828 |
846 if (is_synchronous_pass) { | 829 if (is_synchronous_pass) { |
847 if (!update_delay_timer_.IsRunning()) { | 830 if (!update_delay_timer_.IsRunning()) { |
848 update_delay_timer_.Start( | 831 update_delay_timer_.Start( |
849 TimeDelta::FromMilliseconds(kUpdateDelayMs), | 832 TimeDelta::FromMilliseconds(kUpdateDelayMs), |
850 this, &AutocompleteController::DelayTimerFired); | 833 this, &AutocompleteController::DelayTimerFired); |
851 } | 834 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
895 // TODO(pkasting): Eliminate this ordering requirement. | 878 // TODO(pkasting): Eliminate this ordering requirement. |
896 NotificationService::current()->Notify( | 879 NotificationService::current()->Notify( |
897 NotificationType::AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED, | 880 NotificationType::AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED, |
898 Source<AutocompleteController>(this), | 881 Source<AutocompleteController>(this), |
899 Details<const AutocompleteResult>(&result_)); | 882 Details<const AutocompleteResult>(&result_)); |
900 } | 883 } |
901 if (!done_) | 884 if (!done_) |
902 update_delay_timer_.Reset(); | 885 update_delay_timer_.Reset(); |
903 } | 886 } |
904 | 887 |
905 ACMatches AutocompleteController::GetMatchesNotInLatestResult( | |
906 const AutocompleteProvider* provider) const { | |
907 DCHECK(provider); | |
908 | |
909 // Determine the set of destination URLs. | |
910 std::set<GURL> destination_urls; | |
911 for (AutocompleteResult::const_iterator i(latest_result_.begin()); | |
912 i != latest_result_.end(); ++i) | |
913 destination_urls.insert(i->destination_url); | |
914 | |
915 ACMatches matches; | |
916 const ACMatches& provider_matches = provider->matches(); | |
917 for (ACMatches::const_iterator i = provider_matches.begin(); | |
918 i != provider_matches.end(); ++i) { | |
919 if (destination_urls.find(i->destination_url) == destination_urls.end()) | |
920 matches.push_back(*i); | |
921 } | |
922 | |
923 return matches; | |
924 } | |
925 | |
926 void AutocompleteController::AddHistoryContentsShortcut() { | |
927 DCHECK(history_contents_provider_); | |
928 // Only check the history contents provider if the history contents provider | |
929 // is done and has matches. | |
930 if (!history_contents_provider_->done() || | |
931 !history_contents_provider_->db_match_count()) { | |
932 return; | |
933 } | |
934 | |
935 if ((history_contents_provider_->db_match_count() <= | |
936 (latest_result_.size() + 1)) || | |
937 (history_contents_provider_->db_match_count() == 1)) { | |
938 // We only want to add a shortcut if we're not already showing the matches. | |
939 ACMatches matches(GetMatchesNotInLatestResult(history_contents_provider_)); | |
940 if (matches.empty()) | |
941 return; | |
942 if (matches.size() == 1) { | |
943 // Only one match not shown, add it. The relevance may be negative, | |
944 // which means we need to negate it to get the true relevance. | |
945 AutocompleteMatch& match = matches.front(); | |
946 if (match.relevance < 0) | |
947 match.relevance = -match.relevance; | |
948 latest_result_.AddMatch(match); | |
949 return; | |
950 } // else, fall through and add item. | |
951 } | |
952 | |
953 AutocompleteMatch match(NULL, 0, false, AutocompleteMatch::OPEN_HISTORY_PAGE); | |
954 match.fill_into_edit = input_.text(); | |
955 | |
956 // Mark up the text such that the user input text is bold. | |
957 size_t keyword_offset = std::wstring::npos; // Offset into match.contents. | |
958 if (history_contents_provider_->db_match_count() == | |
959 history_contents_provider_->kMaxMatchCount) { | |
960 // History contents searcher has maxed out. | |
961 match.contents = UTF16ToWideHack( | |
962 l10n_util::GetStringFUTF16(IDS_OMNIBOX_RECENT_HISTORY_MANY, | |
963 WideToUTF16Hack(input_.text()), | |
964 &keyword_offset)); | |
965 } else { | |
966 // We can report exact matches when there aren't too many. | |
967 std::vector<size_t> content_param_offsets; | |
968 match.contents = UTF16ToWideHack(l10n_util::GetStringFUTF16( | |
969 IDS_OMNIBOX_RECENT_HISTORY, | |
970 base::FormatNumber(history_contents_provider_-> | |
971 db_match_count()), | |
972 WideToUTF16Hack(input_.text()), | |
973 &content_param_offsets)); | |
974 | |
975 // content_param_offsets is ordered based on supplied params, we expect | |
976 // that the second one contains the query (first is the number). | |
977 if (content_param_offsets.size() == 2) { | |
978 keyword_offset = content_param_offsets[1]; | |
979 } else { | |
980 // See comments on an identical NOTREACHED() in search_provider.cc. | |
981 NOTREACHED(); | |
982 } | |
983 } | |
984 | |
985 // NOTE: This comparison succeeds when keyword_offset == std::wstring::npos. | |
986 if (keyword_offset > 0) { | |
987 match.contents_class.push_back( | |
988 ACMatchClassification(0, ACMatchClassification::NONE)); | |
989 } | |
990 match.contents_class.push_back( | |
991 ACMatchClassification(keyword_offset, ACMatchClassification::MATCH)); | |
992 if (keyword_offset + input_.text().size() < match.contents.size()) { | |
993 match.contents_class.push_back( | |
994 ACMatchClassification(keyword_offset + input_.text().size(), | |
995 ACMatchClassification::NONE)); | |
996 } | |
997 match.destination_url = | |
998 HistoryUI::GetHistoryURLWithSearchText(WideToUTF16(input_.text())); | |
999 match.transition = PageTransition::AUTO_BOOKMARK; | |
1000 match.provider = history_contents_provider_; | |
1001 latest_result_.AddMatch(match); | |
1002 } | |
1003 | |
1004 void AutocompleteController::CheckIfDone() { | 888 void AutocompleteController::CheckIfDone() { |
1005 for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); | 889 for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); |
1006 ++i) { | 890 ++i) { |
1007 if (!(*i)->done()) { | 891 if (!(*i)->done()) { |
1008 done_ = false; | 892 done_ = false; |
1009 return; | 893 return; |
1010 } | 894 } |
1011 } | 895 } |
1012 done_ = true; | 896 done_ = true; |
1013 } | 897 } |
OLD | NEW |