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