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

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

Issue 347183005: autofill names - dont parse when calling SetRawInfo(FULL_NAME) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix buncha stuff Created 6 years, 5 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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698