• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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