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/i18n/case_conversion.h"
16 #include "base/i18n/char_iterator.h"
17 #include "base/logging.h"
18 #include "base/sha1.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/utf_string_conversion_utils.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "components/autofill/core/browser/address.h"
23 #include "components/autofill/core/browser/address_i18n.h"
24 #include "components/autofill/core/browser/autofill_country.h"
25 #include "components/autofill/core/browser/autofill_field.h"
26 #include "components/autofill/core/browser/autofill_type.h"
27 #include "components/autofill/core/browser/contact_info.h"
28 #include "components/autofill/core/browser/phone_number.h"
29 #include "components/autofill/core/browser/phone_number_i18n.h"
30 #include "components/autofill/core/browser/validation.h"
31 #include "components/autofill/core/common/autofill_l10n_util.h"
32 #include "components/autofill/core/common/form_field_data.h"
33 #include "grit/components_strings.h"
34 #include "third_party/icu/source/common/unicode/uchar.h"
35 #include "third_party/libaddressinput/chromium/addressinput_util.h"
36 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
37 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_formatter.h"
38 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_metadata.h"
39 #include "ui/base/l10n/l10n_util.h"
41 using base::ASCIIToUTF16
;
42 using base::UTF16ToUTF8
;
43 using i18n::addressinput::AddressData
;
44 using i18n::addressinput::AddressField
;
49 // Like |AutofillType::GetStorableType()|, but also returns |NAME_FULL| for
50 // first, middle, and last name field types, and groups phone number types
52 ServerFieldType
GetStorableTypeCollapsingGroups(ServerFieldType type
) {
53 ServerFieldType storable_type
= AutofillType(type
).GetStorableType();
54 if (AutofillType(storable_type
).group() == NAME
)
57 if (AutofillType(storable_type
).group() == PHONE_HOME
)
58 return PHONE_HOME_WHOLE_NUMBER
;
63 // Returns a value that represents specificity/privacy of the given type. This
64 // is used for prioritizing which data types are shown in inferred labels. For
65 // example, if the profile is going to fill ADDRESS_HOME_ZIP, it should
66 // prioritize showing that over ADDRESS_HOME_STATE in the suggestion sublabel.
67 int SpecificityForType(ServerFieldType type
) {
69 case ADDRESS_HOME_LINE1
:
72 case ADDRESS_HOME_LINE2
:
78 case PHONE_HOME_WHOLE_NUMBER
:
84 case ADDRESS_HOME_ZIP
:
87 case ADDRESS_HOME_SORTING_CODE
:
93 case ADDRESS_HOME_CITY
:
96 case ADDRESS_HOME_STATE
:
99 case ADDRESS_HOME_COUNTRY
:
106 // The priority of other types is arbitrary, but deterministic.
110 bool CompareSpecificity(ServerFieldType type1
, ServerFieldType type2
) {
111 return SpecificityForType(type1
) < SpecificityForType(type2
);
114 // Fills |distinguishing_fields| with a list of fields to use when creating
115 // labels that can help to distinguish between two profiles. Draws fields from
116 // |suggested_fields| if it is non-NULL; otherwise returns a default list.
117 // If |suggested_fields| is non-NULL, does not include |excluded_field| in the
118 // list. Otherwise, |excluded_field| is ignored, and should be set to
119 // |UNKNOWN_TYPE| by convention. The resulting list of fields is sorted in
120 // decreasing order of importance.
121 void GetFieldsForDistinguishingProfiles(
122 const std::vector
<ServerFieldType
>* suggested_fields
,
123 ServerFieldType excluded_field
,
124 std::vector
<ServerFieldType
>* distinguishing_fields
) {
125 static const ServerFieldType kDefaultDistinguishingFields
[] = {
129 ADDRESS_HOME_DEPENDENT_LOCALITY
,
133 ADDRESS_HOME_SORTING_CODE
,
134 ADDRESS_HOME_COUNTRY
,
136 PHONE_HOME_WHOLE_NUMBER
,
140 std::vector
<ServerFieldType
> default_fields
;
141 if (!suggested_fields
) {
142 default_fields
.assign(
143 kDefaultDistinguishingFields
,
144 kDefaultDistinguishingFields
+ arraysize(kDefaultDistinguishingFields
));
145 if (excluded_field
== UNKNOWN_TYPE
) {
146 distinguishing_fields
->swap(default_fields
);
149 suggested_fields
= &default_fields
;
152 // Keep track of which fields we've seen so that we avoid duplicate entries.
153 // Always ignore fields of unknown type and the excluded field.
154 std::set
<ServerFieldType
> seen_fields
;
155 seen_fields
.insert(UNKNOWN_TYPE
);
156 seen_fields
.insert(GetStorableTypeCollapsingGroups(excluded_field
));
158 distinguishing_fields
->clear();
159 for (std::vector
<ServerFieldType
>::const_iterator it
=
160 suggested_fields
->begin();
161 it
!= suggested_fields
->end(); ++it
) {
162 ServerFieldType suggested_type
= GetStorableTypeCollapsingGroups(*it
);
163 if (seen_fields
.insert(suggested_type
).second
)
164 distinguishing_fields
->push_back(suggested_type
);
167 std::sort(distinguishing_fields
->begin(), distinguishing_fields
->end(),
170 // Special case: If the excluded field is a partial name (e.g. first name) and
171 // the suggested fields include other name fields, include |NAME_FULL| in the
172 // list of distinguishing fields as a last-ditch fallback. This allows us to
173 // distinguish between profiles that are identical except for the name.
174 ServerFieldType effective_excluded_type
=
175 GetStorableTypeCollapsingGroups(excluded_field
);
176 if (excluded_field
!= effective_excluded_type
) {
177 for (std::vector
<ServerFieldType
>::const_iterator it
=
178 suggested_fields
->begin();
179 it
!= suggested_fields
->end(); ++it
) {
180 if (*it
!= excluded_field
&&
181 GetStorableTypeCollapsingGroups(*it
) == effective_excluded_type
) {
182 distinguishing_fields
->push_back(effective_excluded_type
);
189 // Collapse compound field types to their "full" type. I.e. First name
190 // collapses to full name, area code collapses to full phone, etc.
191 void CollapseCompoundFieldTypes(ServerFieldTypeSet
* type_set
) {
192 ServerFieldTypeSet collapsed_set
;
193 for (ServerFieldTypeSet::iterator it
= type_set
->begin();
194 it
!= type_set
->end(); ++it
) {
199 case NAME_MIDDLE_INITIAL
:
202 collapsed_set
.insert(NAME_FULL
);
205 case PHONE_HOME_NUMBER
:
206 case PHONE_HOME_CITY_CODE
:
207 case PHONE_HOME_COUNTRY_CODE
:
208 case PHONE_HOME_CITY_AND_NUMBER
:
209 case PHONE_HOME_WHOLE_NUMBER
:
210 collapsed_set
.insert(PHONE_HOME_WHOLE_NUMBER
);
214 collapsed_set
.insert(*it
);
217 std::swap(*type_set
, collapsed_set
);
222 FindByPhone(const base::string16
& phone
,
223 const std::string
& country_code
,
224 const std::string
& app_locale
)
226 country_code_(country_code
),
227 app_locale_(app_locale
) {}
229 bool operator()(const base::string16
& phone
) {
230 return i18n::PhoneNumbersMatch(phone
, phone_
, country_code_
, app_locale_
);
234 base::string16 phone_
;
235 std::string country_code_
;
236 std::string app_locale_
;
241 AutofillProfile::AutofillProfile(const std::string
& guid
,
242 const std::string
& origin
)
243 : AutofillDataModel(guid
, origin
),
244 record_type_(LOCAL_PROFILE
),
245 phone_number_(this) {
248 AutofillProfile::AutofillProfile(RecordType type
, const std::string
& server_id
)
249 : AutofillDataModel(base::GenerateGUID(), std::string()),
252 server_id_(server_id
) {
253 DCHECK(type
== SERVER_PROFILE
);
256 AutofillProfile::AutofillProfile()
257 : AutofillDataModel(base::GenerateGUID(), std::string()),
258 record_type_(LOCAL_PROFILE
),
259 phone_number_(this) {
262 AutofillProfile::AutofillProfile(const AutofillProfile
& profile
)
263 : AutofillDataModel(std::string(), std::string()), phone_number_(this) {
267 AutofillProfile::~AutofillProfile() {
270 AutofillProfile
& AutofillProfile::operator=(const AutofillProfile
& profile
) {
271 set_use_count(profile
.use_count());
272 set_use_date(profile
.use_date());
273 set_modification_date(profile
.modification_date());
275 if (this == &profile
)
278 set_guid(profile
.guid());
279 set_origin(profile
.origin());
281 record_type_
= profile
.record_type_
;
283 name_
= profile
.name_
;
284 email_
= profile
.email_
;
285 company_
= profile
.company_
;
286 phone_number_
= profile
.phone_number_
;
287 phone_number_
.set_profile(this);
289 address_
= profile
.address_
;
290 set_language_code(profile
.language_code());
292 server_id_
= profile
.server_id();
297 void AutofillProfile::GetMatchingTypes(
298 const base::string16
& text
,
299 const std::string
& app_locale
,
300 ServerFieldTypeSet
* matching_types
) const {
301 FormGroupList info
= FormGroups();
302 for (FormGroupList::const_iterator it
= info
.begin(); it
!= info
.end(); ++it
)
303 (*it
)->GetMatchingTypes(text
, app_locale
, matching_types
);
306 base::string16
AutofillProfile::GetRawInfo(ServerFieldType type
) const {
307 const FormGroup
* form_group
= FormGroupForType(AutofillType(type
));
309 return base::string16();
311 return form_group
->GetRawInfo(type
);
314 void AutofillProfile::SetRawInfo(ServerFieldType type
,
315 const base::string16
& value
) {
316 FormGroup
* form_group
= MutableFormGroupForType(AutofillType(type
));
318 form_group
->SetRawInfo(type
, value
);
321 base::string16
AutofillProfile::GetInfo(const AutofillType
& type
,
322 const std::string
& app_locale
) const {
323 if (type
.html_type() == HTML_TYPE_FULL_ADDRESS
) {
324 scoped_ptr
<AddressData
> address_data
=
325 i18n::CreateAddressDataFromAutofillProfile(*this, app_locale
);
326 if (!addressinput::HasAllRequiredFields(*address_data
))
327 return base::string16();
329 std::vector
<std::string
> lines
;
330 ::i18n::addressinput::GetFormattedNationalAddress(*address_data
, &lines
);
331 return base::UTF8ToUTF16(base::JoinString(lines
, "\n"));
334 const FormGroup
* form_group
= FormGroupForType(type
);
336 return base::string16();
338 return form_group
->GetInfo(type
, app_locale
);
341 bool AutofillProfile::SetInfo(const AutofillType
& type
,
342 const base::string16
& value
,
343 const std::string
& app_locale
) {
344 FormGroup
* form_group
= MutableFormGroupForType(type
);
348 base::string16 trimmed_value
;
349 base::TrimWhitespace(value
, base::TRIM_ALL
, &trimmed_value
);
350 return form_group
->SetInfo(type
, trimmed_value
, app_locale
);
353 bool AutofillProfile::IsEmpty(const std::string
& app_locale
) const {
354 ServerFieldTypeSet types
;
355 GetNonEmptyTypes(app_locale
, &types
);
356 return types
.empty();
359 bool AutofillProfile::IsPresentButInvalid(ServerFieldType type
) const {
360 std::string country
= UTF16ToUTF8(GetRawInfo(ADDRESS_HOME_COUNTRY
));
361 base::string16 data
= GetRawInfo(type
);
366 case ADDRESS_HOME_STATE
:
367 return country
== "US" && !IsValidState(data
);
369 case ADDRESS_HOME_ZIP
:
370 return country
== "US" && !IsValidZip(data
);
372 case PHONE_HOME_WHOLE_NUMBER
:
373 return !i18n::PhoneObject(data
, country
).IsValidNumber();
376 return !IsValidEmailAddress(data
);
384 int AutofillProfile::Compare(const AutofillProfile
& profile
) const {
385 const ServerFieldType types
[] = {
391 ADDRESS_HOME_STREET_ADDRESS
,
392 ADDRESS_HOME_DEPENDENT_LOCALITY
,
396 ADDRESS_HOME_SORTING_CODE
,
397 ADDRESS_HOME_COUNTRY
,
399 PHONE_HOME_WHOLE_NUMBER
,
402 for (size_t i
= 0; i
< arraysize(types
); ++i
) {
403 int comparison
= GetRawInfo(types
[i
]).compare(profile
.GetRawInfo(types
[i
]));
404 if (comparison
!= 0) {
412 bool AutofillProfile::EqualsSansOrigin(const AutofillProfile
& profile
) const {
413 return guid() == profile
.guid() &&
414 language_code() == profile
.language_code() &&
415 Compare(profile
) == 0;
418 bool AutofillProfile::EqualsForSyncPurposes(const AutofillProfile
& profile
)
420 return use_count() == profile
.use_count() &&
421 use_date() == profile
.use_date() &&
422 EqualsSansGuid(profile
);
425 bool AutofillProfile::operator==(const AutofillProfile
& profile
) const {
426 return guid() == profile
.guid() && EqualsSansGuid(profile
);
429 bool AutofillProfile::operator!=(const AutofillProfile
& profile
) const {
430 return !operator==(profile
);
433 const base::string16
AutofillProfile::PrimaryValue() const {
434 return GetRawInfo(ADDRESS_HOME_LINE1
) + GetRawInfo(ADDRESS_HOME_CITY
);
437 bool AutofillProfile::IsSubsetOf(const AutofillProfile
& profile
,
438 const std::string
& app_locale
) const {
439 ServerFieldTypeSet types
;
440 GetSupportedTypes(&types
);
441 return IsSubsetOfForFieldSet(profile
, app_locale
, types
);
444 bool AutofillProfile::IsSubsetOfForFieldSet(
445 const AutofillProfile
& profile
,
446 const std::string
& app_locale
,
447 const ServerFieldTypeSet
& types
) const {
448 scoped_ptr
<l10n::CaseInsensitiveCompare
> compare
;
450 for (ServerFieldType type
: types
) {
451 base::string16 value
= GetRawInfo(type
);
455 if (type
== NAME_FULL
|| type
== ADDRESS_HOME_STREET_ADDRESS
) {
456 // Ignore the compound "full name" field type. We are only interested in
457 // comparing the constituent parts. For example, if |this| has a middle
458 // name saved, but |profile| lacks one, |profile| could still be a subset
459 // of |this|. Likewise, ignore the compound "street address" type, as we
460 // are only interested in matching line-by-line.
462 } else if (AutofillType(type
).group() == PHONE_HOME
) {
463 // Phone numbers should be canonicalized prior to being compared.
464 if (type
!= PHONE_HOME_WHOLE_NUMBER
) {
466 } else if (!i18n::PhoneNumbersMatch(
467 value
, profile
.GetRawInfo(type
),
468 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY
)),
474 compare
.reset(new l10n::CaseInsensitiveCompare());
475 if (!compare
->StringsEqual(value
, profile
.GetRawInfo(type
)))
483 void AutofillProfile::OverwriteName(const NameInfo
& imported_name
,
484 const std::string
& app_locale
) {
485 if (name_
.ParsedNamesAreEqual(imported_name
)) {
486 if (name_
.GetRawInfo(NAME_FULL
).empty())
487 name_
.SetRawInfo(NAME_FULL
, imported_name
.GetRawInfo(NAME_FULL
));
491 l10n::CaseInsensitiveCompare compare
;
492 AutofillType type
= AutofillType(NAME_FULL
);
493 base::string16 full_name
= name_
.GetInfo(type
, app_locale
);
494 if (compare
.StringsEqual(full_name
,
495 imported_name
.GetInfo(type
, app_locale
))) {
496 // The imported name has the same full name string as the name for this
497 // profile. Because full names are _heuristically_ parsed into
498 // {first, middle, last} name components, it's possible that either the
499 // existing name or the imported name was misparsed. Prefer to keep the
500 // name whose {first, middle, last} components do not match those computed
501 // by the heuristic parse, as this more likely represents the correct,
502 // user-input parse of the name.
503 NameInfo heuristically_parsed_name
;
504 heuristically_parsed_name
.SetInfo(type
, full_name
, app_locale
);
505 if (imported_name
.ParsedNamesAreEqual(heuristically_parsed_name
))
509 name_
= imported_name
;
512 void AutofillProfile::OverwriteWith(const AutofillProfile
& profile
,
513 const std::string
& app_locale
) {
514 // Verified profiles should never be overwritten with unverified data.
515 DCHECK(!IsVerified() || profile
.IsVerified());
516 set_origin(profile
.origin());
517 set_language_code(profile
.language_code());
518 set_use_count(profile
.use_count() + use_count());
519 if (profile
.use_date() > use_date())
520 set_use_date(profile
.use_date());
522 ServerFieldTypeSet field_types
;
523 profile
.GetNonEmptyTypes(app_locale
, &field_types
);
525 // Only transfer "full" types (e.g. full name) and not fragments (e.g.
526 // first name, last name).
527 CollapseCompoundFieldTypes(&field_types
);
529 // Remove ADDRESS_HOME_STREET_ADDRESS to ensure a merge of the address line by
530 // line. See comment below.
531 field_types
.erase(ADDRESS_HOME_STREET_ADDRESS
);
533 l10n::CaseInsensitiveCompare compare
;
535 // Special case for addresses. With the whole address comparison, it is now
536 // necessary to make sure to keep the best address format: both lines used.
537 // This is because some sites might not have an address line 2 and the
538 // previous value should not be replaced with an empty string in that case.
539 if (compare
.StringsEqual(
540 CanonicalizeProfileString(
541 profile
.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS
)),
542 CanonicalizeProfileString(GetRawInfo(ADDRESS_HOME_STREET_ADDRESS
))) &&
543 profile
.GetRawInfo(ADDRESS_HOME_LINE2
) == base::UTF8ToUTF16("")) {
544 field_types
.erase(ADDRESS_HOME_LINE1
);
545 field_types
.erase(ADDRESS_HOME_LINE2
);
548 for (ServerFieldTypeSet::const_iterator iter
= field_types
.begin();
549 iter
!= field_types
.end(); ++iter
) {
550 FieldTypeGroup group
= AutofillType(*iter
).group();
551 // Special case names.
553 OverwriteName(profile
.name_
, app_locale
);
557 base::string16 new_value
= profile
.GetRawInfo(*iter
);
558 if (!compare
.StringsEqual(GetRawInfo(*iter
), new_value
))
559 SetRawInfo(*iter
, new_value
);
563 bool AutofillProfile::SaveAdditionalInfo(const AutofillProfile
& profile
,
564 const std::string
& app_locale
) {
565 ServerFieldTypeSet field_types
, other_field_types
;
566 GetNonEmptyTypes(app_locale
, &field_types
);
567 profile
.GetNonEmptyTypes(app_locale
, &other_field_types
);
568 // The address needs to be compared line by line to take into account the
569 // logic for empty fields implemented in the loop.
570 field_types
.erase(ADDRESS_HOME_STREET_ADDRESS
);
571 l10n::CaseInsensitiveCompare compare
;
572 for (ServerFieldType field_type
: field_types
) {
573 if (other_field_types
.count(field_type
)) {
574 AutofillType type
= AutofillType(field_type
);
575 // Special cases for name and phone. If the whole/full value matches, skip
576 // the individual fields comparison.
577 if (type
.group() == NAME
&&
578 compare
.StringsEqual(
579 profile
.GetInfo(AutofillType(NAME_FULL
), app_locale
),
580 GetInfo(AutofillType(NAME_FULL
), app_locale
))) {
583 if (type
.group() == PHONE_HOME
&&
584 i18n::PhoneNumbersMatch(
585 GetRawInfo(PHONE_HOME_WHOLE_NUMBER
),
586 profile
.GetRawInfo(PHONE_HOME_WHOLE_NUMBER
),
587 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY
)),
591 // Special case for the address because the comparison uses canonicalized
592 // values. Start by comparing the address line by line. If it fails, make
593 // sure that the address as a whole is different before returning false.
594 // It is possible that the user put the info from line 2 on line 1 because
595 // of a certain form for example.
596 if (field_type
== ADDRESS_HOME_LINE1
||
597 field_type
== ADDRESS_HOME_LINE2
) {
598 if (!compare
.StringsEqual(
599 CanonicalizeProfileString(profile
.GetRawInfo(field_type
)),
600 CanonicalizeProfileString(GetRawInfo(field_type
))) &&
601 !compare
.StringsEqual(CanonicalizeProfileString(profile
.GetRawInfo(
602 ADDRESS_HOME_STREET_ADDRESS
)),
603 CanonicalizeProfileString(GetRawInfo(
604 ADDRESS_HOME_STREET_ADDRESS
)))) {
609 if (!compare
.StringsEqual(profile
.GetRawInfo(field_type
),
610 GetRawInfo(field_type
))) {
616 if (!IsVerified() || profile
.IsVerified())
617 OverwriteWith(profile
, app_locale
);
622 bool AutofillProfile::SupportsMultiValue(ServerFieldType type
) {
623 FieldTypeGroup group
= AutofillType(type
).group();
624 return group
== NAME
||
625 group
== NAME_BILLING
||
627 group
== PHONE_HOME
||
628 group
== PHONE_BILLING
;
632 void AutofillProfile::CreateDifferentiatingLabels(
633 const std::vector
<AutofillProfile
*>& profiles
,
634 const std::string
& app_locale
,
635 std::vector
<base::string16
>* labels
) {
636 const size_t kMinimalFieldsShown
= 2;
637 CreateInferredLabels(profiles
, NULL
, UNKNOWN_TYPE
, kMinimalFieldsShown
,
639 DCHECK_EQ(profiles
.size(), labels
->size());
643 void AutofillProfile::CreateInferredLabels(
644 const std::vector
<AutofillProfile
*>& profiles
,
645 const std::vector
<ServerFieldType
>* suggested_fields
,
646 ServerFieldType excluded_field
,
647 size_t minimal_fields_shown
,
648 const std::string
& app_locale
,
649 std::vector
<base::string16
>* labels
) {
650 std::vector
<ServerFieldType
> fields_to_use
;
651 GetFieldsForDistinguishingProfiles(suggested_fields
, excluded_field
,
654 // Construct the default label for each profile. Also construct a map that
655 // associates each label with the profiles that have this label. This map is
656 // then used to detect which labels need further differentiating fields.
657 std::map
<base::string16
, std::list
<size_t> > labels_to_profiles
;
658 for (size_t i
= 0; i
< profiles
.size(); ++i
) {
659 base::string16 label
=
660 profiles
[i
]->ConstructInferredLabel(fields_to_use
,
661 minimal_fields_shown
,
663 labels_to_profiles
[label
].push_back(i
);
666 labels
->resize(profiles
.size());
667 for (std::map
<base::string16
, std::list
<size_t> >::const_iterator it
=
668 labels_to_profiles
.begin();
669 it
!= labels_to_profiles
.end(); ++it
) {
670 if (it
->second
.size() == 1) {
671 // This label is unique, so use it without any further ado.
672 base::string16 label
= it
->first
;
673 size_t profile_index
= it
->second
.front();
674 (*labels
)[profile_index
] = label
;
676 // We have more than one profile with the same label, so add
677 // differentiating fields.
678 CreateInferredLabelsHelper(profiles
, it
->second
, fields_to_use
,
679 minimal_fields_shown
, app_locale
, labels
);
684 void AutofillProfile::GenerateServerProfileIdentifier() {
685 DCHECK_EQ(SERVER_PROFILE
, record_type());
686 base::string16 contents
= GetRawInfo(NAME_FIRST
);
687 contents
.append(GetRawInfo(NAME_MIDDLE
));
688 contents
.append(GetRawInfo(NAME_LAST
));
689 contents
.append(GetRawInfo(EMAIL_ADDRESS
));
690 contents
.append(GetRawInfo(COMPANY_NAME
));
691 contents
.append(GetRawInfo(ADDRESS_HOME_STREET_ADDRESS
));
692 contents
.append(GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY
));
693 contents
.append(GetRawInfo(ADDRESS_HOME_CITY
));
694 contents
.append(GetRawInfo(ADDRESS_HOME_STATE
));
695 contents
.append(GetRawInfo(ADDRESS_HOME_ZIP
));
696 contents
.append(GetRawInfo(ADDRESS_HOME_SORTING_CODE
));
697 contents
.append(GetRawInfo(ADDRESS_HOME_COUNTRY
));
698 contents
.append(GetRawInfo(PHONE_HOME_WHOLE_NUMBER
));
699 std::string contents_utf8
= UTF16ToUTF8(contents
);
700 contents_utf8
.append(language_code());
701 server_id_
= base::SHA1HashString(contents_utf8
);
705 base::string16
AutofillProfile::CanonicalizeProfileString(
706 const base::string16
& str
) {
708 ret
.reserve(str
.size());
710 bool previous_was_whitespace
= false;
712 // This algorithm isn't designed to be perfect, we could get arbitrarily
713 // fancy here trying to canonicalize address lines. Instead, this is designed
714 // to handle common cases for all types of data (addresses and names)
715 // without the need of domain-specific logic.
716 base::i18n::UTF16CharIterator
iter(&str
);
717 while (!iter
.end()) {
718 switch (u_charType(iter
.get())) {
719 case U_DASH_PUNCTUATION
:
720 case U_START_PUNCTUATION
:
721 case U_END_PUNCTUATION
:
722 case U_CONNECTOR_PUNCTUATION
:
723 case U_OTHER_PUNCTUATION
:
724 // Convert punctuation to spaces. This will convert "Mid-Island Plz."
725 // -> "Mid Island Plz" (the trailing space will be trimmed off at the
727 if (!previous_was_whitespace
) {
729 previous_was_whitespace
= true;
733 case U_CONTROL_CHAR
: // To escape the '\n' character.
734 case U_SPACE_SEPARATOR
:
735 case U_LINE_SEPARATOR
:
736 case U_PARAGRAPH_SEPARATOR
:
737 // Convert sequences of spaces to single spaces.
738 if (!previous_was_whitespace
) {
740 previous_was_whitespace
= true;
744 case U_UPPERCASE_LETTER
:
745 case U_TITLECASE_LETTER
:
746 previous_was_whitespace
= false;
747 base::WriteUnicodeCharacter(u_tolower(iter
.get()), &ret
);
751 previous_was_whitespace
= false;
752 base::WriteUnicodeCharacter(iter
.get(), &ret
);
758 // Trim off trailing whitespace if we left one.
759 if (previous_was_whitespace
)
760 ret
.resize(ret
.size() - 1);
766 bool AutofillProfile::AreProfileStringsSimilar(const base::string16
& a
,
767 const base::string16
& b
) {
768 return CanonicalizeProfileString(a
) == CanonicalizeProfileString(b
);
771 void AutofillProfile::GetSupportedTypes(
772 ServerFieldTypeSet
* supported_types
) const {
773 FormGroupList info
= FormGroups();
774 for (FormGroupList::const_iterator it
= info
.begin(); it
!= info
.end(); ++it
)
775 (*it
)->GetSupportedTypes(supported_types
);
778 base::string16
AutofillProfile::ConstructInferredLabel(
779 const std::vector
<ServerFieldType
>& included_fields
,
780 size_t num_fields_to_use
,
781 const std::string
& app_locale
) const {
782 // TODO(estade): use libaddressinput?
783 base::string16 separator
=
784 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR
);
786 AutofillType
region_code_type(HTML_TYPE_COUNTRY_CODE
, HTML_MODE_NONE
);
787 const base::string16
& profile_region_code
=
788 GetInfo(region_code_type
, app_locale
);
789 std::string address_region_code
= UTF16ToUTF8(profile_region_code
);
791 // A copy of |this| pruned down to contain only data for the address fields in
792 // |included_fields|.
793 AutofillProfile
trimmed_profile(guid(), origin());
794 trimmed_profile
.SetInfo(region_code_type
, profile_region_code
, app_locale
);
795 trimmed_profile
.set_language_code(language_code());
797 std::vector
<ServerFieldType
> remaining_fields
;
798 for (std::vector
<ServerFieldType
>::const_iterator it
=
799 included_fields
.begin();
800 it
!= included_fields
.end() && num_fields_to_use
> 0;
802 AddressField address_field
;
803 if (!i18n::FieldForType(*it
, &address_field
) ||
804 !::i18n::addressinput::IsFieldUsed(
805 address_field
, address_region_code
) ||
806 address_field
== ::i18n::addressinput::COUNTRY
) {
807 remaining_fields
.push_back(*it
);
811 AutofillType
autofill_type(*it
);
812 const base::string16
& field_value
= GetInfo(autofill_type
, app_locale
);
813 if (field_value
.empty())
816 trimmed_profile
.SetInfo(autofill_type
, field_value
, app_locale
);
820 scoped_ptr
<AddressData
> address_data
=
821 i18n::CreateAddressDataFromAutofillProfile(trimmed_profile
, app_locale
);
822 std::string address_line
;
823 ::i18n::addressinput::GetFormattedNationalAddressLine(
824 *address_data
, &address_line
);
825 base::string16 label
= base::UTF8ToUTF16(address_line
);
827 for (std::vector
<ServerFieldType
>::const_iterator it
=
828 remaining_fields
.begin();
829 it
!= remaining_fields
.end() && num_fields_to_use
> 0;
831 const base::string16
& field_value
= GetInfo(AutofillType(*it
), app_locale
);
832 if (field_value
.empty())
836 label
.append(separator
);
838 label
.append(field_value
);
842 // If country code is missing, libaddressinput won't be used to format the
843 // address. In this case the suggestion might include a multi-line street
844 // address which needs to be flattened.
845 base::ReplaceChars(label
, base::ASCIIToUTF16("\n"), separator
, &label
);
851 void AutofillProfile::CreateInferredLabelsHelper(
852 const std::vector
<AutofillProfile
*>& profiles
,
853 const std::list
<size_t>& indices
,
854 const std::vector
<ServerFieldType
>& fields
,
855 size_t num_fields_to_include
,
856 const std::string
& app_locale
,
857 std::vector
<base::string16
>* labels
) {
858 // For efficiency, we first construct a map of fields to their text values and
859 // each value's frequency.
860 std::map
<ServerFieldType
,
861 std::map
<base::string16
, size_t> > field_text_frequencies_by_field
;
862 for (std::vector
<ServerFieldType
>::const_iterator field
= fields
.begin();
863 field
!= fields
.end(); ++field
) {
864 std::map
<base::string16
, size_t>& field_text_frequencies
=
865 field_text_frequencies_by_field
[*field
];
867 for (std::list
<size_t>::const_iterator it
= indices
.begin();
868 it
!= indices
.end(); ++it
) {
869 const AutofillProfile
* profile
= profiles
[*it
];
870 base::string16 field_text
=
871 profile
->GetInfo(AutofillType(*field
), app_locale
);
873 // If this label is not already in the map, add it with frequency 0.
874 if (!field_text_frequencies
.count(field_text
))
875 field_text_frequencies
[field_text
] = 0;
877 // Now, increment the frequency for this label.
878 ++field_text_frequencies
[field_text
];
882 // Now comes the meat of the algorithm. For each profile, we scan the list of
883 // fields to use, looking for two things:
884 // 1. A (non-empty) field that differentiates the profile from all others
885 // 2. At least |num_fields_to_include| non-empty fields
886 // Before we've satisfied condition (2), we include all fields, even ones that
887 // are identical across all the profiles. Once we've satisfied condition (2),
888 // we only include fields that that have at last two distinct values.
889 for (std::list
<size_t>::const_iterator it
= indices
.begin();
890 it
!= indices
.end(); ++it
) {
891 const AutofillProfile
* profile
= profiles
[*it
];
893 std::vector
<ServerFieldType
> label_fields
;
894 bool found_differentiating_field
= false;
895 for (std::vector
<ServerFieldType
>::const_iterator field
= fields
.begin();
896 field
!= fields
.end(); ++field
) {
897 // Skip over empty fields.
898 base::string16 field_text
=
899 profile
->GetInfo(AutofillType(*field
), app_locale
);
900 if (field_text
.empty())
903 std::map
<base::string16
, size_t>& field_text_frequencies
=
904 field_text_frequencies_by_field
[*field
];
905 found_differentiating_field
|=
906 !field_text_frequencies
.count(base::string16()) &&
907 (field_text_frequencies
[field_text
] == 1);
909 // Once we've found enough non-empty fields, skip over any remaining
910 // fields that are identical across all the profiles.
911 if (label_fields
.size() >= num_fields_to_include
&&
912 (field_text_frequencies
.size() == 1))
915 label_fields
.push_back(*field
);
917 // If we've (1) found a differentiating field and (2) found at least
918 // |num_fields_to_include| non-empty fields, we're done!
919 if (found_differentiating_field
&&
920 label_fields
.size() >= num_fields_to_include
)
924 (*labels
)[*it
] = profile
->ConstructInferredLabel(
925 label_fields
, label_fields
.size(), app_locale
);
929 AutofillProfile::FormGroupList
AutofillProfile::FormGroups() const {
934 v
[3] = &phone_number_
;
939 const FormGroup
* AutofillProfile::FormGroupForType(
940 const AutofillType
& type
) const {
941 return const_cast<AutofillProfile
*>(this)->MutableFormGroupForType(type
);
944 FormGroup
* AutofillProfile::MutableFormGroupForType(const AutofillType
& type
) {
945 switch (type
.group()) {
958 return &phone_number_
;
961 case ADDRESS_BILLING
:
976 bool AutofillProfile::EqualsSansGuid(const AutofillProfile
& profile
) const {
977 return origin() == profile
.origin() &&
978 language_code() == profile
.language_code() &&
979 Compare(profile
) == 0;
982 // So we can compare AutofillProfiles with EXPECT_EQ().
983 std::ostream
& operator<<(std::ostream
& os
, const AutofillProfile
& profile
) {
984 return os
<< profile
.guid() << " " << profile
.origin() << " "
985 << UTF16ToUTF8(profile
.GetRawInfo(NAME_FIRST
)) << " "
986 << UTF16ToUTF8(profile
.GetRawInfo(NAME_MIDDLE
)) << " "
987 << UTF16ToUTF8(profile
.GetRawInfo(NAME_LAST
)) << " "
988 << UTF16ToUTF8(profile
.GetRawInfo(EMAIL_ADDRESS
)) << " "
989 << UTF16ToUTF8(profile
.GetRawInfo(COMPANY_NAME
)) << " "
990 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_LINE1
)) << " "
991 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_LINE2
)) << " "
992 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY
))
993 << " " << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_CITY
)) << " "
994 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_STATE
)) << " "
995 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_ZIP
)) << " "
996 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_SORTING_CODE
)) << " "
997 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_COUNTRY
)) << " "
998 << profile
.language_code() << " "
999 << UTF16ToUTF8(profile
.GetRawInfo(PHONE_HOME_WHOLE_NUMBER
));
1002 } // namespace autofill