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/autofill_country.h"
20 #include "components/autofill/core/browser/autofill_field.h"
21 #include "components/autofill/core/browser/autofill_type.h"
22 #include "components/autofill/core/browser/contact_info.h"
23 #include "components/autofill/core/browser/phone_number.h"
24 #include "components/autofill/core/browser/phone_number_i18n.h"
25 #include "components/autofill/core/browser/validation.h"
26 #include "components/autofill/core/common/form_field_data.h"
27 #include "grit/component_strings.h"
28 #include "ui/base/l10n/l10n_util.h"
33 // Like |AutofillType::GetStorableType()|, but also returns |NAME_FULL| for
34 // first, middle, and last name field types.
35 ServerFieldType GetStorableTypeCollapsingNames(ServerFieldType type) {
36 ServerFieldType storable_type = AutofillType(type).GetStorableType();
37 if (AutofillType(storable_type).group() == NAME)
43 // Fills |distinguishing_fields| with a list of fields to use when creating
44 // labels that can help to distinguish between two profiles. Draws fields from
45 // |suggested_fields| if it is non-NULL; otherwise returns a default list.
46 // If |suggested_fields| is non-NULL, does not include |excluded_field| in the
47 // list. Otherwise, |excluded_field| is ignored, and should be set to
48 // |UNKNOWN_TYPE| by convention. The resulting list of fields is sorted in
49 // decreasing order of importance.
50 void GetFieldsForDistinguishingProfiles(
51 const std::vector<ServerFieldType>* suggested_fields,
52 ServerFieldType excluded_field,
53 std::vector<ServerFieldType>* distinguishing_fields) {
54 static const ServerFieldType kDefaultDistinguishingFields[] = {
63 PHONE_HOME_WHOLE_NUMBER,
67 if (!suggested_fields) {
68 DCHECK_EQ(excluded_field, UNKNOWN_TYPE);
69 distinguishing_fields->assign(
70 kDefaultDistinguishingFields,
71 kDefaultDistinguishingFields + arraysize(kDefaultDistinguishingFields));
75 // Keep track of which fields we've seen so that we avoid duplicate entries.
76 // Always ignore fields of unknown type and the excluded field.
77 std::set<ServerFieldType> seen_fields;
78 seen_fields.insert(UNKNOWN_TYPE);
79 seen_fields.insert(GetStorableTypeCollapsingNames(excluded_field));
81 distinguishing_fields->clear();
82 for (std::vector<ServerFieldType>::const_iterator it =
83 suggested_fields->begin();
84 it != suggested_fields->end(); ++it) {
85 ServerFieldType suggested_type = GetStorableTypeCollapsingNames(*it);
86 if (seen_fields.insert(suggested_type).second)
87 distinguishing_fields->push_back(suggested_type);
90 // Special case: If the excluded field is a partial name (e.g. first name) and
91 // the suggested fields include other name fields, include |NAME_FULL| in the
92 // list of distinguishing fields as a last-ditch fallback. This allows us to
93 // distinguish between profiles that are identical except for the name.
94 if (excluded_field != NAME_FULL &&
95 GetStorableTypeCollapsingNames(excluded_field) == NAME_FULL) {
96 for (std::vector<ServerFieldType>::const_iterator it =
97 suggested_fields->begin();
98 it != suggested_fields->end(); ++it) {
99 if (*it != excluded_field &&
100 GetStorableTypeCollapsingNames(*it) == NAME_FULL) {
101 distinguishing_fields->push_back(NAME_FULL);
108 // A helper function for string streaming. Concatenates multi-valued entries
109 // stored for a given |type| into a single string. This string is returned.
110 const base::string16 MultiString(const AutofillProfile& p,
111 ServerFieldType type) {
112 std::vector<base::string16> values;
113 p.GetRawMultiInfo(type, &values);
114 base::string16 accumulate;
115 for (size_t i = 0; i < values.size(); ++i) {
117 accumulate += ASCIIToUTF16(" ");
118 accumulate += values[i];
123 base::string16 GetFormGroupInfo(const FormGroup& form_group,
124 const AutofillType& type,
125 const std::string& app_locale) {
126 return app_locale.empty() ?
127 form_group.GetRawInfo(type.GetStorableType()) :
128 form_group.GetInfo(type, app_locale);
132 void CopyValuesToItems(ServerFieldType type,
133 const std::vector<base::string16>& values,
134 std::vector<T>* form_group_items,
135 const T& prototype) {
136 form_group_items->resize(values.size(), prototype);
137 for (size_t i = 0; i < form_group_items->size(); ++i) {
138 (*form_group_items)[i].SetRawInfo(type,
139 CollapseWhitespace(values[i], false));
141 // Must have at least one (possibly empty) element.
142 if (form_group_items->empty())
143 form_group_items->resize(1, prototype);
147 void CopyItemsToValues(const AutofillType& type,
148 const std::vector<T>& form_group_items,
149 const std::string& app_locale,
150 std::vector<base::string16>* values) {
151 values->resize(form_group_items.size());
152 for (size_t i = 0; i < values->size(); ++i) {
153 (*values)[i] = GetFormGroupInfo(form_group_items[i], type, app_locale);
157 // Collapse compound field types to their "full" type. I.e. First name
158 // collapses to full name, area code collapses to full phone, etc.
159 void CollapseCompoundFieldTypes(ServerFieldTypeSet* type_set) {
160 ServerFieldTypeSet collapsed_set;
161 for (ServerFieldTypeSet::iterator it = type_set->begin();
162 it != type_set->end(); ++it) {
167 case NAME_MIDDLE_INITIAL:
170 collapsed_set.insert(NAME_FULL);
173 case PHONE_HOME_NUMBER:
174 case PHONE_HOME_CITY_CODE:
175 case PHONE_HOME_COUNTRY_CODE:
176 case PHONE_HOME_CITY_AND_NUMBER:
177 case PHONE_HOME_WHOLE_NUMBER:
178 collapsed_set.insert(PHONE_HOME_WHOLE_NUMBER);
182 collapsed_set.insert(*it);
185 std::swap(*type_set, collapsed_set);
190 FindByPhone(const base::string16& phone,
191 const std::string& country_code,
192 const std::string& app_locale)
194 country_code_(country_code),
195 app_locale_(app_locale) {
198 bool operator()(const base::string16& phone) {
199 return i18n::PhoneNumbersMatch(phone, phone_, country_code_, app_locale_);
202 bool operator()(const base::string16* phone) {
203 return i18n::PhoneNumbersMatch(*phone, phone_, country_code_, app_locale_);
207 base::string16 phone_;
208 std::string country_code_;
209 std::string app_locale_;
212 // Functor used to check for case-insensitive equality of two strings.
213 struct CaseInsensitiveStringEquals
214 : public std::binary_function<base::string16, base::string16, bool>
216 bool operator()(const base::string16& x, const base::string16& y) const {
218 x.size() == y.size() && StringToLowerASCII(x) == StringToLowerASCII(y);
224 AutofillProfile::AutofillProfile(const std::string& guid,
225 const std::string& origin)
226 : AutofillDataModel(guid, origin),
229 phone_number_(1, PhoneNumber(this)) {
232 AutofillProfile::AutofillProfile()
233 : AutofillDataModel(base::GenerateGUID(), std::string()),
236 phone_number_(1, PhoneNumber(this)) {
239 AutofillProfile::AutofillProfile(const AutofillProfile& profile)
240 : AutofillDataModel(std::string(), std::string()) {
244 AutofillProfile::~AutofillProfile() {
247 AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
248 if (this == &profile)
251 set_guid(profile.guid());
252 set_origin(profile.origin());
254 label_ = profile.label_;
255 name_ = profile.name_;
256 email_ = profile.email_;
257 company_ = profile.company_;
258 phone_number_ = profile.phone_number_;
260 for (size_t i = 0; i < phone_number_.size(); ++i)
261 phone_number_[i].set_profile(this);
263 address_ = profile.address_;
268 void AutofillProfile::GetMatchingTypes(
269 const base::string16& text,
270 const std::string& app_locale,
271 ServerFieldTypeSet* matching_types) const {
272 FormGroupList info = FormGroups();
273 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
274 (*it)->GetMatchingTypes(text, app_locale, matching_types);
277 base::string16 AutofillProfile::GetRawInfo(ServerFieldType type) const {
278 const FormGroup* form_group = FormGroupForType(AutofillType(type));
280 return base::string16();
282 return form_group->GetRawInfo(type);
285 void AutofillProfile::SetRawInfo(ServerFieldType type,
286 const base::string16& value) {
287 FormGroup* form_group = MutableFormGroupForType(AutofillType(type));
289 form_group->SetRawInfo(type, CollapseWhitespace(value, false));
292 base::string16 AutofillProfile::GetInfo(const AutofillType& type,
293 const std::string& app_locale) const {
294 const FormGroup* form_group = FormGroupForType(type);
296 return base::string16();
298 return form_group->GetInfo(type, app_locale);
301 bool AutofillProfile::SetInfo(const AutofillType& type,
302 const base::string16& value,
303 const std::string& app_locale) {
304 FormGroup* form_group = MutableFormGroupForType(type);
309 form_group->SetInfo(type, CollapseWhitespace(value, false), app_locale);
312 base::string16 AutofillProfile::GetInfoForVariant(
313 const AutofillType& type,
315 const std::string& app_locale) const {
316 std::vector<base::string16> values;
317 GetMultiInfo(type, app_locale, &values);
319 if (variant >= values.size()) {
320 // If the variant is unavailable, bail. This case is reachable, for
321 // example if Sync updates a profile during the filling process.
322 return base::string16();
325 return values[variant];
328 void AutofillProfile::SetRawMultiInfo(
329 ServerFieldType type,
330 const std::vector<base::string16>& values) {
331 switch (AutofillType(type).group()) {
334 CopyValuesToItems(type, values, &name_, NameInfo());
337 CopyValuesToItems(type, values, &email_, EmailInfo());
341 CopyValuesToItems(type,
347 if (values.size() == 1) {
348 SetRawInfo(type, values[0]);
349 } else if (values.size() == 0) {
350 SetRawInfo(type, base::string16());
352 // Shouldn't attempt to set multiple values on single-valued field.
359 void AutofillProfile::GetRawMultiInfo(
360 ServerFieldType type,
361 std::vector<base::string16>* values) const {
362 GetMultiInfoImpl(AutofillType(type), std::string(), values);
365 void AutofillProfile::GetMultiInfo(const AutofillType& type,
366 const std::string& app_locale,
367 std::vector<base::string16>* values) const {
368 GetMultiInfoImpl(type, app_locale, values);
371 const base::string16 AutofillProfile::Label() const {
375 bool AutofillProfile::IsEmpty(const std::string& app_locale) const {
376 ServerFieldTypeSet types;
377 GetNonEmptyTypes(app_locale, &types);
378 return types.empty();
381 bool AutofillProfile::IsPresentButInvalid(ServerFieldType type) const {
382 std::string country = UTF16ToUTF8(GetRawInfo(ADDRESS_HOME_COUNTRY));
383 base::string16 data = GetRawInfo(type);
388 case ADDRESS_HOME_STATE:
389 return country == "US" && !autofill::IsValidState(data);
391 case ADDRESS_HOME_ZIP:
392 return country == "US" && !autofill::IsValidZip(data);
394 case PHONE_HOME_WHOLE_NUMBER:
395 return !i18n::PhoneObject(data, country).IsValidNumber();
398 return !autofill::IsValidEmailAddress(data);
407 int AutofillProfile::Compare(const AutofillProfile& profile) const {
408 const ServerFieldType single_value_types[] = { COMPANY_NAME,
414 ADDRESS_HOME_COUNTRY };
416 for (size_t i = 0; i < arraysize(single_value_types); ++i) {
417 int comparison = GetRawInfo(single_value_types[i]).compare(
418 profile.GetRawInfo(single_value_types[i]));
423 const ServerFieldType multi_value_types[] = { NAME_FIRST,
427 PHONE_HOME_WHOLE_NUMBER };
429 for (size_t i = 0; i < arraysize(multi_value_types); ++i) {
430 std::vector<base::string16> values_a;
431 std::vector<base::string16> values_b;
432 GetRawMultiInfo(multi_value_types[i], &values_a);
433 profile.GetRawMultiInfo(multi_value_types[i], &values_b);
434 if (values_a.size() < values_b.size())
436 if (values_a.size() > values_b.size())
438 for (size_t j = 0; j < values_a.size(); ++j) {
439 int comparison = values_a[j].compare(values_b[j]);
448 bool AutofillProfile::operator==(const AutofillProfile& profile) const {
449 return guid() == profile.guid() &&
450 origin() == profile.origin() &&
451 Compare(profile) == 0;
454 bool AutofillProfile::operator!=(const AutofillProfile& profile) const {
455 return !operator==(profile);
458 const base::string16 AutofillProfile::PrimaryValue() const {
459 return GetRawInfo(ADDRESS_HOME_LINE1) + GetRawInfo(ADDRESS_HOME_CITY);
462 bool AutofillProfile::IsSubsetOf(const AutofillProfile& profile,
463 const std::string& app_locale) const {
464 ServerFieldTypeSet types;
465 GetNonEmptyTypes(app_locale, &types);
467 for (ServerFieldTypeSet::const_iterator it = types.begin(); it != types.end();
469 if (*it == NAME_FULL) {
470 // Ignore the compound "full name" field type. We are only interested in
471 // comparing the constituent parts. For example, if |this| has a middle
472 // name saved, but |profile| lacks one, |profile| could still be a subset
475 } else if (AutofillType(*it).group() == PHONE_HOME) {
476 // Phone numbers should be canonicalized prior to being compared.
477 if (*it != PHONE_HOME_WHOLE_NUMBER) {
479 } else if (!i18n::PhoneNumbersMatch(
481 profile.GetRawInfo(*it),
482 UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)),
486 } else if (StringToLowerASCII(GetRawInfo(*it)) !=
487 StringToLowerASCII(profile.GetRawInfo(*it))) {
495 void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile,
496 const std::string& app_locale) {
497 // Verified profiles should never be overwritten with unverified data.
498 DCHECK(!IsVerified() || profile.IsVerified());
499 set_origin(profile.origin());
501 ServerFieldTypeSet field_types;
502 profile.GetNonEmptyTypes(app_locale, &field_types);
504 // Only transfer "full" types (e.g. full name) and not fragments (e.g.
505 // first name, last name).
506 CollapseCompoundFieldTypes(&field_types);
508 for (ServerFieldTypeSet::const_iterator iter = field_types.begin();
509 iter != field_types.end(); ++iter) {
510 if (AutofillProfile::SupportsMultiValue(*iter)) {
511 std::vector<base::string16> new_values;
512 profile.GetRawMultiInfo(*iter, &new_values);
513 std::vector<base::string16> existing_values;
514 GetRawMultiInfo(*iter, &existing_values);
516 // GetMultiInfo always returns at least one element, even if the profile
517 // has no data stored for this field type.
518 if (existing_values.size() == 1 && existing_values.front().empty())
519 existing_values.clear();
521 FieldTypeGroup group = AutofillType(*iter).group();
522 for (std::vector<base::string16>::iterator value_iter =
524 value_iter != new_values.end(); ++value_iter) {
525 // Don't add duplicates.
526 if (group == PHONE_HOME) {
527 AddPhoneIfUnique(*value_iter, app_locale, &existing_values);
529 std::vector<base::string16>::const_iterator existing_iter =
531 existing_values.begin(), existing_values.end(),
532 std::bind1st(CaseInsensitiveStringEquals(), *value_iter));
533 if (existing_iter == existing_values.end())
534 existing_values.insert(existing_values.end(), *value_iter);
537 SetRawMultiInfo(*iter, existing_values);
539 base::string16 new_value = profile.GetRawInfo(*iter);
540 if (StringToLowerASCII(GetRawInfo(*iter)) !=
541 StringToLowerASCII(new_value)) {
542 SetRawInfo(*iter, new_value);
549 bool AutofillProfile::SupportsMultiValue(ServerFieldType type) {
550 FieldTypeGroup group = AutofillType(type).group();
551 return group == NAME ||
552 group == NAME_BILLING ||
554 group == PHONE_HOME ||
555 group == PHONE_BILLING;
559 bool AutofillProfile::AdjustInferredLabels(
560 std::vector<AutofillProfile*>* profiles) {
561 const size_t kMinimalFieldsShown = 2;
563 std::vector<base::string16> created_labels;
564 CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
566 DCHECK_EQ(profiles->size(), created_labels.size());
568 bool updated_labels = false;
569 for (size_t i = 0; i < profiles->size(); ++i) {
570 if ((*profiles)[i]->Label() != created_labels[i]) {
571 updated_labels = true;
572 (*profiles)[i]->label_ = created_labels[i];
575 return updated_labels;
579 void AutofillProfile::CreateInferredLabels(
580 const std::vector<AutofillProfile*>* profiles,
581 const std::vector<ServerFieldType>* suggested_fields,
582 ServerFieldType excluded_field,
583 size_t minimal_fields_shown,
584 std::vector<base::string16>* created_labels) {
586 DCHECK(created_labels);
588 std::vector<ServerFieldType> fields_to_use;
589 GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
592 // Construct the default label for each profile. Also construct a map that
593 // associates each label with the profiles that have this label. This map is
594 // then used to detect which labels need further differentiating fields.
595 std::map<base::string16, std::list<size_t> > labels;
596 for (size_t i = 0; i < profiles->size(); ++i) {
597 base::string16 label =
598 (*profiles)[i]->ConstructInferredLabel(fields_to_use,
599 minimal_fields_shown);
600 labels[label].push_back(i);
603 created_labels->resize(profiles->size());
604 for (std::map<base::string16, std::list<size_t> >::const_iterator it =
606 it != labels.end(); ++it) {
607 if (it->second.size() == 1) {
608 // This label is unique, so use it without any further ado.
609 base::string16 label = it->first;
610 size_t profile_index = it->second.front();
611 (*created_labels)[profile_index] = label;
613 // We have more than one profile with the same label, so add
614 // differentiating fields.
615 CreateDifferentiatingLabels(*profiles, it->second, fields_to_use,
616 minimal_fields_shown, created_labels);
621 void AutofillProfile::GetSupportedTypes(
622 ServerFieldTypeSet* supported_types) const {
623 FormGroupList info = FormGroups();
624 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
625 (*it)->GetSupportedTypes(supported_types);
628 void AutofillProfile::GetMultiInfoImpl(
629 const AutofillType& type,
630 const std::string& app_locale,
631 std::vector<base::string16>* values) const {
632 switch (type.group()) {
635 CopyItemsToValues(type, name_, app_locale, values);
638 CopyItemsToValues(type, email_, app_locale, values);
642 CopyItemsToValues(type, phone_number_, app_locale, values);
646 (*values)[0] = GetFormGroupInfo(*this, type, app_locale);
650 void AutofillProfile::AddPhoneIfUnique(
651 const base::string16& phone,
652 const std::string& app_locale,
653 std::vector<base::string16>* existing_phones) {
654 DCHECK(existing_phones);
655 // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377",
656 // "(800)356-9377" and "356-9377" are considered the same.
657 std::string country_code = UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY));
658 if (std::find_if(existing_phones->begin(), existing_phones->end(),
659 FindByPhone(phone, country_code, app_locale)) ==
660 existing_phones->end()) {
661 existing_phones->push_back(phone);
665 base::string16 AutofillProfile::ConstructInferredLabel(
666 const std::vector<ServerFieldType>& included_fields,
667 size_t num_fields_to_use) const {
668 const base::string16 separator =
669 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
671 base::string16 label;
672 size_t num_fields_used = 0;
673 for (std::vector<ServerFieldType>::const_iterator it =
674 included_fields.begin();
675 it != included_fields.end() && num_fields_used < num_fields_to_use;
677 base::string16 field = GetRawInfo(*it);
682 label.append(separator);
691 void AutofillProfile::CreateDifferentiatingLabels(
692 const std::vector<AutofillProfile*>& profiles,
693 const std::list<size_t>& indices,
694 const std::vector<ServerFieldType>& fields,
695 size_t num_fields_to_include,
696 std::vector<base::string16>* created_labels) {
697 // For efficiency, we first construct a map of fields to their text values and
698 // each value's frequency.
699 std::map<ServerFieldType,
700 std::map<base::string16, size_t> > field_text_frequencies_by_field;
701 for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
702 field != fields.end(); ++field) {
703 std::map<base::string16, size_t>& field_text_frequencies =
704 field_text_frequencies_by_field[*field];
706 for (std::list<size_t>::const_iterator it = indices.begin();
707 it != indices.end(); ++it) {
708 const AutofillProfile* profile = profiles[*it];
709 base::string16 field_text = profile->GetRawInfo(*field);
711 // If this label is not already in the map, add it with frequency 0.
712 if (!field_text_frequencies.count(field_text))
713 field_text_frequencies[field_text] = 0;
715 // Now, increment the frequency for this label.
716 ++field_text_frequencies[field_text];
720 // Now comes the meat of the algorithm. For each profile, we scan the list of
721 // fields to use, looking for two things:
722 // 1. A (non-empty) field that differentiates the profile from all others
723 // 2. At least |num_fields_to_include| non-empty fields
724 // Before we've satisfied condition (2), we include all fields, even ones that
725 // are identical across all the profiles. Once we've satisfied condition (2),
726 // we only include fields that that have at last two distinct values.
727 for (std::list<size_t>::const_iterator it = indices.begin();
728 it != indices.end(); ++it) {
729 const AutofillProfile* profile = profiles[*it];
731 std::vector<ServerFieldType> label_fields;
732 bool found_differentiating_field = false;
733 for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
734 field != fields.end(); ++field) {
735 // Skip over empty fields.
736 base::string16 field_text = profile->GetRawInfo(*field);
737 if (field_text.empty())
740 std::map<base::string16, size_t>& field_text_frequencies =
741 field_text_frequencies_by_field[*field];
742 found_differentiating_field |=
743 !field_text_frequencies.count(base::string16()) &&
744 (field_text_frequencies[field_text] == 1);
746 // Once we've found enough non-empty fields, skip over any remaining
747 // fields that are identical across all the profiles.
748 if (label_fields.size() >= num_fields_to_include &&
749 (field_text_frequencies.size() == 1))
752 label_fields.push_back(*field);
754 // If we've (1) found a differentiating field and (2) found at least
755 // |num_fields_to_include| non-empty fields, we're done!
756 if (found_differentiating_field &&
757 label_fields.size() >= num_fields_to_include)
761 (*created_labels)[*it] =
762 profile->ConstructInferredLabel(label_fields,
763 label_fields.size());
767 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
772 v[3] = &phone_number_[0];
777 const FormGroup* AutofillProfile::FormGroupForType(
778 const AutofillType& type) const {
779 return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
782 FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) {
783 switch (type.group()) {
796 return &phone_number_[0];
799 case ADDRESS_BILLING:
812 // So we can compare AutofillProfiles with EXPECT_EQ().
813 std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
815 << UTF16ToUTF8(profile.Label())
821 << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
823 << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
825 << UTF16ToUTF8(MultiString(profile, NAME_LAST))
827 << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
829 << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME))
831 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1))
833 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2))
835 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY))
837 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE))
839 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP))
841 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))
843 << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER));
846 } // namespace autofill