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