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.
4
5 #include "components/autofill/core/browser/autofill_profile.h"
6
7 #include <algorithm>
8 #include <functional>
9 #include <map>
10 #include <ostream>
11 #include <set>
12
13 #include "base/basictypes.h"
14 #include "base/guid.h"
15 #include "base/logging.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "components/autofill/core/browser/address.h"
19 #include "components/autofill/core/browser/autofill_country.h"
20 #include "components/autofill/core/browser/autofill_field.h"
21 #include "components/autofill/core/browser/autofill_type.h"
22 #include "components/autofill/core/browser/contact_info.h"
23 #include "components/autofill/core/browser/phone_number.h"
24 #include "components/autofill/core/browser/phone_number_i18n.h"
25 #include "components/autofill/core/browser/validation.h"
26 #include "components/autofill/core/common/form_field_data.h"
27 #include "grit/component_strings.h"
28 #include "ui/base/l10n/l10n_util.h"
29
30 namespace autofill {
31 namespace {
32
33 // Like |AutofillType::GetStorableType()|, but also returns |NAME_FULL| for
34 // first, middle, and last name field types.
GetStorableTypeCollapsingNames(ServerFieldType type)35 ServerFieldType GetStorableTypeCollapsingNames(ServerFieldType type) {
36 ServerFieldType storable_type = AutofillType(type).GetStorableType();
37 if (AutofillType(storable_type).group() == NAME)
38 return NAME_FULL;
39
40 return storable_type;
41 }
42
43 // Fills |distinguishing_fields| with a list of fields to use when creating
44 // labels that can help to distinguish between two profiles. Draws fields from
45 // |suggested_fields| if it is non-NULL; otherwise returns a default list.
46 // If |suggested_fields| is non-NULL, does not include |excluded_field| in the
47 // list. Otherwise, |excluded_field| is ignored, and should be set to
48 // |UNKNOWN_TYPE| by convention. The resulting list of fields is sorted in
49 // decreasing order of importance.
GetFieldsForDistinguishingProfiles(const std::vector<ServerFieldType> * suggested_fields,ServerFieldType excluded_field,std::vector<ServerFieldType> * distinguishing_fields)50 void GetFieldsForDistinguishingProfiles(
51 const std::vector<ServerFieldType>* suggested_fields,
52 ServerFieldType excluded_field,
53 std::vector<ServerFieldType>* distinguishing_fields) {
54 static const ServerFieldType kDefaultDistinguishingFields[] = {
55 NAME_FULL,
56 ADDRESS_HOME_LINE1,
57 ADDRESS_HOME_LINE2,
58 ADDRESS_HOME_CITY,
59 ADDRESS_HOME_STATE,
60 ADDRESS_HOME_ZIP,
61 ADDRESS_HOME_COUNTRY,
62 EMAIL_ADDRESS,
63 PHONE_HOME_WHOLE_NUMBER,
64 COMPANY_NAME,
65 };
66
67 if (!suggested_fields) {
68 DCHECK_EQ(excluded_field, UNKNOWN_TYPE);
69 distinguishing_fields->assign(
70 kDefaultDistinguishingFields,
71 kDefaultDistinguishingFields + arraysize(kDefaultDistinguishingFields));
72 return;
73 }
74
75 // Keep track of which fields we've seen so that we avoid duplicate entries.
76 // Always ignore fields of unknown type and the excluded field.
77 std::set<ServerFieldType> seen_fields;
78 seen_fields.insert(UNKNOWN_TYPE);
79 seen_fields.insert(GetStorableTypeCollapsingNames(excluded_field));
80
81 distinguishing_fields->clear();
82 for (std::vector<ServerFieldType>::const_iterator it =
83 suggested_fields->begin();
84 it != suggested_fields->end(); ++it) {
85 ServerFieldType suggested_type = GetStorableTypeCollapsingNames(*it);
86 if (seen_fields.insert(suggested_type).second)
87 distinguishing_fields->push_back(suggested_type);
88 }
89
90 // Special case: If the excluded field is a partial name (e.g. first name) and
91 // the suggested fields include other name fields, include |NAME_FULL| in the
92 // list of distinguishing fields as a last-ditch fallback. This allows us to
93 // distinguish between profiles that are identical except for the name.
94 if (excluded_field != NAME_FULL &&
95 GetStorableTypeCollapsingNames(excluded_field) == NAME_FULL) {
96 for (std::vector<ServerFieldType>::const_iterator it =
97 suggested_fields->begin();
98 it != suggested_fields->end(); ++it) {
99 if (*it != excluded_field &&
100 GetStorableTypeCollapsingNames(*it) == NAME_FULL) {
101 distinguishing_fields->push_back(NAME_FULL);
102 break;
103 }
104 }
105 }
106 }
107
108 // A helper function for string streaming. Concatenates multi-valued entries
109 // stored for a given |type| into a single string. This string is returned.
MultiString(const AutofillProfile & p,ServerFieldType type)110 const base::string16 MultiString(const AutofillProfile& p,
111 ServerFieldType type) {
112 std::vector<base::string16> values;
113 p.GetRawMultiInfo(type, &values);
114 base::string16 accumulate;
115 for (size_t i = 0; i < values.size(); ++i) {
116 if (i > 0)
117 accumulate += ASCIIToUTF16(" ");
118 accumulate += values[i];
119 }
120 return accumulate;
121 }
122
GetFormGroupInfo(const FormGroup & form_group,const AutofillType & type,const std::string & app_locale)123 base::string16 GetFormGroupInfo(const FormGroup& form_group,
124 const AutofillType& type,
125 const std::string& app_locale) {
126 return app_locale.empty() ?
127 form_group.GetRawInfo(type.GetStorableType()) :
128 form_group.GetInfo(type, app_locale);
129 }
130
131 template <class T>
CopyValuesToItems(ServerFieldType type,const std::vector<base::string16> & values,std::vector<T> * form_group_items,const T & prototype)132 void CopyValuesToItems(ServerFieldType type,
133 const std::vector<base::string16>& values,
134 std::vector<T>* form_group_items,
135 const T& prototype) {
136 form_group_items->resize(values.size(), prototype);
137 for (size_t i = 0; i < form_group_items->size(); ++i) {
138 (*form_group_items)[i].SetRawInfo(type, values[i]);
139 }
140 // Must have at least one (possibly empty) element.
141 if (form_group_items->empty())
142 form_group_items->resize(1, prototype);
143 }
144
145 template <class T>
CopyItemsToValues(const AutofillType & type,const std::vector<T> & form_group_items,const std::string & app_locale,std::vector<base::string16> * values)146 void CopyItemsToValues(const AutofillType& type,
147 const std::vector<T>& form_group_items,
148 const std::string& app_locale,
149 std::vector<base::string16>* values) {
150 values->resize(form_group_items.size());
151 for (size_t i = 0; i < values->size(); ++i) {
152 (*values)[i] = GetFormGroupInfo(form_group_items[i], type, app_locale);
153 }
154 }
155
156 // Collapse compound field types to their "full" type. I.e. First name
157 // collapses to full name, area code collapses to full phone, etc.
CollapseCompoundFieldTypes(ServerFieldTypeSet * type_set)158 void CollapseCompoundFieldTypes(ServerFieldTypeSet* type_set) {
159 ServerFieldTypeSet collapsed_set;
160 for (ServerFieldTypeSet::iterator it = type_set->begin();
161 it != type_set->end(); ++it) {
162 switch (*it) {
163 case NAME_FIRST:
164 case NAME_MIDDLE:
165 case NAME_LAST:
166 case NAME_MIDDLE_INITIAL:
167 case NAME_FULL:
168 case NAME_SUFFIX:
169 collapsed_set.insert(NAME_FULL);
170 break;
171
172 case PHONE_HOME_NUMBER:
173 case PHONE_HOME_CITY_CODE:
174 case PHONE_HOME_COUNTRY_CODE:
175 case PHONE_HOME_CITY_AND_NUMBER:
176 case PHONE_HOME_WHOLE_NUMBER:
177 collapsed_set.insert(PHONE_HOME_WHOLE_NUMBER);
178 break;
179
180 default:
181 collapsed_set.insert(*it);
182 }
183 }
184 std::swap(*type_set, collapsed_set);
185 }
186
187 class FindByPhone {
188 public:
FindByPhone(const base::string16 & phone,const std::string & country_code,const std::string & app_locale)189 FindByPhone(const base::string16& phone,
190 const std::string& country_code,
191 const std::string& app_locale)
192 : phone_(phone),
193 country_code_(country_code),
194 app_locale_(app_locale) {
195 }
196
operator ()(const base::string16 & phone)197 bool operator()(const base::string16& phone) {
198 return i18n::PhoneNumbersMatch(phone, phone_, country_code_, app_locale_);
199 }
200
operator ()(const base::string16 * phone)201 bool operator()(const base::string16* phone) {
202 return i18n::PhoneNumbersMatch(*phone, phone_, country_code_, app_locale_);
203 }
204
205 private:
206 base::string16 phone_;
207 std::string country_code_;
208 std::string app_locale_;
209 };
210
211 // Functor used to check for case-insensitive equality of two strings.
212 struct CaseInsensitiveStringEquals
213 : public std::binary_function<base::string16, base::string16, bool>
214 {
operator ()autofill::__anonbe666c480111::CaseInsensitiveStringEquals215 bool operator()(const base::string16& x, const base::string16& y) const {
216 return
217 x.size() == y.size() && StringToLowerASCII(x) == StringToLowerASCII(y);
218 }
219 };
220
221 } // namespace
222
AutofillProfile(const std::string & guid,const std::string & origin)223 AutofillProfile::AutofillProfile(const std::string& guid,
224 const std::string& origin)
225 : AutofillDataModel(guid, origin),
226 name_(1),
227 email_(1),
228 phone_number_(1, PhoneNumber(this)) {
229 }
230
AutofillProfile()231 AutofillProfile::AutofillProfile()
232 : AutofillDataModel(base::GenerateGUID(), std::string()),
233 name_(1),
234 email_(1),
235 phone_number_(1, PhoneNumber(this)) {
236 }
237
AutofillProfile(const AutofillProfile & profile)238 AutofillProfile::AutofillProfile(const AutofillProfile& profile)
239 : AutofillDataModel(std::string(), std::string()) {
240 operator=(profile);
241 }
242
~AutofillProfile()243 AutofillProfile::~AutofillProfile() {
244 }
245
operator =(const AutofillProfile & profile)246 AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
247 if (this == &profile)
248 return *this;
249
250 set_guid(profile.guid());
251 set_origin(profile.origin());
252
253 name_ = profile.name_;
254 email_ = profile.email_;
255 company_ = profile.company_;
256 phone_number_ = profile.phone_number_;
257
258 for (size_t i = 0; i < phone_number_.size(); ++i)
259 phone_number_[i].set_profile(this);
260
261 address_ = profile.address_;
262
263 return *this;
264 }
265
GetMatchingTypes(const base::string16 & text,const std::string & app_locale,ServerFieldTypeSet * matching_types) const266 void AutofillProfile::GetMatchingTypes(
267 const base::string16& text,
268 const std::string& app_locale,
269 ServerFieldTypeSet* matching_types) const {
270 FormGroupList info = FormGroups();
271 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
272 (*it)->GetMatchingTypes(text, app_locale, matching_types);
273 }
274
GetRawInfo(ServerFieldType type) const275 base::string16 AutofillProfile::GetRawInfo(ServerFieldType type) const {
276 const FormGroup* form_group = FormGroupForType(AutofillType(type));
277 if (!form_group)
278 return base::string16();
279
280 return form_group->GetRawInfo(type);
281 }
282
SetRawInfo(ServerFieldType type,const base::string16 & value)283 void AutofillProfile::SetRawInfo(ServerFieldType type,
284 const base::string16& value) {
285 FormGroup* form_group = MutableFormGroupForType(AutofillType(type));
286 if (form_group)
287 form_group->SetRawInfo(type, value);
288 }
289
GetInfo(const AutofillType & type,const std::string & app_locale) const290 base::string16 AutofillProfile::GetInfo(const AutofillType& type,
291 const std::string& app_locale) const {
292 const FormGroup* form_group = FormGroupForType(type);
293 if (!form_group)
294 return base::string16();
295
296 return form_group->GetInfo(type, app_locale);
297 }
298
SetInfo(const AutofillType & type,const base::string16 & value,const std::string & app_locale)299 bool AutofillProfile::SetInfo(const AutofillType& type,
300 const base::string16& value,
301 const std::string& app_locale) {
302 FormGroup* form_group = MutableFormGroupForType(type);
303 if (!form_group)
304 return false;
305
306 base::string16 trimmed_value;
307 TrimWhitespace(value, TRIM_ALL, &trimmed_value);
308 return form_group->SetInfo(type, trimmed_value, app_locale);
309 }
310
GetInfoForVariant(const AutofillType & type,size_t variant,const std::string & app_locale) const311 base::string16 AutofillProfile::GetInfoForVariant(
312 const AutofillType& type,
313 size_t variant,
314 const std::string& app_locale) const {
315 std::vector<base::string16> values;
316 GetMultiInfo(type, app_locale, &values);
317
318 if (variant >= values.size()) {
319 // If the variant is unavailable, bail. This case is reachable, for
320 // example if Sync updates a profile during the filling process.
321 return base::string16();
322 }
323
324 return values[variant];
325 }
326
SetRawMultiInfo(ServerFieldType type,const std::vector<base::string16> & values)327 void AutofillProfile::SetRawMultiInfo(
328 ServerFieldType type,
329 const std::vector<base::string16>& values) {
330 switch (AutofillType(type).group()) {
331 case NAME:
332 case NAME_BILLING:
333 CopyValuesToItems(type, values, &name_, NameInfo());
334 break;
335 case EMAIL:
336 CopyValuesToItems(type, values, &email_, EmailInfo());
337 break;
338 case PHONE_HOME:
339 case PHONE_BILLING:
340 CopyValuesToItems(type,
341 values,
342 &phone_number_,
343 PhoneNumber(this));
344 break;
345 default:
346 if (values.size() == 1) {
347 SetRawInfo(type, values[0]);
348 } else if (values.size() == 0) {
349 SetRawInfo(type, base::string16());
350 } else {
351 // Shouldn't attempt to set multiple values on single-valued field.
352 NOTREACHED();
353 }
354 break;
355 }
356 }
357
GetRawMultiInfo(ServerFieldType type,std::vector<base::string16> * values) const358 void AutofillProfile::GetRawMultiInfo(
359 ServerFieldType type,
360 std::vector<base::string16>* values) const {
361 GetMultiInfoImpl(AutofillType(type), std::string(), values);
362 }
363
GetMultiInfo(const AutofillType & type,const std::string & app_locale,std::vector<base::string16> * values) const364 void AutofillProfile::GetMultiInfo(const AutofillType& type,
365 const std::string& app_locale,
366 std::vector<base::string16>* values) const {
367 GetMultiInfoImpl(type, app_locale, values);
368 }
369
IsEmpty(const std::string & app_locale) const370 bool AutofillProfile::IsEmpty(const std::string& app_locale) const {
371 ServerFieldTypeSet types;
372 GetNonEmptyTypes(app_locale, &types);
373 return types.empty();
374 }
375
IsPresentButInvalid(ServerFieldType type) const376 bool AutofillProfile::IsPresentButInvalid(ServerFieldType type) const {
377 std::string country = UTF16ToUTF8(GetRawInfo(ADDRESS_HOME_COUNTRY));
378 base::string16 data = GetRawInfo(type);
379 if (data.empty())
380 return false;
381
382 switch (type) {
383 case ADDRESS_HOME_STATE:
384 return country == "US" && !autofill::IsValidState(data);
385
386 case ADDRESS_HOME_ZIP:
387 return country == "US" && !autofill::IsValidZip(data);
388
389 case PHONE_HOME_WHOLE_NUMBER:
390 return !i18n::PhoneObject(data, country).IsValidNumber();
391
392 case EMAIL_ADDRESS:
393 return !autofill::IsValidEmailAddress(data);
394
395 default:
396 NOTREACHED();
397 return false;
398 }
399 }
400
401
Compare(const AutofillProfile & profile) const402 int AutofillProfile::Compare(const AutofillProfile& profile) const {
403 const ServerFieldType single_value_types[] = {
404 COMPANY_NAME,
405 ADDRESS_HOME_LINE1,
406 ADDRESS_HOME_LINE2,
407 ADDRESS_HOME_DEPENDENT_LOCALITY,
408 ADDRESS_HOME_CITY,
409 ADDRESS_HOME_STATE,
410 ADDRESS_HOME_ZIP,
411 ADDRESS_HOME_SORTING_CODE,
412 ADDRESS_HOME_COUNTRY,
413 };
414
415 for (size_t i = 0; i < arraysize(single_value_types); ++i) {
416 int comparison = GetRawInfo(single_value_types[i]).compare(
417 profile.GetRawInfo(single_value_types[i]));
418 if (comparison != 0)
419 return comparison;
420 }
421
422 const ServerFieldType multi_value_types[] = { NAME_FIRST,
423 NAME_MIDDLE,
424 NAME_LAST,
425 EMAIL_ADDRESS,
426 PHONE_HOME_WHOLE_NUMBER };
427
428 for (size_t i = 0; i < arraysize(multi_value_types); ++i) {
429 std::vector<base::string16> values_a;
430 std::vector<base::string16> values_b;
431 GetRawMultiInfo(multi_value_types[i], &values_a);
432 profile.GetRawMultiInfo(multi_value_types[i], &values_b);
433 if (values_a.size() < values_b.size())
434 return -1;
435 if (values_a.size() > values_b.size())
436 return 1;
437 for (size_t j = 0; j < values_a.size(); ++j) {
438 int comparison = values_a[j].compare(values_b[j]);
439 if (comparison != 0)
440 return comparison;
441 }
442 }
443
444 return 0;
445 }
446
operator ==(const AutofillProfile & profile) const447 bool AutofillProfile::operator==(const AutofillProfile& profile) const {
448 return guid() == profile.guid() &&
449 origin() == profile.origin() &&
450 Compare(profile) == 0;
451 }
452
operator !=(const AutofillProfile & profile) const453 bool AutofillProfile::operator!=(const AutofillProfile& profile) const {
454 return !operator==(profile);
455 }
456
PrimaryValue() const457 const base::string16 AutofillProfile::PrimaryValue() const {
458 return GetRawInfo(ADDRESS_HOME_LINE1) + GetRawInfo(ADDRESS_HOME_CITY);
459 }
460
IsSubsetOf(const AutofillProfile & profile,const std::string & app_locale) const461 bool AutofillProfile::IsSubsetOf(const AutofillProfile& profile,
462 const std::string& app_locale) const {
463 ServerFieldTypeSet types;
464 GetNonEmptyTypes(app_locale, &types);
465
466 for (ServerFieldTypeSet::const_iterator it = types.begin(); it != types.end();
467 ++it) {
468 if (*it == NAME_FULL || *it == ADDRESS_HOME_STREET_ADDRESS) {
469 // Ignore the compound "full name" field type. We are only interested in
470 // comparing the constituent parts. For example, if |this| has a middle
471 // name saved, but |profile| lacks one, |profile| could still be a subset
472 // of |this|. Likewise, ignore the compound "street address" type, as we
473 // are only interested in matching line-by-line.
474 continue;
475 } else if (AutofillType(*it).group() == PHONE_HOME) {
476 // Phone numbers should be canonicalized prior to being compared.
477 if (*it != PHONE_HOME_WHOLE_NUMBER) {
478 continue;
479 } else if (!i18n::PhoneNumbersMatch(
480 GetRawInfo(*it),
481 profile.GetRawInfo(*it),
482 UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)),
483 app_locale)) {
484 return false;
485 }
486 } else if (StringToLowerASCII(GetRawInfo(*it)) !=
487 StringToLowerASCII(profile.GetRawInfo(*it))) {
488 return false;
489 }
490 }
491
492 return true;
493 }
494
OverwriteWithOrAddTo(const AutofillProfile & profile,const std::string & app_locale)495 void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile,
496 const std::string& app_locale) {
497 // Verified profiles should never be overwritten with unverified data.
498 DCHECK(!IsVerified() || profile.IsVerified());
499 set_origin(profile.origin());
500
501 ServerFieldTypeSet field_types;
502 profile.GetNonEmptyTypes(app_locale, &field_types);
503
504 // Only transfer "full" types (e.g. full name) and not fragments (e.g.
505 // first name, last name).
506 CollapseCompoundFieldTypes(&field_types);
507
508 // TODO(isherman): Revisit this decision in the context of i18n and storing
509 // full addresses rather than storing 1-to-2 lines of an address.
510 // For addresses, do the opposite: transfer individual address lines, rather
511 // than full addresses.
512 field_types.erase(ADDRESS_HOME_STREET_ADDRESS);
513
514 for (ServerFieldTypeSet::const_iterator iter = field_types.begin();
515 iter != field_types.end(); ++iter) {
516 if (AutofillProfile::SupportsMultiValue(*iter)) {
517 std::vector<base::string16> new_values;
518 profile.GetRawMultiInfo(*iter, &new_values);
519 std::vector<base::string16> existing_values;
520 GetRawMultiInfo(*iter, &existing_values);
521
522 // GetMultiInfo always returns at least one element, even if the profile
523 // has no data stored for this field type.
524 if (existing_values.size() == 1 && existing_values.front().empty())
525 existing_values.clear();
526
527 FieldTypeGroup group = AutofillType(*iter).group();
528 for (std::vector<base::string16>::iterator value_iter =
529 new_values.begin();
530 value_iter != new_values.end(); ++value_iter) {
531 // Don't add duplicates.
532 if (group == PHONE_HOME) {
533 AddPhoneIfUnique(*value_iter, app_locale, &existing_values);
534 } else {
535 std::vector<base::string16>::const_iterator existing_iter =
536 std::find_if(
537 existing_values.begin(), existing_values.end(),
538 std::bind1st(CaseInsensitiveStringEquals(), *value_iter));
539 if (existing_iter == existing_values.end())
540 existing_values.insert(existing_values.end(), *value_iter);
541 }
542 }
543 SetRawMultiInfo(*iter, existing_values);
544 } else {
545 base::string16 new_value = profile.GetRawInfo(*iter);
546 if (StringToLowerASCII(GetRawInfo(*iter)) !=
547 StringToLowerASCII(new_value)) {
548 SetRawInfo(*iter, new_value);
549 }
550 }
551 }
552 }
553
554 // static
SupportsMultiValue(ServerFieldType type)555 bool AutofillProfile::SupportsMultiValue(ServerFieldType type) {
556 FieldTypeGroup group = AutofillType(type).group();
557 return group == NAME ||
558 group == NAME_BILLING ||
559 group == EMAIL ||
560 group == PHONE_HOME ||
561 group == PHONE_BILLING;
562 }
563
564 // static
CreateDifferentiatingLabels(const std::vector<AutofillProfile * > & profiles,std::vector<base::string16> * labels)565 void AutofillProfile::CreateDifferentiatingLabels(
566 const std::vector<AutofillProfile*>& profiles,
567 std::vector<base::string16>* labels) {
568 const size_t kMinimalFieldsShown = 2;
569 CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
570 labels);
571 DCHECK_EQ(profiles.size(), labels->size());
572 }
573
574 // static
CreateInferredLabels(const std::vector<AutofillProfile * > & profiles,const std::vector<ServerFieldType> * suggested_fields,ServerFieldType excluded_field,size_t minimal_fields_shown,std::vector<base::string16> * labels)575 void AutofillProfile::CreateInferredLabels(
576 const std::vector<AutofillProfile*>& profiles,
577 const std::vector<ServerFieldType>* suggested_fields,
578 ServerFieldType excluded_field,
579 size_t minimal_fields_shown,
580 std::vector<base::string16>* labels) {
581 std::vector<ServerFieldType> fields_to_use;
582 GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
583 &fields_to_use);
584
585 // Construct the default label for each profile. Also construct a map that
586 // associates each label with the profiles that have this label. This map is
587 // then used to detect which labels need further differentiating fields.
588 std::map<base::string16, std::list<size_t> > labels_to_profiles;
589 for (size_t i = 0; i < profiles.size(); ++i) {
590 base::string16 label =
591 profiles[i]->ConstructInferredLabel(fields_to_use,
592 minimal_fields_shown);
593 labels_to_profiles[label].push_back(i);
594 }
595
596 labels->resize(profiles.size());
597 for (std::map<base::string16, std::list<size_t> >::const_iterator it =
598 labels_to_profiles.begin();
599 it != labels_to_profiles.end(); ++it) {
600 if (it->second.size() == 1) {
601 // This label is unique, so use it without any further ado.
602 base::string16 label = it->first;
603 size_t profile_index = it->second.front();
604 (*labels)[profile_index] = label;
605 } else {
606 // We have more than one profile with the same label, so add
607 // differentiating fields.
608 CreateInferredLabelsHelper(profiles, it->second, fields_to_use,
609 minimal_fields_shown, labels);
610 }
611 }
612 }
613
GetSupportedTypes(ServerFieldTypeSet * supported_types) const614 void AutofillProfile::GetSupportedTypes(
615 ServerFieldTypeSet* supported_types) const {
616 FormGroupList info = FormGroups();
617 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
618 (*it)->GetSupportedTypes(supported_types);
619 }
620
GetMultiInfoImpl(const AutofillType & type,const std::string & app_locale,std::vector<base::string16> * values) const621 void AutofillProfile::GetMultiInfoImpl(
622 const AutofillType& type,
623 const std::string& app_locale,
624 std::vector<base::string16>* values) const {
625 switch (type.group()) {
626 case NAME:
627 case NAME_BILLING:
628 CopyItemsToValues(type, name_, app_locale, values);
629 break;
630 case EMAIL:
631 CopyItemsToValues(type, email_, app_locale, values);
632 break;
633 case PHONE_HOME:
634 case PHONE_BILLING:
635 CopyItemsToValues(type, phone_number_, app_locale, values);
636 break;
637 default:
638 values->resize(1);
639 (*values)[0] = GetFormGroupInfo(*this, type, app_locale);
640 }
641 }
642
AddPhoneIfUnique(const base::string16 & phone,const std::string & app_locale,std::vector<base::string16> * existing_phones)643 void AutofillProfile::AddPhoneIfUnique(
644 const base::string16& phone,
645 const std::string& app_locale,
646 std::vector<base::string16>* existing_phones) {
647 DCHECK(existing_phones);
648 // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377",
649 // "(800)356-9377" and "356-9377" are considered the same.
650 std::string country_code = UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY));
651 if (std::find_if(existing_phones->begin(), existing_phones->end(),
652 FindByPhone(phone, country_code, app_locale)) ==
653 existing_phones->end()) {
654 existing_phones->push_back(phone);
655 }
656 }
657
ConstructInferredLabel(const std::vector<ServerFieldType> & included_fields,size_t num_fields_to_use) const658 base::string16 AutofillProfile::ConstructInferredLabel(
659 const std::vector<ServerFieldType>& included_fields,
660 size_t num_fields_to_use) const {
661 const base::string16 separator =
662 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
663
664 base::string16 label;
665 size_t num_fields_used = 0;
666 for (std::vector<ServerFieldType>::const_iterator it =
667 included_fields.begin();
668 it != included_fields.end() && num_fields_used < num_fields_to_use;
669 ++it) {
670 base::string16 field = GetRawInfo(*it);
671 if (field.empty())
672 continue;
673
674 if (!label.empty())
675 label.append(separator);
676
677 label.append(field);
678 ++num_fields_used;
679 }
680
681 // Flatten the label if need be.
682 const char16 kNewline[] = { '\n', 0 };
683 const base::string16 newline_separator =
684 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_SEPARATOR);
685 base::ReplaceChars(label, kNewline, newline_separator, &label);
686
687 return label;
688 }
689
690 // static
CreateInferredLabelsHelper(const std::vector<AutofillProfile * > & profiles,const std::list<size_t> & indices,const std::vector<ServerFieldType> & fields,size_t num_fields_to_include,std::vector<base::string16> * labels)691 void AutofillProfile::CreateInferredLabelsHelper(
692 const std::vector<AutofillProfile*>& profiles,
693 const std::list<size_t>& indices,
694 const std::vector<ServerFieldType>& fields,
695 size_t num_fields_to_include,
696 std::vector<base::string16>* labels) {
697 // For efficiency, we first construct a map of fields to their text values and
698 // each value's frequency.
699 std::map<ServerFieldType,
700 std::map<base::string16, size_t> > field_text_frequencies_by_field;
701 for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
702 field != fields.end(); ++field) {
703 std::map<base::string16, size_t>& field_text_frequencies =
704 field_text_frequencies_by_field[*field];
705
706 for (std::list<size_t>::const_iterator it = indices.begin();
707 it != indices.end(); ++it) {
708 const AutofillProfile* profile = profiles[*it];
709 base::string16 field_text = profile->GetRawInfo(*field);
710
711 // If this label is not already in the map, add it with frequency 0.
712 if (!field_text_frequencies.count(field_text))
713 field_text_frequencies[field_text] = 0;
714
715 // Now, increment the frequency for this label.
716 ++field_text_frequencies[field_text];
717 }
718 }
719
720 // Now comes the meat of the algorithm. For each profile, we scan the list of
721 // fields to use, looking for two things:
722 // 1. A (non-empty) field that differentiates the profile from all others
723 // 2. At least |num_fields_to_include| non-empty fields
724 // Before we've satisfied condition (2), we include all fields, even ones that
725 // are identical across all the profiles. Once we've satisfied condition (2),
726 // we only include fields that that have at last two distinct values.
727 for (std::list<size_t>::const_iterator it = indices.begin();
728 it != indices.end(); ++it) {
729 const AutofillProfile* profile = profiles[*it];
730
731 std::vector<ServerFieldType> label_fields;
732 bool found_differentiating_field = false;
733 for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
734 field != fields.end(); ++field) {
735 // Skip over empty fields.
736 base::string16 field_text = profile->GetRawInfo(*field);
737 if (field_text.empty())
738 continue;
739
740 std::map<base::string16, size_t>& field_text_frequencies =
741 field_text_frequencies_by_field[*field];
742 found_differentiating_field |=
743 !field_text_frequencies.count(base::string16()) &&
744 (field_text_frequencies[field_text] == 1);
745
746 // Once we've found enough non-empty fields, skip over any remaining
747 // fields that are identical across all the profiles.
748 if (label_fields.size() >= num_fields_to_include &&
749 (field_text_frequencies.size() == 1))
750 continue;
751
752 label_fields.push_back(*field);
753
754 // If we've (1) found a differentiating field and (2) found at least
755 // |num_fields_to_include| non-empty fields, we're done!
756 if (found_differentiating_field &&
757 label_fields.size() >= num_fields_to_include)
758 break;
759 }
760
761 (*labels)[*it] =
762 profile->ConstructInferredLabel(label_fields, label_fields.size());
763 }
764 }
765
FormGroups() const766 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
767 FormGroupList v(5);
768 v[0] = &name_[0];
769 v[1] = &email_[0];
770 v[2] = &company_;
771 v[3] = &phone_number_[0];
772 v[4] = &address_;
773 return v;
774 }
775
FormGroupForType(const AutofillType & type) const776 const FormGroup* AutofillProfile::FormGroupForType(
777 const AutofillType& type) const {
778 return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
779 }
780
MutableFormGroupForType(const AutofillType & type)781 FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) {
782 switch (type.group()) {
783 case NAME:
784 case NAME_BILLING:
785 return &name_[0];
786
787 case EMAIL:
788 return &email_[0];
789
790 case COMPANY:
791 return &company_;
792
793 case PHONE_HOME:
794 case PHONE_BILLING:
795 return &phone_number_[0];
796
797 case ADDRESS_HOME:
798 case ADDRESS_BILLING:
799 return &address_;
800
801 case NO_GROUP:
802 case CREDIT_CARD:
803 case PASSWORD_FIELD:
804 return NULL;
805 }
806
807 NOTREACHED();
808 return NULL;
809 }
810
811 // So we can compare AutofillProfiles with EXPECT_EQ().
operator <<(std::ostream & os,const AutofillProfile & profile)812 std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
813 return os
814 << profile.guid()
815 << " "
816 << profile.origin()
817 << " "
818 << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
819 << " "
820 << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
821 << " "
822 << UTF16ToUTF8(MultiString(profile, NAME_LAST))
823 << " "
824 << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
825 << " "
826 << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME))
827 << " "
828 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1))
829 << " "
830 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2))
831 << " "
832 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))
833 << " "
834 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY))
835 << " "
836 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE))
837 << " "
838 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP))
839 << " "
840 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE))
841 << " "
842 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))
843 << " "
844 << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER));
845 }
846
847 } // namespace autofill
848