Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / autofill / core / browser / autofill_profile.cc
blob06a3878689035c98781c432a71e356c2b53d272a
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"
7 #include <algorithm>
8 #include <functional>
9 #include <map>
10 #include <ostream>
11 #include <set>
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;
46 namespace autofill {
47 namespace {
49 // Like |AutofillType::GetStorableType()|, but also returns |NAME_FULL| for
50 // first, middle, and last name field types, and groups phone number types
51 // similarly.
52 ServerFieldType GetStorableTypeCollapsingGroups(ServerFieldType type) {
53 ServerFieldType storable_type = AutofillType(type).GetStorableType();
54 if (AutofillType(storable_type).group() == NAME)
55 return NAME_FULL;
57 if (AutofillType(storable_type).group() == PHONE_HOME)
58 return PHONE_HOME_WHOLE_NUMBER;
60 return storable_type;
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) {
68 switch (type) {
69 case ADDRESS_HOME_LINE1:
70 return 1;
72 case ADDRESS_HOME_LINE2:
73 return 2;
75 case EMAIL_ADDRESS:
76 return 3;
78 case PHONE_HOME_WHOLE_NUMBER:
79 return 4;
81 case NAME_FULL:
82 return 5;
84 case ADDRESS_HOME_ZIP:
85 return 6;
87 case ADDRESS_HOME_SORTING_CODE:
88 return 7;
90 case COMPANY_NAME:
91 return 8;
93 case ADDRESS_HOME_CITY:
94 return 9;
96 case ADDRESS_HOME_STATE:
97 return 10;
99 case ADDRESS_HOME_COUNTRY:
100 return 11;
102 default:
103 break;
106 // The priority of other types is arbitrary, but deterministic.
107 return 100 + type;
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[] = {
126 NAME_FULL,
127 ADDRESS_HOME_LINE1,
128 ADDRESS_HOME_LINE2,
129 ADDRESS_HOME_DEPENDENT_LOCALITY,
130 ADDRESS_HOME_CITY,
131 ADDRESS_HOME_STATE,
132 ADDRESS_HOME_ZIP,
133 ADDRESS_HOME_SORTING_CODE,
134 ADDRESS_HOME_COUNTRY,
135 EMAIL_ADDRESS,
136 PHONE_HOME_WHOLE_NUMBER,
137 COMPANY_NAME,
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);
147 return;
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(),
168 CompareSpecificity);
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);
183 break;
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) {
195 switch (*it) {
196 case NAME_FIRST:
197 case NAME_MIDDLE:
198 case NAME_LAST:
199 case NAME_MIDDLE_INITIAL:
200 case NAME_FULL:
201 case NAME_SUFFIX:
202 collapsed_set.insert(NAME_FULL);
203 break;
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);
211 break;
213 default:
214 collapsed_set.insert(*it);
217 std::swap(*type_set, collapsed_set);
220 class FindByPhone {
221 public:
222 FindByPhone(const base::string16& phone,
223 const std::string& country_code,
224 const std::string& app_locale)
225 : phone_(phone),
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_);
233 private:
234 base::string16 phone_;
235 std::string country_code_;
236 std::string app_locale_;
239 } // namespace
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()),
250 record_type_(type),
251 phone_number_(this),
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) {
264 operator=(profile);
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)
276 return *this;
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();
294 return *this;
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));
308 if (!form_group)
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));
317 if (form_group)
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);
335 if (!form_group)
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);
345 if (!form_group)
346 return false;
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);
362 if (data.empty())
363 return false;
365 switch (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();
375 case EMAIL_ADDRESS:
376 return !IsValidEmailAddress(data);
378 default:
379 NOTREACHED();
380 return false;
384 int AutofillProfile::Compare(const AutofillProfile& profile) const {
385 const ServerFieldType types[] = {
386 NAME_FULL,
387 NAME_FIRST,
388 NAME_MIDDLE,
389 NAME_LAST,
390 COMPANY_NAME,
391 ADDRESS_HOME_STREET_ADDRESS,
392 ADDRESS_HOME_DEPENDENT_LOCALITY,
393 ADDRESS_HOME_CITY,
394 ADDRESS_HOME_STATE,
395 ADDRESS_HOME_ZIP,
396 ADDRESS_HOME_SORTING_CODE,
397 ADDRESS_HOME_COUNTRY,
398 EMAIL_ADDRESS,
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) {
405 return comparison;
409 return 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)
419 const {
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);
452 if (value.empty())
453 continue;
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.
461 continue;
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) {
465 continue;
466 } else if (!i18n::PhoneNumbersMatch(
467 value, profile.GetRawInfo(type),
468 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)),
469 app_locale)) {
470 return false;
472 } else {
473 if (!compare)
474 compare.reset(new l10n::CaseInsensitiveCompare());
475 if (!compare->StringsEqual(value, profile.GetRawInfo(type)))
476 return false;
480 return true;
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));
488 return;
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))
506 return;
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.
552 if (group == NAME) {
553 OverwriteName(profile.name_, app_locale);
554 continue;
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))) {
581 continue;
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)),
588 app_locale)) {
589 continue;
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)))) {
605 return false;
607 continue;
609 if (!compare.StringsEqual(profile.GetRawInfo(field_type),
610 GetRawInfo(field_type))) {
611 return false;
616 if (!IsVerified() || profile.IsVerified())
617 OverwriteWith(profile, app_locale);
618 return true;
621 // static
622 bool AutofillProfile::SupportsMultiValue(ServerFieldType type) {
623 FieldTypeGroup group = AutofillType(type).group();
624 return group == NAME ||
625 group == NAME_BILLING ||
626 group == EMAIL ||
627 group == PHONE_HOME ||
628 group == PHONE_BILLING;
631 // static
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,
638 app_locale, labels);
639 DCHECK_EQ(profiles.size(), labels->size());
642 // static
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,
652 &fields_to_use);
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,
662 app_locale);
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;
675 } else {
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);
704 // static
705 base::string16 AutofillProfile::CanonicalizeProfileString(
706 const base::string16& str) {
707 base::string16 ret;
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
726 // end of the loop).
727 if (!previous_was_whitespace) {
728 ret.push_back(' ');
729 previous_was_whitespace = true;
731 break;
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) {
739 ret.push_back(' ');
740 previous_was_whitespace = true;
742 break;
744 case U_UPPERCASE_LETTER:
745 case U_TITLECASE_LETTER:
746 previous_was_whitespace = false;
747 base::WriteUnicodeCharacter(u_tolower(iter.get()), &ret);
748 break;
750 default:
751 previous_was_whitespace = false;
752 base::WriteUnicodeCharacter(iter.get(), &ret);
753 break;
755 iter.Advance();
758 // Trim off trailing whitespace if we left one.
759 if (previous_was_whitespace)
760 ret.resize(ret.size() - 1);
762 return ret;
765 // static
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;
801 ++it) {
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);
808 continue;
811 AutofillType autofill_type(*it);
812 const base::string16& field_value = GetInfo(autofill_type, app_locale);
813 if (field_value.empty())
814 continue;
816 trimmed_profile.SetInfo(autofill_type, field_value, app_locale);
817 --num_fields_to_use;
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;
830 ++it) {
831 const base::string16& field_value = GetInfo(AutofillType(*it), app_locale);
832 if (field_value.empty())
833 continue;
835 if (!label.empty())
836 label.append(separator);
838 label.append(field_value);
839 --num_fields_to_use;
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);
847 return label;
850 // static
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())
901 continue;
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))
913 continue;
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)
921 break;
924 (*labels)[*it] = profile->ConstructInferredLabel(
925 label_fields, label_fields.size(), app_locale);
929 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
930 FormGroupList v(5);
931 v[0] = &name_;
932 v[1] = &email_;
933 v[2] = &company_;
934 v[3] = &phone_number_;
935 v[4] = &address_;
936 return v;
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()) {
946 case NAME:
947 case NAME_BILLING:
948 return &name_;
950 case EMAIL:
951 return &email_;
953 case COMPANY:
954 return &company_;
956 case PHONE_HOME:
957 case PHONE_BILLING:
958 return &phone_number_;
960 case ADDRESS_HOME:
961 case ADDRESS_BILLING:
962 return &address_;
964 case NO_GROUP:
965 case CREDIT_CARD:
966 case PASSWORD_FIELD:
967 case USERNAME_FIELD:
968 case TRANSACTION:
969 return NULL;
972 NOTREACHED();
973 return NULL;
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