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