Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: components/autofill/core/browser/personal_data_manager.cc

Issue 962673004: [Autofill/Autocomplete Feature] Substring matching instead of prefix matching. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Incorporated Evan's review. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "components/autofill/core/browser/personal_data_manager.h" 5 #include "components/autofill/core/browser/personal_data_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <functional> 8 #include <functional>
9 #include <iterator> 9 #include <iterator>
10 10
(...skipping 12 matching lines...) Expand all
23 #include "components/autofill/core/browser/autofill_experiments.h" 23 #include "components/autofill/core/browser/autofill_experiments.h"
24 #include "components/autofill/core/browser/autofill_field.h" 24 #include "components/autofill/core/browser/autofill_field.h"
25 #include "components/autofill/core/browser/autofill_metrics.h" 25 #include "components/autofill/core/browser/autofill_metrics.h"
26 #include "components/autofill/core/browser/form_structure.h" 26 #include "components/autofill/core/browser/form_structure.h"
27 #include "components/autofill/core/browser/personal_data_manager_observer.h" 27 #include "components/autofill/core/browser/personal_data_manager_observer.h"
28 #include "components/autofill/core/browser/phone_number.h" 28 #include "components/autofill/core/browser/phone_number.h"
29 #include "components/autofill/core/browser/phone_number_i18n.h" 29 #include "components/autofill/core/browser/phone_number_i18n.h"
30 #include "components/autofill/core/browser/validation.h" 30 #include "components/autofill/core/browser/validation.h"
31 #include "components/autofill/core/common/autofill_pref_names.h" 31 #include "components/autofill/core/common/autofill_pref_names.h"
32 #include "components/autofill/core/common/autofill_switches.h" 32 #include "components/autofill/core/common/autofill_switches.h"
33 #include "components/autofill/core/common/autofill_util.h"
33 #include "components/signin/core/browser/account_tracker_service.h" 34 #include "components/signin/core/browser/account_tracker_service.h"
34 #include "components/signin/core/common/signin_pref_names.h" 35 #include "components/signin/core/common/signin_pref_names.h"
35 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_da ta.h" 36 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_da ta.h"
36 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_fo rmatter.h" 37 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_fo rmatter.h"
37 38
38 namespace autofill { 39 namespace autofill {
39 namespace { 40 namespace {
40 41
41 using ::i18n::addressinput::AddressField; 42 using ::i18n::addressinput::AddressField;
42 using ::i18n::addressinput::GetStreetAddressLinesAsSingleLine; 43 using ::i18n::addressinput::GetStreetAddressLinesAsSingleLine;
(...skipping 710 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 754
754 const std::vector<CreditCard*>& PersonalDataManager::GetCreditCards() const { 755 const std::vector<CreditCard*>& PersonalDataManager::GetCreditCards() const {
755 credit_cards_.clear(); 756 credit_cards_.clear();
756 credit_cards_.insert(credit_cards_.end(), local_credit_cards_.begin(), 757 credit_cards_.insert(credit_cards_.end(), local_credit_cards_.begin(),
757 local_credit_cards_.end()); 758 local_credit_cards_.end());
758 if (IsExperimentalWalletIntegrationEnabled() && 759 if (IsExperimentalWalletIntegrationEnabled() &&
759 pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled)) { 760 pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled)) {
760 credit_cards_.insert(credit_cards_.end(), server_credit_cards_.begin(), 761 credit_cards_.insert(credit_cards_.end(), server_credit_cards_.begin(),
761 server_credit_cards_.end()); 762 server_credit_cards_.end());
762 } 763 }
764
763 return credit_cards_; 765 return credit_cards_;
764 } 766 }
765 767
766 bool PersonalDataManager::HasServerData() const { 768 bool PersonalDataManager::HasServerData() const {
767 return !server_credit_cards_.empty() || !server_profiles_.empty(); 769 return !server_credit_cards_.empty() || !server_profiles_.empty();
768 } 770 }
769 771
770 void PersonalDataManager::Refresh() { 772 void PersonalDataManager::Refresh() {
771 LoadProfiles(); 773 LoadProfiles();
772 LoadCreditCards(); 774 LoadCreditCards();
(...skipping 12 matching lines...) Expand all
785 787
786 std::vector<Suggestion> suggestions; 788 std::vector<Suggestion> suggestions;
787 // Match based on a prefix search. 789 // Match based on a prefix search.
788 std::vector<AutofillProfile*> matched_profiles; 790 std::vector<AutofillProfile*> matched_profiles;
789 for (AutofillProfile* profile : profiles) { 791 for (AutofillProfile* profile : profiles) {
790 base::string16 value = GetInfoInOneLine(profile, type, app_locale_); 792 base::string16 value = GetInfoInOneLine(profile, type, app_locale_);
791 if (value.empty()) 793 if (value.empty())
792 continue; 794 continue;
793 base::string16 value_canon = 795 base::string16 value_canon =
794 AutofillProfile::CanonicalizeProfileString(value); 796 AutofillProfile::CanonicalizeProfileString(value);
795 if (StartsWith(value_canon, field_contents_canon, true)) { 797 // CanonicalizeProfileString() returns lower-case string with all
796 // Prefix match, add suggestion. 798 // separator substituted by whitespaces and trims off trailing whitespace
799 // if any. Passing |value_canon| and |field_contents_canon| to
800 // ContainsTokenThatStartsWith() may lead to unexpected result, hence
801 // preferred passing |values[i]| and |field_contents| instead.
802 bool substring_matched_suggestion = false;
803 if (StartsWith(value_canon, field_contents_canon, true) ||
804 (substring_matched_suggestion =
805 ContainsTokenThatStartsWith(value, field_contents, false))) {
797 matched_profiles.push_back(profile); 806 matched_profiles.push_back(profile);
798 suggestions.push_back(Suggestion(value)); 807 suggestions.push_back(Suggestion(value));
799 suggestions.back().backend_id = profile->guid(); 808 suggestions.back().backend_id = profile->guid();
809 suggestions.back().match = substring_matched_suggestion
810 ? Suggestion::SUBSTRING_MATCH
811 : Suggestion::PREFIX_MATCH;
800 } 812 }
801 } 813 }
802 814
815 // Prefix matches should precede other token matches.
816 if (IsFeatureSubstringMatchEnabled()) {
817 std::stable_sort(suggestions.begin(), suggestions.end(),
818 [](const Suggestion& a, const Suggestion& b) {
819 return a.match < b.match;
820 });
821 }
822
803 // Don't show two suggestions if one is a subset of the other. 823 // Don't show two suggestions if one is a subset of the other.
804 std::vector<AutofillProfile*> unique_matched_profiles; 824 std::vector<AutofillProfile*> unique_matched_profiles;
805 std::vector<Suggestion> unique_suggestions; 825 std::vector<Suggestion> unique_suggestions;
806 ServerFieldTypeSet types(other_field_types.begin(), other_field_types.end()); 826 ServerFieldTypeSet types(other_field_types.begin(), other_field_types.end());
807 for (size_t i = 0; i < matched_profiles.size(); ++i) { 827 for (size_t i = 0; i < matched_profiles.size(); ++i) {
808 bool include = true; 828 bool include = true;
809 AutofillProfile* profile_a = matched_profiles[i]; 829 AutofillProfile* profile_a = matched_profiles[i];
810 for (size_t j = 0; j < matched_profiles.size(); ++j) { 830 for (size_t j = 0; j < matched_profiles.size(); ++j) {
811 AutofillProfile* profile_b = matched_profiles[j]; 831 AutofillProfile* profile_b = matched_profiles[j];
812 // Check if profile A is a subset of profile B. If not, continue. 832 // Check if profile A is a subset of profile B. If not, continue.
(...skipping 28 matching lines...) Expand all
841 for (size_t i = 0; i < labels.size(); i++) 861 for (size_t i = 0; i < labels.size(); i++)
842 unique_suggestions[i].label = labels[i]; 862 unique_suggestions[i].label = labels[i];
843 863
844 return unique_suggestions; 864 return unique_suggestions;
845 } 865 }
846 866
847 std::vector<Suggestion> PersonalDataManager::GetCreditCardSuggestions( 867 std::vector<Suggestion> PersonalDataManager::GetCreditCardSuggestions(
848 const AutofillType& type, 868 const AutofillType& type,
849 const base::string16& field_contents) { 869 const base::string16& field_contents) {
850 std::list<const CreditCard*> cards_to_suggest; 870 std::list<const CreditCard*> cards_to_suggest;
871 std::list<const CreditCard*> substring_matched_suggestions;
851 for (const CreditCard* credit_card : GetCreditCards()) { 872 for (const CreditCard* credit_card : GetCreditCards()) {
852 // The value of the stored data for this field type in the |credit_card|. 873 // The value of the stored data for this field type in the |credit_card|.
853 base::string16 creditcard_field_value = 874 base::string16 creditcard_field_value =
854 credit_card->GetInfo(type, app_locale_); 875 credit_card->GetInfo(type, app_locale_);
855 if (creditcard_field_value.empty()) 876 if (creditcard_field_value.empty())
856 continue; 877 continue;
857 878
858 // For card number fields, suggest the card if: 879 // For card number fields, suggest the card if:
859 // - the number matches any part of the card, or 880 // - the number matches any part of the card, or
860 // - it's a masked card and there are 6 or fewers typed so far. 881 // - it's a masked card and there are 6 or fewers typed so far.
861 // For other fields, require that the field contents match the beginning of 882 // For other fields, require that the field contents match the beginning of
862 // the stored data. 883 // the stored data.
863 if (type.GetStorableType() == CREDIT_CARD_NUMBER) { 884 if (type.GetStorableType() == CREDIT_CARD_NUMBER) {
864 if (creditcard_field_value.find(field_contents) == base::string16::npos && 885 if (creditcard_field_value.find(field_contents) == base::string16::npos &&
865 (credit_card->record_type() != CreditCard::MASKED_SERVER_CARD || 886 (credit_card->record_type() != CreditCard::MASKED_SERVER_CARD ||
866 field_contents.size() >= 6)) { 887 field_contents.size() >= 6)) {
867 continue; 888 continue;
868 } 889 }
869 } else if (!StartsWith(creditcard_field_value, field_contents, false)) { 890 cards_to_suggest.push_back(credit_card);
870 continue; 891 } else if (StartsWith(creditcard_field_value, field_contents, false)) {
892 cards_to_suggest.push_back(credit_card);
893 } else if (ContainsTokenThatStartsWith(creditcard_field_value,
894 field_contents, false)) {
895 substring_matched_suggestions.push_back(credit_card);
871 } 896 }
897 }
872 898
873 cards_to_suggest.push_back(credit_card); 899 cards_to_suggest.sort(RankByMfu);
900
901 // Prefix matches should precede other token matches.
902 if (IsFeatureSubstringMatchEnabled()) {
903 substring_matched_suggestions.sort(RankByMfu);
904 cards_to_suggest.insert(cards_to_suggest.end(),
905 substring_matched_suggestions.begin(),
906 substring_matched_suggestions.end());
874 } 907 }
875 908
876 // De-dupe card suggestions. Full server cards shadow local cards, and 909 // De-dupe card suggestions. Full server cards shadow local cards, and
877 // local cards shadow masked server cards. 910 // local cards shadow masked server cards.
878 for (auto outer_it = cards_to_suggest.begin(); 911 for (auto outer_it = cards_to_suggest.begin();
879 outer_it != cards_to_suggest.end(); 912 outer_it != cards_to_suggest.end();
880 ++outer_it) { 913 ++outer_it) {
881 914
882 if ((*outer_it)->record_type() == CreditCard::FULL_SERVER_CARD) { 915 if ((*outer_it)->record_type() == CreditCard::FULL_SERVER_CARD) {
883 for (auto inner_it = cards_to_suggest.begin(); 916 for (auto inner_it = cards_to_suggest.begin();
884 inner_it != cards_to_suggest.end();) { 917 inner_it != cards_to_suggest.end();) {
885 auto inner_it_copy = inner_it++; 918 auto inner_it_copy = inner_it++;
886 if ((*inner_it_copy)->IsLocalDuplicateOfServerCard(**outer_it)) 919 if ((*inner_it_copy)->IsLocalDuplicateOfServerCard(**outer_it))
887 cards_to_suggest.erase(inner_it_copy); 920 cards_to_suggest.erase(inner_it_copy);
888 } 921 }
889 } else if ((*outer_it)->record_type() == CreditCard::LOCAL_CARD) { 922 } else if ((*outer_it)->record_type() == CreditCard::LOCAL_CARD) {
890 for (auto inner_it = cards_to_suggest.begin(); 923 for (auto inner_it = cards_to_suggest.begin();
891 inner_it != cards_to_suggest.end();) { 924 inner_it != cards_to_suggest.end();) {
892 auto inner_it_copy = inner_it++; 925 auto inner_it_copy = inner_it++;
893 if ((*inner_it_copy)->record_type() == CreditCard::MASKED_SERVER_CARD && 926 if ((*inner_it_copy)->record_type() == CreditCard::MASKED_SERVER_CARD &&
894 (*outer_it)->IsLocalDuplicateOfServerCard(**inner_it_copy)) { 927 (*outer_it)->IsLocalDuplicateOfServerCard(**inner_it_copy)) {
895 cards_to_suggest.erase(inner_it_copy); 928 cards_to_suggest.erase(inner_it_copy);
896 } 929 }
897 } 930 }
898 } 931 }
899 } 932 }
900 933
901 cards_to_suggest.sort(RankByMfu);
902
903 std::vector<Suggestion> suggestions; 934 std::vector<Suggestion> suggestions;
904 for (const CreditCard* credit_card : cards_to_suggest) { 935 for (const CreditCard* credit_card : cards_to_suggest) {
905 // Make a new suggestion. 936 // Make a new suggestion.
906 suggestions.push_back(Suggestion()); 937 suggestions.push_back(Suggestion());
907 Suggestion* suggestion = &suggestions.back(); 938 Suggestion* suggestion = &suggestions.back();
908 939
909 suggestion->value = credit_card->GetInfo(type, app_locale_); 940 suggestion->value = credit_card->GetInfo(type, app_locale_);
910 suggestion->icon = base::UTF8ToUTF16(credit_card->type()); 941 suggestion->icon = base::UTF8ToUTF16(credit_card->type());
911 suggestion->backend_id = credit_card->guid(); 942 suggestion->backend_id = credit_card->guid();
912 943
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after
1326 } 1357 }
1327 if (IsExperimentalWalletIntegrationEnabled() && 1358 if (IsExperimentalWalletIntegrationEnabled() &&
1328 pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled)) { 1359 pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled)) {
1329 profiles_.insert( 1360 profiles_.insert(
1330 profiles_.end(), server_profiles_.begin(), server_profiles_.end()); 1361 profiles_.end(), server_profiles_.begin(), server_profiles_.end());
1331 } 1362 }
1332 return profiles_; 1363 return profiles_;
1333 } 1364 }
1334 1365
1335 } // namespace autofill 1366 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698