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