• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "chrome/browser/autofill/autofill_profile.h"
6 
7 #include <algorithm>
8 #include <map>
9 #include <set>
10 
11 #include "base/basictypes.h"
12 #include "base/logging.h"
13 #include "base/string_util.h"
14 #include "base/utf_string_conversions.h"
15 #include "chrome/browser/autofill/address.h"
16 #include "chrome/browser/autofill/autofill_type.h"
17 #include "chrome/browser/autofill/contact_info.h"
18 #include "chrome/browser/autofill/fax_number.h"
19 #include "chrome/browser/autofill/home_phone_number.h"
20 #include "chrome/common/guid.h"
21 #include "grit/generated_resources.h"
22 #include "ui/base/l10n/l10n_util.h"
23 
24 namespace {
25 
26 // Like |AutofillType::GetEquivalentFieldType()|, but also returns |NAME_FULL|
27 // for first, middle, and last name field types.
GetEquivalentFieldTypeCollapsingNames(AutofillFieldType field_type)28 AutofillFieldType GetEquivalentFieldTypeCollapsingNames(
29     AutofillFieldType field_type) {
30   if (field_type == NAME_FIRST || field_type == NAME_MIDDLE ||
31       field_type == NAME_LAST)
32     return NAME_FULL;
33 
34   return AutofillType::GetEquivalentFieldType(field_type);
35 }
36 
37 // Fills |distinguishing_fields| with a list of fields to use when creating
38 // labels that can help to distinguish between two profiles. Draws fields from
39 // |suggested_fields| if it is non-NULL; otherwise returns a default list.
40 // If |suggested_fields| is non-NULL, does not include |excluded_field| in the
41 // list. Otherwise, |excluded_field| is ignored, and should be set to
42 // |UNKNOWN_TYPE| by convention. The resulting list of fields is sorted in
43 // decreasing order of importance.
GetFieldsForDistinguishingProfiles(const std::vector<AutofillFieldType> * suggested_fields,AutofillFieldType excluded_field,std::vector<AutofillFieldType> * distinguishing_fields)44 void GetFieldsForDistinguishingProfiles(
45     const std::vector<AutofillFieldType>* suggested_fields,
46     AutofillFieldType excluded_field,
47     std::vector<AutofillFieldType>* distinguishing_fields) {
48   static const AutofillFieldType kDefaultDistinguishingFields[] = {
49     NAME_FULL,
50     ADDRESS_HOME_LINE1,
51     ADDRESS_HOME_CITY,
52     ADDRESS_HOME_STATE,
53     ADDRESS_HOME_ZIP,
54     ADDRESS_HOME_COUNTRY,
55     EMAIL_ADDRESS,
56     PHONE_HOME_WHOLE_NUMBER,
57     PHONE_FAX_WHOLE_NUMBER,
58     COMPANY_NAME,
59   };
60 
61   if (!suggested_fields) {
62     DCHECK_EQ(excluded_field, UNKNOWN_TYPE);
63     distinguishing_fields->assign(
64         kDefaultDistinguishingFields,
65         kDefaultDistinguishingFields + arraysize(kDefaultDistinguishingFields));
66     return;
67   }
68 
69   // Keep track of which fields we've seen so that we avoid duplicate entries.
70   // Always ignore fields of unknown type and the excluded field.
71   std::set<AutofillFieldType> seen_fields;
72   seen_fields.insert(UNKNOWN_TYPE);
73   seen_fields.insert(GetEquivalentFieldTypeCollapsingNames(excluded_field));
74 
75   distinguishing_fields->clear();
76   for (std::vector<AutofillFieldType>::const_iterator it =
77            suggested_fields->begin();
78        it != suggested_fields->end(); ++it) {
79     AutofillFieldType suggested_type =
80         GetEquivalentFieldTypeCollapsingNames(*it);
81     if (seen_fields.insert(suggested_type).second)
82       distinguishing_fields->push_back(suggested_type);
83   }
84 
85   // Special case: If the excluded field is a partial name (e.g. first name) and
86   // the suggested fields include other name fields, include |NAME_FULL| in the
87   // list of distinguishing fields as a last-ditch fallback. This allows us to
88   // distinguish between profiles that are identical except for the name.
89   if (excluded_field != NAME_FULL &&
90       GetEquivalentFieldTypeCollapsingNames(excluded_field) == NAME_FULL) {
91     for (std::vector<AutofillFieldType>::const_iterator it =
92              suggested_fields->begin();
93          it != suggested_fields->end(); ++it) {
94       if (*it != excluded_field &&
95           GetEquivalentFieldTypeCollapsingNames(*it) == NAME_FULL) {
96         distinguishing_fields->push_back(NAME_FULL);
97         break;
98       }
99     }
100   }
101 }
102 
103 // A helper function for string streaming.  Concatenates multi-valued entries
104 // stored for a given |type| into a single string.  This string is returned.
MultiString(const AutofillProfile & p,AutofillFieldType type)105 const string16 MultiString(const AutofillProfile& p, AutofillFieldType type) {
106   std::vector<string16> values;
107   p.GetMultiInfo(type, &values);
108   string16 accumulate;
109   for (size_t i = 0; i < values.size(); ++i) {
110     if (i > 0)
111       accumulate += ASCIIToUTF16(" ");
112     accumulate += values[i];
113   }
114   return accumulate;
115 }
116 
117 template <class T>
CopyValuesToItems(AutofillFieldType type,const std::vector<string16> & values,std::vector<T> * form_group_items)118 void CopyValuesToItems(AutofillFieldType type,
119                        const std::vector<string16>& values,
120                        std::vector<T>* form_group_items) {
121   form_group_items->resize(values.size());
122   for (size_t i = 0; i < form_group_items->size(); ++i)
123     (*form_group_items)[i].SetInfo(type, CollapseWhitespace(values[i], false));
124   // Must have at least one (possibly empty) element.
125   if (form_group_items->empty())
126     form_group_items->resize(1);
127 }
128 
129 template <class T>
CopyItemsToValues(AutofillFieldType type,const std::vector<T> & form_group_items,std::vector<string16> * values)130 void CopyItemsToValues(AutofillFieldType type,
131                        const std::vector<T>& form_group_items,
132                        std::vector<string16>* values) {
133   values->resize(form_group_items.size());
134   for (size_t i = 0; i < values->size(); ++i)
135     (*values)[i] = form_group_items[i].GetInfo(type);
136 }
137 
138 // Collapse compound field types to their "full" type.  I.e. First name
139 // collapses to full name, area code collapses to full phone, etc.
CollapseCompoundFieldTypes(FieldTypeSet * type_set)140 void CollapseCompoundFieldTypes(FieldTypeSet* type_set) {
141   FieldTypeSet collapsed_set;
142   for (FieldTypeSet::iterator iter = type_set->begin(); iter != type_set->end();
143        ++iter) {
144     switch (*iter) {
145       case NAME_FIRST:
146       case NAME_MIDDLE:
147       case NAME_LAST:
148       case NAME_MIDDLE_INITIAL:
149       case NAME_FULL:
150       case NAME_SUFFIX:
151         collapsed_set.insert(NAME_FULL);
152         break;
153 
154       case PHONE_HOME_NUMBER:
155       case PHONE_HOME_CITY_CODE:
156       case PHONE_HOME_COUNTRY_CODE:
157       case PHONE_HOME_CITY_AND_NUMBER:
158       case PHONE_HOME_WHOLE_NUMBER:
159         collapsed_set.insert(PHONE_HOME_WHOLE_NUMBER);
160         break;
161 
162       case PHONE_FAX_NUMBER:
163       case PHONE_FAX_CITY_CODE:
164       case PHONE_FAX_COUNTRY_CODE:
165       case PHONE_FAX_CITY_AND_NUMBER:
166       case PHONE_FAX_WHOLE_NUMBER:
167         collapsed_set.insert(PHONE_FAX_WHOLE_NUMBER);
168         break;
169 
170       default:
171         collapsed_set.insert(*iter);
172     }
173   }
174   std::swap(*type_set, collapsed_set);
175 }
176 
177 }  // namespace
178 
AutofillProfile(const std::string & guid)179 AutofillProfile::AutofillProfile(const std::string& guid)
180     : guid_(guid), name_(1), email_(1), home_number_(1), fax_number_(1) {
181 }
182 
AutofillProfile()183 AutofillProfile::AutofillProfile()
184     : guid_(guid::GenerateGUID()),
185       name_(1),
186       email_(1),
187       home_number_(1),
188       fax_number_(1) {
189 }
190 
AutofillProfile(const AutofillProfile & profile)191 AutofillProfile::AutofillProfile(const AutofillProfile& profile)
192     : FormGroup() {
193   operator=(profile);
194 }
195 
~AutofillProfile()196 AutofillProfile::~AutofillProfile() {
197 }
198 
operator =(const AutofillProfile & profile)199 AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
200   if (this == &profile)
201     return *this;
202 
203   label_ = profile.label_;
204   guid_ = profile.guid_;
205 
206   name_ = profile.name_;
207   email_ = profile.email_;
208   company_ = profile.company_;
209   home_number_ = profile.home_number_;
210   fax_number_ = profile.fax_number_;
211   address_ = profile.address_;
212 
213   return *this;
214 }
215 
GetPossibleFieldTypes(const string16 & text,FieldTypeSet * possible_types) const216 void AutofillProfile::GetPossibleFieldTypes(
217     const string16& text,
218     FieldTypeSet* possible_types) const {
219   FormGroupList info = FormGroups();
220   for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
221     (*it)->GetPossibleFieldTypes(text, possible_types);
222 }
223 
GetAvailableFieldTypes(FieldTypeSet * available_types) const224 void AutofillProfile::GetAvailableFieldTypes(
225     FieldTypeSet* available_types) const {
226   FormGroupList info = FormGroups();
227   for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
228     (*it)->GetAvailableFieldTypes(available_types);
229 }
230 
GetInfo(AutofillFieldType type) const231 string16 AutofillProfile::GetInfo(AutofillFieldType type) const {
232   AutofillFieldType return_type = AutofillType::GetEquivalentFieldType(type);
233   const FormGroup* form_group = FormGroupForType(return_type);
234   if (!form_group)
235     return string16();
236 
237   return form_group->GetInfo(return_type);
238 }
239 
SetInfo(AutofillFieldType type,const string16 & value)240 void AutofillProfile::SetInfo(AutofillFieldType type, const string16& value) {
241   FormGroup* form_group = MutableFormGroupForType(type);
242   if (form_group)
243     form_group->SetInfo(type, CollapseWhitespace(value, false));
244 }
245 
SetMultiInfo(AutofillFieldType type,const std::vector<string16> & values)246 void AutofillProfile::SetMultiInfo(AutofillFieldType type,
247                                    const std::vector<string16>& values) {
248   switch (AutofillType(type).group()) {
249     case AutofillType::NAME:
250       CopyValuesToItems(type, values, &name_);
251       break;
252     case AutofillType::EMAIL:
253       CopyValuesToItems(type, values, &email_);
254       break;
255     case AutofillType::PHONE_HOME:
256       CopyValuesToItems(type, values, &home_number_);
257       break;
258     case AutofillType::PHONE_FAX:
259       CopyValuesToItems(type, values, &fax_number_);
260       break;
261     default:
262       if (values.size() == 1) {
263         SetInfo(type, values[0]);
264       } else if (values.size() == 0) {
265         SetInfo(type, string16());
266       } else {
267         NOTREACHED()
268             << "Attempt to set multiple values on single-valued field.";
269       }
270       break;
271   }
272 }
273 
GetMultiInfo(AutofillFieldType type,std::vector<string16> * values) const274 void AutofillProfile::GetMultiInfo(AutofillFieldType type,
275                                    std::vector<string16>* values) const {
276   switch (AutofillType(type).group()) {
277     case AutofillType::NAME:
278       CopyItemsToValues(type, name_, values);
279       break;
280     case AutofillType::EMAIL:
281       CopyItemsToValues(type, email_, values);
282       break;
283     case AutofillType::PHONE_HOME:
284       CopyItemsToValues(type, home_number_, values);
285       break;
286     case AutofillType::PHONE_FAX:
287       CopyItemsToValues(type, fax_number_, values);
288       break;
289     default:
290       values->resize(1);
291       (*values)[0] = GetInfo(type);
292   }
293 }
294 
295 // static
SupportsMultiValue(AutofillFieldType type)296 bool AutofillProfile::SupportsMultiValue(AutofillFieldType type) {
297   AutofillType::FieldTypeGroup group = AutofillType(type).group();
298   return group == AutofillType::NAME ||
299          group == AutofillType::EMAIL ||
300          group == AutofillType::PHONE_HOME ||
301          group == AutofillType::PHONE_FAX;
302 }
303 
Label() const304 const string16 AutofillProfile::Label() const {
305   return label_;
306 }
307 
CountryCode() const308 const std::string AutofillProfile::CountryCode() const {
309   return address_.country_code();
310 }
311 
SetCountryCode(const std::string & country_code)312 void AutofillProfile::SetCountryCode(const std::string& country_code) {
313   address_.set_country_code(country_code);
314 }
315 
316 // static
AdjustInferredLabels(std::vector<AutofillProfile * > * profiles)317 bool AutofillProfile::AdjustInferredLabels(
318     std::vector<AutofillProfile*>* profiles) {
319   const size_t kMinimalFieldsShown = 2;
320 
321   std::vector<string16> created_labels;
322   CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
323                        &created_labels);
324   DCHECK_EQ(profiles->size(), created_labels.size());
325 
326   bool updated_labels = false;
327   for (size_t i = 0; i < profiles->size(); ++i) {
328     if ((*profiles)[i]->Label() != created_labels[i]) {
329       updated_labels = true;
330       (*profiles)[i]->label_ = created_labels[i];
331     }
332   }
333   return updated_labels;
334 }
335 
336 // static
CreateInferredLabels(const std::vector<AutofillProfile * > * profiles,const std::vector<AutofillFieldType> * suggested_fields,AutofillFieldType excluded_field,size_t minimal_fields_shown,std::vector<string16> * created_labels)337 void AutofillProfile::CreateInferredLabels(
338     const std::vector<AutofillProfile*>* profiles,
339     const std::vector<AutofillFieldType>* suggested_fields,
340     AutofillFieldType excluded_field,
341     size_t minimal_fields_shown,
342     std::vector<string16>* created_labels) {
343   DCHECK(profiles);
344   DCHECK(created_labels);
345 
346   std::vector<AutofillFieldType> fields_to_use;
347   GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
348                                      &fields_to_use);
349 
350   // Construct the default label for each profile. Also construct a map that
351   // associates each label with the profiles that have this label. This map is
352   // then used to detect which labels need further differentiating fields.
353   std::map<string16, std::list<size_t> > labels;
354   for (size_t i = 0; i < profiles->size(); ++i) {
355     string16 label =
356         (*profiles)[i]->ConstructInferredLabel(fields_to_use,
357                                                minimal_fields_shown);
358     labels[label].push_back(i);
359   }
360 
361   created_labels->resize(profiles->size());
362   for (std::map<string16, std::list<size_t> >::const_iterator it =
363            labels.begin();
364        it != labels.end(); ++it) {
365     if (it->second.size() == 1) {
366       // This label is unique, so use it without any further ado.
367       string16 label = it->first;
368       size_t profile_index = it->second.front();
369       (*created_labels)[profile_index] = label;
370     } else {
371       // We have more than one profile with the same label, so add
372       // differentiating fields.
373       CreateDifferentiatingLabels(*profiles, it->second, fields_to_use,
374                                   minimal_fields_shown, created_labels);
375     }
376   }
377 }
378 
IsEmpty() const379 bool AutofillProfile::IsEmpty() const {
380   FieldTypeSet types;
381   GetAvailableFieldTypes(&types);
382   return types.empty();
383 }
384 
Compare(const AutofillProfile & profile) const385 int AutofillProfile::Compare(const AutofillProfile& profile) const {
386   // The following Autofill field types are the only types we store in the WebDB
387   // so far, so we're only concerned with matching these types in the profile.
388   const AutofillFieldType types[] = { NAME_FIRST,
389                                       NAME_MIDDLE,
390                                       NAME_LAST,
391                                       EMAIL_ADDRESS,
392                                       COMPANY_NAME,
393                                       ADDRESS_HOME_LINE1,
394                                       ADDRESS_HOME_LINE2,
395                                       ADDRESS_HOME_CITY,
396                                       ADDRESS_HOME_STATE,
397                                       ADDRESS_HOME_ZIP,
398                                       ADDRESS_HOME_COUNTRY,
399                                       PHONE_HOME_NUMBER,
400                                       PHONE_FAX_NUMBER };
401 
402   for (size_t index = 0; index < arraysize(types); ++index) {
403     int comparison = GetInfo(types[index]).compare(
404         profile.GetInfo(types[index]));
405     if (comparison != 0)
406       return comparison;
407   }
408 
409   return 0;
410 }
411 
CompareMulti(const AutofillProfile & profile) const412 int AutofillProfile::CompareMulti(const AutofillProfile& profile) const {
413   const AutofillFieldType single_value_types[] = { COMPANY_NAME,
414                                                    ADDRESS_HOME_LINE1,
415                                                    ADDRESS_HOME_LINE2,
416                                                    ADDRESS_HOME_CITY,
417                                                    ADDRESS_HOME_STATE,
418                                                    ADDRESS_HOME_ZIP,
419                                                    ADDRESS_HOME_COUNTRY };
420 
421   for (size_t i = 0; i < arraysize(single_value_types); ++i) {
422     int comparison = GetInfo(single_value_types[i]).compare(
423         profile.GetInfo(single_value_types[i]));
424     if (comparison != 0)
425       return comparison;
426   }
427 
428   const AutofillFieldType multi_value_types[] = { NAME_FIRST,
429                                                   NAME_MIDDLE,
430                                                   NAME_LAST,
431                                                   EMAIL_ADDRESS,
432                                                   PHONE_HOME_NUMBER,
433                                                   PHONE_FAX_NUMBER };
434 
435   for (size_t i = 0; i < arraysize(multi_value_types); ++i) {
436     std::vector<string16> values_a;
437     std::vector<string16> values_b;
438     GetMultiInfo(multi_value_types[i], &values_a);
439     profile.GetMultiInfo(multi_value_types[i], &values_b);
440     if (values_a.size() < values_b.size())
441       return -1;
442     if (values_a.size() > values_b.size())
443       return 1;
444     for (size_t j = 0; j < values_a.size(); ++j) {
445       int comparison = values_a[j].compare(values_b[j]);
446       if (comparison != 0)
447         return comparison;
448     }
449   }
450 
451   return 0;
452 }
453 
operator ==(const AutofillProfile & profile) const454 bool AutofillProfile::operator==(const AutofillProfile& profile) const {
455   return guid_ == profile.guid_ && Compare(profile) == 0;
456 }
457 
operator !=(const AutofillProfile & profile) const458 bool AutofillProfile::operator!=(const AutofillProfile& profile) const {
459   return !operator==(profile);
460 }
461 
PrimaryValue() const462 const string16 AutofillProfile::PrimaryValue() const {
463   return GetInfo(ADDRESS_HOME_LINE1) +
464          GetInfo(ADDRESS_HOME_CITY);
465 }
466 
OverwriteWithOrAddTo(const AutofillProfile & profile)467 void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile) {
468   FieldTypeSet field_types;
469   profile.GetAvailableFieldTypes(&field_types);
470 
471   // Only transfer "full" types (e.g. full name) and not fragments (e.g.
472   // first name, last name).
473   CollapseCompoundFieldTypes(&field_types);
474 
475   for (FieldTypeSet::const_iterator iter = field_types.begin();
476        iter != field_types.end(); ++iter) {
477     if (AutofillProfile::SupportsMultiValue(*iter)) {
478       std::vector<string16> new_values;
479       profile.GetMultiInfo(*iter, &new_values);
480       std::vector<string16> existing_values;
481       GetMultiInfo(*iter, &existing_values);
482       for (std::vector<string16>::iterator value_iter = new_values.begin();
483            value_iter != new_values.end(); ++value_iter) {
484         // Don't add duplicates.
485         if (std::find(existing_values.begin(), existing_values.end(),
486                       *value_iter) == existing_values.end()) {
487           existing_values.insert(existing_values.end(), *value_iter);
488         }
489       }
490       SetMultiInfo(*iter, existing_values);
491     } else {
492       SetInfo(*iter, profile.GetInfo(*iter));
493     }
494   }
495 }
496 
ConstructInferredLabel(const std::vector<AutofillFieldType> & included_fields,size_t num_fields_to_use) const497 string16 AutofillProfile::ConstructInferredLabel(
498     const std::vector<AutofillFieldType>& included_fields,
499     size_t num_fields_to_use) const {
500   const string16 separator =
501       l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_SEPARATOR);
502 
503   string16 label;
504   size_t num_fields_used = 0;
505   for (std::vector<AutofillFieldType>::const_iterator it =
506            included_fields.begin();
507        it != included_fields.end() && num_fields_used < num_fields_to_use;
508        ++it) {
509     string16 field = GetInfo(*it);
510     if (field.empty())
511       continue;
512 
513     if (!label.empty())
514       label.append(separator);
515 
516 #ifndef ANDROID
517     // Fax number has special format, to indicate that this is a fax number.
518     if (*it == PHONE_FAX_WHOLE_NUMBER) {
519       field = l10n_util::GetStringFUTF16(
520           IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_FAX_FORMAT, field);
521     }
522 #endif
523     label.append(field);
524     ++num_fields_used;
525   }
526   return label;
527 }
528 
529 // static
CreateDifferentiatingLabels(const std::vector<AutofillProfile * > & profiles,const std::list<size_t> & indices,const std::vector<AutofillFieldType> & fields,size_t num_fields_to_include,std::vector<string16> * created_labels)530 void AutofillProfile::CreateDifferentiatingLabels(
531     const std::vector<AutofillProfile*>& profiles,
532     const std::list<size_t>& indices,
533     const std::vector<AutofillFieldType>& fields,
534     size_t num_fields_to_include,
535     std::vector<string16>* created_labels) {
536   // For efficiency, we first construct a map of fields to their text values and
537   // each value's frequency.
538   std::map<AutofillFieldType,
539            std::map<string16, size_t> > field_text_frequencies_by_field;
540   for (std::vector<AutofillFieldType>::const_iterator field = fields.begin();
541        field != fields.end(); ++field) {
542     std::map<string16, size_t>& field_text_frequencies =
543         field_text_frequencies_by_field[*field];
544 
545     for (std::list<size_t>::const_iterator it = indices.begin();
546          it != indices.end(); ++it) {
547       const AutofillProfile* profile = profiles[*it];
548       string16 field_text = profile->GetInfo(*field);
549 
550       // If this label is not already in the map, add it with frequency 0.
551       if (!field_text_frequencies.count(field_text))
552         field_text_frequencies[field_text] = 0;
553 
554       // Now, increment the frequency for this label.
555       ++field_text_frequencies[field_text];
556     }
557   }
558 
559   // Now comes the meat of the algorithm. For each profile, we scan the list of
560   // fields to use, looking for two things:
561   //  1. A (non-empty) field that differentiates the profile from all others
562   //  2. At least |num_fields_to_include| non-empty fields
563   // Before we've satisfied condition (2), we include all fields, even ones that
564   // are identical across all the profiles. Once we've satisfied condition (2),
565   // we only include fields that that have at last two distinct values.
566   for (std::list<size_t>::const_iterator it = indices.begin();
567        it != indices.end(); ++it) {
568     const AutofillProfile* profile = profiles[*it];
569 
570     std::vector<AutofillFieldType> label_fields;
571     bool found_differentiating_field = false;
572     for (std::vector<AutofillFieldType>::const_iterator field = fields.begin();
573          field != fields.end(); ++field) {
574       // Skip over empty fields.
575       string16 field_text = profile->GetInfo(*field);
576       if (field_text.empty())
577         continue;
578 
579       std::map<string16, size_t>& field_text_frequencies =
580           field_text_frequencies_by_field[*field];
581       found_differentiating_field |=
582           !field_text_frequencies.count(string16()) &&
583           (field_text_frequencies[field_text] == 1);
584 
585       // Once we've found enough non-empty fields, skip over any remaining
586       // fields that are identical across all the profiles.
587       if (label_fields.size() >= num_fields_to_include &&
588           (field_text_frequencies.size() == 1))
589         continue;
590 
591       label_fields.push_back(*field);
592 
593       // If we've (1) found a differentiating field and (2) found at least
594       // |num_fields_to_include| non-empty fields, we're done!
595       if (found_differentiating_field &&
596           label_fields.size() >= num_fields_to_include)
597         break;
598     }
599 
600     (*created_labels)[*it] =
601         profile->ConstructInferredLabel(label_fields,
602                                         label_fields.size());
603   }
604 }
605 
FormGroups() const606 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
607   FormGroupList v(6);
608   v[0] = &name_[0];
609   v[1] = &email_[0];
610   v[2] = &company_;
611   v[3] = &home_number_[0];
612   v[4] = &fax_number_[0];
613   v[5] = &address_;
614   return v;
615 }
616 
FormGroupForType(AutofillFieldType type) const617 const FormGroup* AutofillProfile::FormGroupForType(
618     AutofillFieldType type) const {
619   return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
620 }
621 
MutableFormGroupForType(AutofillFieldType type)622 FormGroup* AutofillProfile::MutableFormGroupForType(AutofillFieldType type) {
623  FormGroup* form_group = NULL;
624   switch (AutofillType(type).group()) {
625     case AutofillType::NAME:
626       form_group = &name_[0];
627       break;
628     case AutofillType::EMAIL:
629       form_group = &email_[0];
630       break;
631     case AutofillType::COMPANY:
632       form_group = &company_;
633       break;
634     case AutofillType::PHONE_HOME:
635       form_group = &home_number_[0];
636       break;
637     case AutofillType::PHONE_FAX:
638       form_group = &fax_number_[0];
639       break;
640     case AutofillType::ADDRESS_HOME:
641       form_group = &address_;
642       break;
643     default:
644       break;
645   }
646   return form_group;
647 }
648 
649 // So we can compare AutofillProfiles with EXPECT_EQ().
operator <<(std::ostream & os,const AutofillProfile & profile)650 std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
651   return os
652       << UTF16ToUTF8(profile.Label())
653       << " "
654       << profile.guid()
655       << " "
656       << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
657       << " "
658       << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
659       << " "
660       << UTF16ToUTF8(MultiString(profile, NAME_LAST))
661       << " "
662       << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
663       << " "
664       << UTF16ToUTF8(profile.GetInfo(COMPANY_NAME))
665       << " "
666       << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE1))
667       << " "
668       << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE2))
669       << " "
670       << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_CITY))
671       << " "
672       << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_STATE))
673       << " "
674       << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_ZIP))
675       << " "
676       << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_COUNTRY))
677       << " "
678       << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER))
679       << " "
680       << UTF16ToUTF8(MultiString(profile, PHONE_FAX_WHOLE_NUMBER));
681 }
682