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 32 using base::ASCIIToUTF16; 33 using base::UTF16ToUTF8; 34 35 namespace autofill { 36 namespace { 37 38 // Like |AutofillType::GetStorableType()|, but also returns |NAME_FULL| for 39 // first, middle, and last name field types. 40 ServerFieldType 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. 55 void 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. 115 const 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 128 base::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 136 template <class T> 137 void 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 150 template <class T> 151 void 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. 163 void 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 192 class 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. 217 struct 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 228 AutofillProfile::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 236 AutofillProfile::AutofillProfile() 237 : AutofillDataModel(base::GenerateGUID(), std::string()), 238 name_(1), 239 email_(1), 240 phone_number_(1, PhoneNumber(this)) { 241 } 242 243 AutofillProfile::AutofillProfile(const AutofillProfile& profile) 244 : AutofillDataModel(std::string(), std::string()) { 245 operator=(profile); 246 } 247 248 AutofillProfile::~AutofillProfile() { 249 } 250 251 AutofillProfile& 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 272 void 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 281 base::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 289 void 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 296 base::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 316 bool 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 328 base::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 344 void 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 375 void AutofillProfile::GetRawMultiInfo( 376 ServerFieldType type, 377 std::vector<base::string16>* values) const { 378 GetMultiInfoImpl(AutofillType(type), std::string(), values); 379 } 380 381 void 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 387 bool AutofillProfile::IsEmpty(const std::string& app_locale) const { 388 ServerFieldTypeSet types; 389 GetNonEmptyTypes(app_locale, &types); 390 return types.empty(); 391 } 392 393 bool 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 418 int AutofillProfile::Compare(const AutofillProfile& profile) const { 419 const ServerFieldType single_value_types[] = { 420 COMPANY_NAME, 421 ADDRESS_HOME_STREET_ADDRESS, 422 ADDRESS_HOME_DEPENDENT_LOCALITY, 423 ADDRESS_HOME_CITY, 424 ADDRESS_HOME_STATE, 425 ADDRESS_HOME_ZIP, 426 ADDRESS_HOME_SORTING_CODE, 427 ADDRESS_HOME_COUNTRY, 428 }; 429 430 for (size_t i = 0; i < arraysize(single_value_types); ++i) { 431 int comparison = GetRawInfo(single_value_types[i]).compare( 432 profile.GetRawInfo(single_value_types[i])); 433 if (comparison != 0) 434 return comparison; 435 } 436 437 const ServerFieldType multi_value_types[] = { NAME_FIRST, 438 NAME_MIDDLE, 439 NAME_LAST, 440 EMAIL_ADDRESS, 441 PHONE_HOME_WHOLE_NUMBER }; 442 443 for (size_t i = 0; i < arraysize(multi_value_types); ++i) { 444 std::vector<base::string16> values_a; 445 std::vector<base::string16> values_b; 446 GetRawMultiInfo(multi_value_types[i], &values_a); 447 profile.GetRawMultiInfo(multi_value_types[i], &values_b); 448 if (values_a.size() < values_b.size()) 449 return -1; 450 if (values_a.size() > values_b.size()) 451 return 1; 452 for (size_t j = 0; j < values_a.size(); ++j) { 453 int comparison = values_a[j].compare(values_b[j]); 454 if (comparison != 0) 455 return comparison; 456 } 457 } 458 459 return 0; 460 } 461 462 bool AutofillProfile::EqualsSansOrigin(const AutofillProfile& profile) const { 463 return guid() == profile.guid() && 464 language_code() == profile.language_code() && 465 Compare(profile) == 0; 466 } 467 468 bool AutofillProfile::EqualsSansGuid(const AutofillProfile& profile) const { 469 return origin() == profile.origin() && 470 language_code() == profile.language_code() && 471 Compare(profile) == 0; 472 } 473 474 bool AutofillProfile::operator==(const AutofillProfile& profile) const { 475 return guid() == profile.guid() && EqualsSansGuid(profile); 476 } 477 478 bool AutofillProfile::operator!=(const AutofillProfile& profile) const { 479 return !operator==(profile); 480 } 481 482 const base::string16 AutofillProfile::PrimaryValue() const { 483 return GetRawInfo(ADDRESS_HOME_LINE1) + GetRawInfo(ADDRESS_HOME_CITY); 484 } 485 486 bool AutofillProfile::IsSubsetOf(const AutofillProfile& profile, 487 const std::string& app_locale) const { 488 ServerFieldTypeSet types; 489 GetNonEmptyTypes(app_locale, &types); 490 491 for (ServerFieldTypeSet::const_iterator it = types.begin(); it != types.end(); 492 ++it) { 493 if (*it == NAME_FULL || *it == ADDRESS_HOME_STREET_ADDRESS) { 494 // Ignore the compound "full name" field type. We are only interested in 495 // comparing the constituent parts. For example, if |this| has a middle 496 // name saved, but |profile| lacks one, |profile| could still be a subset 497 // of |this|. Likewise, ignore the compound "street address" type, as we 498 // are only interested in matching line-by-line. 499 continue; 500 } else if (AutofillType(*it).group() == PHONE_HOME) { 501 // Phone numbers should be canonicalized prior to being compared. 502 if (*it != PHONE_HOME_WHOLE_NUMBER) { 503 continue; 504 } else if (!i18n::PhoneNumbersMatch( 505 GetRawInfo(*it), 506 profile.GetRawInfo(*it), 507 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)), 508 app_locale)) { 509 return false; 510 } 511 } else if (StringToLowerASCII(GetRawInfo(*it)) != 512 StringToLowerASCII(profile.GetRawInfo(*it))) { 513 return false; 514 } 515 } 516 517 return true; 518 } 519 520 void AutofillProfile::OverwriteOrAppendNames( 521 const std::vector<NameInfo>& names) { 522 std::vector<NameInfo> results(name_); 523 for (std::vector<NameInfo>::const_iterator it = names.begin(); 524 it != names.end(); 525 ++it) { 526 NameInfo imported_name = *it; 527 bool should_append_imported_name = true; 528 529 for (size_t index = 0; index < name_.size(); ++index) { 530 NameInfo current_name = name_[index]; 531 if (current_name.EqualsIgnoreCase(imported_name)) { 532 should_append_imported_name = false; 533 break; 534 } 535 536 base::string16 full_name = current_name.GetRawInfo(NAME_FULL); 537 if (StringToLowerASCII(full_name) == 538 StringToLowerASCII(imported_name.GetRawInfo(NAME_FULL))) { 539 // The imported name has the same full name string as one of the 540 // existing names for this profile. Because full names are 541 // _heuristically_ parsed into {first, middle, last} name components, 542 // it's possible that either the existing name or the imported name 543 // was misparsed. Prefer to keep the name whose {first, middle, 544 // last} components do not match those computed by the heuristic 545 // parse, as this more likely represents the correct, user-input parse 546 // of the name. 547 NameInfo heuristically_parsed_name; 548 heuristically_parsed_name.SetRawInfo(NAME_FULL, full_name); 549 if (imported_name.EqualsIgnoreCase(heuristically_parsed_name)) { 550 should_append_imported_name = false; 551 break; 552 } 553 554 if (current_name.EqualsIgnoreCase(heuristically_parsed_name)) { 555 results[index] = imported_name; 556 should_append_imported_name = false; 557 break; 558 } 559 } 560 } 561 562 // Append unique names to the list. 563 if (should_append_imported_name) 564 results.push_back(imported_name); 565 } 566 567 name_.swap(results); 568 } 569 570 void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile, 571 const std::string& app_locale) { 572 // Verified profiles should never be overwritten with unverified data. 573 DCHECK(!IsVerified() || profile.IsVerified()); 574 set_origin(profile.origin()); 575 set_language_code(profile.language_code()); 576 577 ServerFieldTypeSet field_types; 578 profile.GetNonEmptyTypes(app_locale, &field_types); 579 580 // Only transfer "full" types (e.g. full name) and not fragments (e.g. 581 // first name, last name). 582 CollapseCompoundFieldTypes(&field_types); 583 584 // 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. 586 // For addresses, do the opposite: transfer individual address lines, rather 587 // than full addresses. 588 field_types.erase(ADDRESS_HOME_STREET_ADDRESS); 589 590 for (ServerFieldTypeSet::const_iterator iter = field_types.begin(); 591 iter != field_types.end(); ++iter) { 592 if (AutofillProfile::SupportsMultiValue(*iter)) { 593 std::vector<base::string16> new_values; 594 profile.GetRawMultiInfo(*iter, &new_values); 595 std::vector<base::string16> existing_values; 596 GetRawMultiInfo(*iter, &existing_values); 597 598 // GetMultiInfo always returns at least one element, even if the profile 599 // has no data stored for this field type. 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); 625 if (StringToLowerASCII(GetRawInfo(*iter)) != 626 StringToLowerASCII(new_value)) { 627 SetRawInfo(*iter, new_value); 628 } 629 } 630 } 631 } 632 633 // static 634 bool AutofillProfile::SupportsMultiValue(ServerFieldType type) { 635 FieldTypeGroup group = AutofillType(type).group(); 636 return group == NAME || 637 group == NAME_BILLING || 638 group == EMAIL || 639 group == PHONE_HOME || 640 group == PHONE_BILLING; 641 } 642 643 // static 644 void AutofillProfile::CreateDifferentiatingLabels( 645 const std::vector<AutofillProfile*>& profiles, 646 std::vector<base::string16>* labels) { 647 const size_t kMinimalFieldsShown = 2; 648 CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown, 649 labels); 650 DCHECK_EQ(profiles.size(), labels->size()); 651 } 652 653 // static 654 void AutofillProfile::CreateInferredLabels( 655 const std::vector<AutofillProfile*>& profiles, 656 const std::vector<ServerFieldType>* suggested_fields, 657 ServerFieldType excluded_field, 658 size_t minimal_fields_shown, 659 std::vector<base::string16>* labels) { 660 std::vector<ServerFieldType> fields_to_use; 661 GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field, 662 &fields_to_use); 663 664 // 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 666 // then used to detect which labels need further differentiating fields. 667 std::map<base::string16, std::list<size_t> > labels_to_profiles; 668 for (size_t i = 0; i < profiles.size(); ++i) { 669 base::string16 label = 670 profiles[i]->ConstructInferredLabel(fields_to_use, 671 minimal_fields_shown); 672 labels_to_profiles[label].push_back(i); 673 } 674 675 labels->resize(profiles.size()); 676 for (std::map<base::string16, std::list<size_t> >::const_iterator it = 677 labels_to_profiles.begin(); 678 it != labels_to_profiles.end(); ++it) { 679 if (it->second.size() == 1) { 680 // This label is unique, so use it without any further ado. 681 base::string16 label = it->first; 682 size_t profile_index = it->second.front(); 683 (*labels)[profile_index] = label; 684 } else { 685 // We have more than one profile with the same label, so add 686 // differentiating fields. 687 CreateInferredLabelsHelper(profiles, it->second, fields_to_use, 688 minimal_fields_shown, labels); 689 } 690 } 691 } 692 693 void AutofillProfile::GetSupportedTypes( 694 ServerFieldTypeSet* supported_types) const { 695 FormGroupList info = FormGroups(); 696 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it) 697 (*it)->GetSupportedTypes(supported_types); 698 } 699 700 void AutofillProfile::GetMultiInfoImpl( 701 const AutofillType& type, 702 const std::string& app_locale, 703 std::vector<base::string16>* values) const { 704 switch (type.group()) { 705 case NAME: 706 case NAME_BILLING: 707 CopyItemsToValues(type, name_, app_locale, values); 708 break; 709 case EMAIL: 710 CopyItemsToValues(type, email_, app_locale, values); 711 break; 712 case PHONE_HOME: 713 case PHONE_BILLING: 714 CopyItemsToValues(type, phone_number_, app_locale, values); 715 break; 716 default: 717 values->resize(1); 718 (*values)[0] = GetFormGroupInfo(*this, type, app_locale); 719 } 720 } 721 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( 739 const std::vector<ServerFieldType>& included_fields, 740 size_t num_fields_to_use) const { 741 const base::string16 separator = 742 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR); 743 744 base::string16 label; 745 size_t num_fields_used = 0; 746 for (std::vector<ServerFieldType>::const_iterator it = 747 included_fields.begin(); 748 it != included_fields.end() && num_fields_used < num_fields_to_use; 749 ++it) { 750 base::string16 field = GetRawInfo(*it); 751 if (field.empty()) 752 continue; 753 754 if (!label.empty()) 755 label.append(separator); 756 757 label.append(field); 758 ++num_fields_used; 759 } 760 761 // Flatten the label if need be. 762 const base::string16& line_separator = 763 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_SEPARATOR); 764 base::ReplaceChars(label, base::ASCIIToUTF16("\n"), line_separator, &label); 765 766 return label; 767 } 768 769 // static 770 void AutofillProfile::CreateInferredLabelsHelper( 771 const std::vector<AutofillProfile*>& profiles, 772 const std::list<size_t>& indices, 773 const std::vector<ServerFieldType>& fields, 774 size_t num_fields_to_include, 775 std::vector<base::string16>* labels) { 776 // For efficiency, we first construct a map of fields to their text values and 777 // each value's frequency. 778 std::map<ServerFieldType, 779 std::map<base::string16, size_t> > field_text_frequencies_by_field; 780 for (std::vector<ServerFieldType>::const_iterator field = fields.begin(); 781 field != fields.end(); ++field) { 782 std::map<base::string16, size_t>& field_text_frequencies = 783 field_text_frequencies_by_field[*field]; 784 785 for (std::list<size_t>::const_iterator it = indices.begin(); 786 it != indices.end(); ++it) { 787 const AutofillProfile* profile = profiles[*it]; 788 base::string16 field_text = profile->GetRawInfo(*field); 789 790 // If this label is not already in the map, add it with frequency 0. 791 if (!field_text_frequencies.count(field_text)) 792 field_text_frequencies[field_text] = 0; 793 794 // Now, increment the frequency for this label. 795 ++field_text_frequencies[field_text]; 796 } 797 } 798 799 // Now comes the meat of the algorithm. For each profile, we scan the list of 800 // fields to use, looking for two things: 801 // 1. A (non-empty) field that differentiates the profile from all others 802 // 2. At least |num_fields_to_include| non-empty fields 803 // 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), 805 // we only include fields that that have at last two distinct values. 806 for (std::list<size_t>::const_iterator it = indices.begin(); 807 it != indices.end(); ++it) { 808 const AutofillProfile* profile = profiles[*it]; 809 810 std::vector<ServerFieldType> label_fields; 811 bool found_differentiating_field = false; 812 for (std::vector<ServerFieldType>::const_iterator field = fields.begin(); 813 field != fields.end(); ++field) { 814 // Skip over empty fields. 815 base::string16 field_text = profile->GetRawInfo(*field); 816 if (field_text.empty()) 817 continue; 818 819 std::map<base::string16, size_t>& field_text_frequencies = 820 field_text_frequencies_by_field[*field]; 821 found_differentiating_field |= 822 !field_text_frequencies.count(base::string16()) && 823 (field_text_frequencies[field_text] == 1); 824 825 // Once we've found enough non-empty fields, skip over any remaining 826 // fields that are identical across all the profiles. 827 if (label_fields.size() >= num_fields_to_include && 828 (field_text_frequencies.size() == 1)) 829 continue; 830 831 label_fields.push_back(*field); 832 833 // If we've (1) found a differentiating field and (2) found at least 834 // |num_fields_to_include| non-empty fields, we're done! 835 if (found_differentiating_field && 836 label_fields.size() >= num_fields_to_include) 837 break; 838 } 839 840 (*labels)[*it] = 841 profile->ConstructInferredLabel(label_fields, label_fields.size()); 842 } 843 } 844 845 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const { 846 FormGroupList v(5); 847 v[0] = &name_[0]; 848 v[1] = &email_[0]; 849 v[2] = &company_; 850 v[3] = &phone_number_[0]; 851 v[4] = &address_; 852 return v; 853 } 854 855 const FormGroup* AutofillProfile::FormGroupForType( 856 const AutofillType& type) const { 857 return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type); 858 } 859 860 FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) { 861 switch (type.group()) { 862 case NAME: 863 case NAME_BILLING: 864 return &name_[0]; 865 866 case EMAIL: 867 return &email_[0]; 868 869 case COMPANY: 870 return &company_; 871 872 case PHONE_HOME: 873 case PHONE_BILLING: 874 return &phone_number_[0]; 875 876 case ADDRESS_HOME: 877 case ADDRESS_BILLING: 878 return &address_; 879 880 case NO_GROUP: 881 case CREDIT_CARD: 882 case PASSWORD_FIELD: 883 return NULL; 884 } 885 886 NOTREACHED(); 887 return NULL; 888 } 889 890 // So we can compare AutofillProfiles with EXPECT_EQ(). 891 std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) { 892 return os 893 << profile.guid() 894 << " " 895 << profile.origin() 896 << " " 897 << UTF16ToUTF8(MultiString(profile, NAME_FIRST)) 898 << " " 899 << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE)) 900 << " " 901 << UTF16ToUTF8(MultiString(profile, NAME_LAST)) 902 << " " 903 << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS)) 904 << " " 905 << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME)) 906 << " " 907 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1)) 908 << " " 909 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2)) 910 << " " 911 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)) 912 << " " 913 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY)) 914 << " " 915 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE)) 916 << " " 917 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP)) 918 << " " 919 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)) 920 << " " 921 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)) 922 << " " 923 << profile.language_code() 924 << " " 925 << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER)); 926 } 927 928 } // namespace autofill 929