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 "third_party/libaddressinput/src/cpp/include/libaddressinput/address_metadata.h"
33 #include "ui/base/l10n/l10n_util.h"
35 using base::ASCIIToUTF16;
36 using base::UTF16ToUTF8;
37 using i18n::addressinput::AddressData;
38 using i18n::addressinput::AddressField;
43 // Like |AutofillType::GetStorableType()|, but also returns |NAME_FULL| for
44 // first, middle, and last name field types.
45 ServerFieldType GetStorableTypeCollapsingNames(ServerFieldType type) {
46 ServerFieldType storable_type = AutofillType(type).GetStorableType();
47 if (AutofillType(storable_type).group() == NAME)
53 // Fills |distinguishing_fields| with a list of fields to use when creating
54 // labels that can help to distinguish between two profiles. Draws fields from
55 // |suggested_fields| if it is non-NULL; otherwise returns a default list.
56 // If |suggested_fields| is non-NULL, does not include |excluded_field| in the
57 // list. Otherwise, |excluded_field| is ignored, and should be set to
58 // |UNKNOWN_TYPE| by convention. The resulting list of fields is sorted in
59 // decreasing order of importance.
60 void GetFieldsForDistinguishingProfiles(
61 const std::vector<ServerFieldType>* suggested_fields,
62 ServerFieldType excluded_field,
63 std::vector<ServerFieldType>* distinguishing_fields) {
64 static const ServerFieldType kDefaultDistinguishingFields[] = {
68 ADDRESS_HOME_DEPENDENT_LOCALITY,
72 ADDRESS_HOME_SORTING_CODE,
75 PHONE_HOME_WHOLE_NUMBER,
79 std::vector<ServerFieldType> default_fields;
80 if (!suggested_fields) {
81 default_fields.assign(
82 kDefaultDistinguishingFields,
83 kDefaultDistinguishingFields + arraysize(kDefaultDistinguishingFields));
84 if (excluded_field == UNKNOWN_TYPE) {
85 distinguishing_fields->swap(default_fields);
88 suggested_fields = &default_fields;
91 // Keep track of which fields we've seen so that we avoid duplicate entries.
92 // Always ignore fields of unknown type and the excluded field.
93 std::set<ServerFieldType> seen_fields;
94 seen_fields.insert(UNKNOWN_TYPE);
95 seen_fields.insert(GetStorableTypeCollapsingNames(excluded_field));
97 distinguishing_fields->clear();
98 for (std::vector<ServerFieldType>::const_iterator it =
99 suggested_fields->begin();
100 it != suggested_fields->end(); ++it) {
101 ServerFieldType suggested_type = GetStorableTypeCollapsingNames(*it);
102 if (seen_fields.insert(suggested_type).second)
103 distinguishing_fields->push_back(suggested_type);
106 // Special case: If the excluded field is a partial name (e.g. first name) and
107 // the suggested fields include other name fields, include |NAME_FULL| in the
108 // list of distinguishing fields as a last-ditch fallback. This allows us to
109 // distinguish between profiles that are identical except for the name.
110 if (excluded_field != NAME_FULL &&
111 GetStorableTypeCollapsingNames(excluded_field) == NAME_FULL) {
112 for (std::vector<ServerFieldType>::const_iterator it =
113 suggested_fields->begin();
114 it != suggested_fields->end(); ++it) {
115 if (*it != excluded_field &&
116 GetStorableTypeCollapsingNames(*it) == NAME_FULL) {
117 distinguishing_fields->push_back(NAME_FULL);
124 // A helper function for string streaming. Concatenates multi-valued entries
125 // stored for a given |type| into a single string. This string is returned.
126 const base::string16 MultiString(const AutofillProfile& p,
127 ServerFieldType type) {
128 std::vector<base::string16> values;
129 p.GetRawMultiInfo(type, &values);
130 base::string16 accumulate;
131 for (size_t i = 0; i < values.size(); ++i) {
133 accumulate += ASCIIToUTF16(" ");
134 accumulate += values[i];
139 base::string16 GetFormGroupInfo(const FormGroup& form_group,
140 const AutofillType& type,
141 const std::string& app_locale) {
142 return app_locale.empty() ?
143 form_group.GetRawInfo(type.GetStorableType()) :
144 form_group.GetInfo(type, app_locale);
148 void CopyRawValuesToItems(ServerFieldType type,
149 const std::vector<base::string16>& values,
151 std::vector<T>* form_group_items) {
152 form_group_items->resize(values.size(), prototype);
153 for (size_t i = 0; i < form_group_items->size(); ++i) {
154 (*form_group_items)[i].SetRawInfo(type, values[i]);
156 // Must have at least one (possibly empty) element.
157 form_group_items->resize(std::max<size_t>(1UL, values.size()), prototype);
161 void CopyValuesToItems(AutofillType type,
162 const std::vector<base::string16>& values,
164 const std::string& app_locale,
165 std::vector<T>* form_group_items) {
166 form_group_items->resize(values.size(), prototype);
167 for (size_t i = 0; i < form_group_items->size(); ++i) {
168 (*form_group_items)[i].SetInfo(type, values[i], app_locale);
170 // Must have at least one (possibly empty) element.
171 form_group_items->resize(std::max<size_t>(1UL, values.size()), prototype);
175 void CopyItemsToValues(const AutofillType& type,
176 const std::vector<T>& form_group_items,
177 const std::string& app_locale,
178 std::vector<base::string16>* values) {
179 values->resize(form_group_items.size());
180 for (size_t i = 0; i < values->size(); ++i) {
181 (*values)[i] = GetFormGroupInfo(form_group_items[i], type, app_locale);
185 // Collapse compound field types to their "full" type. I.e. First name
186 // collapses to full name, area code collapses to full phone, etc.
187 void CollapseCompoundFieldTypes(ServerFieldTypeSet* type_set) {
188 ServerFieldTypeSet collapsed_set;
189 for (ServerFieldTypeSet::iterator it = type_set->begin();
190 it != type_set->end(); ++it) {
195 case NAME_MIDDLE_INITIAL:
198 collapsed_set.insert(NAME_FULL);
201 case PHONE_HOME_NUMBER:
202 case PHONE_HOME_CITY_CODE:
203 case PHONE_HOME_COUNTRY_CODE:
204 case PHONE_HOME_CITY_AND_NUMBER:
205 case PHONE_HOME_WHOLE_NUMBER:
206 collapsed_set.insert(PHONE_HOME_WHOLE_NUMBER);
210 collapsed_set.insert(*it);
213 std::swap(*type_set, collapsed_set);
218 FindByPhone(const base::string16& phone,
219 const std::string& country_code,
220 const std::string& app_locale)
222 country_code_(country_code),
223 app_locale_(app_locale) {}
225 bool operator()(const base::string16& phone) {
226 return i18n::PhoneNumbersMatch(phone, phone_, country_code_, app_locale_);
230 base::string16 phone_;
231 std::string country_code_;
232 std::string app_locale_;
235 // Functor used to check for case-insensitive equality of two strings.
236 struct CaseInsensitiveStringEquals {
238 CaseInsensitiveStringEquals(const base::string16& other)
241 bool operator()(const base::string16& x) const {
242 return x.size() == other_.size() &&
243 base::StringToLowerASCII(x) == base::StringToLowerASCII(other_);
247 const base::string16& other_;
252 AutofillProfile::AutofillProfile(const std::string& guid,
253 const std::string& origin)
254 : AutofillDataModel(guid, origin),
257 phone_number_(1, PhoneNumber(this)) {
260 AutofillProfile::AutofillProfile()
261 : AutofillDataModel(base::GenerateGUID(), std::string()),
264 phone_number_(1, PhoneNumber(this)) {
267 AutofillProfile::AutofillProfile(const AutofillProfile& profile)
268 : AutofillDataModel(std::string(), std::string()) {
272 AutofillProfile::~AutofillProfile() {
275 AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
276 if (this == &profile)
279 set_guid(profile.guid());
280 set_origin(profile.origin());
282 name_ = profile.name_;
283 email_ = profile.email_;
284 company_ = profile.company_;
285 phone_number_ = profile.phone_number_;
287 for (size_t i = 0; i < phone_number_.size(); ++i)
288 phone_number_[i].set_profile(this);
290 address_ = profile.address_;
291 set_language_code(profile.language_code());
296 void AutofillProfile::GetMatchingTypes(
297 const base::string16& text,
298 const std::string& app_locale,
299 ServerFieldTypeSet* matching_types) const {
300 FormGroupList info = FormGroups();
301 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
302 (*it)->GetMatchingTypes(text, app_locale, matching_types);
305 base::string16 AutofillProfile::GetRawInfo(ServerFieldType type) const {
306 const FormGroup* form_group = FormGroupForType(AutofillType(type));
308 return base::string16();
310 return form_group->GetRawInfo(type);
313 void AutofillProfile::SetRawInfo(ServerFieldType type,
314 const base::string16& value) {
315 FormGroup* form_group = MutableFormGroupForType(AutofillType(type));
317 form_group->SetRawInfo(type, value);
320 base::string16 AutofillProfile::GetInfo(const AutofillType& type,
321 const std::string& app_locale) const {
322 if (type.html_type() == HTML_TYPE_FULL_ADDRESS) {
323 scoped_ptr<AddressData> address_data =
324 i18n::CreateAddressDataFromAutofillProfile(*this, app_locale);
325 if (!addressinput::HasAllRequiredFields(*address_data))
326 return base::string16();
328 std::vector<std::string> lines;
329 ::i18n::addressinput::GetFormattedNationalAddress(*address_data, &lines);
330 return base::UTF8ToUTF16(JoinString(lines, '\n'));
333 const FormGroup* form_group = FormGroupForType(type);
335 return base::string16();
337 return form_group->GetInfo(type, app_locale);
340 bool AutofillProfile::SetInfo(const AutofillType& type,
341 const base::string16& value,
342 const std::string& app_locale) {
343 FormGroup* form_group = MutableFormGroupForType(type);
347 base::string16 trimmed_value;
348 base::TrimWhitespace(value, base::TRIM_ALL, &trimmed_value);
349 return form_group->SetInfo(type, trimmed_value, app_locale);
352 base::string16 AutofillProfile::GetInfoForVariant(
353 const AutofillType& type,
355 const std::string& app_locale) const {
356 std::vector<base::string16> values;
357 GetMultiInfo(type, app_locale, &values);
359 if (variant >= values.size()) {
360 // If the variant is unavailable, bail. This case is reachable, for
361 // example if Sync updates a profile during the filling process.
362 return base::string16();
365 return values[variant];
368 void AutofillProfile::SetRawMultiInfo(
369 ServerFieldType type,
370 const std::vector<base::string16>& values) {
371 switch (AutofillType(type).group()) {
374 CopyRawValuesToItems(type, values, NameInfo(), &name_);
378 CopyRawValuesToItems(type, values, EmailInfo(), &email_);
383 CopyRawValuesToItems(type, values, PhoneNumber(this), &phone_number_);
387 if (values.size() == 1U) {
388 SetRawInfo(type, values[0]);
389 } else if (values.empty()) {
390 SetRawInfo(type, base::string16());
392 // Shouldn't attempt to set multiple values on single-valued field.
399 void AutofillProfile::GetRawMultiInfo(
400 ServerFieldType type,
401 std::vector<base::string16>* values) const {
402 GetMultiInfoImpl(AutofillType(type), std::string(), values);
405 void AutofillProfile::SetMultiInfo(const AutofillType& type,
406 const std::vector<base::string16>& values,
407 const std::string& app_locale) {
408 switch (AutofillType(type).group()) {
411 CopyValuesToItems(type, values, NameInfo(), app_locale, &name_);
415 CopyValuesToItems(type, values, EmailInfo(), app_locale, &email_);
421 type, values, PhoneNumber(this), app_locale, &phone_number_);
425 if (values.size() == 1U) {
426 SetInfo(type, values[0], app_locale);
427 } else if (values.empty()) {
428 SetInfo(type, base::string16(), app_locale);
430 // Shouldn't attempt to set multiple values on single-valued field.
437 void AutofillProfile::GetMultiInfo(const AutofillType& type,
438 const std::string& app_locale,
439 std::vector<base::string16>* values) const {
440 GetMultiInfoImpl(type, app_locale, values);
443 bool AutofillProfile::IsEmpty(const std::string& app_locale) const {
444 ServerFieldTypeSet types;
445 GetNonEmptyTypes(app_locale, &types);
446 return types.empty();
449 bool AutofillProfile::IsPresentButInvalid(ServerFieldType type) const {
450 std::string country = UTF16ToUTF8(GetRawInfo(ADDRESS_HOME_COUNTRY));
451 base::string16 data = GetRawInfo(type);
456 case ADDRESS_HOME_STATE:
457 return country == "US" && !autofill::IsValidState(data);
459 case ADDRESS_HOME_ZIP:
460 return country == "US" && !autofill::IsValidZip(data);
462 case PHONE_HOME_WHOLE_NUMBER:
463 return !i18n::PhoneObject(data, country).IsValidNumber();
466 return !autofill::IsValidEmailAddress(data);
474 int AutofillProfile::Compare(const AutofillProfile& profile) const {
475 const ServerFieldType single_value_types[] = {
477 ADDRESS_HOME_STREET_ADDRESS,
478 ADDRESS_HOME_DEPENDENT_LOCALITY,
482 ADDRESS_HOME_SORTING_CODE,
483 ADDRESS_HOME_COUNTRY,
486 for (size_t i = 0; i < arraysize(single_value_types); ++i) {
487 int comparison = GetRawInfo(single_value_types[i]).compare(
488 profile.GetRawInfo(single_value_types[i]));
493 const ServerFieldType multi_value_types[] = { NAME_FULL,
498 PHONE_HOME_WHOLE_NUMBER };
500 for (size_t i = 0; i < arraysize(multi_value_types); ++i) {
501 std::vector<base::string16> values_a;
502 std::vector<base::string16> values_b;
503 GetRawMultiInfo(multi_value_types[i], &values_a);
504 profile.GetRawMultiInfo(multi_value_types[i], &values_b);
505 if (values_a.size() < values_b.size())
507 if (values_a.size() > values_b.size())
509 for (size_t j = 0; j < values_a.size(); ++j) {
510 int comparison = values_a[j].compare(values_b[j]);
519 bool AutofillProfile::EqualsSansOrigin(const AutofillProfile& profile) const {
520 return guid() == profile.guid() &&
521 language_code() == profile.language_code() &&
522 Compare(profile) == 0;
525 bool AutofillProfile::EqualsSansGuid(const AutofillProfile& profile) const {
526 return origin() == profile.origin() &&
527 language_code() == profile.language_code() &&
528 Compare(profile) == 0;
531 bool AutofillProfile::operator==(const AutofillProfile& profile) const {
532 return guid() == profile.guid() && EqualsSansGuid(profile);
535 bool AutofillProfile::operator!=(const AutofillProfile& profile) const {
536 return !operator==(profile);
539 const base::string16 AutofillProfile::PrimaryValue() const {
540 return GetRawInfo(ADDRESS_HOME_LINE1) + GetRawInfo(ADDRESS_HOME_CITY);
543 bool AutofillProfile::IsSubsetOf(const AutofillProfile& profile,
544 const std::string& app_locale) const {
545 ServerFieldTypeSet types;
546 GetNonEmptyTypes(app_locale, &types);
548 for (ServerFieldTypeSet::const_iterator it = types.begin(); it != types.end();
550 if (*it == NAME_FULL || *it == ADDRESS_HOME_STREET_ADDRESS) {
551 // Ignore the compound "full name" field type. We are only interested in
552 // comparing the constituent parts. For example, if |this| has a middle
553 // name saved, but |profile| lacks one, |profile| could still be a subset
554 // of |this|. Likewise, ignore the compound "street address" type, as we
555 // are only interested in matching line-by-line.
557 } else if (AutofillType(*it).group() == PHONE_HOME) {
558 // Phone numbers should be canonicalized prior to being compared.
559 if (*it != PHONE_HOME_WHOLE_NUMBER) {
561 } else if (!i18n::PhoneNumbersMatch(
563 profile.GetRawInfo(*it),
564 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)),
568 } else if (base::StringToLowerASCII(GetRawInfo(*it)) !=
569 base::StringToLowerASCII(profile.GetRawInfo(*it))) {
577 void AutofillProfile::OverwriteOrAppendNames(
578 const std::vector<NameInfo>& names,
579 const std::string& app_locale) {
580 std::vector<NameInfo> results(name_);
581 for (std::vector<NameInfo>::const_iterator it = names.begin();
584 NameInfo imported_name = *it;
585 bool should_append_imported_name = true;
587 for (size_t index = 0; index < name_.size(); ++index) {
588 NameInfo current_name = name_[index];
589 if (current_name.ParsedNamesAreEqual(imported_name)) {
590 if (current_name.GetRawInfo(NAME_FULL).empty()) {
591 current_name.SetRawInfo(NAME_FULL,
592 imported_name.GetRawInfo(NAME_FULL));
595 should_append_imported_name = false;
599 AutofillType type = AutofillType(NAME_FULL);
600 base::string16 full_name = current_name.GetInfo(type, app_locale);
601 if (base::StringToLowerASCII(full_name) ==
602 base::StringToLowerASCII(imported_name.GetInfo(type, app_locale))) {
603 // The imported name has the same full name string as one of the
604 // existing names for this profile. Because full names are
605 // _heuristically_ parsed into {first, middle, last} name components,
606 // it's possible that either the existing name or the imported name
607 // was misparsed. Prefer to keep the name whose {first, middle,
608 // last} components do not match those computed by the heuristic
609 // parse, as this more likely represents the correct, user-input parse
611 NameInfo heuristically_parsed_name;
612 heuristically_parsed_name.SetInfo(type, full_name, app_locale);
613 if (imported_name.ParsedNamesAreEqual(heuristically_parsed_name)) {
614 should_append_imported_name = false;
618 if (current_name.ParsedNamesAreEqual(heuristically_parsed_name)) {
619 results[index] = imported_name;
620 should_append_imported_name = false;
626 // Append unique names to the list.
627 if (should_append_imported_name)
628 results.push_back(imported_name);
634 void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile,
635 const std::string& app_locale) {
636 // Verified profiles should never be overwritten with unverified data.
637 DCHECK(!IsVerified() || profile.IsVerified());
638 set_origin(profile.origin());
639 set_language_code(profile.language_code());
641 ServerFieldTypeSet field_types;
642 profile.GetNonEmptyTypes(app_locale, &field_types);
644 // Only transfer "full" types (e.g. full name) and not fragments (e.g.
645 // first name, last name).
646 CollapseCompoundFieldTypes(&field_types);
648 // TODO(isherman): Revisit this decision in the context of i18n and storing
649 // full addresses rather than storing 1-to-2 lines of an address.
650 // For addresses, do the opposite: transfer individual address lines, rather
651 // than full addresses.
652 field_types.erase(ADDRESS_HOME_STREET_ADDRESS);
654 for (ServerFieldTypeSet::const_iterator iter = field_types.begin();
655 iter != field_types.end(); ++iter) {
656 FieldTypeGroup group = AutofillType(*iter).group();
657 // Special case names.
659 OverwriteOrAppendNames(profile.name_, app_locale);
663 // Single value field --- overwrite.
664 if (!AutofillProfile::SupportsMultiValue(*iter)) {
665 base::string16 new_value = profile.GetRawInfo(*iter);
666 if (base::StringToLowerASCII(GetRawInfo(*iter)) !=
667 base::StringToLowerASCII(new_value)) {
668 SetRawInfo(*iter, new_value);
673 // Multi value field --- overwrite/append.
674 std::vector<base::string16> new_values;
675 profile.GetRawMultiInfo(*iter, &new_values);
676 std::vector<base::string16> existing_values;
677 GetRawMultiInfo(*iter, &existing_values);
679 // GetMultiInfo always returns at least one element, even if the profile
680 // has no data stored for this field type.
681 if (existing_values.size() == 1 && existing_values.front().empty())
682 existing_values.clear();
684 for (std::vector<base::string16>::iterator value_iter =
686 value_iter != new_values.end(); ++value_iter) {
687 // Don't add duplicates. Most types get case insensitive matching.
688 std::vector<base::string16>::const_iterator existing_iter;
690 if (group == PHONE_HOME) {
691 // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377",
692 // "(800)356-9377" and "356-9377" are considered the same.
693 std::string country_code =
694 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY));
696 std::find_if(existing_values.begin(), existing_values.end(),
697 FindByPhone(*value_iter, country_code, app_locale));
700 std::find_if(existing_values.begin(), existing_values.end(),
701 CaseInsensitiveStringEquals(*value_iter));
704 if (existing_iter == existing_values.end())
705 existing_values.insert(existing_values.end(), *value_iter);
708 SetRawMultiInfo(*iter, existing_values);
713 bool AutofillProfile::SupportsMultiValue(ServerFieldType type) {
714 FieldTypeGroup group = AutofillType(type).group();
715 return group == NAME ||
716 group == NAME_BILLING ||
718 group == PHONE_HOME ||
719 group == PHONE_BILLING;
723 void AutofillProfile::CreateDifferentiatingLabels(
724 const std::vector<AutofillProfile*>& profiles,
725 const std::string& app_locale,
726 std::vector<base::string16>* labels) {
727 const size_t kMinimalFieldsShown = 2;
728 CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
730 DCHECK_EQ(profiles.size(), labels->size());
734 void AutofillProfile::CreateInferredLabels(
735 const std::vector<AutofillProfile*>& profiles,
736 const std::vector<ServerFieldType>* suggested_fields,
737 ServerFieldType excluded_field,
738 size_t minimal_fields_shown,
739 const std::string& app_locale,
740 std::vector<base::string16>* labels) {
741 std::vector<ServerFieldType> fields_to_use;
742 GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
745 // Construct the default label for each profile. Also construct a map that
746 // associates each label with the profiles that have this label. This map is
747 // then used to detect which labels need further differentiating fields.
748 std::map<base::string16, std::list<size_t> > labels_to_profiles;
749 for (size_t i = 0; i < profiles.size(); ++i) {
750 base::string16 label =
751 profiles[i]->ConstructInferredLabel(fields_to_use,
752 minimal_fields_shown,
754 labels_to_profiles[label].push_back(i);
757 labels->resize(profiles.size());
758 for (std::map<base::string16, std::list<size_t> >::const_iterator it =
759 labels_to_profiles.begin();
760 it != labels_to_profiles.end(); ++it) {
761 if (it->second.size() == 1) {
762 // This label is unique, so use it without any further ado.
763 base::string16 label = it->first;
764 size_t profile_index = it->second.front();
765 (*labels)[profile_index] = label;
767 // We have more than one profile with the same label, so add
768 // differentiating fields.
769 CreateInferredLabelsHelper(profiles, it->second, fields_to_use,
770 minimal_fields_shown, app_locale, labels);
775 void AutofillProfile::GetSupportedTypes(
776 ServerFieldTypeSet* supported_types) const {
777 FormGroupList info = FormGroups();
778 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
779 (*it)->GetSupportedTypes(supported_types);
782 void AutofillProfile::GetMultiInfoImpl(
783 const AutofillType& type,
784 const std::string& app_locale,
785 std::vector<base::string16>* values) const {
786 switch (type.group()) {
789 CopyItemsToValues(type, name_, app_locale, values);
792 CopyItemsToValues(type, email_, app_locale, values);
796 CopyItemsToValues(type, phone_number_, app_locale, values);
800 (*values)[0] = GetFormGroupInfo(*this, type, app_locale);
804 base::string16 AutofillProfile::ConstructInferredLabel(
805 const std::vector<ServerFieldType>& included_fields,
806 size_t num_fields_to_use,
807 const std::string& app_locale) const {
808 base::string16 separator =
809 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
811 AutofillType region_code_type(HTML_TYPE_COUNTRY_CODE, HTML_MODE_NONE);
812 const base::string16& profile_region_code =
813 GetInfo(region_code_type, app_locale);
814 std::string address_region_code = UTF16ToUTF8(profile_region_code);
816 // A copy of |this| pruned down to contain only data for the address fields in
817 // |included_fields|.
818 AutofillProfile trimmed_profile(guid(), origin());
819 trimmed_profile.SetInfo(region_code_type, profile_region_code, app_locale);
820 trimmed_profile.set_language_code(language_code());
822 std::vector<ServerFieldType> remaining_fields;
823 for (std::vector<ServerFieldType>::const_iterator it =
824 included_fields.begin();
825 it != included_fields.end() && num_fields_to_use > 0;
827 AddressField address_field;
828 if (!i18n::FieldForType(*it, &address_field) ||
829 !::i18n::addressinput::IsFieldUsed(
830 address_field, address_region_code) ||
831 address_field == ::i18n::addressinput::COUNTRY) {
832 remaining_fields.push_back(*it);
836 AutofillType autofill_type(*it);
837 const base::string16& field_value = GetInfo(autofill_type, app_locale);
838 if (field_value.empty())
841 trimmed_profile.SetInfo(autofill_type, field_value, app_locale);
845 scoped_ptr<AddressData> address_data =
846 i18n::CreateAddressDataFromAutofillProfile(trimmed_profile, app_locale);
847 std::string address_line;
848 ::i18n::addressinput::GetFormattedNationalAddressLine(
849 *address_data, &address_line);
850 base::string16 label = base::UTF8ToUTF16(address_line);
852 for (std::vector<ServerFieldType>::const_iterator it =
853 remaining_fields.begin();
854 it != remaining_fields.end() && num_fields_to_use > 0;
856 const base::string16& field_value = GetInfo(AutofillType(*it), app_locale);
857 if (field_value.empty())
861 label.append(separator);
863 label.append(field_value);
867 // If country code is missing, libaddressinput won't be used to format the
868 // address. In this case the suggestion might include a multi-line street
869 // address which needs to be flattened.
870 base::ReplaceChars(label, base::ASCIIToUTF16("\n"), separator, &label);
876 void AutofillProfile::CreateInferredLabelsHelper(
877 const std::vector<AutofillProfile*>& profiles,
878 const std::list<size_t>& indices,
879 const std::vector<ServerFieldType>& fields,
880 size_t num_fields_to_include,
881 const std::string& app_locale,
882 std::vector<base::string16>* labels) {
883 // For efficiency, we first construct a map of fields to their text values and
884 // each value's frequency.
885 std::map<ServerFieldType,
886 std::map<base::string16, size_t> > field_text_frequencies_by_field;
887 for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
888 field != fields.end(); ++field) {
889 std::map<base::string16, size_t>& field_text_frequencies =
890 field_text_frequencies_by_field[*field];
892 for (std::list<size_t>::const_iterator it = indices.begin();
893 it != indices.end(); ++it) {
894 const AutofillProfile* profile = profiles[*it];
895 base::string16 field_text =
896 profile->GetInfo(AutofillType(*field), app_locale);
898 // If this label is not already in the map, add it with frequency 0.
899 if (!field_text_frequencies.count(field_text))
900 field_text_frequencies[field_text] = 0;
902 // Now, increment the frequency for this label.
903 ++field_text_frequencies[field_text];
907 // Now comes the meat of the algorithm. For each profile, we scan the list of
908 // fields to use, looking for two things:
909 // 1. A (non-empty) field that differentiates the profile from all others
910 // 2. At least |num_fields_to_include| non-empty fields
911 // Before we've satisfied condition (2), we include all fields, even ones that
912 // are identical across all the profiles. Once we've satisfied condition (2),
913 // we only include fields that that have at last two distinct values.
914 for (std::list<size_t>::const_iterator it = indices.begin();
915 it != indices.end(); ++it) {
916 const AutofillProfile* profile = profiles[*it];
918 std::vector<ServerFieldType> label_fields;
919 bool found_differentiating_field = false;
920 for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
921 field != fields.end(); ++field) {
922 // Skip over empty fields.
923 base::string16 field_text =
924 profile->GetInfo(AutofillType(*field), app_locale);
925 if (field_text.empty())
928 std::map<base::string16, size_t>& field_text_frequencies =
929 field_text_frequencies_by_field[*field];
930 found_differentiating_field |=
931 !field_text_frequencies.count(base::string16()) &&
932 (field_text_frequencies[field_text] == 1);
934 // Once we've found enough non-empty fields, skip over any remaining
935 // fields that are identical across all the profiles.
936 if (label_fields.size() >= num_fields_to_include &&
937 (field_text_frequencies.size() == 1))
940 label_fields.push_back(*field);
942 // If we've (1) found a differentiating field and (2) found at least
943 // |num_fields_to_include| non-empty fields, we're done!
944 if (found_differentiating_field &&
945 label_fields.size() >= num_fields_to_include)
949 (*labels)[*it] = profile->ConstructInferredLabel(
950 label_fields, label_fields.size(), app_locale);
954 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
959 v[3] = &phone_number_[0];
964 const FormGroup* AutofillProfile::FormGroupForType(
965 const AutofillType& type) const {
966 return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
969 FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) {
970 switch (type.group()) {
983 return &phone_number_[0];
986 case ADDRESS_BILLING:
1000 // So we can compare AutofillProfiles with EXPECT_EQ().
1001 std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
1007 << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
1009 << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
1011 << UTF16ToUTF8(MultiString(profile, NAME_LAST))
1013 << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
1015 << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME))
1017 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1))
1019 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2))
1021 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))
1023 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY))
1025 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE))
1027 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP))
1029 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE))
1031 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))
1033 << profile.language_code()
1035 << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER));
1038 } // namespace autofill