Chromium Code Reviews| 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 |