OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/autofill/core/browser/autofill_profile.h" | 5 #include "components/autofill/core/browser/autofill_profile.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 #include <map> | 9 #include <map> |
10 #include <ostream> | 10 #include <ostream> |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
182 collapsed_set.insert(PHONE_HOME_WHOLE_NUMBER); | 182 collapsed_set.insert(PHONE_HOME_WHOLE_NUMBER); |
183 break; | 183 break; |
184 | 184 |
185 default: | 185 default: |
186 collapsed_set.insert(*it); | 186 collapsed_set.insert(*it); |
187 } | 187 } |
188 } | 188 } |
189 std::swap(*type_set, collapsed_set); | 189 std::swap(*type_set, collapsed_set); |
190 } | 190 } |
191 | 191 |
192 class FindByPhone { | 192 class FindByPhone |
193 : public std::unary_function<const base::string16&, bool> { | |
Ilya Sherman
2014/06/27 06:25:08
FWIW, it looks like std::unary_function is depreca
Evan Stade
2014/06/28 01:01:35
thanks for reminding me to remove this. It was onl
| |
193 public: | 194 public: |
194 FindByPhone(const base::string16& phone, | 195 FindByPhone(const base::string16& phone, |
195 const std::string& country_code, | 196 const std::string& country_code, |
196 const std::string& app_locale) | 197 const std::string& app_locale) |
197 : phone_(phone), | 198 : phone_(phone), |
198 country_code_(country_code), | 199 country_code_(country_code), |
199 app_locale_(app_locale) { | 200 app_locale_(app_locale) {} |
200 } | |
201 | 201 |
202 bool operator()(const base::string16& phone) { | 202 bool operator()(const base::string16& phone) { |
203 return i18n::PhoneNumbersMatch(phone, phone_, country_code_, app_locale_); | 203 return i18n::PhoneNumbersMatch(phone, phone_, country_code_, app_locale_); |
204 } | 204 } |
205 | 205 |
206 bool operator()(const base::string16* phone) { | |
207 return i18n::PhoneNumbersMatch(*phone, phone_, country_code_, app_locale_); | |
208 } | |
209 | |
210 private: | 206 private: |
211 base::string16 phone_; | 207 base::string16 phone_; |
212 std::string country_code_; | 208 std::string country_code_; |
213 std::string app_locale_; | 209 std::string app_locale_; |
214 }; | 210 }; |
215 | 211 |
216 // Functor used to check for case-insensitive equality of two strings. | 212 // Functor used to check for case-insensitive equality of two strings. |
217 struct CaseInsensitiveStringEquals | 213 struct CaseInsensitiveStringEquals |
218 : public std::binary_function<base::string16, base::string16, bool> | 214 : public std::unary_function<const base::string16&, bool> { |
219 { | 215 public: |
220 bool operator()(const base::string16& x, const base::string16& y) const { | 216 CaseInsensitiveStringEquals(const base::string16& other) |
221 return | 217 : other_(other) {} |
222 x.size() == y.size() && StringToLowerASCII(x) == StringToLowerASCII(y); | 218 |
219 bool operator()(const base::string16& x) const { | |
220 return x.size() == other_.size() && | |
221 StringToLowerASCII(x) == StringToLowerASCII(other_); | |
223 } | 222 } |
223 | |
224 private: | |
225 const base::string16& other_; | |
224 }; | 226 }; |
225 | 227 |
226 } // namespace | 228 } // namespace |
227 | 229 |
228 AutofillProfile::AutofillProfile(const std::string& guid, | 230 AutofillProfile::AutofillProfile(const std::string& guid, |
229 const std::string& origin) | 231 const std::string& origin) |
230 : AutofillDataModel(guid, origin), | 232 : AutofillDataModel(guid, origin), |
231 name_(1), | 233 name_(1), |
232 email_(1), | 234 email_(1), |
233 phone_number_(1, PhoneNumber(this)) { | 235 phone_number_(1, PhoneNumber(this)) { |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
427 ADDRESS_HOME_COUNTRY, | 429 ADDRESS_HOME_COUNTRY, |
428 }; | 430 }; |
429 | 431 |
430 for (size_t i = 0; i < arraysize(single_value_types); ++i) { | 432 for (size_t i = 0; i < arraysize(single_value_types); ++i) { |
431 int comparison = GetRawInfo(single_value_types[i]).compare( | 433 int comparison = GetRawInfo(single_value_types[i]).compare( |
432 profile.GetRawInfo(single_value_types[i])); | 434 profile.GetRawInfo(single_value_types[i])); |
433 if (comparison != 0) | 435 if (comparison != 0) |
434 return comparison; | 436 return comparison; |
435 } | 437 } |
436 | 438 |
437 const ServerFieldType multi_value_types[] = { NAME_FIRST, | 439 const ServerFieldType multi_value_types[] = { NAME_FULL, |
440 NAME_FIRST, | |
438 NAME_MIDDLE, | 441 NAME_MIDDLE, |
439 NAME_LAST, | 442 NAME_LAST, |
440 EMAIL_ADDRESS, | 443 EMAIL_ADDRESS, |
441 PHONE_HOME_WHOLE_NUMBER }; | 444 PHONE_HOME_WHOLE_NUMBER }; |
442 | 445 |
443 for (size_t i = 0; i < arraysize(multi_value_types); ++i) { | 446 for (size_t i = 0; i < arraysize(multi_value_types); ++i) { |
444 std::vector<base::string16> values_a; | 447 std::vector<base::string16> values_a; |
445 std::vector<base::string16> values_b; | 448 std::vector<base::string16> values_b; |
446 GetRawMultiInfo(multi_value_types[i], &values_a); | 449 GetRawMultiInfo(multi_value_types[i], &values_a); |
447 profile.GetRawMultiInfo(multi_value_types[i], &values_b); | 450 profile.GetRawMultiInfo(multi_value_types[i], &values_b); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
511 } else if (StringToLowerASCII(GetRawInfo(*it)) != | 514 } else if (StringToLowerASCII(GetRawInfo(*it)) != |
512 StringToLowerASCII(profile.GetRawInfo(*it))) { | 515 StringToLowerASCII(profile.GetRawInfo(*it))) { |
513 return false; | 516 return false; |
514 } | 517 } |
515 } | 518 } |
516 | 519 |
517 return true; | 520 return true; |
518 } | 521 } |
519 | 522 |
520 void AutofillProfile::OverwriteOrAppendNames( | 523 void AutofillProfile::OverwriteOrAppendNames( |
521 const std::vector<NameInfo>& names) { | 524 const std::vector<NameInfo>& names, |
525 const std::string& app_locale) { | |
522 std::vector<NameInfo> results(name_); | 526 std::vector<NameInfo> results(name_); |
523 for (std::vector<NameInfo>::const_iterator it = names.begin(); | 527 for (std::vector<NameInfo>::const_iterator it = names.begin(); |
524 it != names.end(); | 528 it != names.end(); |
525 ++it) { | 529 ++it) { |
526 NameInfo imported_name = *it; | 530 NameInfo imported_name = *it; |
527 bool should_append_imported_name = true; | 531 bool should_append_imported_name = true; |
528 | 532 |
529 for (size_t index = 0; index < name_.size(); ++index) { | 533 for (size_t index = 0; index < name_.size(); ++index) { |
530 NameInfo current_name = name_[index]; | 534 NameInfo current_name = name_[index]; |
531 if (current_name.EqualsIgnoreCase(imported_name)) { | 535 if (current_name.ParsedBitsAreEqual(imported_name)) { |
536 if (current_name.GetRawInfo(NAME_FULL).empty()) { | |
537 current_name.SetRawInfo(NAME_FULL, | |
538 imported_name.GetRawInfo(NAME_FULL)); | |
539 } | |
540 | |
532 should_append_imported_name = false; | 541 should_append_imported_name = false; |
533 break; | 542 break; |
534 } | 543 } |
535 | 544 |
536 base::string16 full_name = current_name.GetRawInfo(NAME_FULL); | 545 AutofillType type = AutofillType(NAME_FULL); |
546 base::string16 full_name = current_name.GetInfo(type, app_locale); | |
537 if (StringToLowerASCII(full_name) == | 547 if (StringToLowerASCII(full_name) == |
538 StringToLowerASCII(imported_name.GetRawInfo(NAME_FULL))) { | 548 StringToLowerASCII(imported_name.GetInfo(type, app_locale))) { |
539 // The imported name has the same full name string as one of the | 549 // The imported name has the same full name string as one of the |
540 // existing names for this profile. Because full names are | 550 // existing names for this profile. Because full names are |
541 // _heuristically_ parsed into {first, middle, last} name components, | 551 // _heuristically_ parsed into {first, middle, last} name components, |
542 // it's possible that either the existing name or the imported name | 552 // it's possible that either the existing name or the imported name |
543 // was misparsed. Prefer to keep the name whose {first, middle, | 553 // was misparsed. Prefer to keep the name whose {first, middle, |
544 // last} components do not match those computed by the heuristic | 554 // last} components do not match those computed by the heuristic |
545 // parse, as this more likely represents the correct, user-input parse | 555 // parse, as this more likely represents the correct, user-input parse |
546 // of the name. | 556 // of the name. |
547 NameInfo heuristically_parsed_name; | 557 NameInfo heuristically_parsed_name; |
548 heuristically_parsed_name.SetRawInfo(NAME_FULL, full_name); | 558 heuristically_parsed_name.SetInfo(type, full_name, app_locale); |
549 if (imported_name.EqualsIgnoreCase(heuristically_parsed_name)) { | 559 if (imported_name.ParsedBitsAreEqual(heuristically_parsed_name)) { |
550 should_append_imported_name = false; | 560 should_append_imported_name = false; |
551 break; | 561 break; |
552 } | 562 } |
553 | 563 |
554 if (current_name.EqualsIgnoreCase(heuristically_parsed_name)) { | 564 if (current_name.ParsedBitsAreEqual(heuristically_parsed_name)) { |
555 results[index] = imported_name; | 565 results[index] = imported_name; |
556 should_append_imported_name = false; | 566 should_append_imported_name = false; |
557 break; | 567 break; |
558 } | 568 } |
559 } | 569 } |
560 } | 570 } |
561 | 571 |
562 // Append unique names to the list. | 572 // Append unique names to the list. |
563 if (should_append_imported_name) | 573 if (should_append_imported_name) |
564 results.push_back(imported_name); | 574 results.push_back(imported_name); |
(...skipping 17 matching lines...) Expand all Loading... | |
582 CollapseCompoundFieldTypes(&field_types); | 592 CollapseCompoundFieldTypes(&field_types); |
583 | 593 |
584 // TODO(isherman): Revisit this decision in the context of i18n and storing | 594 // TODO(isherman): Revisit this decision in the context of i18n and storing |
585 // full addresses rather than storing 1-to-2 lines of an address. | 595 // full addresses rather than storing 1-to-2 lines of an address. |
586 // For addresses, do the opposite: transfer individual address lines, rather | 596 // For addresses, do the opposite: transfer individual address lines, rather |
587 // than full addresses. | 597 // than full addresses. |
588 field_types.erase(ADDRESS_HOME_STREET_ADDRESS); | 598 field_types.erase(ADDRESS_HOME_STREET_ADDRESS); |
589 | 599 |
590 for (ServerFieldTypeSet::const_iterator iter = field_types.begin(); | 600 for (ServerFieldTypeSet::const_iterator iter = field_types.begin(); |
591 iter != field_types.end(); ++iter) { | 601 iter != field_types.end(); ++iter) { |
592 if (AutofillProfile::SupportsMultiValue(*iter)) { | 602 FieldTypeGroup group = AutofillType(*iter).group(); |
593 std::vector<base::string16> new_values; | 603 // Special case names. |
594 profile.GetRawMultiInfo(*iter, &new_values); | 604 if (group == NAME) { |
595 std::vector<base::string16> existing_values; | 605 OverwriteOrAppendNames(profile.name_, app_locale); |
596 GetRawMultiInfo(*iter, &existing_values); | 606 continue; |
Ilya Sherman
2014/06/27 06:25:08
Optional nit: I prefer to only use "continue" stmt
Evan Stade
2014/06/28 01:01:35
I'll pass on this nit, as I prefer less indentatio
| |
607 } | |
597 | 608 |
598 // GetMultiInfo always returns at least one element, even if the profile | 609 // Single value field --- overwrite. |
599 // has no data stored for this field type. | 610 if (!AutofillProfile::SupportsMultiValue(*iter)) { |
600 if (existing_values.size() == 1 && existing_values.front().empty()) | |
601 existing_values.clear(); | |
602 | |
603 FieldTypeGroup group = AutofillType(*iter).group(); | |
604 for (std::vector<base::string16>::iterator value_iter = | |
605 new_values.begin(); | |
606 value_iter != new_values.end(); ++value_iter) { | |
607 // Don't add duplicates. | |
608 if (group == PHONE_HOME) { | |
609 AddPhoneIfUnique(*value_iter, app_locale, &existing_values); | |
610 } else { | |
611 std::vector<base::string16>::const_iterator existing_iter = | |
612 std::find_if( | |
613 existing_values.begin(), existing_values.end(), | |
614 std::bind1st(CaseInsensitiveStringEquals(), *value_iter)); | |
615 if (existing_iter == existing_values.end()) | |
616 existing_values.insert(existing_values.end(), *value_iter); | |
617 } | |
618 } | |
619 if (group == NAME) | |
620 OverwriteOrAppendNames(profile.name_); | |
621 else | |
622 SetRawMultiInfo(*iter, existing_values); | |
623 } else { | |
624 base::string16 new_value = profile.GetRawInfo(*iter); | 611 base::string16 new_value = profile.GetRawInfo(*iter); |
625 if (StringToLowerASCII(GetRawInfo(*iter)) != | 612 if (StringToLowerASCII(GetRawInfo(*iter)) != |
626 StringToLowerASCII(new_value)) { | 613 StringToLowerASCII(new_value)) { |
627 SetRawInfo(*iter, new_value); | 614 SetRawInfo(*iter, new_value); |
628 } | 615 } |
616 continue; | |
617 } | |
618 | |
619 // Multi value field --- overwrite/append. | |
620 std::vector<base::string16> new_values; | |
621 profile.GetRawMultiInfo(*iter, &new_values); | |
622 std::vector<base::string16> existing_values; | |
623 GetRawMultiInfo(*iter, &existing_values); | |
624 | |
625 // GetMultiInfo always returns at least one element, even if the profile | |
626 // has no data stored for this field type. | |
627 if (existing_values.size() == 1 && existing_values.front().empty()) | |
628 existing_values.clear(); | |
629 | |
630 for (std::vector<base::string16>::iterator value_iter = | |
631 new_values.begin(); | |
632 value_iter != new_values.end(); ++value_iter) { | |
633 // Don't add duplicates. Most types get case insensitive matching. | |
634 std::vector<base::string16>::const_iterator existing_iter; | |
635 | |
636 if (group == PHONE_HOME) { | |
637 // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377", | |
638 // "(800)356-9377" and "356-9377" are considered the same. | |
639 std::string country_code = | |
640 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)); | |
641 existing_iter = | |
642 std::find_if(existing_values.begin(), existing_values.end(), | |
643 FindByPhone(*value_iter, country_code, app_locale)); | |
644 } else { | |
645 existing_iter = | |
646 std::find_if(existing_values.begin(), existing_values.end(), | |
647 CaseInsensitiveStringEquals(*value_iter)); | |
648 } | |
649 | |
650 if (existing_iter == existing_values.end()) | |
651 existing_values.insert(existing_values.end(), *value_iter); | |
652 SetRawMultiInfo(*iter, existing_values); | |
Ilya Sherman
2014/06/27 06:25:08
It seems like this ought to be outside the inner f
Evan Stade
2014/06/28 01:01:35
good catch. This is the unfortunate kind of bug a
| |
629 } | 653 } |
630 } | 654 } |
631 } | 655 } |
632 | 656 |
633 // static | 657 // static |
634 bool AutofillProfile::SupportsMultiValue(ServerFieldType type) { | 658 bool AutofillProfile::SupportsMultiValue(ServerFieldType type) { |
635 FieldTypeGroup group = AutofillType(type).group(); | 659 FieldTypeGroup group = AutofillType(type).group(); |
636 return group == NAME || | 660 return group == NAME || |
637 group == NAME_BILLING || | 661 group == NAME_BILLING || |
638 group == EMAIL || | 662 group == EMAIL || |
639 group == PHONE_HOME || | 663 group == PHONE_HOME || |
640 group == PHONE_BILLING; | 664 group == PHONE_BILLING; |
641 } | 665 } |
642 | 666 |
643 // static | 667 // static |
644 void AutofillProfile::CreateDifferentiatingLabels( | 668 void AutofillProfile::CreateDifferentiatingLabels( |
645 const std::vector<AutofillProfile*>& profiles, | 669 const std::vector<AutofillProfile*>& profiles, |
670 const std::string& app_locale, | |
646 std::vector<base::string16>* labels) { | 671 std::vector<base::string16>* labels) { |
647 const size_t kMinimalFieldsShown = 2; | 672 const size_t kMinimalFieldsShown = 2; |
648 CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown, | 673 CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown, |
649 labels); | 674 app_locale, labels); |
650 DCHECK_EQ(profiles.size(), labels->size()); | 675 DCHECK_EQ(profiles.size(), labels->size()); |
651 } | 676 } |
652 | 677 |
653 // static | 678 // static |
654 void AutofillProfile::CreateInferredLabels( | 679 void AutofillProfile::CreateInferredLabels( |
655 const std::vector<AutofillProfile*>& profiles, | 680 const std::vector<AutofillProfile*>& profiles, |
656 const std::vector<ServerFieldType>* suggested_fields, | 681 const std::vector<ServerFieldType>* suggested_fields, |
657 ServerFieldType excluded_field, | 682 ServerFieldType excluded_field, |
658 size_t minimal_fields_shown, | 683 size_t minimal_fields_shown, |
684 const std::string& app_locale, | |
659 std::vector<base::string16>* labels) { | 685 std::vector<base::string16>* labels) { |
660 std::vector<ServerFieldType> fields_to_use; | 686 std::vector<ServerFieldType> fields_to_use; |
661 GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field, | 687 GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field, |
662 &fields_to_use); | 688 &fields_to_use); |
663 | 689 |
664 // Construct the default label for each profile. Also construct a map that | 690 // Construct the default label for each profile. Also construct a map that |
665 // associates each label with the profiles that have this label. This map is | 691 // associates each label with the profiles that have this label. This map is |
666 // then used to detect which labels need further differentiating fields. | 692 // then used to detect which labels need further differentiating fields. |
667 std::map<base::string16, std::list<size_t> > labels_to_profiles; | 693 std::map<base::string16, std::list<size_t> > labels_to_profiles; |
668 for (size_t i = 0; i < profiles.size(); ++i) { | 694 for (size_t i = 0; i < profiles.size(); ++i) { |
669 base::string16 label = | 695 base::string16 label = |
670 profiles[i]->ConstructInferredLabel(fields_to_use, | 696 profiles[i]->ConstructInferredLabel(fields_to_use, |
671 minimal_fields_shown); | 697 minimal_fields_shown, |
698 app_locale); | |
672 labels_to_profiles[label].push_back(i); | 699 labels_to_profiles[label].push_back(i); |
673 } | 700 } |
674 | 701 |
675 labels->resize(profiles.size()); | 702 labels->resize(profiles.size()); |
676 for (std::map<base::string16, std::list<size_t> >::const_iterator it = | 703 for (std::map<base::string16, std::list<size_t> >::const_iterator it = |
677 labels_to_profiles.begin(); | 704 labels_to_profiles.begin(); |
678 it != labels_to_profiles.end(); ++it) { | 705 it != labels_to_profiles.end(); ++it) { |
679 if (it->second.size() == 1) { | 706 if (it->second.size() == 1) { |
680 // This label is unique, so use it without any further ado. | 707 // This label is unique, so use it without any further ado. |
681 base::string16 label = it->first; | 708 base::string16 label = it->first; |
682 size_t profile_index = it->second.front(); | 709 size_t profile_index = it->second.front(); |
683 (*labels)[profile_index] = label; | 710 (*labels)[profile_index] = label; |
684 } else { | 711 } else { |
685 // We have more than one profile with the same label, so add | 712 // We have more than one profile with the same label, so add |
686 // differentiating fields. | 713 // differentiating fields. |
687 CreateInferredLabelsHelper(profiles, it->second, fields_to_use, | 714 CreateInferredLabelsHelper(profiles, it->second, fields_to_use, |
688 minimal_fields_shown, labels); | 715 minimal_fields_shown, app_locale, labels); |
689 } | 716 } |
690 } | 717 } |
691 } | 718 } |
692 | 719 |
693 void AutofillProfile::GetSupportedTypes( | 720 void AutofillProfile::GetSupportedTypes( |
694 ServerFieldTypeSet* supported_types) const { | 721 ServerFieldTypeSet* supported_types) const { |
695 FormGroupList info = FormGroups(); | 722 FormGroupList info = FormGroups(); |
696 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it) | 723 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it) |
697 (*it)->GetSupportedTypes(supported_types); | 724 (*it)->GetSupportedTypes(supported_types); |
698 } | 725 } |
(...skipping 13 matching lines...) Expand all Loading... | |
712 case PHONE_HOME: | 739 case PHONE_HOME: |
713 case PHONE_BILLING: | 740 case PHONE_BILLING: |
714 CopyItemsToValues(type, phone_number_, app_locale, values); | 741 CopyItemsToValues(type, phone_number_, app_locale, values); |
715 break; | 742 break; |
716 default: | 743 default: |
717 values->resize(1); | 744 values->resize(1); |
718 (*values)[0] = GetFormGroupInfo(*this, type, app_locale); | 745 (*values)[0] = GetFormGroupInfo(*this, type, app_locale); |
719 } | 746 } |
720 } | 747 } |
721 | 748 |
722 void AutofillProfile::AddPhoneIfUnique( | |
723 const base::string16& phone, | |
724 const std::string& app_locale, | |
725 std::vector<base::string16>* existing_phones) { | |
726 DCHECK(existing_phones); | |
727 // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377", | |
728 // "(800)356-9377" and "356-9377" are considered the same. | |
729 std::string country_code = | |
730 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)); | |
731 if (std::find_if(existing_phones->begin(), existing_phones->end(), | |
732 FindByPhone(phone, country_code, app_locale)) == | |
733 existing_phones->end()) { | |
734 existing_phones->push_back(phone); | |
735 } | |
736 } | |
737 | |
738 base::string16 AutofillProfile::ConstructInferredLabel( | 749 base::string16 AutofillProfile::ConstructInferredLabel( |
739 const std::vector<ServerFieldType>& included_fields, | 750 const std::vector<ServerFieldType>& included_fields, |
740 size_t num_fields_to_use) const { | 751 size_t num_fields_to_use, |
752 const std::string& app_locale) const { | |
741 const base::string16 separator = | 753 const base::string16 separator = |
742 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR); | 754 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR); |
743 | 755 |
744 base::string16 label; | 756 base::string16 label; |
745 size_t num_fields_used = 0; | 757 size_t num_fields_used = 0; |
746 for (std::vector<ServerFieldType>::const_iterator it = | 758 for (std::vector<ServerFieldType>::const_iterator it = |
747 included_fields.begin(); | 759 included_fields.begin(); |
748 it != included_fields.end() && num_fields_used < num_fields_to_use; | 760 it != included_fields.end() && num_fields_used < num_fields_to_use; |
749 ++it) { | 761 ++it) { |
750 base::string16 field = GetRawInfo(*it); | 762 base::string16 field = GetInfo(AutofillType(*it), app_locale); |
751 if (field.empty()) | 763 if (field.empty()) |
752 continue; | 764 continue; |
753 | 765 |
754 if (!label.empty()) | 766 if (!label.empty()) |
755 label.append(separator); | 767 label.append(separator); |
756 | 768 |
757 label.append(field); | 769 label.append(field); |
758 ++num_fields_used; | 770 ++num_fields_used; |
759 } | 771 } |
760 | 772 |
761 // Flatten the label if need be. | 773 // Flatten the label if need be. |
762 const base::string16& line_separator = | 774 const base::string16& line_separator = |
763 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_SEPARATOR); | 775 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_SEPARATOR); |
764 base::ReplaceChars(label, base::ASCIIToUTF16("\n"), line_separator, &label); | 776 base::ReplaceChars(label, base::ASCIIToUTF16("\n"), line_separator, &label); |
765 | 777 |
766 return label; | 778 return label; |
767 } | 779 } |
768 | 780 |
769 // static | 781 // static |
770 void AutofillProfile::CreateInferredLabelsHelper( | 782 void AutofillProfile::CreateInferredLabelsHelper( |
771 const std::vector<AutofillProfile*>& profiles, | 783 const std::vector<AutofillProfile*>& profiles, |
772 const std::list<size_t>& indices, | 784 const std::list<size_t>& indices, |
773 const std::vector<ServerFieldType>& fields, | 785 const std::vector<ServerFieldType>& fields, |
774 size_t num_fields_to_include, | 786 size_t num_fields_to_include, |
787 const std::string& app_locale, | |
775 std::vector<base::string16>* labels) { | 788 std::vector<base::string16>* labels) { |
776 // For efficiency, we first construct a map of fields to their text values and | 789 // For efficiency, we first construct a map of fields to their text values and |
777 // each value's frequency. | 790 // each value's frequency. |
778 std::map<ServerFieldType, | 791 std::map<ServerFieldType, |
779 std::map<base::string16, size_t> > field_text_frequencies_by_field; | 792 std::map<base::string16, size_t> > field_text_frequencies_by_field; |
780 for (std::vector<ServerFieldType>::const_iterator field = fields.begin(); | 793 for (std::vector<ServerFieldType>::const_iterator field = fields.begin(); |
781 field != fields.end(); ++field) { | 794 field != fields.end(); ++field) { |
782 std::map<base::string16, size_t>& field_text_frequencies = | 795 std::map<base::string16, size_t>& field_text_frequencies = |
783 field_text_frequencies_by_field[*field]; | 796 field_text_frequencies_by_field[*field]; |
784 | 797 |
785 for (std::list<size_t>::const_iterator it = indices.begin(); | 798 for (std::list<size_t>::const_iterator it = indices.begin(); |
786 it != indices.end(); ++it) { | 799 it != indices.end(); ++it) { |
787 const AutofillProfile* profile = profiles[*it]; | 800 const AutofillProfile* profile = profiles[*it]; |
788 base::string16 field_text = profile->GetRawInfo(*field); | 801 base::string16 field_text = |
802 profile->GetInfo(AutofillType(*field), app_locale); | |
789 | 803 |
790 // If this label is not already in the map, add it with frequency 0. | 804 // If this label is not already in the map, add it with frequency 0. |
791 if (!field_text_frequencies.count(field_text)) | 805 if (!field_text_frequencies.count(field_text)) |
792 field_text_frequencies[field_text] = 0; | 806 field_text_frequencies[field_text] = 0; |
793 | 807 |
794 // Now, increment the frequency for this label. | 808 // Now, increment the frequency for this label. |
795 ++field_text_frequencies[field_text]; | 809 ++field_text_frequencies[field_text]; |
796 } | 810 } |
797 } | 811 } |
798 | 812 |
799 // Now comes the meat of the algorithm. For each profile, we scan the list of | 813 // Now comes the meat of the algorithm. For each profile, we scan the list of |
800 // fields to use, looking for two things: | 814 // fields to use, looking for two things: |
801 // 1. A (non-empty) field that differentiates the profile from all others | 815 // 1. A (non-empty) field that differentiates the profile from all others |
802 // 2. At least |num_fields_to_include| non-empty fields | 816 // 2. At least |num_fields_to_include| non-empty fields |
803 // Before we've satisfied condition (2), we include all fields, even ones that | 817 // Before we've satisfied condition (2), we include all fields, even ones that |
804 // are identical across all the profiles. Once we've satisfied condition (2), | 818 // are identical across all the profiles. Once we've satisfied condition (2), |
805 // we only include fields that that have at last two distinct values. | 819 // we only include fields that that have at last two distinct values. |
806 for (std::list<size_t>::const_iterator it = indices.begin(); | 820 for (std::list<size_t>::const_iterator it = indices.begin(); |
807 it != indices.end(); ++it) { | 821 it != indices.end(); ++it) { |
808 const AutofillProfile* profile = profiles[*it]; | 822 const AutofillProfile* profile = profiles[*it]; |
809 | 823 |
810 std::vector<ServerFieldType> label_fields; | 824 std::vector<ServerFieldType> label_fields; |
811 bool found_differentiating_field = false; | 825 bool found_differentiating_field = false; |
812 for (std::vector<ServerFieldType>::const_iterator field = fields.begin(); | 826 for (std::vector<ServerFieldType>::const_iterator field = fields.begin(); |
813 field != fields.end(); ++field) { | 827 field != fields.end(); ++field) { |
814 // Skip over empty fields. | 828 // Skip over empty fields. |
815 base::string16 field_text = profile->GetRawInfo(*field); | 829 base::string16 field_text = |
830 profile->GetInfo(AutofillType(*field), app_locale); | |
816 if (field_text.empty()) | 831 if (field_text.empty()) |
817 continue; | 832 continue; |
818 | 833 |
819 std::map<base::string16, size_t>& field_text_frequencies = | 834 std::map<base::string16, size_t>& field_text_frequencies = |
820 field_text_frequencies_by_field[*field]; | 835 field_text_frequencies_by_field[*field]; |
821 found_differentiating_field |= | 836 found_differentiating_field |= |
822 !field_text_frequencies.count(base::string16()) && | 837 !field_text_frequencies.count(base::string16()) && |
823 (field_text_frequencies[field_text] == 1); | 838 (field_text_frequencies[field_text] == 1); |
824 | 839 |
825 // Once we've found enough non-empty fields, skip over any remaining | 840 // Once we've found enough non-empty fields, skip over any remaining |
826 // fields that are identical across all the profiles. | 841 // fields that are identical across all the profiles. |
827 if (label_fields.size() >= num_fields_to_include && | 842 if (label_fields.size() >= num_fields_to_include && |
828 (field_text_frequencies.size() == 1)) | 843 (field_text_frequencies.size() == 1)) |
829 continue; | 844 continue; |
830 | 845 |
831 label_fields.push_back(*field); | 846 label_fields.push_back(*field); |
832 | 847 |
833 // If we've (1) found a differentiating field and (2) found at least | 848 // If we've (1) found a differentiating field and (2) found at least |
834 // |num_fields_to_include| non-empty fields, we're done! | 849 // |num_fields_to_include| non-empty fields, we're done! |
835 if (found_differentiating_field && | 850 if (found_differentiating_field && |
836 label_fields.size() >= num_fields_to_include) | 851 label_fields.size() >= num_fields_to_include) |
837 break; | 852 break; |
838 } | 853 } |
839 | 854 |
840 (*labels)[*it] = | 855 (*labels)[*it] = profile->ConstructInferredLabel( |
841 profile->ConstructInferredLabel(label_fields, label_fields.size()); | 856 label_fields, label_fields.size(), app_locale); |
842 } | 857 } |
843 } | 858 } |
844 | 859 |
845 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const { | 860 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const { |
846 FormGroupList v(5); | 861 FormGroupList v(5); |
847 v[0] = &name_[0]; | 862 v[0] = &name_[0]; |
848 v[1] = &email_[0]; | 863 v[1] = &email_[0]; |
849 v[2] = &company_; | 864 v[2] = &company_; |
850 v[3] = &phone_number_[0]; | 865 v[3] = &phone_number_[0]; |
851 v[4] = &address_; | 866 v[4] = &address_; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
920 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)) | 935 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)) |
921 << " " | 936 << " " |
922 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)) | 937 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)) |
923 << " " | 938 << " " |
924 << profile.language_code() | 939 << profile.language_code() |
925 << " " | 940 << " " |
926 << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER)); | 941 << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER)); |
927 } | 942 } |
928 | 943 |
929 } // namespace autofill | 944 } // namespace autofill |
OLD | NEW |