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" && !autofill::IsValidState(data
);
369 case ADDRESS_HOME_ZIP
:
370 return country
== "US" && !autofill::IsValidZip(data
);
372 case PHONE_HOME_WHOLE_NUMBER
:
373 return !i18n::PhoneObject(data
, country
).IsValidNumber();
376 return !autofill::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 // TODO(isherman): Revisit this decision in the context of i18n and storing
530 // full addresses rather than storing 1-to-2 lines of an address.
531 // For addresses, do the opposite: transfer individual address lines, rather
532 // than full addresses.
533 field_types
.erase(ADDRESS_HOME_STREET_ADDRESS
);
535 l10n::CaseInsensitiveCompare compare
;
537 for (ServerFieldTypeSet::const_iterator iter
= field_types
.begin();
538 iter
!= field_types
.end(); ++iter
) {
539 FieldTypeGroup group
= AutofillType(*iter
).group();
540 // Special case names.
542 OverwriteName(profile
.name_
, app_locale
);
546 base::string16 new_value
= profile
.GetRawInfo(*iter
);
547 if (!compare
.StringsEqual(GetRawInfo(*iter
), new_value
))
548 SetRawInfo(*iter
, new_value
);
552 bool AutofillProfile::SaveAdditionalInfo(const AutofillProfile
& profile
,
553 const std::string
& app_locale
) {
554 ServerFieldTypeSet field_types
, other_field_types
;
555 GetNonEmptyTypes(app_locale
, &field_types
);
556 profile
.GetNonEmptyTypes(app_locale
, &other_field_types
);
557 // See note in OverwriteWith.
558 field_types
.erase(ADDRESS_HOME_STREET_ADDRESS
);
559 l10n::CaseInsensitiveCompare compare
;
560 for (ServerFieldType field_type
: field_types
) {
561 if (other_field_types
.count(field_type
)) {
562 AutofillType type
= AutofillType(field_type
);
563 if (type
.group() == NAME
&&
564 compare
.StringsEqual(
565 profile
.GetInfo(AutofillType(NAME_FULL
), app_locale
),
566 GetInfo(AutofillType(NAME_FULL
), app_locale
))) {
569 if (type
.group() == PHONE_HOME
&&
570 i18n::PhoneNumbersMatch(
571 GetRawInfo(PHONE_HOME_WHOLE_NUMBER
),
572 profile
.GetRawInfo(PHONE_HOME_WHOLE_NUMBER
),
573 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY
)),
577 if (!compare
.StringsEqual(profile
.GetRawInfo(field_type
),
578 GetRawInfo(field_type
))) {
584 if (!IsVerified() || profile
.IsVerified())
585 OverwriteWith(profile
, app_locale
);
590 bool AutofillProfile::SupportsMultiValue(ServerFieldType type
) {
591 FieldTypeGroup group
= AutofillType(type
).group();
592 return group
== NAME
||
593 group
== NAME_BILLING
||
595 group
== PHONE_HOME
||
596 group
== PHONE_BILLING
;
600 void AutofillProfile::CreateDifferentiatingLabels(
601 const std::vector
<AutofillProfile
*>& profiles
,
602 const std::string
& app_locale
,
603 std::vector
<base::string16
>* labels
) {
604 const size_t kMinimalFieldsShown
= 2;
605 CreateInferredLabels(profiles
, NULL
, UNKNOWN_TYPE
, kMinimalFieldsShown
,
607 DCHECK_EQ(profiles
.size(), labels
->size());
611 void AutofillProfile::CreateInferredLabels(
612 const std::vector
<AutofillProfile
*>& profiles
,
613 const std::vector
<ServerFieldType
>* suggested_fields
,
614 ServerFieldType excluded_field
,
615 size_t minimal_fields_shown
,
616 const std::string
& app_locale
,
617 std::vector
<base::string16
>* labels
) {
618 std::vector
<ServerFieldType
> fields_to_use
;
619 GetFieldsForDistinguishingProfiles(suggested_fields
, excluded_field
,
622 // Construct the default label for each profile. Also construct a map that
623 // associates each label with the profiles that have this label. This map is
624 // then used to detect which labels need further differentiating fields.
625 std::map
<base::string16
, std::list
<size_t> > labels_to_profiles
;
626 for (size_t i
= 0; i
< profiles
.size(); ++i
) {
627 base::string16 label
=
628 profiles
[i
]->ConstructInferredLabel(fields_to_use
,
629 minimal_fields_shown
,
631 labels_to_profiles
[label
].push_back(i
);
634 labels
->resize(profiles
.size());
635 for (std::map
<base::string16
, std::list
<size_t> >::const_iterator it
=
636 labels_to_profiles
.begin();
637 it
!= labels_to_profiles
.end(); ++it
) {
638 if (it
->second
.size() == 1) {
639 // This label is unique, so use it without any further ado.
640 base::string16 label
= it
->first
;
641 size_t profile_index
= it
->second
.front();
642 (*labels
)[profile_index
] = label
;
644 // We have more than one profile with the same label, so add
645 // differentiating fields.
646 CreateInferredLabelsHelper(profiles
, it
->second
, fields_to_use
,
647 minimal_fields_shown
, app_locale
, labels
);
652 void AutofillProfile::GenerateServerProfileIdentifier() {
653 DCHECK_EQ(SERVER_PROFILE
, record_type());
654 base::string16 contents
= GetRawInfo(NAME_FIRST
);
655 contents
.append(GetRawInfo(NAME_MIDDLE
));
656 contents
.append(GetRawInfo(NAME_LAST
));
657 contents
.append(GetRawInfo(EMAIL_ADDRESS
));
658 contents
.append(GetRawInfo(COMPANY_NAME
));
659 contents
.append(GetRawInfo(ADDRESS_HOME_STREET_ADDRESS
));
660 contents
.append(GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY
));
661 contents
.append(GetRawInfo(ADDRESS_HOME_CITY
));
662 contents
.append(GetRawInfo(ADDRESS_HOME_STATE
));
663 contents
.append(GetRawInfo(ADDRESS_HOME_ZIP
));
664 contents
.append(GetRawInfo(ADDRESS_HOME_SORTING_CODE
));
665 contents
.append(GetRawInfo(ADDRESS_HOME_COUNTRY
));
666 contents
.append(GetRawInfo(PHONE_HOME_WHOLE_NUMBER
));
667 std::string contents_utf8
= UTF16ToUTF8(contents
);
668 contents_utf8
.append(language_code());
669 server_id_
= base::SHA1HashString(contents_utf8
);
673 base::string16
AutofillProfile::CanonicalizeProfileString(
674 const base::string16
& str
) {
676 ret
.reserve(str
.size());
678 bool previous_was_whitespace
= false;
680 // This algorithm isn't designed to be perfect, we could get arbitrarily
681 // fancy here trying to canonicalize address lines. Instead, this is designed
682 // to handle common cases for all types of data (addresses and names)
683 // without the need of domain-specific logic.
684 base::i18n::UTF16CharIterator
iter(&str
);
685 while (!iter
.end()) {
686 switch (u_charType(iter
.get())) {
687 case U_DASH_PUNCTUATION
:
688 case U_START_PUNCTUATION
:
689 case U_END_PUNCTUATION
:
690 case U_CONNECTOR_PUNCTUATION
:
691 case U_OTHER_PUNCTUATION
:
692 // Convert punctuation to spaces. This will convert "Mid-Island Plz."
693 // -> "Mid Island Plz" (the trailing space will be trimmed off at the
695 if (!previous_was_whitespace
) {
697 previous_was_whitespace
= true;
701 case U_SPACE_SEPARATOR
:
702 case U_LINE_SEPARATOR
:
703 case U_PARAGRAPH_SEPARATOR
:
704 // Convert sequences of spaces to single spaces.
705 if (!previous_was_whitespace
) {
707 previous_was_whitespace
= true;
711 case U_UPPERCASE_LETTER
:
712 case U_TITLECASE_LETTER
:
713 previous_was_whitespace
= false;
714 base::WriteUnicodeCharacter(u_tolower(iter
.get()), &ret
);
718 previous_was_whitespace
= false;
719 base::WriteUnicodeCharacter(iter
.get(), &ret
);
725 // Trim off trailing whitespace if we left one.
726 if (previous_was_whitespace
)
727 ret
.resize(ret
.size() - 1);
733 bool AutofillProfile::AreProfileStringsSimilar(const base::string16
& a
,
734 const base::string16
& b
) {
735 return CanonicalizeProfileString(a
) == CanonicalizeProfileString(b
);
738 void AutofillProfile::GetSupportedTypes(
739 ServerFieldTypeSet
* supported_types
) const {
740 FormGroupList info
= FormGroups();
741 for (FormGroupList::const_iterator it
= info
.begin(); it
!= info
.end(); ++it
)
742 (*it
)->GetSupportedTypes(supported_types
);
745 base::string16
AutofillProfile::ConstructInferredLabel(
746 const std::vector
<ServerFieldType
>& included_fields
,
747 size_t num_fields_to_use
,
748 const std::string
& app_locale
) const {
749 // TODO(estade): use libaddressinput?
750 base::string16 separator
=
751 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR
);
753 AutofillType
region_code_type(HTML_TYPE_COUNTRY_CODE
, HTML_MODE_NONE
);
754 const base::string16
& profile_region_code
=
755 GetInfo(region_code_type
, app_locale
);
756 std::string address_region_code
= UTF16ToUTF8(profile_region_code
);
758 // A copy of |this| pruned down to contain only data for the address fields in
759 // |included_fields|.
760 AutofillProfile
trimmed_profile(guid(), origin());
761 trimmed_profile
.SetInfo(region_code_type
, profile_region_code
, app_locale
);
762 trimmed_profile
.set_language_code(language_code());
764 std::vector
<ServerFieldType
> remaining_fields
;
765 for (std::vector
<ServerFieldType
>::const_iterator it
=
766 included_fields
.begin();
767 it
!= included_fields
.end() && num_fields_to_use
> 0;
769 AddressField address_field
;
770 if (!i18n::FieldForType(*it
, &address_field
) ||
771 !::i18n::addressinput::IsFieldUsed(
772 address_field
, address_region_code
) ||
773 address_field
== ::i18n::addressinput::COUNTRY
) {
774 remaining_fields
.push_back(*it
);
778 AutofillType
autofill_type(*it
);
779 const base::string16
& field_value
= GetInfo(autofill_type
, app_locale
);
780 if (field_value
.empty())
783 trimmed_profile
.SetInfo(autofill_type
, field_value
, app_locale
);
787 scoped_ptr
<AddressData
> address_data
=
788 i18n::CreateAddressDataFromAutofillProfile(trimmed_profile
, app_locale
);
789 std::string address_line
;
790 ::i18n::addressinput::GetFormattedNationalAddressLine(
791 *address_data
, &address_line
);
792 base::string16 label
= base::UTF8ToUTF16(address_line
);
794 for (std::vector
<ServerFieldType
>::const_iterator it
=
795 remaining_fields
.begin();
796 it
!= remaining_fields
.end() && num_fields_to_use
> 0;
798 const base::string16
& field_value
= GetInfo(AutofillType(*it
), app_locale
);
799 if (field_value
.empty())
803 label
.append(separator
);
805 label
.append(field_value
);
809 // If country code is missing, libaddressinput won't be used to format the
810 // address. In this case the suggestion might include a multi-line street
811 // address which needs to be flattened.
812 base::ReplaceChars(label
, base::ASCIIToUTF16("\n"), separator
, &label
);
818 void AutofillProfile::CreateInferredLabelsHelper(
819 const std::vector
<AutofillProfile
*>& profiles
,
820 const std::list
<size_t>& indices
,
821 const std::vector
<ServerFieldType
>& fields
,
822 size_t num_fields_to_include
,
823 const std::string
& app_locale
,
824 std::vector
<base::string16
>* labels
) {
825 // For efficiency, we first construct a map of fields to their text values and
826 // each value's frequency.
827 std::map
<ServerFieldType
,
828 std::map
<base::string16
, size_t> > field_text_frequencies_by_field
;
829 for (std::vector
<ServerFieldType
>::const_iterator field
= fields
.begin();
830 field
!= fields
.end(); ++field
) {
831 std::map
<base::string16
, size_t>& field_text_frequencies
=
832 field_text_frequencies_by_field
[*field
];
834 for (std::list
<size_t>::const_iterator it
= indices
.begin();
835 it
!= indices
.end(); ++it
) {
836 const AutofillProfile
* profile
= profiles
[*it
];
837 base::string16 field_text
=
838 profile
->GetInfo(AutofillType(*field
), app_locale
);
840 // If this label is not already in the map, add it with frequency 0.
841 if (!field_text_frequencies
.count(field_text
))
842 field_text_frequencies
[field_text
] = 0;
844 // Now, increment the frequency for this label.
845 ++field_text_frequencies
[field_text
];
849 // Now comes the meat of the algorithm. For each profile, we scan the list of
850 // fields to use, looking for two things:
851 // 1. A (non-empty) field that differentiates the profile from all others
852 // 2. At least |num_fields_to_include| non-empty fields
853 // Before we've satisfied condition (2), we include all fields, even ones that
854 // are identical across all the profiles. Once we've satisfied condition (2),
855 // we only include fields that that have at last two distinct values.
856 for (std::list
<size_t>::const_iterator it
= indices
.begin();
857 it
!= indices
.end(); ++it
) {
858 const AutofillProfile
* profile
= profiles
[*it
];
860 std::vector
<ServerFieldType
> label_fields
;
861 bool found_differentiating_field
= false;
862 for (std::vector
<ServerFieldType
>::const_iterator field
= fields
.begin();
863 field
!= fields
.end(); ++field
) {
864 // Skip over empty fields.
865 base::string16 field_text
=
866 profile
->GetInfo(AutofillType(*field
), app_locale
);
867 if (field_text
.empty())
870 std::map
<base::string16
, size_t>& field_text_frequencies
=
871 field_text_frequencies_by_field
[*field
];
872 found_differentiating_field
|=
873 !field_text_frequencies
.count(base::string16()) &&
874 (field_text_frequencies
[field_text
] == 1);
876 // Once we've found enough non-empty fields, skip over any remaining
877 // fields that are identical across all the profiles.
878 if (label_fields
.size() >= num_fields_to_include
&&
879 (field_text_frequencies
.size() == 1))
882 label_fields
.push_back(*field
);
884 // If we've (1) found a differentiating field and (2) found at least
885 // |num_fields_to_include| non-empty fields, we're done!
886 if (found_differentiating_field
&&
887 label_fields
.size() >= num_fields_to_include
)
891 (*labels
)[*it
] = profile
->ConstructInferredLabel(
892 label_fields
, label_fields
.size(), app_locale
);
896 AutofillProfile::FormGroupList
AutofillProfile::FormGroups() const {
901 v
[3] = &phone_number_
;
906 const FormGroup
* AutofillProfile::FormGroupForType(
907 const AutofillType
& type
) const {
908 return const_cast<AutofillProfile
*>(this)->MutableFormGroupForType(type
);
911 FormGroup
* AutofillProfile::MutableFormGroupForType(const AutofillType
& type
) {
912 switch (type
.group()) {
925 return &phone_number_
;
928 case ADDRESS_BILLING
:
943 bool AutofillProfile::EqualsSansGuid(const AutofillProfile
& profile
) const {
944 return origin() == profile
.origin() &&
945 language_code() == profile
.language_code() &&
946 Compare(profile
) == 0;
949 // So we can compare AutofillProfiles with EXPECT_EQ().
950 std::ostream
& operator<<(std::ostream
& os
, const AutofillProfile
& profile
) {
951 return os
<< profile
.guid() << " " << profile
.origin() << " "
952 << UTF16ToUTF8(profile
.GetRawInfo(NAME_FIRST
)) << " "
953 << UTF16ToUTF8(profile
.GetRawInfo(NAME_MIDDLE
)) << " "
954 << UTF16ToUTF8(profile
.GetRawInfo(NAME_LAST
)) << " "
955 << UTF16ToUTF8(profile
.GetRawInfo(EMAIL_ADDRESS
)) << " "
956 << UTF16ToUTF8(profile
.GetRawInfo(COMPANY_NAME
)) << " "
957 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_LINE1
)) << " "
958 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_LINE2
)) << " "
959 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY
))
960 << " " << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_CITY
)) << " "
961 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_STATE
)) << " "
962 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_ZIP
)) << " "
963 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_SORTING_CODE
)) << " "
964 << UTF16ToUTF8(profile
.GetRawInfo(ADDRESS_HOME_COUNTRY
)) << " "
965 << profile
.language_code() << " "
966 << UTF16ToUTF8(profile
.GetRawInfo(PHONE_HOME_WHOLE_NUMBER
));
969 } // namespace autofill