autofill_profile.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 266 return *this; 267} 268 269void AutofillProfile::GetMatchingTypes( 270 const base::string16& text, 271 const std::string& app_locale, 272 ServerFieldTypeSet* matching_types) const { 273 FormGroupList info = FormGroups(); 274 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it) 275 (*it)->GetMatchingTypes(text, app_locale, matching_types); 276} 277 278base::string16 AutofillProfile::GetRawInfo(ServerFieldType type) const { 279 const FormGroup* form_group = FormGroupForType(AutofillType(type)); 280 if (!form_group) 281 return base::string16(); 282 283 return form_group->GetRawInfo(type); 284} 285 286void AutofillProfile::SetRawInfo(ServerFieldType type, 287 const base::string16& value) { 288 FormGroup* form_group = MutableFormGroupForType(AutofillType(type)); 289 if (form_group) 290 form_group->SetRawInfo(type, value); 291} 292 293base::string16 AutofillProfile::GetInfo(const AutofillType& type, 294 const std::string& app_locale) const { 295 const FormGroup* form_group = FormGroupForType(type); 296 if (!form_group) 297 return base::string16(); 298 299 return form_group->GetInfo(type, app_locale); 300} 301 302bool AutofillProfile::SetInfo(const AutofillType& type, 303 const base::string16& value, 304 const std::string& app_locale) { 305 FormGroup* form_group = MutableFormGroupForType(type); 306 if (!form_group) 307 return false; 308 309 base::string16 trimmed_value; 310 base::TrimWhitespace(value, base::TRIM_ALL, &trimmed_value); 311 return form_group->SetInfo(type, trimmed_value, app_locale); 312} 313 314base::string16 AutofillProfile::GetInfoForVariant( 315 const AutofillType& type, 316 size_t variant, 317 const std::string& app_locale) const { 318 std::vector<base::string16> values; 319 GetMultiInfo(type, app_locale, &values); 320 321 if (variant >= values.size()) { 322 // If the variant is unavailable, bail. This case is reachable, for 323 // example if Sync updates a profile during the filling process. 324 return base::string16(); 325 } 326 327 return values[variant]; 328} 329 330void AutofillProfile::SetRawMultiInfo( 331 ServerFieldType type, 332 const std::vector<base::string16>& values) { 333 switch (AutofillType(type).group()) { 334 case NAME: 335 case NAME_BILLING: 336 CopyValuesToItems(type, values, &name_, NameInfo()); 337 break; 338 case EMAIL: 339 CopyValuesToItems(type, values, &email_, EmailInfo()); 340 break; 341 case PHONE_HOME: 342 case PHONE_BILLING: 343 CopyValuesToItems(type, 344 values, 345 &phone_number_, 346 PhoneNumber(this)); 347 break; 348 default: 349 if (values.size() == 1) { 350 SetRawInfo(type, values[0]); 351 } else if (values.size() == 0) { 352 SetRawInfo(type, base::string16()); 353 } else { 354 // Shouldn't attempt to set multiple values on single-valued field. 355 NOTREACHED(); 356 } 357 break; 358 } 359} 360 361void AutofillProfile::GetRawMultiInfo( 362 ServerFieldType type, 363 std::vector<base::string16>* values) const { 364 GetMultiInfoImpl(AutofillType(type), std::string(), values); 365} 366 367void AutofillProfile::GetMultiInfo(const AutofillType& type, 368 const std::string& app_locale, 369 std::vector<base::string16>* values) const { 370 GetMultiInfoImpl(type, app_locale, values); 371} 372 373bool AutofillProfile::IsEmpty(const std::string& app_locale) const { 374 ServerFieldTypeSet types; 375 GetNonEmptyTypes(app_locale, &types); 376 return types.empty(); 377} 378 379bool AutofillProfile::IsPresentButInvalid(ServerFieldType type) const { 380 std::string country = UTF16ToUTF8(GetRawInfo(ADDRESS_HOME_COUNTRY)); 381 base::string16 data = GetRawInfo(type); 382 if (data.empty()) 383 return false; 384 385 switch (type) { 386 case ADDRESS_HOME_STATE: 387 return country == "US" && !autofill::IsValidState(data); 388 389 case ADDRESS_HOME_ZIP: 390 return country == "US" && !autofill::IsValidZip(data); 391 392 case PHONE_HOME_WHOLE_NUMBER: 393 return !i18n::PhoneObject(data, country).IsValidNumber(); 394 395 case EMAIL_ADDRESS: 396 return !autofill::IsValidEmailAddress(data); 397 398 default: 399 NOTREACHED(); 400 return false; 401 } 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::operator==(const AutofillProfile& profile) const { 451 return guid() == profile.guid() && 452 origin() == profile.origin() && 453 Compare(profile) == 0; 454} 455 456bool AutofillProfile::operator!=(const AutofillProfile& profile) const { 457 return !operator==(profile); 458} 459 460const base::string16 AutofillProfile::PrimaryValue() const { 461 return GetRawInfo(ADDRESS_HOME_LINE1) + GetRawInfo(ADDRESS_HOME_CITY); 462} 463 464bool AutofillProfile::IsSubsetOf(const AutofillProfile& profile, 465 const std::string& app_locale) const { 466 ServerFieldTypeSet types; 467 GetNonEmptyTypes(app_locale, &types); 468 469 for (ServerFieldTypeSet::const_iterator it = types.begin(); it != types.end(); 470 ++it) { 471 if (*it == NAME_FULL || *it == ADDRESS_HOME_STREET_ADDRESS) { 472 // Ignore the compound "full name" field type. We are only interested in 473 // comparing the constituent parts. For example, if |this| has a middle 474 // name saved, but |profile| lacks one, |profile| could still be a subset 475 // of |this|. Likewise, ignore the compound "street address" type, as we 476 // are only interested in matching line-by-line. 477 continue; 478 } else if (AutofillType(*it).group() == PHONE_HOME) { 479 // Phone numbers should be canonicalized prior to being compared. 480 if (*it != PHONE_HOME_WHOLE_NUMBER) { 481 continue; 482 } else if (!i18n::PhoneNumbersMatch( 483 GetRawInfo(*it), 484 profile.GetRawInfo(*it), 485 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)), 486 app_locale)) { 487 return false; 488 } 489 } else if (StringToLowerASCII(GetRawInfo(*it)) != 490 StringToLowerASCII(profile.GetRawInfo(*it))) { 491 return false; 492 } 493 } 494 495 return true; 496} 497 498void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile, 499 const std::string& app_locale) { 500 // Verified profiles should never be overwritten with unverified data. 501 DCHECK(!IsVerified() || profile.IsVerified()); 502 set_origin(profile.origin()); 503 504 ServerFieldTypeSet field_types; 505 profile.GetNonEmptyTypes(app_locale, &field_types); 506 507 // Only transfer "full" types (e.g. full name) and not fragments (e.g. 508 // first name, last name). 509 CollapseCompoundFieldTypes(&field_types); 510 511 // TODO(isherman): Revisit this decision in the context of i18n and storing 512 // full addresses rather than storing 1-to-2 lines of an address. 513 // For addresses, do the opposite: transfer individual address lines, rather 514 // than full addresses. 515 field_types.erase(ADDRESS_HOME_STREET_ADDRESS); 516 517 for (ServerFieldTypeSet::const_iterator iter = field_types.begin(); 518 iter != field_types.end(); ++iter) { 519 if (AutofillProfile::SupportsMultiValue(*iter)) { 520 std::vector<base::string16> new_values; 521 profile.GetRawMultiInfo(*iter, &new_values); 522 std::vector<base::string16> existing_values; 523 GetRawMultiInfo(*iter, &existing_values); 524 525 // GetMultiInfo always returns at least one element, even if the profile 526 // has no data stored for this field type. 527 if (existing_values.size() == 1 && existing_values.front().empty()) 528 existing_values.clear(); 529 530 FieldTypeGroup group = AutofillType(*iter).group(); 531 for (std::vector<base::string16>::iterator value_iter = 532 new_values.begin(); 533 value_iter != new_values.end(); ++value_iter) { 534 // Don't add duplicates. 535 if (group == PHONE_HOME) { 536 AddPhoneIfUnique(*value_iter, app_locale, &existing_values); 537 } else { 538 std::vector<base::string16>::const_iterator existing_iter = 539 std::find_if( 540 existing_values.begin(), existing_values.end(), 541 std::bind1st(CaseInsensitiveStringEquals(), *value_iter)); 542 if (existing_iter == existing_values.end()) 543 existing_values.insert(existing_values.end(), *value_iter); 544 } 545 } 546 SetRawMultiInfo(*iter, existing_values); 547 } else { 548 base::string16 new_value = profile.GetRawInfo(*iter); 549 if (StringToLowerASCII(GetRawInfo(*iter)) != 550 StringToLowerASCII(new_value)) { 551 SetRawInfo(*iter, new_value); 552 } 553 } 554 } 555} 556 557// static 558bool AutofillProfile::SupportsMultiValue(ServerFieldType type) { 559 FieldTypeGroup group = AutofillType(type).group(); 560 return group == NAME || 561 group == NAME_BILLING || 562 group == EMAIL || 563 group == PHONE_HOME || 564 group == PHONE_BILLING; 565} 566 567// static 568void AutofillProfile::CreateDifferentiatingLabels( 569 const std::vector<AutofillProfile*>& profiles, 570 std::vector<base::string16>* labels) { 571 const size_t kMinimalFieldsShown = 2; 572 CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown, 573 labels); 574 DCHECK_EQ(profiles.size(), labels->size()); 575} 576 577// static 578void AutofillProfile::CreateInferredLabels( 579 const std::vector<AutofillProfile*>& profiles, 580 const std::vector<ServerFieldType>* suggested_fields, 581 ServerFieldType excluded_field, 582 size_t minimal_fields_shown, 583 std::vector<base::string16>* labels) { 584 std::vector<ServerFieldType> fields_to_use; 585 GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field, 586 &fields_to_use); 587 588 // Construct the default label for each profile. Also construct a map that 589 // associates each label with the profiles that have this label. This map is 590 // then used to detect which labels need further differentiating fields. 591 std::map<base::string16, std::list<size_t> > labels_to_profiles; 592 for (size_t i = 0; i < profiles.size(); ++i) { 593 base::string16 label = 594 profiles[i]->ConstructInferredLabel(fields_to_use, 595 minimal_fields_shown); 596 labels_to_profiles[label].push_back(i); 597 } 598 599 labels->resize(profiles.size()); 600 for (std::map<base::string16, std::list<size_t> >::const_iterator it = 601 labels_to_profiles.begin(); 602 it != labels_to_profiles.end(); ++it) { 603 if (it->second.size() == 1) { 604 // This label is unique, so use it without any further ado. 605 base::string16 label = it->first; 606 size_t profile_index = it->second.front(); 607 (*labels)[profile_index] = label; 608 } else { 609 // We have more than one profile with the same label, so add 610 // differentiating fields. 611 CreateInferredLabelsHelper(profiles, it->second, fields_to_use, 612 minimal_fields_shown, labels); 613 } 614 } 615} 616 617void AutofillProfile::GetSupportedTypes( 618 ServerFieldTypeSet* supported_types) const { 619 FormGroupList info = FormGroups(); 620 for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it) 621 (*it)->GetSupportedTypes(supported_types); 622} 623 624void AutofillProfile::GetMultiInfoImpl( 625 const AutofillType& type, 626 const std::string& app_locale, 627 std::vector<base::string16>* values) const { 628 switch (type.group()) { 629 case NAME: 630 case NAME_BILLING: 631 CopyItemsToValues(type, name_, app_locale, values); 632 break; 633 case EMAIL: 634 CopyItemsToValues(type, email_, app_locale, values); 635 break; 636 case PHONE_HOME: 637 case PHONE_BILLING: 638 CopyItemsToValues(type, phone_number_, app_locale, values); 639 break; 640 default: 641 values->resize(1); 642 (*values)[0] = GetFormGroupInfo(*this, type, app_locale); 643 } 644} 645 646void AutofillProfile::AddPhoneIfUnique( 647 const base::string16& phone, 648 const std::string& app_locale, 649 std::vector<base::string16>* existing_phones) { 650 DCHECK(existing_phones); 651 // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377", 652 // "(800)356-9377" and "356-9377" are considered the same. 653 std::string country_code = 654 base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)); 655 if (std::find_if(existing_phones->begin(), existing_phones->end(), 656 FindByPhone(phone, country_code, app_locale)) == 657 existing_phones->end()) { 658 existing_phones->push_back(phone); 659 } 660} 661 662base::string16 AutofillProfile::ConstructInferredLabel( 663 const std::vector<ServerFieldType>& included_fields, 664 size_t num_fields_to_use) const { 665 const base::string16 separator = 666 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR); 667 668 base::string16 label; 669 size_t num_fields_used = 0; 670 for (std::vector<ServerFieldType>::const_iterator it = 671 included_fields.begin(); 672 it != included_fields.end() && num_fields_used < num_fields_to_use; 673 ++it) { 674 base::string16 field = GetRawInfo(*it); 675 if (field.empty()) 676 continue; 677 678 if (!label.empty()) 679 label.append(separator); 680 681 label.append(field); 682 ++num_fields_used; 683 } 684 685 // Flatten the label if need be. 686 const base::char16 kNewline[] = { '\n', 0 }; 687 const base::string16 newline_separator = 688 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_SEPARATOR); 689 base::ReplaceChars(label, kNewline, newline_separator, &label); 690 691 return label; 692} 693 694// static 695void AutofillProfile::CreateInferredLabelsHelper( 696 const std::vector<AutofillProfile*>& profiles, 697 const std::list<size_t>& indices, 698 const std::vector<ServerFieldType>& fields, 699 size_t num_fields_to_include, 700 std::vector<base::string16>* labels) { 701 // For efficiency, we first construct a map of fields to their text values and 702 // each value's frequency. 703 std::map<ServerFieldType, 704 std::map<base::string16, size_t> > field_text_frequencies_by_field; 705 for (std::vector<ServerFieldType>::const_iterator field = fields.begin(); 706 field != fields.end(); ++field) { 707 std::map<base::string16, size_t>& field_text_frequencies = 708 field_text_frequencies_by_field[*field]; 709 710 for (std::list<size_t>::const_iterator it = indices.begin(); 711 it != indices.end(); ++it) { 712 const AutofillProfile* profile = profiles[*it]; 713 base::string16 field_text = profile->GetRawInfo(*field); 714 715 // If this label is not already in the map, add it with frequency 0. 716 if (!field_text_frequencies.count(field_text)) 717 field_text_frequencies[field_text] = 0; 718 719 // Now, increment the frequency for this label. 720 ++field_text_frequencies[field_text]; 721 } 722 } 723 724 // Now comes the meat of the algorithm. For each profile, we scan the list of 725 // fields to use, looking for two things: 726 // 1. A (non-empty) field that differentiates the profile from all others 727 // 2. At least |num_fields_to_include| non-empty fields 728 // Before we've satisfied condition (2), we include all fields, even ones that 729 // are identical across all the profiles. Once we've satisfied condition (2), 730 // we only include fields that that have at last two distinct values. 731 for (std::list<size_t>::const_iterator it = indices.begin(); 732 it != indices.end(); ++it) { 733 const AutofillProfile* profile = profiles[*it]; 734 735 std::vector<ServerFieldType> label_fields; 736 bool found_differentiating_field = false; 737 for (std::vector<ServerFieldType>::const_iterator field = fields.begin(); 738 field != fields.end(); ++field) { 739 // Skip over empty fields. 740 base::string16 field_text = profile->GetRawInfo(*field); 741 if (field_text.empty()) 742 continue; 743 744 std::map<base::string16, size_t>& field_text_frequencies = 745 field_text_frequencies_by_field[*field]; 746 found_differentiating_field |= 747 !field_text_frequencies.count(base::string16()) && 748 (field_text_frequencies[field_text] == 1); 749 750 // Once we've found enough non-empty fields, skip over any remaining 751 // fields that are identical across all the profiles. 752 if (label_fields.size() >= num_fields_to_include && 753 (field_text_frequencies.size() == 1)) 754 continue; 755 756 label_fields.push_back(*field); 757 758 // If we've (1) found a differentiating field and (2) found at least 759 // |num_fields_to_include| non-empty fields, we're done! 760 if (found_differentiating_field && 761 label_fields.size() >= num_fields_to_include) 762 break; 763 } 764 765 (*labels)[*it] = 766 profile->ConstructInferredLabel(label_fields, label_fields.size()); 767 } 768} 769 770AutofillProfile::FormGroupList AutofillProfile::FormGroups() const { 771 FormGroupList v(5); 772 v[0] = &name_[0]; 773 v[1] = &email_[0]; 774 v[2] = &company_; 775 v[3] = &phone_number_[0]; 776 v[4] = &address_; 777 return v; 778} 779 780const FormGroup* AutofillProfile::FormGroupForType( 781 const AutofillType& type) const { 782 return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type); 783} 784 785FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) { 786 switch (type.group()) { 787 case NAME: 788 case NAME_BILLING: 789 return &name_[0]; 790 791 case EMAIL: 792 return &email_[0]; 793 794 case COMPANY: 795 return &company_; 796 797 case PHONE_HOME: 798 case PHONE_BILLING: 799 return &phone_number_[0]; 800 801 case ADDRESS_HOME: 802 case ADDRESS_BILLING: 803 return &address_; 804 805 case NO_GROUP: 806 case CREDIT_CARD: 807 case PASSWORD_FIELD: 808 return NULL; 809 } 810 811 NOTREACHED(); 812 return NULL; 813} 814 815// So we can compare AutofillProfiles with EXPECT_EQ(). 816std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) { 817 return os 818 << profile.guid() 819 << " " 820 << profile.origin() 821 << " " 822 << UTF16ToUTF8(MultiString(profile, NAME_FIRST)) 823 << " " 824 << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE)) 825 << " " 826 << UTF16ToUTF8(MultiString(profile, NAME_LAST)) 827 << " " 828 << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS)) 829 << " " 830 << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME)) 831 << " " 832 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1)) 833 << " " 834 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2)) 835 << " " 836 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)) 837 << " " 838 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY)) 839 << " " 840 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE)) 841 << " " 842 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP)) 843 << " " 844 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)) 845 << " " 846 << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)) 847 << " " 848 << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER)); 849} 850 851} // namespace autofill 852