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

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 Rouslan'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 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 745 matching lines...) Expand 10 before | Expand all | Expand 10 after
788 789
789 std::vector<Suggestion> suggestions; 790 std::vector<Suggestion> suggestions;
790 // Match based on a prefix search. 791 // Match based on a prefix search.
791 std::vector<AutofillProfile*> matched_profiles; 792 std::vector<AutofillProfile*> matched_profiles;
792 for (AutofillProfile* profile : profiles) { 793 for (AutofillProfile* profile : profiles) {
793 base::string16 value = GetInfoInOneLine(profile, type, app_locale_); 794 base::string16 value = GetInfoInOneLine(profile, type, app_locale_);
794 if (value.empty()) 795 if (value.empty())
795 continue; 796 continue;
796 base::string16 value_canon = 797 base::string16 value_canon =
797 AutofillProfile::CanonicalizeProfileString(value); 798 AutofillProfile::CanonicalizeProfileString(value);
798 if (base::StartsWith(value_canon, field_contents_canon, true)) { 799 // CanonicalizeProfileString() returns lower-case string with separators;
799 // Prefix match, add suggestion. 800 // includes space, line and paragraph along with punctuations like dash,
801 // start, end and others {U_DASH_PUNCTUATION, U_START_PUNCTUATION,
802 // U_END_PUNCTUATION, U_CONNECTOR_PUNCTUATION, U_OTHER_PUNCTUATION,
803 // U_SPACE_SEPARATOR, U_LINE_SEPARATOR, U_PARAGRAPH_SEPARATOR}; substituted
804 // by whitespaces and trims off trailing whitespace if any. Passing
805 // |value_canon| and |field_contents_canon| to ContainsTokenThatStartsWith()
806 // may lead to unexpected result, hence preferred passing |value| and
807 // |field_contents| instead.
please use gerrit instead 2015/06/30 19:06:23 I would prefer removing this comment entirely, to
Pritam Nikam 2015/07/01 17:26:00 Done.
808 bool prefix_matched_suggestion =
809 base::StartsWith(value_canon, field_contents_canon, true);
810 if (prefix_matched_suggestion ||
811 ContainsTokenThatStartsWith(value, field_contents, false)) {
800 matched_profiles.push_back(profile); 812 matched_profiles.push_back(profile);
801 suggestions.push_back(Suggestion(value)); 813 suggestions.push_back(Suggestion(value));
802 suggestions.back().backend_id = profile->guid(); 814 suggestions.back().backend_id = profile->guid();
815 suggestions.back().match = prefix_matched_suggestion
816 ? Suggestion::PREFIX_MATCH
817 : Suggestion::SUBSTRING_MATCH;
803 } 818 }
804 } 819 }
805 820
821 // Prefix matches should precede other token matches.
822 if (IsFeatureSubstringMatchEnabled()) {
823 std::stable_sort(suggestions.begin(), suggestions.end(),
824 [](const Suggestion& a, const Suggestion& b) {
825 return a.match < b.match;
826 });
827 }
828
806 // Don't show two suggestions if one is a subset of the other. 829 // Don't show two suggestions if one is a subset of the other.
807 std::vector<AutofillProfile*> unique_matched_profiles; 830 std::vector<AutofillProfile*> unique_matched_profiles;
808 std::vector<Suggestion> unique_suggestions; 831 std::vector<Suggestion> unique_suggestions;
809 ServerFieldTypeSet types(other_field_types.begin(), other_field_types.end()); 832 ServerFieldTypeSet types(other_field_types.begin(), other_field_types.end());
810 for (size_t i = 0; i < matched_profiles.size(); ++i) { 833 for (size_t i = 0; i < matched_profiles.size(); ++i) {
811 bool include = true; 834 bool include = true;
812 AutofillProfile* profile_a = matched_profiles[i]; 835 AutofillProfile* profile_a = matched_profiles[i];
813 for (size_t j = 0; j < matched_profiles.size(); ++j) { 836 for (size_t j = 0; j < matched_profiles.size(); ++j) {
814 AutofillProfile* profile_b = matched_profiles[j]; 837 AutofillProfile* profile_b = matched_profiles[j];
815 // Check if profile A is a subset of profile B. If not, continue. 838 // 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
847 return unique_suggestions; 870 return unique_suggestions;
848 } 871 }
849 872
850 std::vector<Suggestion> PersonalDataManager::GetCreditCardSuggestions( 873 std::vector<Suggestion> PersonalDataManager::GetCreditCardSuggestions(
851 const AutofillType& type, 874 const AutofillType& type,
852 const base::string16& field_contents) { 875 const base::string16& field_contents) {
853 if (IsInAutofillSuggestionsDisabledExperiment()) 876 if (IsInAutofillSuggestionsDisabledExperiment())
854 return std::vector<Suggestion>(); 877 return std::vector<Suggestion>();
855 878
856 std::list<const CreditCard*> cards_to_suggest; 879 std::list<const CreditCard*> cards_to_suggest;
880 std::list<const CreditCard*> substring_matched_cards;
857 for (const CreditCard* credit_card : GetCreditCards()) { 881 for (const CreditCard* credit_card : GetCreditCards()) {
858 // The value of the stored data for this field type in the |credit_card|. 882 // The value of the stored data for this field type in the |credit_card|.
859 base::string16 creditcard_field_value = 883 base::string16 creditcard_field_value =
860 credit_card->GetInfo(type, app_locale_); 884 credit_card->GetInfo(type, app_locale_);
861 if (creditcard_field_value.empty()) 885 if (creditcard_field_value.empty())
862 continue; 886 continue;
863 887
864 // For card number fields, suggest the card if: 888 // For card number fields, suggest the card if:
865 // - the number matches any part of the card, or 889 // - the number matches any part of the card, or
866 // - it's a masked card and there are 6 or fewers typed so far. 890 // - it's a masked card and there are 6 or fewers typed so far.
867 // For other fields, require that the field contents match the beginning of 891 // For other fields, require that the field contents match the beginning of
868 // the stored data. 892 // the stored data.
869 if (type.GetStorableType() == CREDIT_CARD_NUMBER) { 893 if (type.GetStorableType() == CREDIT_CARD_NUMBER) {
870 if (creditcard_field_value.find(field_contents) == base::string16::npos && 894 if (creditcard_field_value.find(field_contents) == base::string16::npos &&
871 (credit_card->record_type() != CreditCard::MASKED_SERVER_CARD || 895 (credit_card->record_type() != CreditCard::MASKED_SERVER_CARD ||
872 field_contents.size() >= 6)) { 896 field_contents.size() >= 6)) {
873 continue; 897 continue;
874 } 898 }
875 } else if (!base::StartsWith(creditcard_field_value, field_contents, 899 cards_to_suggest.push_back(credit_card);
876 false)) { 900 } else if (base::StartsWith(creditcard_field_value, field_contents,
877 continue; 901 false)) {
902 cards_to_suggest.push_back(credit_card);
903 } else if (ContainsTokenThatStartsWith(creditcard_field_value,
904 field_contents, false)) {
905 substring_matched_cards.push_back(credit_card);
878 } 906 }
907 }
879 908
880 cards_to_suggest.push_back(credit_card); 909 cards_to_suggest.sort(RankByMfu);
910
911 // Prefix matches should precede other token matches.
912 if (IsFeatureSubstringMatchEnabled()) {
913 substring_matched_cards.sort(RankByMfu);
914 cards_to_suggest.insert(cards_to_suggest.end(),
915 substring_matched_cards.begin(),
916 substring_matched_cards.end());
881 } 917 }
882 918
883 // De-dupe card suggestions. Full server cards shadow local cards, and 919 // De-dupe card suggestions. Full server cards shadow local cards, and
884 // local cards shadow masked server cards. 920 // local cards shadow masked server cards.
885 for (auto outer_it = cards_to_suggest.begin(); 921 for (auto outer_it = cards_to_suggest.begin();
886 outer_it != cards_to_suggest.end(); 922 outer_it != cards_to_suggest.end();
887 ++outer_it) { 923 ++outer_it) {
888 924
889 if ((*outer_it)->record_type() == CreditCard::FULL_SERVER_CARD) { 925 if ((*outer_it)->record_type() == CreditCard::FULL_SERVER_CARD) {
890 for (auto inner_it = cards_to_suggest.begin(); 926 for (auto inner_it = cards_to_suggest.begin();
891 inner_it != cards_to_suggest.end();) { 927 inner_it != cards_to_suggest.end();) {
892 auto inner_it_copy = inner_it++; 928 auto inner_it_copy = inner_it++;
893 if ((*inner_it_copy)->IsLocalDuplicateOfServerCard(**outer_it)) 929 if ((*inner_it_copy)->IsLocalDuplicateOfServerCard(**outer_it))
894 cards_to_suggest.erase(inner_it_copy); 930 cards_to_suggest.erase(inner_it_copy);
895 } 931 }
896 } else if ((*outer_it)->record_type() == CreditCard::LOCAL_CARD) { 932 } else if ((*outer_it)->record_type() == CreditCard::LOCAL_CARD) {
897 for (auto inner_it = cards_to_suggest.begin(); 933 for (auto inner_it = cards_to_suggest.begin();
898 inner_it != cards_to_suggest.end();) { 934 inner_it != cards_to_suggest.end();) {
899 auto inner_it_copy = inner_it++; 935 auto inner_it_copy = inner_it++;
900 if ((*inner_it_copy)->record_type() == CreditCard::MASKED_SERVER_CARD && 936 if ((*inner_it_copy)->record_type() == CreditCard::MASKED_SERVER_CARD &&
901 (*outer_it)->IsLocalDuplicateOfServerCard(**inner_it_copy)) { 937 (*outer_it)->IsLocalDuplicateOfServerCard(**inner_it_copy)) {
902 cards_to_suggest.erase(inner_it_copy); 938 cards_to_suggest.erase(inner_it_copy);
903 } 939 }
904 } 940 }
905 } 941 }
906 } 942 }
907 943
908 cards_to_suggest.sort(RankByMfu);
909
910 std::vector<Suggestion> suggestions; 944 std::vector<Suggestion> suggestions;
911 for (const CreditCard* credit_card : cards_to_suggest) { 945 for (const CreditCard* credit_card : cards_to_suggest) {
912 // Make a new suggestion. 946 // Make a new suggestion.
913 suggestions.push_back(Suggestion()); 947 suggestions.push_back(Suggestion());
914 Suggestion* suggestion = &suggestions.back(); 948 Suggestion* suggestion = &suggestions.back();
915 949
916 suggestion->value = credit_card->GetInfo(type, app_locale_); 950 suggestion->value = credit_card->GetInfo(type, app_locale_);
917 suggestion->icon = base::UTF8ToUTF16(credit_card->type()); 951 suggestion->icon = base::UTF8ToUTF16(credit_card->type());
918 suggestion->backend_id = credit_card->guid(); 952 suggestion->backend_id = credit_card->guid();
919 953
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after
1333 } 1367 }
1334 if (IsExperimentalWalletIntegrationEnabled() && 1368 if (IsExperimentalWalletIntegrationEnabled() &&
1335 pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled)) { 1369 pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled)) {
1336 profiles_.insert( 1370 profiles_.insert(
1337 profiles_.end(), server_profiles_.begin(), server_profiles_.end()); 1371 profiles_.end(), server_profiles_.begin(), server_profiles_.end());
1338 } 1372 }
1339 return profiles_; 1373 return profiles_;
1340 } 1374 }
1341 1375
1342 } // namespace autofill 1376 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698