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
3 // found in the LICENSE file.
5 #include "components/autofill/core/browser/autofill_profile.h"
13 #include "base/basictypes.h"
14 #include "base/guid.h"
15 #include "base/logging.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "components/autofill/core/browser/address.h"
19 #include "components/autofill/core/browser/address_i18n.h"
20 #include "components/autofill/core/browser/autofill_country.h"
21 #include "components/autofill/core/browser/autofill_field.h"
22 #include "components/autofill/core/browser/autofill_type.h"
23 #include "components/autofill/core/browser/contact_info.h"
24 #include "components/autofill/core/browser/phone_number.h"
25 #include "components/autofill/core/browser/phone_number_i18n.h"
26 #include "components/autofill/core/browser/validation.h"
27 #include "components/autofill/core/common/form_field_data.h"
28 #include "grit/components_strings.h"
29 #include "third_party/libaddressinput/chromium/addressinput_util.h"
30 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
31 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_formatter.h"
32 #include "ui/base/l10n/l10n_util.h"
34 using base::ASCIIToUTF16;
35 using base::UTF16ToUTF8;
40 // Like |AutofillType::GetStorableType()|, but also returns |NAME_FULL| for
41 // first, middle, and last name field types.
42 ServerFieldType GetStorableTypeCollapsingNames(ServerFieldType type) {
43 ServerFieldType storable_type = AutofillType(type).GetStorableType();
44 if (AutofillType(storable_type).group() == NAME)
50 // Fills |distinguishing_fields| with a list of fields to use when creating
51 // labels that can help to distinguish between two profiles. Draws fields from
52 // |suggested_fields| if it is non-NULL; otherwise returns a default list.
53 // If |suggested_fields| is non-NULL, does not include |excluded_field| in the
54 // list. Otherwise, |excluded_field| is ignored, and should be set to
55 // |UNKNOWN_TYPE| by convention. The resulting list of fields is sorted in
56 // decreasing order of importance.
57 void GetFieldsForDistinguishingProfiles(
58 const std::vector<ServerFieldType>* suggested_fields,
59 ServerFieldType excluded_field,
60 std::vector<ServerFieldType>* distinguishing_fields) {
61 static const ServerFieldType kDefaultDistinguishingFields[] = {
70 PHONE_HOME_WHOLE_NUMBER,
74 std::vector<ServerFieldType> default_fields;
75 if (!suggested_fields) {
76 default_fields.assign(
77 kDefaultDistinguishingFields,
78 kDefaultDistinguishingFields + arraysize(kDefaultDistinguishingFields));
79 if (excluded_field == UNKNOWN_TYPE) {
80 distinguishing_fields->swap(default_fields);
83 suggested_fields = &default_fields;
86 // Keep track of which fields we've seen so that we avoid duplicate entries.
87 // Always ignore fields of unknown type and the excluded field.
88 std::set<ServerFieldType> seen_fields;
89 seen_fields.insert(UNKNOWN_TYPE);
90 seen_fields.insert(GetStorableTypeCollapsingNames(excluded_field));
92 distinguishing_fields->clear();
93 for (std::vector<ServerFieldType>::const_iterator it =
94 suggested_fields->begin();
95 it != suggested_fields->end(); ++it) {
96 ServerFieldType suggested_type = GetStorableTypeCollapsingNames(*it);
97 if (seen_fields.insert(suggested_type).second)
98 distinguishing_fields->push_back(suggested_type);
101 // Special case: If the excluded field is a partial name (e.g. first name) and
102 // the suggested fields include other name fields, include |NAME_FULL| in the
103 // list of distinguishing fields as a last-ditch fallback. This allows us to
104 // distinguish between profiles that are identical except for the name.
105 if (excluded_field != NAME_FULL &&
106 GetStorableTypeCollapsingNames(excluded_field) == NAME_FULL) {
107 for (std::vector<ServerFieldType>::const_iterator it =
108 suggested_fields->begin();
109 it != suggested_fields->end(); ++it) {
110 if (*it != excluded_field &&
111 GetStorableTypeCollapsingNames(*it) == NAME_FULL) {
112 distinguishing_fields->push_back(NAME_FULL);
119 // A helper function for string streaming. Concatenates multi-valued entries
120 // stored for a given |type| into a single string. This string is returned.
121 const base::string16 MultiString(const AutofillProfile& p,
122 ServerFieldType type) {
123 std::vector<base::string16> values;
124 p.GetRawMultiInfo(type, &values);
125 base::string16 accumulate;
126 for (size_t i = 0; i < values.size(); ++i) {
128 accumulate += ASCIIToUTF16(" ");
129 accumulate += values[i];
134 base::string16 GetFormGroupInfo(const FormGroup& form_group,
135 const AutofillType& type,
136 const std::string& app_locale) {
137 return app_locale.empty() ?
138 form_group.GetRawInfo(type.GetStorableType()) :
139 form_group.GetInfo(type, app_locale);
143 void CopyRawValuesToItems(ServerFieldType type,
144 const std::vector<base::string16>& values,
146 std::vector<T>* form_group_items) {
147 form_group_items->resize(values.size(), prototype);
148 for (size_t i = 0; i < form_group_items->size(); ++i) {
149 (*form_group_items)[i].SetRawInfo(type, values[i]);
151 // Must have at least one (possibly empty) element.
152 form_group_items->resize(std::max<size_t>(1UL, values.size()), prototype);
156 void CopyValuesToItems(AutofillType type,
157 const std::vector<base::string16>& values,
159 const std::string& app_locale,
160 std::vector<T>* form_group_items) {
161 form_group_items->resize(values.size(), prototype);
162 for (size_t i = 0; i < form_group_items->size(); ++i) {
163 (*form_group_items)[i].SetInfo(type, values[i], app_locale);
165 // Must have at least one (possibly empty) element.
166 form_group_items->resize(std::max<size_t>(1UL, values.size()), prototype);
170 void CopyItemsToValues(const AutofillType& type,
171 const std::vector<T>& form_group_items,
172 const std::string& app_locale,
173 std::vector<base::string16>* values) {
174 values->resize(form_group_items.size());
175 for (size_t i = 0; i < values->size(); ++i) {
176 (*values)[i] = GetFormGroupInfo(form_group_items[i], type, app_locale);
180 // Collapse compound field types to their "full" type. I.e. First name
181 // collapses to full name, area code collapses to full phone, etc.
182 void CollapseCompoundFieldTypes(ServerFieldTypeSet* type_set) {
183 ServerFieldTypeSet collapsed_set;
184 for (ServerFieldTypeSet::iterator it = type_set->begin();
185 it != type_set->end(); ++it) {
190 case NAME_MIDDLE_INITIAL:
193 collapsed_set.insert(NAME_FULL);
196 case PHONE_HOME_NUMBER:
197 case PHONE_HOME_CITY_CODE:
198 case PHONE_HOME_COUNTRY_CODE:
199 case PHONE_HOME_CITY_AND_NUMBER:
200 case PHONE_HOME_WHOLE_NUMBER:
201 collapsed_set.insert(PHONE_HOME_WHOLE_NUMBER);
205 collapsed_set.insert(*it);
208 std::swap(*type_set, collapsed_set);
213 FindByPhone(const base::string16& phone,
214 const std::string& country_code,
215 const std::string& app_locale)
217 country_code_(country_code),
218 app_locale_(app_locale) {}
220 bool operator()(const base::string16& phone) {
221 return i18n::PhoneNumbersMatch(phone, phone_, country_code_, app_locale_);
225 base::string16 phone_;
226 std::string country_code_;
227 std::string app_locale_;
230 // Functor used to check for case-insensitive equality of two strings.
231 struct CaseInsensitiveStringEquals {
233 CaseInsensitiveStringEquals(const base::string16& other)
236 bool operator()(const base::string16& x) const {
237 return x.size() == other_.size() &&
238 base::StringToLowerASCII(x) == base::StringToLowerASCII(other_);
242 const base::string16& other_;
247 AutofillProfile::AutofillProfile(const std::string& guid,
248 const std::string& origin)
249 : AutofillDataModel(guid, origin),
252 phone_number_(1, PhoneNumber(this)) {
255 AutofillProfile::AutofillProfile()
256 : AutofillDataModel(base::GenerateGUID(), std::string()),
259 phone_number_(1, PhoneNumber(this)) {
262 AutofillProfile::AutofillProfile(const AutofillProfile& profile)
263 : AutofillDataModel(std::string(), std::string()) {
267 AutofillProfile::~AutofillProfile() {
270 AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
271 if (this == &profile)
274 set_guid(profile.guid());
275 set_origin(profile.origin());
277 name_ = profile.name_;
278 email_ = profile.email_;
279 company_ = profile.company_;
280 phone_number_ = profile.phone_number_;
282 for (size_t i = 0; i < phone_number_.size(); ++i)
283 phone_number_[i].set_profile(this);
285 address_ = profile.address_;
286 set_language_code(profile.language_code());
291 void AutofillProfile::GetMatchingTypes(
292 const base::string16& text,
293 const std::string& app_locale,
294 ServerFieldTypeSet* matching_types) const {
295 FormGroupList info = FormGroups();
296 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
297 (*it)->GetMatchingTypes(text, app_locale, matching_types);
300 base::string16 AutofillProfile::GetRawInfo(ServerFieldType type) const {
301 const FormGroup* form_group = FormGroupForType(AutofillType(type));
303 return base::string16();
305 return form_group->GetRawInfo(type);
308 void AutofillProfile::SetRawInfo(ServerFieldType type,
309 const base::string16& value) {
310 FormGroup* form_group = MutableFormGroupForType(AutofillType(type));
312 form_group->SetRawInfo(type, value);
315 base::string16 AutofillProfile::GetInfo(const AutofillType& type,
316 const std::string& app_locale) const {
317 if (type.html_type() == HTML_TYPE_FULL_ADDRESS) {
318 scoped_ptr< ::i18n::addressinput::AddressData> address_data =
319 i18n::CreateAddressDataFromAutofillProfile(*this, app_locale);
320 if (!addressinput::HasAllRequiredFields(*address_data))
321 return base::string16();
323 std::vector<std::string> lines;
324 ::i18n::addressinput::GetFormattedNationalAddress(*address_data, &lines);
325 return base::UTF8ToUTF16(JoinString(lines, '\n'));
328 const FormGroup* form_group = FormGroupForType(type);
330 return base::string16();
332 return form_group->GetInfo(type, app_locale);
335 bool AutofillProfile::SetInfo(const AutofillType& type,
336 const base::string16& value,
337 const std::string& app_locale) {
338 FormGroup* form_group = MutableFormGroupForType(type);
342 base::string16 trimmed_value;
343 base::TrimWhitespace(value, base::TRIM_ALL, &trimmed_value);
344 return form_group->SetInfo(type, trimmed_value, app_locale);
347 base::string16 AutofillProfile::GetInfoForVariant(
348 const AutofillType& type,
350 const std::string& app_locale) const {
351 std::vector<base::string16> values;
352 GetMultiInfo(type, app_locale, &values);
354 if (variant >= values.size()) {
355 // If the variant is unavailable, bail. This case is reachable, for
356 // example if Sync updates a profile during the filling process.
357 return base::string16();
360 return values[variant];
363 void AutofillProfile::SetRawMultiInfo(
364 ServerFieldType type,
365 const std::vector<base::string16>& values) {
366 switch (AutofillType(type).group()) {
369 CopyRawValuesToItems(type, values, NameInfo(), &name_);
373 CopyRawValuesToItems(type, values, EmailInfo(), &email_);
378 CopyRawValuesToItems(type, values, PhoneNumber(this), &phone_number_);
382 if (values.size() == 1U) {
383 SetRawInfo(type, values[0]);
384 } else if (values.empty()) {
385 SetRawInfo(type, base::string16());
387 // Shouldn't attempt to set multiple values on single-valued field.
394 void AutofillProfile::GetRawMultiInfo(
395 ServerFieldType type,
396 std::vector<base::string16>* values) const {
397 GetMultiInfoImpl(AutofillType(type), std::string(), values);
400 void AutofillProfile::SetMultiInfo(const AutofillType& type,
401 const std::vector<base::string16>& values,
402 const std::string& app_locale) {
403 switch (AutofillType(type).group()) {
406 CopyValuesToItems(type, values, NameInfo(), app_locale, &name_);
410 CopyValuesToItems(type, values, EmailInfo(), app_locale, &email_);
416 type, values, PhoneNumber(this), app_locale, &phone_number_);
420 if (values.size() == 1U) {
421 SetInfo(type, values[0], app_locale);
422 } else if (values.empty()) {
423 SetInfo(type, base::string16(), app_locale);
425 // Shouldn't attempt to set multiple values on single-valued field.
432 void AutofillProfile::GetMultiInfo(const AutofillType& type,
433 const std::string& app_locale,
434 std::vector<base::string16>* values) const {
435 GetMultiInfoImpl(type, app_locale, values);
438 bool AutofillProfile::IsEmpty(const std::string& app_locale) const {
439 ServerFieldTypeSet types;
440 GetNonEmptyTypes(app_locale, &types);
441 return types.empty();
444 bool AutofillProfile::IsPresentButInvalid(ServerFieldType type) const {
445 std::string country = UTF16ToUTF8(GetRawInfo(ADDRESS_HOME_COUNTRY));
446 base::string16 data = GetRawInfo(type);
451 case ADDRESS_HOME_STATE:
452 return country == "US" && !autofill::IsValidState(data);
454 case ADDRESS_HOME_ZIP:
455 return country == "US" && !autofill::IsValidZip(data);
457 case PHONE_HOME_WHOLE_NUMBER:
458 return !i18n::PhoneObject(data, country).IsValidNumber();
461 return !autofill::IsValidEmailAddress(data);
469 int AutofillProfile::Compare(const AutofillProfile& profile) const {
470 const ServerFieldType single_value_types[] = {
472 ADDRESS_HOME_STREET_ADDRESS,
473 ADDRESS_HOME_DEPENDENT_LOCALITY,
477 ADDRESS_HOME_SORTING_CODE,
478 ADDRESS_HOME_COUNTRY,
481 for (size_t i = 0; i < arraysize(single_value_types); ++i) {
482 int comparison = GetRawInfo(single_value_types[i]).compare(
483 profile.GetRawInfo(single_value_types[i]));
488 const ServerFieldType multi_value_types[] = { NAME_FULL,
493 PHONE_HOME_WHOLE_NUMBER };
495 for (size_t i = 0; i < arraysize(multi_value_types); ++i) {
496 std::vector<base::string16> values_a;
497 std::vector<base::string16> values_b;
498 GetRawMultiInfo(multi_value_types[i], &values_a);
499 profile.GetRawMultiInfo(multi_value_types[i], &values_b);
500 if (values_a.size() < values_b.size())
502 if (values_a.size() > values_b.size())
504 for (size_t j = 0; j < values_a.size(); ++j) {
505 int comparison = values_a[j].compare(values_b[j]);
514 bool AutofillProfile::EqualsSansOrigin(const AutofillProfile& profile) const {
515 return guid() == profile.guid() &&
516 language_code() == profile.language_code() &&
517 Compare(profile) == 0;
520 bool AutofillProfile::EqualsSansGuid(const AutofillProfile& profile) const {
521 return origin() == profile.origin() &&
522 language_code() == profile.language_code() &&
523 Compare(profile) == 0;
526 bool AutofillProfile::operator==(const AutofillProfile& profile) const {
527 return guid() == profile.guid() && EqualsSansGuid(profile);
530 bool AutofillProfile::operator!=(const AutofillProfile& profile) const {
531 return !operator==(profile);
534 const base::string16 AutofillProfile::PrimaryValue() const {
535 return GetRawInfo(ADDRESS_HOME_LINE1) + GetRawInfo(ADDRESS_HOME_CITY);
538 bool AutofillProfile::IsSubsetOf(const AutofillProfile& profile,
539 const std::string& app_locale) const {
540 ServerFieldTypeSet types;
541 GetNonEmptyTypes(app_locale, &types);
543 for (ServerFieldTypeSet::const_iterator it = types.begin(); it != types.end();
545 if (*it == NAME_FULL || *it == ADDRESS_HOME_STREET_ADDRESS) {
546 // Ignore the compound "full name" field type. We are only interested in
547 // comparing the constituent parts. For example, if |this| has a middle
548 // name saved, but |profile| lacks one, |profile| could still be a subset
549 // of |this|. Likewise, ignore the compound "street address" type, as we
550 // are only interested in matching line-by-line.
552 } else if (AutofillType(*it).group() == PHONE_HOME) {
553 // Phone numbers should be canonicalized prior to being compared.
554 if (*it != PHONE_HOME_WHOLE_NUMBER) {
556 } else if (!i18n::PhoneNumbersMatch(
558 profile.GetRawInfo(*it),
559 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)),
563 } else if (base::StringToLowerASCII(GetRawInfo(*it)) !=
564 base::StringToLowerASCII(profile.GetRawInfo(*it))) {
572 void AutofillProfile::OverwriteOrAppendNames(
573 const std::vector<NameInfo>& names,
574 const std::string& app_locale) {
575 std::vector<NameInfo> results(name_);
576 for (std::vector<NameInfo>::const_iterator it = names.begin();
579 NameInfo imported_name = *it;
580 bool should_append_imported_name = true;
582 for (size_t index = 0; index < name_.size(); ++index) {
583 NameInfo current_name = name_[index];
584 if (current_name.ParsedNamesAreEqual(imported_name)) {
585 if (current_name.GetRawInfo(NAME_FULL).empty()) {
586 current_name.SetRawInfo(NAME_FULL,
587 imported_name.GetRawInfo(NAME_FULL));
590 should_append_imported_name = false;
594 AutofillType type = AutofillType(NAME_FULL);
595 base::string16 full_name = current_name.GetInfo(type, app_locale);
596 if (base::StringToLowerASCII(full_name) ==
597 base::StringToLowerASCII(imported_name.GetInfo(type, app_locale))) {
598 // The imported name has the same full name string as one of the
599 // existing names for this profile. Because full names are
600 // _heuristically_ parsed into {first, middle, last} name components,
601 // it's possible that either the existing name or the imported name
602 // was misparsed. Prefer to keep the name whose {first, middle,
603 // last} components do not match those computed by the heuristic
604 // parse, as this more likely represents the correct, user-input parse
606 NameInfo heuristically_parsed_name;
607 heuristically_parsed_name.SetInfo(type, full_name, app_locale);
608 if (imported_name.ParsedNamesAreEqual(heuristically_parsed_name)) {
609 should_append_imported_name = false;
613 if (current_name.ParsedNamesAreEqual(heuristically_parsed_name)) {
614 results[index] = imported_name;
615 should_append_imported_name = false;
621 // Append unique names to the list.
622 if (should_append_imported_name)
623 results.push_back(imported_name);
629 void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile,
630 const std::string& app_locale) {
631 // Verified profiles should never be overwritten with unverified data.
632 DCHECK(!IsVerified() || profile.IsVerified());
633 set_origin(profile.origin());
634 set_language_code(profile.language_code());
636 ServerFieldTypeSet field_types;
637 profile.GetNonEmptyTypes(app_locale, &field_types);
639 // Only transfer "full" types (e.g. full name) and not fragments (e.g.
640 // first name, last name).
641 CollapseCompoundFieldTypes(&field_types);
643 // TODO(isherman): Revisit this decision in the context of i18n and storing
644 // full addresses rather than storing 1-to-2 lines of an address.
645 // For addresses, do the opposite: transfer individual address lines, rather
646 // than full addresses.
647 field_types.erase(ADDRESS_HOME_STREET_ADDRESS);
649 for (ServerFieldTypeSet::const_iterator iter = field_types.begin();
650 iter != field_types.end(); ++iter) {
651 FieldTypeGroup group = AutofillType(*iter).group();
652 // Special case names.
654 OverwriteOrAppendNames(profile.name_, app_locale);
658 // Single value field --- overwrite.
659 if (!AutofillProfile::SupportsMultiValue(*iter)) {
660 base::string16 new_value = profile.GetRawInfo(*iter);
661 if (base::StringToLowerASCII(GetRawInfo(*iter)) !=
662 base::StringToLowerASCII(new_value)) {
663 SetRawInfo(*iter, new_value);
668 // Multi value field --- overwrite/append.
669 std::vector<base::string16> new_values;
670 profile.GetRawMultiInfo(*iter, &new_values);
671 std::vector<base::string16> existing_values;
672 GetRawMultiInfo(*iter, &existing_values);
674 // GetMultiInfo always returns at least one element, even if the profile
675 // has no data stored for this field type.
676 if (existing_values.size() == 1 && existing_values.front().empty())
677 existing_values.clear();
679 for (std::vector<base::string16>::iterator value_iter =
681 value_iter != new_values.end(); ++value_iter) {
682 // Don't add duplicates. Most types get case insensitive matching.
683 std::vector<base::string16>::const_iterator existing_iter;
685 if (group == PHONE_HOME) {
686 // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377",
687 // "(800)356-9377" and "356-9377" are considered the same.
688 std::string country_code =
689 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY));
691 std::find_if(existing_values.begin(), existing_values.end(),
692 FindByPhone(*value_iter, country_code, app_locale));
695 std::find_if(existing_values.begin(), existing_values.end(),
696 CaseInsensitiveStringEquals(*value_iter));
699 if (existing_iter == existing_values.end())
700 existing_values.insert(existing_values.end(), *value_iter);
703 SetRawMultiInfo(*iter, existing_values);
708 bool AutofillProfile::SupportsMultiValue(ServerFieldType type) {
709 FieldTypeGroup group = AutofillType(type).group();
710 return group == NAME ||
711 group == NAME_BILLING ||
713 group == PHONE_HOME ||
714 group == PHONE_BILLING;
718 void AutofillProfile::CreateDifferentiatingLabels(
719 const std::vector<AutofillProfile*>& profiles,
720 const std::string& app_locale,
721 std::vector<base::string16>* labels) {
722 const size_t kMinimalFieldsShown = 2;
723 CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
725 DCHECK_EQ(profiles.size(), labels->size());
729 void AutofillProfile::CreateInferredLabels(
730 const std::vector<AutofillProfile*>& profiles,
731 const std::vector<ServerFieldType>* suggested_fields,
732 ServerFieldType excluded_field,
733 size_t minimal_fields_shown,
734 const std::string& app_locale,
735 std::vector<base::string16>* labels) {
736 std::vector<ServerFieldType> fields_to_use;
737 GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
740 // Construct the default label for each profile. Also construct a map that
741 // associates each label with the profiles that have this label. This map is
742 // then used to detect which labels need further differentiating fields.
743 std::map<base::string16, std::list<size_t> > labels_to_profiles;
744 for (size_t i = 0; i < profiles.size(); ++i) {
745 base::string16 label =
746 profiles[i]->ConstructInferredLabel(fields_to_use,
747 minimal_fields_shown,
749 labels_to_profiles[label].push_back(i);
752 labels->resize(profiles.size());
753 for (std::map<base::string16, std::list<size_t> >::const_iterator it =
754 labels_to_profiles.begin();
755 it != labels_to_profiles.end(); ++it) {
756 if (it->second.size() == 1) {
757 // This label is unique, so use it without any further ado.
758 base::string16 label = it->first;
759 size_t profile_index = it->second.front();
760 (*labels)[profile_index] = label;
762 // We have more than one profile with the same label, so add
763 // differentiating fields.
764 CreateInferredLabelsHelper(profiles, it->second, fields_to_use,
765 minimal_fields_shown, app_locale, labels);
770 void AutofillProfile::GetSupportedTypes(
771 ServerFieldTypeSet* supported_types) const {
772 FormGroupList info = FormGroups();
773 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
774 (*it)->GetSupportedTypes(supported_types);
777 void AutofillProfile::GetMultiInfoImpl(
778 const AutofillType& type,
779 const std::string& app_locale,
780 std::vector<base::string16>* values) const {
781 switch (type.group()) {
784 CopyItemsToValues(type, name_, app_locale, values);
787 CopyItemsToValues(type, email_, app_locale, values);
791 CopyItemsToValues(type, phone_number_, app_locale, values);
795 (*values)[0] = GetFormGroupInfo(*this, type, app_locale);
799 base::string16 AutofillProfile::ConstructInferredLabel(
800 const std::vector<ServerFieldType>& included_fields,
801 size_t num_fields_to_use,
802 const std::string& app_locale) const {
803 const base::string16 separator =
804 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
806 base::string16 label;
807 size_t num_fields_used = 0;
808 for (std::vector<ServerFieldType>::const_iterator it =
809 included_fields.begin();
810 it != included_fields.end() && num_fields_used < num_fields_to_use;
812 base::string16 field = GetInfo(AutofillType(*it), app_locale);
817 label.append(separator);
823 // Flatten the label if need be.
824 const base::string16& line_separator =
825 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_SEPARATOR);
826 base::ReplaceChars(label, base::ASCIIToUTF16("\n"), line_separator, &label);
832 void AutofillProfile::CreateInferredLabelsHelper(
833 const std::vector<AutofillProfile*>& profiles,
834 const std::list<size_t>& indices,
835 const std::vector<ServerFieldType>& fields,
836 size_t num_fields_to_include,
837 const std::string& app_locale,
838 std::vector<base::string16>* labels) {
839 // For efficiency, we first construct a map of fields to their text values and
840 // each value's frequency.
841 std::map<ServerFieldType,
842 std::map<base::string16, size_t> > field_text_frequencies_by_field;
843 for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
844 field != fields.end(); ++field) {
845 std::map<base::string16, size_t>& field_text_frequencies =
846 field_text_frequencies_by_field[*field];
848 for (std::list<size_t>::const_iterator it = indices.begin();
849 it != indices.end(); ++it) {
850 const AutofillProfile* profile = profiles[*it];
851 base::string16 field_text =
852 profile->GetInfo(AutofillType(*field), app_locale);
854 // If this label is not already in the map, add it with frequency 0.
855 if (!field_text_frequencies.count(field_text))
856 field_text_frequencies[field_text] = 0;
858 // Now, increment the frequency for this label.
859 ++field_text_frequencies[field_text];
863 // Now comes the meat of the algorithm. For each profile, we scan the list of
864 // fields to use, looking for two things:
865 // 1. A (non-empty) field that differentiates the profile from all others
866 // 2. At least |num_fields_to_include| non-empty fields
867 // Before we've satisfied condition (2), we include all fields, even ones that
868 // are identical across all the profiles. Once we've satisfied condition (2),
869 // we only include fields that that have at last two distinct values.
870 for (std::list<size_t>::const_iterator it = indices.begin();
871 it != indices.end(); ++it) {
872 const AutofillProfile* profile = profiles[*it];
874 std::vector<ServerFieldType> label_fields;
875 bool found_differentiating_field = false;
876 for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
877 field != fields.end(); ++field) {
878 // Skip over empty fields.
879 base::string16 field_text =
880 profile->GetInfo(AutofillType(*field), app_locale);
881 if (field_text.empty())
884 std::map<base::string16, size_t>& field_text_frequencies =
885 field_text_frequencies_by_field[*field];
886 found_differentiating_field |=
887 !field_text_frequencies.count(base::string16()) &&
888 (field_text_frequencies[field_text] == 1);
890 // Once we've found enough non-empty fields, skip over any remaining
891 // fields that are identical across all the profiles.
892 if (label_fields.size() >= num_fields_to_include &&
893 (field_text_frequencies.size() == 1))
896 label_fields.push_back(*field);
898 // If we've (1) found a differentiating field and (2) found at least
899 // |num_fields_to_include| non-empty fields, we're done!
900 if (found_differentiating_field &&
901 label_fields.size() >= num_fields_to_include)
905 (*labels)[*it] = profile->ConstructInferredLabel(
906 label_fields, label_fields.size(), app_locale);
910 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
915 v[3] = &phone_number_[0];
920 const FormGroup* AutofillProfile::FormGroupForType(
921 const AutofillType& type) const {
922 return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
925 FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) {
926 switch (type.group()) {
939 return &phone_number_[0];
942 case ADDRESS_BILLING:
956 // So we can compare AutofillProfiles with EXPECT_EQ().
957 std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
963 << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
965 << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
967 << UTF16ToUTF8(MultiString(profile, NAME_LAST))
969 << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
971 << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME))
973 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1))
975 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2))
977 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))
979 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY))
981 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE))
983 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP))
985 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE))
987 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))
989 << profile.language_code()
991 << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER));
994 } // namespace autofill