Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(30)

Side by Side Diff: chrome/browser/autofill/autofill_profile.cc

Issue 12434004: Move remaining Autofill code to //components/autofill. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix long lines Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 <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/string_util.h"
17 #include "base/utf_string_conversions.h"
18 #include "chrome/browser/autofill/address.h"
19 #include "chrome/browser/autofill/autofill_country.h"
20 #include "chrome/browser/autofill/autofill_field.h"
21 #include "chrome/browser/autofill/autofill_type.h"
22 #include "chrome/browser/autofill/contact_info.h"
23 #include "chrome/browser/autofill/phone_number.h"
24 #include "chrome/browser/autofill/phone_number_i18n.h"
25 #include "components/autofill/common/form_field_data.h"
26 #include "grit/generated_resources.h"
27 #include "ui/base/l10n/l10n_util.h"
28
29 namespace {
30
31 // Like |AutofillType::GetEquivalentFieldType()|, but also returns |NAME_FULL|
32 // for first, middle, and last name field types.
33 AutofillFieldType GetEquivalentFieldTypeCollapsingNames(
34 AutofillFieldType field_type) {
35 if (field_type == NAME_FIRST || field_type == NAME_MIDDLE ||
36 field_type == NAME_LAST || field_type == NAME_MIDDLE_INITIAL)
37 return NAME_FULL;
38
39 return AutofillType::GetEquivalentFieldType(field_type);
40 }
41
42 // Fills |distinguishing_fields| with a list of fields to use when creating
43 // labels that can help to distinguish between two profiles. Draws fields from
44 // |suggested_fields| if it is non-NULL; otherwise returns a default list.
45 // If |suggested_fields| is non-NULL, does not include |excluded_field| in the
46 // list. Otherwise, |excluded_field| is ignored, and should be set to
47 // |UNKNOWN_TYPE| by convention. The resulting list of fields is sorted in
48 // decreasing order of importance.
49 void GetFieldsForDistinguishingProfiles(
50 const std::vector<AutofillFieldType>* suggested_fields,
51 AutofillFieldType excluded_field,
52 std::vector<AutofillFieldType>* distinguishing_fields) {
53 static const AutofillFieldType kDefaultDistinguishingFields[] = {
54 NAME_FULL,
55 ADDRESS_HOME_LINE1,
56 ADDRESS_HOME_LINE2,
57 ADDRESS_HOME_CITY,
58 ADDRESS_HOME_STATE,
59 ADDRESS_HOME_ZIP,
60 ADDRESS_HOME_COUNTRY,
61 EMAIL_ADDRESS,
62 PHONE_HOME_WHOLE_NUMBER,
63 COMPANY_NAME,
64 };
65
66 if (!suggested_fields) {
67 DCHECK_EQ(excluded_field, UNKNOWN_TYPE);
68 distinguishing_fields->assign(
69 kDefaultDistinguishingFields,
70 kDefaultDistinguishingFields + arraysize(kDefaultDistinguishingFields));
71 return;
72 }
73
74 // Keep track of which fields we've seen so that we avoid duplicate entries.
75 // Always ignore fields of unknown type and the excluded field.
76 std::set<AutofillFieldType> seen_fields;
77 seen_fields.insert(UNKNOWN_TYPE);
78 seen_fields.insert(GetEquivalentFieldTypeCollapsingNames(excluded_field));
79
80 distinguishing_fields->clear();
81 for (std::vector<AutofillFieldType>::const_iterator it =
82 suggested_fields->begin();
83 it != suggested_fields->end(); ++it) {
84 AutofillFieldType suggested_type =
85 GetEquivalentFieldTypeCollapsingNames(*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 GetEquivalentFieldTypeCollapsingNames(excluded_field) == NAME_FULL) {
96 for (std::vector<AutofillFieldType>::const_iterator it =
97 suggested_fields->begin();
98 it != suggested_fields->end(); ++it) {
99 if (*it != excluded_field &&
100 GetEquivalentFieldTypeCollapsingNames(*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.
110 const string16 MultiString(const AutofillProfile& p, AutofillFieldType type) {
111 std::vector<string16> values;
112 p.GetRawMultiInfo(type, &values);
113 string16 accumulate;
114 for (size_t i = 0; i < values.size(); ++i) {
115 if (i > 0)
116 accumulate += ASCIIToUTF16(" ");
117 accumulate += values[i];
118 }
119 return accumulate;
120 }
121
122 string16 GetFormGroupInfo(const FormGroup& form_group,
123 AutofillFieldType type,
124 const std::string& app_locale) {
125 return app_locale.empty() ?
126 form_group.GetRawInfo(type) :
127 form_group.GetInfo(type, app_locale);
128 }
129
130 template <class T>
131 void CopyValuesToItems(AutofillFieldType type,
132 const std::vector<string16>& values,
133 std::vector<T>* form_group_items,
134 const T& prototype) {
135 form_group_items->resize(values.size(), prototype);
136 for (size_t i = 0; i < form_group_items->size(); ++i) {
137 (*form_group_items)[i].SetRawInfo(type,
138 CollapseWhitespace(values[i], false));
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>
146 void CopyItemsToValues(AutofillFieldType type,
147 const std::vector<T>& form_group_items,
148 const std::string& app_locale,
149 std::vector<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.
158 void CollapseCompoundFieldTypes(FieldTypeSet* type_set) {
159 FieldTypeSet collapsed_set;
160 for (FieldTypeSet::iterator iter = type_set->begin(); iter != type_set->end();
161 ++iter) {
162 switch (*iter) {
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(*iter);
182 }
183 }
184 std::swap(*type_set, collapsed_set);
185 }
186
187 class FindByPhone {
188 public:
189 FindByPhone(const string16& phone, const std::string& country_code)
190 : phone_(phone),
191 country_code_(country_code) {
192 }
193
194 bool operator()(const string16& phone) {
195 return autofill_i18n::PhoneNumbersMatch(phone, phone_, country_code_);
196 }
197
198 bool operator()(const string16* phone) {
199 return autofill_i18n::PhoneNumbersMatch(*phone, phone_, country_code_);
200 }
201
202 private:
203 string16 phone_;
204 std::string country_code_;
205 };
206
207 // Functor used to check for case-insensitive equality of two strings.
208 struct CaseInsensitiveStringEquals
209 : public std::binary_function<string16, string16, bool>
210 {
211 bool operator()(const string16& x, const string16& y) const {
212 return
213 x.size() == y.size() && StringToLowerASCII(x) == StringToLowerASCII(y);
214 }
215 };
216
217 } // namespace
218
219 AutofillProfile::AutofillProfile(const std::string& guid)
220 : guid_(guid),
221 name_(1),
222 email_(1),
223 home_number_(1, PhoneNumber(this)) {
224 }
225
226 AutofillProfile::AutofillProfile()
227 : guid_(base::GenerateGUID()),
228 name_(1),
229 email_(1),
230 home_number_(1, PhoneNumber(this)) {
231 }
232
233 AutofillProfile::AutofillProfile(const AutofillProfile& profile)
234 : FormGroup() {
235 operator=(profile);
236 }
237
238 AutofillProfile::~AutofillProfile() {
239 }
240
241 AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
242 if (this == &profile)
243 return *this;
244
245 label_ = profile.label_;
246 guid_ = profile.guid_;
247
248 name_ = profile.name_;
249 email_ = profile.email_;
250 company_ = profile.company_;
251 home_number_ = profile.home_number_;
252
253 for (size_t i = 0; i < home_number_.size(); ++i)
254 home_number_[i].set_profile(this);
255
256 address_ = profile.address_;
257
258 return *this;
259 }
260
261 std::string AutofillProfile::GetGUID() const {
262 return guid();
263 }
264
265 void AutofillProfile::GetMatchingTypes(const string16& text,
266 const std::string& app_locale,
267 FieldTypeSet* matching_types) const {
268 FormGroupList info = FormGroups();
269 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
270 (*it)->GetMatchingTypes(text, app_locale, matching_types);
271 }
272
273 string16 AutofillProfile::GetRawInfo(AutofillFieldType type) const {
274 AutofillFieldType return_type = AutofillType::GetEquivalentFieldType(type);
275 const FormGroup* form_group = FormGroupForType(return_type);
276 if (!form_group)
277 return string16();
278
279 return form_group->GetRawInfo(return_type);
280 }
281
282 void AutofillProfile::SetRawInfo(AutofillFieldType type,
283 const string16& value) {
284 FormGroup* form_group = MutableFormGroupForType(type);
285 if (form_group)
286 form_group->SetRawInfo(type, CollapseWhitespace(value, false));
287 }
288
289 string16 AutofillProfile::GetInfo(AutofillFieldType type,
290 const std::string& app_locale) const {
291 AutofillFieldType return_type = AutofillType::GetEquivalentFieldType(type);
292 const FormGroup* form_group = FormGroupForType(return_type);
293 if (!form_group)
294 return string16();
295
296 return form_group->GetInfo(return_type, app_locale);
297 }
298
299 bool AutofillProfile::SetInfo(AutofillFieldType type,
300 const string16& value,
301 const std::string& app_locale) {
302 FormGroup* form_group = MutableFormGroupForType(type);
303 if (!form_group)
304 return false;
305
306 return
307 form_group->SetInfo(type, CollapseWhitespace(value, false), app_locale);
308 }
309
310 void AutofillProfile::SetRawMultiInfo(AutofillFieldType type,
311 const std::vector<string16>& values) {
312 switch (AutofillType(type).group()) {
313 case AutofillType::NAME:
314 CopyValuesToItems(type, values, &name_, NameInfo());
315 break;
316 case AutofillType::EMAIL:
317 CopyValuesToItems(type, values, &email_, EmailInfo());
318 break;
319 case AutofillType::PHONE:
320 CopyValuesToItems(type,
321 values,
322 &home_number_,
323 PhoneNumber(this));
324 break;
325 default:
326 if (values.size() == 1) {
327 SetRawInfo(type, values[0]);
328 } else if (values.size() == 0) {
329 SetRawInfo(type, string16());
330 } else {
331 // Shouldn't attempt to set multiple values on single-valued field.
332 NOTREACHED();
333 }
334 break;
335 }
336 }
337
338 void AutofillProfile::GetRawMultiInfo(AutofillFieldType type,
339 std::vector<string16>* values) const {
340 GetMultiInfoImpl(type, std::string(), values);
341 }
342
343 void AutofillProfile::GetMultiInfo(AutofillFieldType type,
344 const std::string& app_locale,
345 std::vector<string16>* values) const {
346 GetMultiInfoImpl(type, app_locale, values);
347 }
348
349 void AutofillProfile::FillFormField(const AutofillField& field,
350 size_t variant,
351 FormFieldData* field_data) const {
352 AutofillFieldType type = field.type();
353 DCHECK_NE(AutofillType::CREDIT_CARD, AutofillType(type).group());
354 DCHECK(field_data);
355
356 if (type == PHONE_HOME_NUMBER) {
357 FillPhoneNumberField(field, variant, field_data);
358 } else if (field_data->form_control_type == "select-one") {
359 FillSelectControl(type, field_data);
360 } else {
361 std::vector<string16> values;
362 GetMultiInfo(type, AutofillCountry::ApplicationLocale(), &values);
363 if (variant >= values.size()) {
364 // If the variant is unavailable, bail. This case is reachable, for
365 // example if Sync updates a profile during the filling process.
366 return;
367 }
368
369 field_data->value = values[variant];
370 }
371 }
372
373 void AutofillProfile::FillPhoneNumberField(const AutofillField& field,
374 size_t variant,
375 FormFieldData* field_data) const {
376 std::vector<string16> values;
377 GetMultiInfo(field.type(), AutofillCountry::ApplicationLocale(), &values);
378 DCHECK(variant < values.size());
379
380 // If we are filling a phone number, check to see if the size field
381 // matches the "prefix" or "suffix" sizes and fill accordingly.
382 string16 number = values[variant];
383 if (number.length() ==
384 PhoneNumber::kPrefixLength + PhoneNumber::kSuffixLength) {
385 if (field.phone_part() == AutofillField::PHONE_PREFIX ||
386 field_data->max_length == PhoneNumber::kPrefixLength) {
387 number = number.substr(PhoneNumber::kPrefixOffset,
388 PhoneNumber::kPrefixLength);
389 } else if (field.phone_part() == AutofillField::PHONE_SUFFIX ||
390 field_data->max_length == PhoneNumber::kSuffixLength) {
391 number = number.substr(PhoneNumber::kSuffixOffset,
392 PhoneNumber::kSuffixLength);
393 }
394 }
395
396 field_data->value = number;
397 }
398
399 const string16 AutofillProfile::Label() const {
400 return label_;
401 }
402
403 const std::string AutofillProfile::CountryCode() const {
404 return address_.country_code();
405 }
406
407 void AutofillProfile::SetCountryCode(const std::string& country_code) {
408 address_.set_country_code(country_code);
409 }
410
411 bool AutofillProfile::IsEmpty() const {
412 FieldTypeSet types;
413 GetNonEmptyTypes(AutofillCountry::ApplicationLocale(), &types);
414 return types.empty();
415 }
416
417 int AutofillProfile::Compare(const AutofillProfile& profile) const {
418 const AutofillFieldType single_value_types[] = { COMPANY_NAME,
419 ADDRESS_HOME_LINE1,
420 ADDRESS_HOME_LINE2,
421 ADDRESS_HOME_CITY,
422 ADDRESS_HOME_STATE,
423 ADDRESS_HOME_ZIP,
424 ADDRESS_HOME_COUNTRY };
425
426 for (size_t i = 0; i < arraysize(single_value_types); ++i) {
427 int comparison = GetRawInfo(single_value_types[i]).compare(
428 profile.GetRawInfo(single_value_types[i]));
429 if (comparison != 0)
430 return comparison;
431 }
432
433 const AutofillFieldType multi_value_types[] = { NAME_FIRST,
434 NAME_MIDDLE,
435 NAME_LAST,
436 EMAIL_ADDRESS,
437 PHONE_HOME_WHOLE_NUMBER };
438
439 for (size_t i = 0; i < arraysize(multi_value_types); ++i) {
440 std::vector<string16> values_a;
441 std::vector<string16> values_b;
442 GetRawMultiInfo(multi_value_types[i], &values_a);
443 profile.GetRawMultiInfo(multi_value_types[i], &values_b);
444 if (values_a.size() < values_b.size())
445 return -1;
446 if (values_a.size() > values_b.size())
447 return 1;
448 for (size_t j = 0; j < values_a.size(); ++j) {
449 int comparison = values_a[j].compare(values_b[j]);
450 if (comparison != 0)
451 return comparison;
452 }
453 }
454
455 return 0;
456 }
457
458 bool AutofillProfile::operator==(const AutofillProfile& profile) const {
459 return guid_ == profile.guid_ && Compare(profile) == 0;
460 }
461
462 bool AutofillProfile::operator!=(const AutofillProfile& profile) const {
463 return !operator==(profile);
464 }
465
466 const string16 AutofillProfile::PrimaryValue() const {
467 return GetRawInfo(ADDRESS_HOME_LINE1) + GetRawInfo(ADDRESS_HOME_CITY);
468 }
469
470 bool AutofillProfile::IsSubsetOf(const AutofillProfile& profile) const {
471 FieldTypeSet types;
472 GetNonEmptyTypes(AutofillCountry::ApplicationLocale(), &types);
473
474 for (FieldTypeSet::const_iterator iter = types.begin(); iter != types.end();
475 ++iter) {
476 if (*iter == NAME_FULL) {
477 // Ignore the compound "full name" field type. We are only interested in
478 // comparing the constituent parts. For example, if |this| has a middle
479 // name saved, but |profile| lacks one, |profile| could still be a subset
480 // of |this|.
481 continue;
482 } else if (AutofillType(*iter).group() == AutofillType::PHONE) {
483 // Phone numbers should be canonicalized prior to being compared.
484 if (*iter != PHONE_HOME_WHOLE_NUMBER) {
485 continue;
486 } else if (!autofill_i18n::PhoneNumbersMatch(GetRawInfo(*iter),
487 profile.GetRawInfo(*iter),
488 CountryCode())) {
489 return false;
490 }
491 } else if (StringToLowerASCII(GetRawInfo(*iter)) !=
492 StringToLowerASCII(profile.GetRawInfo(*iter))) {
493 return false;
494 }
495 }
496
497 return true;
498 }
499
500 void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile) {
501 FieldTypeSet field_types;
502 profile.GetNonEmptyTypes(AutofillCountry::ApplicationLocale(), &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 for (FieldTypeSet::const_iterator iter = field_types.begin();
509 iter != field_types.end(); ++iter) {
510 if (AutofillProfile::SupportsMultiValue(*iter)) {
511 std::vector<string16> new_values;
512 profile.GetRawMultiInfo(*iter, &new_values);
513 std::vector<string16> existing_values;
514 GetRawMultiInfo(*iter, &existing_values);
515
516 // GetMultiInfo always returns at least one element, even if the profile
517 // has no data stored for this field type.
518 if (existing_values.size() == 1 && existing_values.front().empty())
519 existing_values.clear();
520
521 FieldTypeGroup group = AutofillType(*iter).group();
522 for (std::vector<string16>::iterator value_iter = new_values.begin();
523 value_iter != new_values.end(); ++value_iter) {
524 // Don't add duplicates.
525 if (group == AutofillType::PHONE) {
526 AddPhoneIfUnique(*value_iter, &existing_values);
527 } else {
528 std::vector<string16>::const_iterator existing_iter = std::find_if(
529 existing_values.begin(), existing_values.end(),
530 std::bind1st(CaseInsensitiveStringEquals(), *value_iter));
531 if (existing_iter == existing_values.end())
532 existing_values.insert(existing_values.end(), *value_iter);
533 }
534 }
535 SetRawMultiInfo(*iter, existing_values);
536 } else {
537 string16 new_value = profile.GetRawInfo(*iter);
538 if (StringToLowerASCII(GetRawInfo(*iter)) !=
539 StringToLowerASCII(new_value)) {
540 SetRawInfo(*iter, new_value);
541 }
542 }
543 }
544 }
545
546 // static
547 bool AutofillProfile::SupportsMultiValue(AutofillFieldType type) {
548 AutofillType::FieldTypeGroup group = AutofillType(type).group();
549 return group == AutofillType::NAME ||
550 group == AutofillType::EMAIL ||
551 group == AutofillType::PHONE;
552 }
553
554 // static
555 bool AutofillProfile::AdjustInferredLabels(
556 std::vector<AutofillProfile*>* profiles) {
557 const size_t kMinimalFieldsShown = 2;
558
559 std::vector<string16> created_labels;
560 CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
561 &created_labels);
562 DCHECK_EQ(profiles->size(), created_labels.size());
563
564 bool updated_labels = false;
565 for (size_t i = 0; i < profiles->size(); ++i) {
566 if ((*profiles)[i]->Label() != created_labels[i]) {
567 updated_labels = true;
568 (*profiles)[i]->label_ = created_labels[i];
569 }
570 }
571 return updated_labels;
572 }
573
574 // static
575 void AutofillProfile::CreateInferredLabels(
576 const std::vector<AutofillProfile*>* profiles,
577 const std::vector<AutofillFieldType>* suggested_fields,
578 AutofillFieldType excluded_field,
579 size_t minimal_fields_shown,
580 std::vector<string16>* created_labels) {
581 DCHECK(profiles);
582 DCHECK(created_labels);
583
584 std::vector<AutofillFieldType> fields_to_use;
585 GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
586 &fields_to_use);
587
588 // Construct the default label for each profile. Also construct a map that
589 // associates each label with the profiles that have this label. This map is
590 // then used to detect which labels need further differentiating fields.
591 std::map<string16, std::list<size_t> > labels;
592 for (size_t i = 0; i < profiles->size(); ++i) {
593 string16 label =
594 (*profiles)[i]->ConstructInferredLabel(fields_to_use,
595 minimal_fields_shown);
596 labels[label].push_back(i);
597 }
598
599 created_labels->resize(profiles->size());
600 for (std::map<string16, std::list<size_t> >::const_iterator it =
601 labels.begin();
602 it != labels.end(); ++it) {
603 if (it->second.size() == 1) {
604 // This label is unique, so use it without any further ado.
605 string16 label = it->first;
606 size_t profile_index = it->second.front();
607 (*created_labels)[profile_index] = label;
608 } else {
609 // We have more than one profile with the same label, so add
610 // differentiating fields.
611 CreateDifferentiatingLabels(*profiles, it->second, fields_to_use,
612 minimal_fields_shown, created_labels);
613 }
614 }
615 }
616
617 void AutofillProfile::GetSupportedTypes(FieldTypeSet* supported_types) const {
618 FormGroupList info = FormGroups();
619 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
620 (*it)->GetSupportedTypes(supported_types);
621 }
622
623 bool AutofillProfile::FillCountrySelectControl(FormFieldData* field_data)
624 const {
625 std::string country_code = CountryCode();
626 std::string app_locale = AutofillCountry::ApplicationLocale();
627
628 DCHECK_EQ(field_data->option_values.size(),
629 field_data->option_contents.size());
630 for (size_t i = 0; i < field_data->option_values.size(); ++i) {
631 // Canonicalize each <option> value to a country code, and compare to the
632 // target country code.
633 string16 value = field_data->option_values[i];
634 string16 contents = field_data->option_contents[i];
635 if (country_code == AutofillCountry::GetCountryCode(value, app_locale) ||
636 country_code == AutofillCountry::GetCountryCode(contents, app_locale)) {
637 field_data->value = value;
638 return true;
639 }
640 }
641
642 return false;
643 }
644
645 void AutofillProfile::GetMultiInfoImpl(AutofillFieldType type,
646 const std::string& app_locale,
647 std::vector<string16>* values) const {
648 switch (AutofillType(type).group()) {
649 case AutofillType::NAME:
650 CopyItemsToValues(type, name_, app_locale, values);
651 break;
652 case AutofillType::EMAIL:
653 CopyItemsToValues(type, email_, app_locale, values);
654 break;
655 case AutofillType::PHONE:
656 CopyItemsToValues(type, home_number_, app_locale, values);
657 break;
658 default:
659 values->resize(1);
660 (*values)[0] = GetFormGroupInfo(*this, type, app_locale);
661 }
662 }
663
664 void AutofillProfile::AddPhoneIfUnique(const string16& phone,
665 std::vector<string16>* existing_phones) {
666 DCHECK(existing_phones);
667 // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377",
668 // "(800)356-9377" and "356-9377" are considered the same.
669 if (std::find_if(existing_phones->begin(), existing_phones->end(),
670 FindByPhone(phone, CountryCode())) ==
671 existing_phones->end()) {
672 existing_phones->push_back(phone);
673 }
674 }
675
676 string16 AutofillProfile::ConstructInferredLabel(
677 const std::vector<AutofillFieldType>& included_fields,
678 size_t num_fields_to_use) const {
679 const string16 separator =
680 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
681
682 string16 label;
683 size_t num_fields_used = 0;
684 for (std::vector<AutofillFieldType>::const_iterator it =
685 included_fields.begin();
686 it != included_fields.end() && num_fields_used < num_fields_to_use;
687 ++it) {
688 string16 field = GetRawInfo(*it);
689 if (field.empty())
690 continue;
691
692 if (!label.empty())
693 label.append(separator);
694
695 label.append(field);
696 ++num_fields_used;
697 }
698 return label;
699 }
700
701 // static
702 void AutofillProfile::CreateDifferentiatingLabels(
703 const std::vector<AutofillProfile*>& profiles,
704 const std::list<size_t>& indices,
705 const std::vector<AutofillFieldType>& fields,
706 size_t num_fields_to_include,
707 std::vector<string16>* created_labels) {
708 // For efficiency, we first construct a map of fields to their text values and
709 // each value's frequency.
710 std::map<AutofillFieldType,
711 std::map<string16, size_t> > field_text_frequencies_by_field;
712 for (std::vector<AutofillFieldType>::const_iterator field = fields.begin();
713 field != fields.end(); ++field) {
714 std::map<string16, size_t>& field_text_frequencies =
715 field_text_frequencies_by_field[*field];
716
717 for (std::list<size_t>::const_iterator it = indices.begin();
718 it != indices.end(); ++it) {
719 const AutofillProfile* profile = profiles[*it];
720 string16 field_text = profile->GetRawInfo(*field);
721
722 // If this label is not already in the map, add it with frequency 0.
723 if (!field_text_frequencies.count(field_text))
724 field_text_frequencies[field_text] = 0;
725
726 // Now, increment the frequency for this label.
727 ++field_text_frequencies[field_text];
728 }
729 }
730
731 // Now comes the meat of the algorithm. For each profile, we scan the list of
732 // fields to use, looking for two things:
733 // 1. A (non-empty) field that differentiates the profile from all others
734 // 2. At least |num_fields_to_include| non-empty fields
735 // Before we've satisfied condition (2), we include all fields, even ones that
736 // are identical across all the profiles. Once we've satisfied condition (2),
737 // we only include fields that that have at last two distinct values.
738 for (std::list<size_t>::const_iterator it = indices.begin();
739 it != indices.end(); ++it) {
740 const AutofillProfile* profile = profiles[*it];
741
742 std::vector<AutofillFieldType> label_fields;
743 bool found_differentiating_field = false;
744 for (std::vector<AutofillFieldType>::const_iterator field = fields.begin();
745 field != fields.end(); ++field) {
746 // Skip over empty fields.
747 string16 field_text = profile->GetRawInfo(*field);
748 if (field_text.empty())
749 continue;
750
751 std::map<string16, size_t>& field_text_frequencies =
752 field_text_frequencies_by_field[*field];
753 found_differentiating_field |=
754 !field_text_frequencies.count(string16()) &&
755 (field_text_frequencies[field_text] == 1);
756
757 // Once we've found enough non-empty fields, skip over any remaining
758 // fields that are identical across all the profiles.
759 if (label_fields.size() >= num_fields_to_include &&
760 (field_text_frequencies.size() == 1))
761 continue;
762
763 label_fields.push_back(*field);
764
765 // If we've (1) found a differentiating field and (2) found at least
766 // |num_fields_to_include| non-empty fields, we're done!
767 if (found_differentiating_field &&
768 label_fields.size() >= num_fields_to_include)
769 break;
770 }
771
772 (*created_labels)[*it] =
773 profile->ConstructInferredLabel(label_fields,
774 label_fields.size());
775 }
776 }
777
778 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
779 FormGroupList v(5);
780 v[0] = &name_[0];
781 v[1] = &email_[0];
782 v[2] = &company_;
783 v[3] = &home_number_[0];
784 v[4] = &address_;
785 return v;
786 }
787
788 const FormGroup* AutofillProfile::FormGroupForType(
789 AutofillFieldType type) const {
790 return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
791 }
792
793 FormGroup* AutofillProfile::MutableFormGroupForType(AutofillFieldType type) {
794 FormGroup* form_group = NULL;
795 switch (AutofillType(type).group()) {
796 case AutofillType::NAME:
797 form_group = &name_[0];
798 break;
799 case AutofillType::EMAIL:
800 form_group = &email_[0];
801 break;
802 case AutofillType::COMPANY:
803 form_group = &company_;
804 break;
805 case AutofillType::PHONE:
806 form_group = &home_number_[0];
807 break;
808 case AutofillType::ADDRESS_HOME:
809 form_group = &address_;
810 break;
811 default:
812 break;
813 }
814
815 return form_group;
816 }
817
818 // So we can compare AutofillProfiles with EXPECT_EQ().
819 std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
820 return os
821 << UTF16ToUTF8(profile.Label())
822 << " "
823 << profile.guid()
824 << " "
825 << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
826 << " "
827 << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
828 << " "
829 << UTF16ToUTF8(MultiString(profile, NAME_LAST))
830 << " "
831 << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
832 << " "
833 << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME))
834 << " "
835 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1))
836 << " "
837 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2))
838 << " "
839 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY))
840 << " "
841 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE))
842 << " "
843 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP))
844 << " "
845 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))
846 << " "
847 << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER));
848 }
OLDNEW
« no previous file with comments | « chrome/browser/autofill/autofill_profile.h ('k') | chrome/browser/autofill/autofill_profile_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698