Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / components / autofill / core / browser / autofill_profile.cc
blobbec11214682f5b63fe05ffd8b2d4c47dd3fd7618
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" && !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();
375 case EMAIL_ADDRESS:
376 return !autofill::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 // 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.
541 if (group == NAME) {
542 OverwriteName(profile.name_, app_locale);
543 continue;
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))) {
567 continue;
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)),
574 app_locale)) {
575 continue;
577 if (!compare.StringsEqual(profile.GetRawInfo(field_type),
578 GetRawInfo(field_type))) {
579 return false;
584 if (!IsVerified() || profile.IsVerified())
585 OverwriteWith(profile, app_locale);
586 return true;
589 // static
590 bool AutofillProfile::SupportsMultiValue(ServerFieldType type) {
591 FieldTypeGroup group = AutofillType(type).group();
592 return group == NAME ||
593 group == NAME_BILLING ||
594 group == EMAIL ||
595 group == PHONE_HOME ||
596 group == PHONE_BILLING;
599 // static
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,
606 app_locale, labels);
607 DCHECK_EQ(profiles.size(), labels->size());
610 // static
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,
620 &fields_to_use);
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,
630 app_locale);
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;
643 } else {
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);
672 // static
673 base::string16 AutofillProfile::CanonicalizeProfileString(
674 const base::string16& str) {
675 base::string16 ret;
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
694 // end of the loop).
695 if (!previous_was_whitespace) {
696 ret.push_back(' ');
697 previous_was_whitespace = true;
699 break;
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) {
706 ret.push_back(' ');
707 previous_was_whitespace = true;
709 break;
711 case U_UPPERCASE_LETTER:
712 case U_TITLECASE_LETTER:
713 previous_was_whitespace = false;
714 base::WriteUnicodeCharacter(u_tolower(iter.get()), &ret);
715 break;
717 default:
718 previous_was_whitespace = false;
719 base::WriteUnicodeCharacter(iter.get(), &ret);
720 break;
722 iter.Advance();
725 // Trim off trailing whitespace if we left one.
726 if (previous_was_whitespace)
727 ret.resize(ret.size() - 1);
729 return ret;
732 // static
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;
768 ++it) {
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);
775 continue;
778 AutofillType autofill_type(*it);
779 const base::string16& field_value = GetInfo(autofill_type, app_locale);
780 if (field_value.empty())
781 continue;
783 trimmed_profile.SetInfo(autofill_type, field_value, app_locale);
784 --num_fields_to_use;
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;
797 ++it) {
798 const base::string16& field_value = GetInfo(AutofillType(*it), app_locale);
799 if (field_value.empty())
800 continue;
802 if (!label.empty())
803 label.append(separator);
805 label.append(field_value);
806 --num_fields_to_use;
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);
814 return label;
817 // static
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())
868 continue;
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))
880 continue;
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)
888 break;
891 (*labels)[*it] = profile->ConstructInferredLabel(
892 label_fields, label_fields.size(), app_locale);
896 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
897 FormGroupList v(5);
898 v[0] = &name_;
899 v[1] = &email_;
900 v[2] = &company_;
901 v[3] = &phone_number_;
902 v[4] = &address_;
903 return v;
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()) {
913 case NAME:
914 case NAME_BILLING:
915 return &name_;
917 case EMAIL:
918 return &email_;
920 case COMPANY:
921 return &company_;
923 case PHONE_HOME:
924 case PHONE_BILLING:
925 return &phone_number_;
927 case ADDRESS_HOME:
928 case ADDRESS_BILLING:
929 return &address_;
931 case NO_GROUP:
932 case CREDIT_CARD:
933 case PASSWORD_FIELD:
934 case USERNAME_FIELD:
935 case TRANSACTION:
936 return NULL;
939 NOTREACHED();
940 return NULL;
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