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