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