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/contact_info.h"
      6 
      7 #include <stddef.h>
      8 #include <ostream>
      9 #include <string>
     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/autofill_type.h"
     16 #include "chrome/browser/autofill/field_types.h"
     17 
     18 static const string16 kNameSplitChars = ASCIIToUTF16("-'. ");
     19 
     20 static const AutofillFieldType kAutofillNameInfoTypes[] = {
     21   NAME_FIRST,
     22   NAME_MIDDLE,
     23   NAME_LAST
     24 };
     25 
     26 static const size_t kAutofillNameInfoLength =
     27     arraysize(kAutofillNameInfoTypes);
     28 
     29 NameInfo::NameInfo() {}
     30 
     31 NameInfo::NameInfo(const NameInfo& info) : FormGroup() {
     32   *this = info;
     33 }
     34 
     35 NameInfo::~NameInfo() {}
     36 
     37 NameInfo& NameInfo::operator=(const NameInfo& info) {
     38   if (this == &info)
     39     return *this;
     40 
     41   first_tokens_ = info.first_tokens_;
     42   middle_tokens_ = info.middle_tokens_;
     43   last_tokens_ = info.last_tokens_;
     44   first_ = info.first_;
     45   middle_ = info.middle_;
     46   last_ = info.last_;
     47   return *this;
     48 }
     49 
     50 void NameInfo::GetPossibleFieldTypes(const string16& text,
     51                                         FieldTypeSet* possible_types) const {
     52   DCHECK(possible_types);
     53 
     54   if (IsFirstName(text))
     55     possible_types->insert(NAME_FIRST);
     56 
     57   if (IsMiddleName(text))
     58     possible_types->insert(NAME_MIDDLE);
     59 
     60   if (IsLastName(text))
     61     possible_types->insert(NAME_LAST);
     62 
     63   if (IsMiddleInitial(text))
     64     possible_types->insert(NAME_MIDDLE_INITIAL);
     65 
     66   if (IsFullName(text))
     67     possible_types->insert(NAME_FULL);
     68 }
     69 
     70 void NameInfo::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
     71   DCHECK(available_types);
     72 
     73   if (!first().empty())
     74     available_types->insert(NAME_FIRST);
     75 
     76   if (!middle().empty())
     77     available_types->insert(NAME_MIDDLE);
     78 
     79   if (!last().empty())
     80     available_types->insert(NAME_LAST);
     81 
     82   if (!MiddleInitial().empty())
     83     available_types->insert(NAME_MIDDLE_INITIAL);
     84 
     85   if (!FullName().empty())
     86     available_types->insert(NAME_FULL);
     87 }
     88 
     89 string16 NameInfo::GetInfo(AutofillFieldType type) const {
     90   if (type == NAME_FIRST)
     91     return first();
     92 
     93   if (type == NAME_MIDDLE)
     94     return middle();
     95 
     96   if (type == NAME_LAST)
     97     return last();
     98 
     99   if (type == NAME_MIDDLE_INITIAL)
    100     return MiddleInitial();
    101 
    102   if (type == NAME_FULL)
    103     return FullName();
    104 
    105   return string16();
    106 }
    107 
    108 void NameInfo::SetInfo(AutofillFieldType type, const string16& value) {
    109   DCHECK_EQ(AutofillType::NAME, AutofillType(type).group());
    110   if (type == NAME_FIRST)
    111     SetFirst(value);
    112   else if (type == NAME_MIDDLE || type == NAME_MIDDLE_INITIAL)
    113     SetMiddle(value);
    114   else if (type == NAME_LAST)
    115     SetLast(value);
    116   else if (type == NAME_FULL)
    117     SetFullName(value);
    118   else
    119     NOTREACHED();
    120 }
    121 
    122 string16 NameInfo::FullName() const {
    123   if (first_.empty())
    124     return string16();
    125 
    126   std::vector<string16> full_name;
    127   full_name.push_back(first_);
    128 
    129   if (!middle_.empty())
    130     full_name.push_back(middle_);
    131 
    132   if (!last_.empty())
    133     full_name.push_back(last_);
    134 
    135   return JoinString(full_name, ' ');
    136 }
    137 
    138 string16 NameInfo::MiddleInitial() const {
    139   if (middle_.empty())
    140     return string16();
    141 
    142   string16 middle_name(middle());
    143   string16 initial;
    144   initial.push_back(middle_name[0]);
    145   return initial;
    146 }
    147 
    148 // If each of the 'words' contained in the text are also present in the first
    149 // name then we will consider the text to be of type kFirstName. This means
    150 // that people with multiple first names will be able to enter any one of
    151 // their first names and have it correctly recognized.
    152 bool NameInfo::IsFirstName(const string16& text) const {
    153   return IsNameMatch(text, first_tokens_);
    154 }
    155 
    156 // If each of the 'words' contained in the text are also present in the middle
    157 // name then we will consider the text to be of type kMiddleName.
    158 bool NameInfo::IsMiddleName(const string16& text) const {
    159   return IsNameMatch(text, middle_tokens_);
    160 }
    161 
    162 // If each of the 'words' contained in the text are also present in the last
    163 // name then we will consider the text to be of type kLastName.
    164 bool NameInfo::IsLastName(const string16& text) const {
    165   return IsNameMatch(text, last_tokens_);
    166 }
    167 
    168 bool NameInfo::IsMiddleInitial(const string16& text) const {
    169   if (text.length() != 1)
    170      return false;
    171 
    172   string16 lower_case = StringToLowerASCII(text);
    173   // If the text entered was a single character and it matches the first letter
    174   // of any of the given middle names then we consider it to be a middle
    175   // initial field.
    176   size_t middle_tokens_size = middle_tokens_.size();
    177   for (size_t i = 0; i < middle_tokens_size; ++i) {
    178     if (middle_tokens_[i][0] == lower_case[0])
    179       return true;
    180   }
    181 
    182   return false;
    183 }
    184 
    185 // A field will be considered to be of type NAME_FULL if:
    186 //    1) it contains at least one word from the first name.
    187 //    2) it contains at least one word from the last name.
    188 //    3) all of the words in the field match a word in either the first,
    189 //       middle, or last name.
    190 bool NameInfo::IsFullName(const string16& text) const {
    191   size_t first_tokens_size = first_tokens_.size();
    192   if (first_tokens_size == 0)
    193     return false;
    194 
    195   size_t middle_tokens_size = middle_tokens_.size();
    196 
    197   size_t last_tokens_size = last_tokens_.size();
    198   if (last_tokens_size == 0)
    199     return false;
    200 
    201   std::vector<string16> text_tokens;
    202   Tokenize(text, kNameSplitChars, &text_tokens);
    203   size_t text_tokens_size = text_tokens.size();
    204   if (text_tokens_size == 0 || text_tokens_size < 2)
    205     return false;
    206 
    207   size_t name_tokens_size =
    208       first_tokens_size + middle_tokens_size + last_tokens_size;
    209   if (text_tokens_size > name_tokens_size)
    210     return false;
    211 
    212   bool first_name_match = false;
    213   bool last_name_match = false;
    214   for (std::vector<string16>::iterator iter = text_tokens.begin();
    215        iter != text_tokens.end(); ++iter) {
    216     bool match = false;
    217     if (IsWordInName(*iter, first_tokens_)) {
    218       match = true;
    219       first_name_match = true;
    220     }
    221 
    222     if (IsWordInName(*iter, last_tokens_)) {
    223       match = true;
    224       last_name_match = true;
    225     }
    226 
    227     if (IsWordInName(*iter, middle_tokens_))
    228       match = true;
    229 
    230     if (!match)
    231       return false;
    232   }
    233 
    234   return (first_name_match && last_name_match);
    235 }
    236 
    237 bool NameInfo::IsNameMatch(const string16& text,
    238                            const std::vector<string16>& name_tokens) const {
    239   size_t name_tokens_size = name_tokens.size();
    240   if (name_tokens_size == 0)
    241     return false;
    242 
    243   std::vector<string16> text_tokens;
    244   Tokenize(text, kNameSplitChars, &text_tokens);
    245   size_t text_tokens_size = text_tokens.size();
    246   if (text_tokens_size == 0)
    247     return false;
    248 
    249   if (text_tokens_size > name_tokens_size)
    250     return false;
    251 
    252   // If each of the 'words' contained in the text are also present in the name,
    253   // then we will consider the text to match the name.
    254   for (std::vector<string16>::iterator iter = text_tokens.begin();
    255        iter != text_tokens.end(); ++iter) {
    256     if (!IsWordInName(*iter, name_tokens))
    257       return false;
    258   }
    259 
    260   return true;
    261 }
    262 
    263 bool NameInfo::IsWordInName(const string16& word,
    264                             const std::vector<string16>& name_tokens) const {
    265   for (std::vector<string16>::const_iterator iter = name_tokens.begin();
    266        iter != name_tokens.end(); ++iter) {
    267     // |*iter| is already lower-cased.
    268     if (StringToLowerASCII(word) == *iter)
    269       return true;
    270   }
    271 
    272   return false;
    273 }
    274 
    275 void NameInfo::SetFirst(const string16& first) {
    276   first_ = first;
    277   first_tokens_.clear();
    278   Tokenize(first, kNameSplitChars, &first_tokens_);
    279   for (std::vector<string16>::iterator iter = first_tokens_.begin();
    280        iter != first_tokens_.end(); ++iter) {
    281     *iter = StringToLowerASCII(*iter);
    282   }
    283 }
    284 
    285 void NameInfo::SetMiddle(const string16& middle) {
    286   middle_ = middle;
    287   middle_tokens_.clear();
    288   Tokenize(middle, kNameSplitChars, &middle_tokens_);
    289   for (std::vector<string16>::iterator iter = middle_tokens_.begin();
    290        iter != middle_tokens_.end(); ++iter) {
    291     *iter = StringToLowerASCII(*iter);
    292   }
    293 }
    294 
    295 void NameInfo::SetLast(const string16& last) {
    296   last_ = last;
    297   last_tokens_.clear();
    298   Tokenize(last, kNameSplitChars, &last_tokens_);
    299   for (std::vector<string16>::iterator iter = last_tokens_.begin();
    300        iter != last_tokens_.end(); ++iter) {
    301     *iter = StringToLowerASCII(*iter);
    302   }
    303 }
    304 
    305 void NameInfo::SetFullName(const string16& full) {
    306   std::vector<string16> full_name_tokens;
    307   Tokenize(full, ASCIIToUTF16(" "), &full_name_tokens);
    308   // Clear the names.
    309   SetFirst(string16());
    310   SetMiddle(string16());
    311   SetLast(string16());
    312 
    313   // There are four possibilities: empty; first name; first and last names;
    314   // first, middle (possibly multiple strings) and then the last name.
    315   if (full_name_tokens.size() > 0) {
    316     SetFirst(full_name_tokens[0]);
    317     if (full_name_tokens.size() > 1) {
    318       SetLast(full_name_tokens.back());
    319       if (full_name_tokens.size() > 2) {
    320         full_name_tokens.erase(full_name_tokens.begin());
    321         full_name_tokens.pop_back();
    322         SetMiddle(JoinString(full_name_tokens, ' '));
    323       }
    324     }
    325   }
    326 }
    327 
    328 EmailInfo::EmailInfo() {}
    329 
    330 EmailInfo::EmailInfo(const EmailInfo& info) : FormGroup() {
    331   *this = info;
    332 }
    333 
    334 EmailInfo::~EmailInfo() {}
    335 
    336 EmailInfo& EmailInfo::operator=(const EmailInfo& info) {
    337   if (this == &info)
    338     return *this;
    339 
    340   email_ = info.email_;
    341   return *this;
    342 }
    343 
    344 void EmailInfo::GetPossibleFieldTypes(const string16& text,
    345                                       FieldTypeSet* possible_types) const {
    346   DCHECK(possible_types);
    347   // TODO(isherman): Investigate case-insensitive comparison.
    348   if (email_ == text)
    349     possible_types->insert(EMAIL_ADDRESS);
    350 }
    351 
    352 void EmailInfo::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
    353   DCHECK(available_types);
    354   if (!email_.empty())
    355     available_types->insert(EMAIL_ADDRESS);
    356 }
    357 
    358 string16 EmailInfo::GetInfo(AutofillFieldType type) const {
    359   if (type == EMAIL_ADDRESS)
    360     return email_;
    361 
    362   return string16();
    363 }
    364 
    365 void EmailInfo::SetInfo(AutofillFieldType type, const string16& value) {
    366   DCHECK_EQ(EMAIL_ADDRESS, type);
    367   email_ = value;
    368 }
    369 
    370 CompanyInfo::CompanyInfo() {}
    371 
    372 CompanyInfo::CompanyInfo(const CompanyInfo& info) : FormGroup() {
    373   *this = info;
    374 }
    375 
    376 CompanyInfo::~CompanyInfo() {}
    377 
    378 CompanyInfo& CompanyInfo::operator=(const CompanyInfo& info) {
    379   if (this == &info)
    380     return *this;
    381 
    382   company_name_ = info.company_name_;
    383   return *this;
    384 }
    385 
    386 void CompanyInfo::GetPossibleFieldTypes(const string16& text,
    387                                         FieldTypeSet* possible_types) const {
    388   DCHECK(possible_types);
    389 
    390   if (company_name_ == text)
    391     possible_types->insert(COMPANY_NAME);
    392 }
    393 
    394 void CompanyInfo::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
    395   DCHECK(available_types);
    396 
    397   if (!company_name_.empty())
    398     available_types->insert(COMPANY_NAME);
    399 }
    400 
    401 string16 CompanyInfo::GetInfo(AutofillFieldType type) const {
    402   if (type == COMPANY_NAME)
    403     return company_name_;
    404 
    405   return string16();
    406 }
    407 
    408 void CompanyInfo::SetInfo(AutofillFieldType type, const string16& value) {
    409   DCHECK_EQ(COMPANY_NAME, type);
    410   company_name_ = value;
    411 }
    412