• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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