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

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

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

Powered by Google App Engine
This is Rietveld 408576698