Home | History | Annotate | Download | only in autofill
      1 // Copyright (c) 2011 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 "chrome/browser/autofill/autofill_profile.h"
      6 
      7 #include <algorithm>
      8 #include <map>
      9 #include <set>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/logging.h"
     13 #include "base/string_util.h"
     14 #include "base/utf_string_conversions.h"
     15 #include "chrome/browser/autofill/address.h"
     16 #include "chrome/browser/autofill/autofill_type.h"
     17 #include "chrome/browser/autofill/contact_info.h"
     18 #include "chrome/browser/autofill/fax_number.h"
     19 #include "chrome/browser/autofill/home_phone_number.h"
     20 #include "chrome/common/guid.h"
     21 #include "grit/generated_resources.h"
     22 #include "ui/base/l10n/l10n_util.h"
     23 
     24 namespace {
     25 
     26 // Like |AutofillType::GetEquivalentFieldType()|, but also returns |NAME_FULL|
     27 // for first, middle, and last name field types.
     28 AutofillFieldType GetEquivalentFieldTypeCollapsingNames(
     29     AutofillFieldType field_type) {
     30   if (field_type == NAME_FIRST || field_type == NAME_MIDDLE ||
     31       field_type == NAME_LAST)
     32     return NAME_FULL;
     33 
     34   return AutofillType::GetEquivalentFieldType(field_type);
     35 }
     36 
     37 // Fills |distinguishing_fields| with a list of fields to use when creating
     38 // labels that can help to distinguish between two profiles. Draws fields from
     39 // |suggested_fields| if it is non-NULL; otherwise returns a default list.
     40 // If |suggested_fields| is non-NULL, does not include |excluded_field| in the
     41 // list. Otherwise, |excluded_field| is ignored, and should be set to
     42 // |UNKNOWN_TYPE| by convention. The resulting list of fields is sorted in
     43 // decreasing order of importance.
     44 void GetFieldsForDistinguishingProfiles(
     45     const std::vector<AutofillFieldType>* suggested_fields,
     46     AutofillFieldType excluded_field,
     47     std::vector<AutofillFieldType>* distinguishing_fields) {
     48   static const AutofillFieldType kDefaultDistinguishingFields[] = {
     49     NAME_FULL,
     50     ADDRESS_HOME_LINE1,
     51     ADDRESS_HOME_CITY,
     52     ADDRESS_HOME_STATE,
     53     ADDRESS_HOME_ZIP,
     54     ADDRESS_HOME_COUNTRY,
     55     EMAIL_ADDRESS,
     56     PHONE_HOME_WHOLE_NUMBER,
     57     PHONE_FAX_WHOLE_NUMBER,
     58     COMPANY_NAME,
     59   };
     60 
     61   if (!suggested_fields) {
     62     DCHECK_EQ(excluded_field, UNKNOWN_TYPE);
     63     distinguishing_fields->assign(
     64         kDefaultDistinguishingFields,
     65         kDefaultDistinguishingFields + arraysize(kDefaultDistinguishingFields));
     66     return;
     67   }
     68 
     69   // Keep track of which fields we've seen so that we avoid duplicate entries.
     70   // Always ignore fields of unknown type and the excluded field.
     71   std::set<AutofillFieldType> seen_fields;
     72   seen_fields.insert(UNKNOWN_TYPE);
     73   seen_fields.insert(GetEquivalentFieldTypeCollapsingNames(excluded_field));
     74 
     75   distinguishing_fields->clear();
     76   for (std::vector<AutofillFieldType>::const_iterator it =
     77            suggested_fields->begin();
     78        it != suggested_fields->end(); ++it) {
     79     AutofillFieldType suggested_type =
     80         GetEquivalentFieldTypeCollapsingNames(*it);
     81     if (seen_fields.insert(suggested_type).second)
     82       distinguishing_fields->push_back(suggested_type);
     83   }
     84 
     85   // Special case: If the excluded field is a partial name (e.g. first name) and
     86   // the suggested fields include other name fields, include |NAME_FULL| in the
     87   // list of distinguishing fields as a last-ditch fallback. This allows us to
     88   // distinguish between profiles that are identical except for the name.
     89   if (excluded_field != NAME_FULL &&
     90       GetEquivalentFieldTypeCollapsingNames(excluded_field) == NAME_FULL) {
     91     for (std::vector<AutofillFieldType>::const_iterator it =
     92              suggested_fields->begin();
     93          it != suggested_fields->end(); ++it) {
     94       if (*it != excluded_field &&
     95           GetEquivalentFieldTypeCollapsingNames(*it) == NAME_FULL) {
     96         distinguishing_fields->push_back(NAME_FULL);
     97         break;
     98       }
     99     }
    100   }
    101 }
    102 
    103 // A helper function for string streaming.  Concatenates multi-valued entries
    104 // stored for a given |type| into a single string.  This string is returned.
    105 const string16 MultiString(const AutofillProfile& p, AutofillFieldType type) {
    106   std::vector<string16> values;
    107   p.GetMultiInfo(type, &values);
    108   string16 accumulate;
    109   for (size_t i = 0; i < values.size(); ++i) {
    110     if (i > 0)
    111       accumulate += ASCIIToUTF16(" ");
    112     accumulate += values[i];
    113   }
    114   return accumulate;
    115 }
    116 
    117 template <class T>
    118 void CopyValuesToItems(AutofillFieldType type,
    119                        const std::vector<string16>& values,
    120                        std::vector<T>* form_group_items) {
    121   form_group_items->resize(values.size());
    122   for (size_t i = 0; i < form_group_items->size(); ++i)
    123     (*form_group_items)[i].SetInfo(type, CollapseWhitespace(values[i], false));
    124   // Must have at least one (possibly empty) element.
    125   if (form_group_items->empty())
    126     form_group_items->resize(1);
    127 }
    128 
    129 template <class T>
    130 void CopyItemsToValues(AutofillFieldType type,
    131                        const std::vector<T>& form_group_items,
    132                        std::vector<string16>* values) {
    133   values->resize(form_group_items.size());
    134   for (size_t i = 0; i < values->size(); ++i)
    135     (*values)[i] = form_group_items[i].GetInfo(type);
    136 }
    137 
    138 // Collapse compound field types to their "full" type.  I.e. First name
    139 // collapses to full name, area code collapses to full phone, etc.
    140 void CollapseCompoundFieldTypes(FieldTypeSet* type_set) {
    141   FieldTypeSet collapsed_set;
    142   for (FieldTypeSet::iterator iter = type_set->begin(); iter != type_set->end();
    143        ++iter) {
    144     switch (*iter) {
    145       case NAME_FIRST:
    146       case NAME_MIDDLE:
    147       case NAME_LAST:
    148       case NAME_MIDDLE_INITIAL:
    149       case NAME_FULL:
    150       case NAME_SUFFIX:
    151         collapsed_set.insert(NAME_FULL);
    152         break;
    153 
    154       case PHONE_HOME_NUMBER:
    155       case PHONE_HOME_CITY_CODE:
    156       case PHONE_HOME_COUNTRY_CODE:
    157       case PHONE_HOME_CITY_AND_NUMBER:
    158       case PHONE_HOME_WHOLE_NUMBER:
    159         collapsed_set.insert(PHONE_HOME_WHOLE_NUMBER);
    160         break;
    161 
    162       case PHONE_FAX_NUMBER:
    163       case PHONE_FAX_CITY_CODE:
    164       case PHONE_FAX_COUNTRY_CODE:
    165       case PHONE_FAX_CITY_AND_NUMBER:
    166       case PHONE_FAX_WHOLE_NUMBER:
    167         collapsed_set.insert(PHONE_FAX_WHOLE_NUMBER);
    168         break;
    169 
    170       default:
    171         collapsed_set.insert(*iter);
    172     }
    173   }
    174   std::swap(*type_set, collapsed_set);
    175 }
    176 
    177 }  // namespace
    178 
    179 AutofillProfile::AutofillProfile(const std::string& guid)
    180     : guid_(guid), name_(1), email_(1), home_number_(1), fax_number_(1) {
    181 }
    182 
    183 AutofillProfile::AutofillProfile()
    184     : guid_(guid::GenerateGUID()),
    185       name_(1),
    186       email_(1),
    187       home_number_(1),
    188       fax_number_(1) {
    189 }
    190 
    191 AutofillProfile::AutofillProfile(const AutofillProfile& profile)
    192     : FormGroup() {
    193   operator=(profile);
    194 }
    195 
    196 AutofillProfile::~AutofillProfile() {
    197 }
    198 
    199 AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
    200   if (this == &profile)
    201     return *this;
    202 
    203   label_ = profile.label_;
    204   guid_ = profile.guid_;
    205 
    206   name_ = profile.name_;
    207   email_ = profile.email_;
    208   company_ = profile.company_;
    209   home_number_ = profile.home_number_;
    210   fax_number_ = profile.fax_number_;
    211   address_ = profile.address_;
    212 
    213   return *this;
    214 }
    215 
    216 void AutofillProfile::GetPossibleFieldTypes(
    217     const string16& text,
    218     FieldTypeSet* possible_types) const {
    219   FormGroupList info = FormGroups();
    220   for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
    221     (*it)->GetPossibleFieldTypes(text, possible_types);
    222 }
    223 
    224 void AutofillProfile::GetAvailableFieldTypes(
    225     FieldTypeSet* available_types) const {
    226   FormGroupList info = FormGroups();
    227   for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
    228     (*it)->GetAvailableFieldTypes(available_types);
    229 }
    230 
    231 string16 AutofillProfile::GetInfo(AutofillFieldType type) const {
    232   AutofillFieldType return_type = AutofillType::GetEquivalentFieldType(type);
    233   const FormGroup* form_group = FormGroupForType(return_type);
    234   if (!form_group)
    235     return string16();
    236 
    237   return form_group->GetInfo(return_type);
    238 }
    239 
    240 void AutofillProfile::SetInfo(AutofillFieldType type, const string16& value) {
    241   FormGroup* form_group = MutableFormGroupForType(type);
    242   if (form_group)
    243     form_group->SetInfo(type, CollapseWhitespace(value, false));
    244 }
    245 
    246 void AutofillProfile::SetMultiInfo(AutofillFieldType type,
    247                                    const std::vector<string16>& values) {
    248   switch (AutofillType(type).group()) {
    249     case AutofillType::NAME:
    250       CopyValuesToItems(type, values, &name_);
    251       break;
    252     case AutofillType::EMAIL:
    253       CopyValuesToItems(type, values, &email_);
    254       break;
    255     case AutofillType::PHONE_HOME:
    256       CopyValuesToItems(type, values, &home_number_);
    257       break;
    258     case AutofillType::PHONE_FAX:
    259       CopyValuesToItems(type, values, &fax_number_);
    260       break;
    261     default:
    262       if (values.size() == 1) {
    263         SetInfo(type, values[0]);
    264       } else if (values.size() == 0) {
    265         SetInfo(type, string16());
    266       } else {
    267         NOTREACHED()
    268             << "Attempt to set multiple values on single-valued field.";
    269       }
    270       break;
    271   }
    272 }
    273 
    274 void AutofillProfile::GetMultiInfo(AutofillFieldType type,
    275                                    std::vector<string16>* values) const {
    276   switch (AutofillType(type).group()) {
    277     case AutofillType::NAME:
    278       CopyItemsToValues(type, name_, values);
    279       break;
    280     case AutofillType::EMAIL:
    281       CopyItemsToValues(type, email_, values);
    282       break;
    283     case AutofillType::PHONE_HOME:
    284       CopyItemsToValues(type, home_number_, values);
    285       break;
    286     case AutofillType::PHONE_FAX:
    287       CopyItemsToValues(type, fax_number_, values);
    288       break;
    289     default:
    290       values->resize(1);
    291       (*values)[0] = GetInfo(type);
    292   }
    293 }
    294 
    295 // static
    296 bool AutofillProfile::SupportsMultiValue(AutofillFieldType type) {
    297   AutofillType::FieldTypeGroup group = AutofillType(type).group();
    298   return group == AutofillType::NAME ||
    299          group == AutofillType::EMAIL ||
    300          group == AutofillType::PHONE_HOME ||
    301          group == AutofillType::PHONE_FAX;
    302 }
    303 
    304 const string16 AutofillProfile::Label() const {
    305   return label_;
    306 }
    307 
    308 const std::string AutofillProfile::CountryCode() const {
    309   return address_.country_code();
    310 }
    311 
    312 void AutofillProfile::SetCountryCode(const std::string& country_code) {
    313   address_.set_country_code(country_code);
    314 }
    315 
    316 // static
    317 bool AutofillProfile::AdjustInferredLabels(
    318     std::vector<AutofillProfile*>* profiles) {
    319   const size_t kMinimalFieldsShown = 2;
    320 
    321   std::vector<string16> created_labels;
    322   CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
    323                        &created_labels);
    324   DCHECK_EQ(profiles->size(), created_labels.size());
    325 
    326   bool updated_labels = false;
    327   for (size_t i = 0; i < profiles->size(); ++i) {
    328     if ((*profiles)[i]->Label() != created_labels[i]) {
    329       updated_labels = true;
    330       (*profiles)[i]->label_ = created_labels[i];
    331     }
    332   }
    333   return updated_labels;
    334 }
    335 
    336 // static
    337 void AutofillProfile::CreateInferredLabels(
    338     const std::vector<AutofillProfile*>* profiles,
    339     const std::vector<AutofillFieldType>* suggested_fields,
    340     AutofillFieldType excluded_field,
    341     size_t minimal_fields_shown,
    342     std::vector<string16>* created_labels) {
    343   DCHECK(profiles);
    344   DCHECK(created_labels);
    345 
    346   std::vector<AutofillFieldType> fields_to_use;
    347   GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
    348                                      &fields_to_use);
    349 
    350   // Construct the default label for each profile. Also construct a map that
    351   // associates each label with the profiles that have this label. This map is
    352   // then used to detect which labels need further differentiating fields.
    353   std::map<string16, std::list<size_t> > labels;
    354   for (size_t i = 0; i < profiles->size(); ++i) {
    355     string16 label =
    356         (*profiles)[i]->ConstructInferredLabel(fields_to_use,
    357                                                minimal_fields_shown);
    358     labels[label].push_back(i);
    359   }
    360 
    361   created_labels->resize(profiles->size());
    362   for (std::map<string16, std::list<size_t> >::const_iterator it =
    363            labels.begin();
    364        it != labels.end(); ++it) {
    365     if (it->second.size() == 1) {
    366       // This label is unique, so use it without any further ado.
    367       string16 label = it->first;
    368       size_t profile_index = it->second.front();
    369       (*created_labels)[profile_index] = label;
    370     } else {
    371       // We have more than one profile with the same label, so add
    372       // differentiating fields.
    373       CreateDifferentiatingLabels(*profiles, it->second, fields_to_use,
    374                                   minimal_fields_shown, created_labels);
    375     }
    376   }
    377 }
    378 
    379 bool AutofillProfile::IsEmpty() const {
    380   FieldTypeSet types;
    381   GetAvailableFieldTypes(&types);
    382   return types.empty();
    383 }
    384 
    385 int AutofillProfile::Compare(const AutofillProfile& profile) const {
    386   // The following Autofill field types are the only types we store in the WebDB
    387   // so far, so we're only concerned with matching these types in the profile.
    388   const AutofillFieldType types[] = { NAME_FIRST,
    389                                       NAME_MIDDLE,
    390                                       NAME_LAST,
    391                                       EMAIL_ADDRESS,
    392                                       COMPANY_NAME,
    393                                       ADDRESS_HOME_LINE1,
    394                                       ADDRESS_HOME_LINE2,
    395                                       ADDRESS_HOME_CITY,
    396                                       ADDRESS_HOME_STATE,
    397                                       ADDRESS_HOME_ZIP,
    398                                       ADDRESS_HOME_COUNTRY,
    399                                       PHONE_HOME_NUMBER,
    400                                       PHONE_FAX_NUMBER };
    401 
    402   for (size_t index = 0; index < arraysize(types); ++index) {
    403     int comparison = GetInfo(types[index]).compare(
    404         profile.GetInfo(types[index]));
    405     if (comparison != 0)
    406       return comparison;
    407   }
    408 
    409   return 0;
    410 }
    411 
    412 int AutofillProfile::CompareMulti(const AutofillProfile& profile) const {
    413   const AutofillFieldType single_value_types[] = { COMPANY_NAME,
    414                                                    ADDRESS_HOME_LINE1,
    415                                                    ADDRESS_HOME_LINE2,
    416                                                    ADDRESS_HOME_CITY,
    417                                                    ADDRESS_HOME_STATE,
    418                                                    ADDRESS_HOME_ZIP,
    419                                                    ADDRESS_HOME_COUNTRY };
    420 
    421   for (size_t i = 0; i < arraysize(single_value_types); ++i) {
    422     int comparison = GetInfo(single_value_types[i]).compare(
    423         profile.GetInfo(single_value_types[i]));
    424     if (comparison != 0)
    425       return comparison;
    426   }
    427 
    428   const AutofillFieldType multi_value_types[] = { NAME_FIRST,
    429                                                   NAME_MIDDLE,
    430                                                   NAME_LAST,
    431                                                   EMAIL_ADDRESS,
    432                                                   PHONE_HOME_NUMBER,
    433                                                   PHONE_FAX_NUMBER };
    434 
    435   for (size_t i = 0; i < arraysize(multi_value_types); ++i) {
    436     std::vector<string16> values_a;
    437     std::vector<string16> values_b;
    438     GetMultiInfo(multi_value_types[i], &values_a);
    439     profile.GetMultiInfo(multi_value_types[i], &values_b);
    440     if (values_a.size() < values_b.size())
    441       return -1;
    442     if (values_a.size() > values_b.size())
    443       return 1;
    444     for (size_t j = 0; j < values_a.size(); ++j) {
    445       int comparison = values_a[j].compare(values_b[j]);
    446       if (comparison != 0)
    447         return comparison;
    448     }
    449   }
    450 
    451   return 0;
    452 }
    453 
    454 bool AutofillProfile::operator==(const AutofillProfile& profile) const {
    455   return guid_ == profile.guid_ && Compare(profile) == 0;
    456 }
    457 
    458 bool AutofillProfile::operator!=(const AutofillProfile& profile) const {
    459   return !operator==(profile);
    460 }
    461 
    462 const string16 AutofillProfile::PrimaryValue() const {
    463   return GetInfo(ADDRESS_HOME_LINE1) +
    464          GetInfo(ADDRESS_HOME_CITY);
    465 }
    466 
    467 void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile) {
    468   FieldTypeSet field_types;
    469   profile.GetAvailableFieldTypes(&field_types);
    470 
    471   // Only transfer "full" types (e.g. full name) and not fragments (e.g.
    472   // first name, last name).
    473   CollapseCompoundFieldTypes(&field_types);
    474 
    475   for (FieldTypeSet::const_iterator iter = field_types.begin();
    476        iter != field_types.end(); ++iter) {
    477     if (AutofillProfile::SupportsMultiValue(*iter)) {
    478       std::vector<string16> new_values;
    479       profile.GetMultiInfo(*iter, &new_values);
    480       std::vector<string16> existing_values;
    481       GetMultiInfo(*iter, &existing_values);
    482       for (std::vector<string16>::iterator value_iter = new_values.begin();
    483            value_iter != new_values.end(); ++value_iter) {
    484         // Don't add duplicates.
    485         if (std::find(existing_values.begin(), existing_values.end(),
    486                       *value_iter) == existing_values.end()) {
    487           existing_values.insert(existing_values.end(), *value_iter);
    488         }
    489       }
    490       SetMultiInfo(*iter, existing_values);
    491     } else {
    492       SetInfo(*iter, profile.GetInfo(*iter));
    493     }
    494   }
    495 }
    496 
    497 string16 AutofillProfile::ConstructInferredLabel(
    498     const std::vector<AutofillFieldType>& included_fields,
    499     size_t num_fields_to_use) const {
    500   const string16 separator =
    501       l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_SEPARATOR);
    502 
    503   string16 label;
    504   size_t num_fields_used = 0;
    505   for (std::vector<AutofillFieldType>::const_iterator it =
    506            included_fields.begin();
    507        it != included_fields.end() && num_fields_used < num_fields_to_use;
    508        ++it) {
    509     string16 field = GetInfo(*it);
    510     if (field.empty())
    511       continue;
    512 
    513     if (!label.empty())
    514       label.append(separator);
    515 
    516 #ifndef ANDROID
    517     // Fax number has special format, to indicate that this is a fax number.
    518     if (*it == PHONE_FAX_WHOLE_NUMBER) {
    519       field = l10n_util::GetStringFUTF16(
    520           IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_FAX_FORMAT, field);
    521     }
    522 #endif
    523     label.append(field);
    524     ++num_fields_used;
    525   }
    526   return label;
    527 }
    528 
    529 // static
    530 void AutofillProfile::CreateDifferentiatingLabels(
    531     const std::vector<AutofillProfile*>& profiles,
    532     const std::list<size_t>& indices,
    533     const std::vector<AutofillFieldType>& fields,
    534     size_t num_fields_to_include,
    535     std::vector<string16>* created_labels) {
    536   // For efficiency, we first construct a map of fields to their text values and
    537   // each value's frequency.
    538   std::map<AutofillFieldType,
    539            std::map<string16, size_t> > field_text_frequencies_by_field;
    540   for (std::vector<AutofillFieldType>::const_iterator field = fields.begin();
    541        field != fields.end(); ++field) {
    542     std::map<string16, size_t>& field_text_frequencies =
    543         field_text_frequencies_by_field[*field];
    544 
    545     for (std::list<size_t>::const_iterator it = indices.begin();
    546          it != indices.end(); ++it) {
    547       const AutofillProfile* profile = profiles[*it];
    548       string16 field_text = profile->GetInfo(*field);
    549 
    550       // If this label is not already in the map, add it with frequency 0.
    551       if (!field_text_frequencies.count(field_text))
    552         field_text_frequencies[field_text] = 0;
    553 
    554       // Now, increment the frequency for this label.
    555       ++field_text_frequencies[field_text];
    556     }
    557   }
    558 
    559   // Now comes the meat of the algorithm. For each profile, we scan the list of
    560   // fields to use, looking for two things:
    561   //  1. A (non-empty) field that differentiates the profile from all others
    562   //  2. At least |num_fields_to_include| non-empty fields
    563   // Before we've satisfied condition (2), we include all fields, even ones that
    564   // are identical across all the profiles. Once we've satisfied condition (2),
    565   // we only include fields that that have at last two distinct values.
    566   for (std::list<size_t>::const_iterator it = indices.begin();
    567        it != indices.end(); ++it) {
    568     const AutofillProfile* profile = profiles[*it];
    569 
    570     std::vector<AutofillFieldType> label_fields;
    571     bool found_differentiating_field = false;
    572     for (std::vector<AutofillFieldType>::const_iterator field = fields.begin();
    573          field != fields.end(); ++field) {
    574       // Skip over empty fields.
    575       string16 field_text = profile->GetInfo(*field);
    576       if (field_text.empty())
    577         continue;
    578 
    579       std::map<string16, size_t>& field_text_frequencies =
    580           field_text_frequencies_by_field[*field];
    581       found_differentiating_field |=
    582           !field_text_frequencies.count(string16()) &&
    583           (field_text_frequencies[field_text] == 1);
    584 
    585       // Once we've found enough non-empty fields, skip over any remaining
    586       // fields that are identical across all the profiles.
    587       if (label_fields.size() >= num_fields_to_include &&
    588           (field_text_frequencies.size() == 1))
    589         continue;
    590 
    591       label_fields.push_back(*field);
    592 
    593       // If we've (1) found a differentiating field and (2) found at least
    594       // |num_fields_to_include| non-empty fields, we're done!
    595       if (found_differentiating_field &&
    596           label_fields.size() >= num_fields_to_include)
    597         break;
    598     }
    599 
    600     (*created_labels)[*it] =
    601         profile->ConstructInferredLabel(label_fields,
    602                                         label_fields.size());
    603   }
    604 }
    605 
    606 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
    607   FormGroupList v(6);
    608   v[0] = &name_[0];
    609   v[1] = &email_[0];
    610   v[2] = &company_;
    611   v[3] = &home_number_[0];
    612   v[4] = &fax_number_[0];
    613   v[5] = &address_;
    614   return v;
    615 }
    616 
    617 const FormGroup* AutofillProfile::FormGroupForType(
    618     AutofillFieldType type) const {
    619   return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
    620 }
    621 
    622 FormGroup* AutofillProfile::MutableFormGroupForType(AutofillFieldType type) {
    623  FormGroup* form_group = NULL;
    624   switch (AutofillType(type).group()) {
    625     case AutofillType::NAME:
    626       form_group = &name_[0];
    627       break;
    628     case AutofillType::EMAIL:
    629       form_group = &email_[0];
    630       break;
    631     case AutofillType::COMPANY:
    632       form_group = &company_;
    633       break;
    634     case AutofillType::PHONE_HOME:
    635       form_group = &home_number_[0];
    636       break;
    637     case AutofillType::PHONE_FAX:
    638       form_group = &fax_number_[0];
    639       break;
    640     case AutofillType::ADDRESS_HOME:
    641       form_group = &address_;
    642       break;
    643     default:
    644       break;
    645   }
    646   return form_group;
    647 }
    648 
    649 // So we can compare AutofillProfiles with EXPECT_EQ().
    650 std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
    651   return os
    652       << UTF16ToUTF8(profile.Label())
    653       << " "
    654       << profile.guid()
    655       << " "
    656       << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
    657       << " "
    658       << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
    659       << " "
    660       << UTF16ToUTF8(MultiString(profile, NAME_LAST))
    661       << " "
    662       << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
    663       << " "
    664       << UTF16ToUTF8(profile.GetInfo(COMPANY_NAME))
    665       << " "
    666       << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE1))
    667       << " "
    668       << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE2))
    669       << " "
    670       << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_CITY))
    671       << " "
    672       << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_STATE))
    673       << " "
    674       << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_ZIP))
    675       << " "
    676       << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_COUNTRY))
    677       << " "
    678       << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER))
    679       << " "
    680       << UTF16ToUTF8(MultiString(profile, PHONE_FAX_WHOLE_NUMBER));
    681 }
    682