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
NameInfo()29 NameInfo::NameInfo() {}
30
NameInfo(const NameInfo & info)31 NameInfo::NameInfo(const NameInfo& info) : FormGroup() {
32 *this = info;
33 }
34
~NameInfo()35 NameInfo::~NameInfo() {}
36
operator =(const NameInfo & info)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
GetPossibleFieldTypes(const string16 & text,FieldTypeSet * possible_types) const50 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
GetAvailableFieldTypes(FieldTypeSet * available_types) const70 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
GetInfo(AutofillFieldType type) const89 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
SetInfo(AutofillFieldType type,const string16 & value)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
FullName() const122 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
MiddleInitial() const138 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.
IsFirstName(const string16 & text) const152 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.
IsMiddleName(const string16 & text) const158 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.
IsLastName(const string16 & text) const164 bool NameInfo::IsLastName(const string16& text) const {
165 return IsNameMatch(text, last_tokens_);
166 }
167
IsMiddleInitial(const string16 & text) const168 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.
IsFullName(const string16 & text) const190 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
IsNameMatch(const string16 & text,const std::vector<string16> & name_tokens) const237 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
IsWordInName(const string16 & word,const std::vector<string16> & name_tokens) const263 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
SetFirst(const string16 & first)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
SetMiddle(const string16 & middle)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
SetLast(const string16 & last)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
SetFullName(const string16 & full)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
EmailInfo()328 EmailInfo::EmailInfo() {}
329
EmailInfo(const EmailInfo & info)330 EmailInfo::EmailInfo(const EmailInfo& info) : FormGroup() {
331 *this = info;
332 }
333
~EmailInfo()334 EmailInfo::~EmailInfo() {}
335
operator =(const EmailInfo & info)336 EmailInfo& EmailInfo::operator=(const EmailInfo& info) {
337 if (this == &info)
338 return *this;
339
340 email_ = info.email_;
341 return *this;
342 }
343
GetPossibleFieldTypes(const string16 & text,FieldTypeSet * possible_types) const344 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
GetAvailableFieldTypes(FieldTypeSet * available_types) const352 void EmailInfo::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
353 DCHECK(available_types);
354 if (!email_.empty())
355 available_types->insert(EMAIL_ADDRESS);
356 }
357
GetInfo(AutofillFieldType type) const358 string16 EmailInfo::GetInfo(AutofillFieldType type) const {
359 if (type == EMAIL_ADDRESS)
360 return email_;
361
362 return string16();
363 }
364
SetInfo(AutofillFieldType type,const string16 & value)365 void EmailInfo::SetInfo(AutofillFieldType type, const string16& value) {
366 DCHECK_EQ(EMAIL_ADDRESS, type);
367 email_ = value;
368 }
369
CompanyInfo()370 CompanyInfo::CompanyInfo() {}
371
CompanyInfo(const CompanyInfo & info)372 CompanyInfo::CompanyInfo(const CompanyInfo& info) : FormGroup() {
373 *this = info;
374 }
375
~CompanyInfo()376 CompanyInfo::~CompanyInfo() {}
377
operator =(const CompanyInfo & info)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
GetPossibleFieldTypes(const string16 & text,FieldTypeSet * possible_types) const386 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
GetAvailableFieldTypes(FieldTypeSet * available_types) const394 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
GetInfo(AutofillFieldType type) const401 string16 CompanyInfo::GetInfo(AutofillFieldType type) const {
402 if (type == COMPANY_NAME)
403 return company_name_;
404
405 return string16();
406 }
407
SetInfo(AutofillFieldType type,const string16 & value)408 void CompanyInfo::SetInfo(AutofillFieldType type, const string16& value) {
409 DCHECK_EQ(COMPANY_NAME, type);
410 company_name_ = value;
411 }
412