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