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

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 Vaclav's review comments. Created 5 years, 5 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 13 matching lines...) Expand all
24 #include "components/autofill/core/browser/autofill_experiments.h" 24 #include "components/autofill/core/browser/autofill_experiments.h"
25 #include "components/autofill/core/browser/autofill_field.h" 25 #include "components/autofill/core/browser/autofill_field.h"
26 #include "components/autofill/core/browser/autofill_metrics.h" 26 #include "components/autofill/core/browser/autofill_metrics.h"
27 #include "components/autofill/core/browser/form_structure.h" 27 #include "components/autofill/core/browser/form_structure.h"
28 #include "components/autofill/core/browser/personal_data_manager_observer.h" 28 #include "components/autofill/core/browser/personal_data_manager_observer.h"
29 #include "components/autofill/core/browser/phone_number.h" 29 #include "components/autofill/core/browser/phone_number.h"
30 #include "components/autofill/core/browser/phone_number_i18n.h" 30 #include "components/autofill/core/browser/phone_number_i18n.h"
31 #include "components/autofill/core/browser/validation.h" 31 #include "components/autofill/core/browser/validation.h"
32 #include "components/autofill/core/common/autofill_pref_names.h" 32 #include "components/autofill/core/common/autofill_pref_names.h"
33 #include "components/autofill/core/common/autofill_switches.h" 33 #include "components/autofill/core/common/autofill_switches.h"
34 #include "components/autofill/core/common/autofill_util.h"
34 #include "components/signin/core/browser/account_tracker_service.h" 35 #include "components/signin/core/browser/account_tracker_service.h"
35 #include "components/signin/core/common/signin_pref_names.h" 36 #include "components/signin/core/common/signin_pref_names.h"
36 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_da ta.h" 37 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_da ta.h"
37 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_fo rmatter.h" 38 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_fo rmatter.h"
38 39
39 namespace autofill { 40 namespace autofill {
40 namespace { 41 namespace {
41 42
42 using ::i18n::addressinput::AddressField; 43 using ::i18n::addressinput::AddressField;
43 using ::i18n::addressinput::GetStreetAddressLinesAsSingleLine; 44 using ::i18n::addressinput::GetStreetAddressLinesAsSingleLine;
(...skipping 745 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 790
790 std::vector<Suggestion> suggestions; 791 std::vector<Suggestion> suggestions;
791 // Match based on a prefix search. 792 // Match based on a prefix search.
792 std::vector<AutofillProfile*> matched_profiles; 793 std::vector<AutofillProfile*> matched_profiles;
793 for (AutofillProfile* profile : profiles) { 794 for (AutofillProfile* profile : profiles) {
794 base::string16 value = GetInfoInOneLine(profile, type, app_locale_); 795 base::string16 value = GetInfoInOneLine(profile, type, app_locale_);
795 if (value.empty()) 796 if (value.empty())
796 continue; 797 continue;
797 base::string16 value_canon = 798 base::string16 value_canon =
798 AutofillProfile::CanonicalizeProfileString(value); 799 AutofillProfile::CanonicalizeProfileString(value);
799 if (base::StartsWith(value_canon, field_contents_canon, 800 bool prefix_matched_suggestion = base::StartsWith(
800 base::CompareCase::SENSITIVE)) { 801 value_canon, field_contents_canon, base::CompareCase::SENSITIVE);
801 // Prefix match, add suggestion. 802 if (prefix_matched_suggestion ||
803 FieldIsSuggestionSubstringStartingOnTokenBoundary(value, field_contents,
804 false)) {
802 matched_profiles.push_back(profile); 805 matched_profiles.push_back(profile);
803 suggestions.push_back(Suggestion(value)); 806 suggestions.push_back(Suggestion(value));
804 suggestions.back().backend_id = profile->guid(); 807 suggestions.back().backend_id = profile->guid();
808 suggestions.back().match = prefix_matched_suggestion
809 ? Suggestion::PREFIX_MATCH
810 : Suggestion::SUBSTRING_MATCH;
805 } 811 }
806 } 812 }
807 813
814 // Prefix matches should precede other token matches.
815 if (IsFeatureSubstringMatchEnabled()) {
816 std::stable_sort(suggestions.begin(), suggestions.end(),
817 [](const Suggestion& a, const Suggestion& b) {
818 return a.match < b.match;
819 });
820 }
821
808 // Don't show two suggestions if one is a subset of the other. 822 // Don't show two suggestions if one is a subset of the other.
809 std::vector<AutofillProfile*> unique_matched_profiles; 823 std::vector<AutofillProfile*> unique_matched_profiles;
810 std::vector<Suggestion> unique_suggestions; 824 std::vector<Suggestion> unique_suggestions;
811 ServerFieldTypeSet types(other_field_types.begin(), other_field_types.end()); 825 ServerFieldTypeSet types(other_field_types.begin(), other_field_types.end());
812 for (size_t i = 0; i < matched_profiles.size(); ++i) { 826 for (size_t i = 0; i < matched_profiles.size(); ++i) {
813 bool include = true; 827 bool include = true;
814 AutofillProfile* profile_a = matched_profiles[i]; 828 AutofillProfile* profile_a = matched_profiles[i];
815 for (size_t j = 0; j < matched_profiles.size(); ++j) { 829 for (size_t j = 0; j < matched_profiles.size(); ++j) {
816 AutofillProfile* profile_b = matched_profiles[j]; 830 AutofillProfile* profile_b = matched_profiles[j];
817 // Check if profile A is a subset of profile B. If not, continue. 831 // Check if profile A is a subset of profile B. If not, continue.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
849 return unique_suggestions; 863 return unique_suggestions;
850 } 864 }
851 865
852 std::vector<Suggestion> PersonalDataManager::GetCreditCardSuggestions( 866 std::vector<Suggestion> PersonalDataManager::GetCreditCardSuggestions(
853 const AutofillType& type, 867 const AutofillType& type,
854 const base::string16& field_contents) { 868 const base::string16& field_contents) {
855 if (IsInAutofillSuggestionsDisabledExperiment()) 869 if (IsInAutofillSuggestionsDisabledExperiment())
856 return std::vector<Suggestion>(); 870 return std::vector<Suggestion>();
857 871
858 std::list<const CreditCard*> cards_to_suggest; 872 std::list<const CreditCard*> cards_to_suggest;
873 std::list<const CreditCard*> substring_matched_cards;
859 base::string16 field_contents_lower = base::i18n::ToLower(field_contents); 874 base::string16 field_contents_lower = base::i18n::ToLower(field_contents);
860 for (const CreditCard* credit_card : GetCreditCards()) { 875 for (const CreditCard* credit_card : GetCreditCards()) {
861 // The value of the stored data for this field type in the |credit_card|. 876 // The value of the stored data for this field type in the |credit_card|.
862 base::string16 creditcard_field_value = 877 base::string16 creditcard_field_value =
863 credit_card->GetInfo(type, app_locale_); 878 credit_card->GetInfo(type, app_locale_);
864 if (creditcard_field_value.empty()) 879 if (creditcard_field_value.empty())
865 continue; 880 continue;
866 base::string16 creditcard_field_lower = 881 base::string16 creditcard_field_lower =
867 base::i18n::ToLower(creditcard_field_value); 882 base::i18n::ToLower(creditcard_field_value);
868 883
869 // For card number fields, suggest the card if: 884 // For card number fields, suggest the card if:
870 // - the number matches any part of the card, or 885 // - the number matches any part of the card, or
871 // - it's a masked card and there are 6 or fewers typed so far. 886 // - it's a masked card and there are 6 or fewers typed so far.
872 // For other fields, require that the field contents match the beginning of 887 // For other fields, require that the field contents match the beginning of
873 // the stored data. 888 // the stored data.
874 if (type.GetStorableType() == CREDIT_CARD_NUMBER) { 889 if (type.GetStorableType() == CREDIT_CARD_NUMBER) {
875 if (creditcard_field_lower.find(field_contents_lower) == 890 if (creditcard_field_lower.find(field_contents_lower) ==
876 base::string16::npos && 891 base::string16::npos &&
877 (credit_card->record_type() != CreditCard::MASKED_SERVER_CARD || 892 (credit_card->record_type() != CreditCard::MASKED_SERVER_CARD ||
878 field_contents.size() >= 6)) { 893 field_contents.size() >= 6)) {
879 continue; 894 continue;
880 } 895 }
881 } else if (!base::StartsWith(creditcard_field_lower, field_contents_lower, 896 cards_to_suggest.push_back(credit_card);
882 base::CompareCase::SENSITIVE)) { 897 } else if (base::StartsWith(creditcard_field_lower, field_contents_lower,
883 continue; 898 base::CompareCase::SENSITIVE)) {
899 cards_to_suggest.push_back(credit_card);
900 } else if (FieldIsSuggestionSubstringStartingOnTokenBoundary(
901 creditcard_field_lower, field_contents_lower, true)) {
902 substring_matched_cards.push_back(credit_card);
884 } 903 }
904 }
885 905
886 cards_to_suggest.push_back(credit_card); 906 cards_to_suggest.sort(RankByMfu);
907
908 // Prefix matches should precede other token matches.
909 if (IsFeatureSubstringMatchEnabled()) {
910 substring_matched_cards.sort(RankByMfu);
911 cards_to_suggest.insert(cards_to_suggest.end(),
912 substring_matched_cards.begin(),
913 substring_matched_cards.end());
887 } 914 }
888 915
889 // De-dupe card suggestions. Full server cards shadow local cards, and 916 // De-dupe card suggestions. Full server cards shadow local cards, and
890 // local cards shadow masked server cards. 917 // local cards shadow masked server cards.
891 for (auto outer_it = cards_to_suggest.begin(); 918 for (auto outer_it = cards_to_suggest.begin();
892 outer_it != cards_to_suggest.end(); 919 outer_it != cards_to_suggest.end();
893 ++outer_it) { 920 ++outer_it) {
894 921
895 if ((*outer_it)->record_type() == CreditCard::FULL_SERVER_CARD) { 922 if ((*outer_it)->record_type() == CreditCard::FULL_SERVER_CARD) {
896 for (auto inner_it = cards_to_suggest.begin(); 923 for (auto inner_it = cards_to_suggest.begin();
897 inner_it != cards_to_suggest.end();) { 924 inner_it != cards_to_suggest.end();) {
898 auto inner_it_copy = inner_it++; 925 auto inner_it_copy = inner_it++;
899 if ((*inner_it_copy)->IsLocalDuplicateOfServerCard(**outer_it)) 926 if ((*inner_it_copy)->IsLocalDuplicateOfServerCard(**outer_it))
900 cards_to_suggest.erase(inner_it_copy); 927 cards_to_suggest.erase(inner_it_copy);
901 } 928 }
902 } else if ((*outer_it)->record_type() == CreditCard::LOCAL_CARD) { 929 } else if ((*outer_it)->record_type() == CreditCard::LOCAL_CARD) {
903 for (auto inner_it = cards_to_suggest.begin(); 930 for (auto inner_it = cards_to_suggest.begin();
904 inner_it != cards_to_suggest.end();) { 931 inner_it != cards_to_suggest.end();) {
905 auto inner_it_copy = inner_it++; 932 auto inner_it_copy = inner_it++;
906 if ((*inner_it_copy)->record_type() == CreditCard::MASKED_SERVER_CARD && 933 if ((*inner_it_copy)->record_type() == CreditCard::MASKED_SERVER_CARD &&
907 (*outer_it)->IsLocalDuplicateOfServerCard(**inner_it_copy)) { 934 (*outer_it)->IsLocalDuplicateOfServerCard(**inner_it_copy)) {
908 cards_to_suggest.erase(inner_it_copy); 935 cards_to_suggest.erase(inner_it_copy);
909 } 936 }
910 } 937 }
911 } 938 }
912 } 939 }
913 940
914 cards_to_suggest.sort(RankByMfu);
915
916 std::vector<Suggestion> suggestions; 941 std::vector<Suggestion> suggestions;
917 for (const CreditCard* credit_card : cards_to_suggest) { 942 for (const CreditCard* credit_card : cards_to_suggest) {
918 // Make a new suggestion. 943 // Make a new suggestion.
919 suggestions.push_back(Suggestion()); 944 suggestions.push_back(Suggestion());
920 Suggestion* suggestion = &suggestions.back(); 945 Suggestion* suggestion = &suggestions.back();
921 946
922 suggestion->value = credit_card->GetInfo(type, app_locale_); 947 suggestion->value = credit_card->GetInfo(type, app_locale_);
923 suggestion->icon = base::UTF8ToUTF16(credit_card->type()); 948 suggestion->icon = base::UTF8ToUTF16(credit_card->type());
924 suggestion->backend_id = credit_card->guid(); 949 suggestion->backend_id = credit_card->guid();
925 950
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after
1339 } 1364 }
1340 if (IsExperimentalWalletIntegrationEnabled() && 1365 if (IsExperimentalWalletIntegrationEnabled() &&
1341 pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled)) { 1366 pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled)) {
1342 profiles_.insert( 1367 profiles_.insert(
1343 profiles_.end(), server_profiles_.begin(), server_profiles_.end()); 1368 profiles_.end(), server_profiles_.begin(), server_profiles_.end());
1344 } 1369 }
1345 return profiles_; 1370 return profiles_;
1346 } 1371 }
1347 1372
1348 } // namespace autofill 1373 } // namespace autofill
OLDNEW
« no previous file with comments | « components/autofill/core/browser/autofill_manager_unittest.cc ('k') | components/autofill/core/browser/suggestion.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698