Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1162)

Side by Side Diff: components/autofill/core/browser/contact_info.cc

Issue 310463005: Fill in more name fields with requestAutocomplete (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: dumb test is dumb Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/autofill/core/browser/contact_info.h" 5 #include "components/autofill/core/browser/contact_info.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <ostream> 8 #include <ostream>
9 #include <string> 9 #include <string>
10 10
11 #include "base/basictypes.h" 11 #include "base/basictypes.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h" 14 #include "base/strings/utf_string_conversions.h"
15 #include "components/autofill/core/browser/autofill_type.h" 15 #include "components/autofill/core/browser/autofill_type.h"
16 16
17 namespace autofill { 17 namespace autofill {
18 18
19 namespace {
20
21 const char* const name_prefixes[] = {
22 "1lt", "1st", "2lt", "2nd", "3rd", "admiral", "capt", "captain", "col",
23 "cpt", "dr", "gen", "general", "lcdr", "lt", "ltc", "ltg", "ltjg", "maj",
24 "major", "mg", "mr", "mrs", "ms", "pastor", "prof", "rep", "reverend",
25 "rev", "sen", "st" };
26
27 const char* const name_suffixes[] = {
28 "b.a", "ba", "d.d.s", "dds", "i", "ii", "iii", "iv", "ix", "jr", "m.a",
29 "m.d", "ma", "md", "ms", "ph.d", "phd", "sr", "v", "vi", "vii", "viii",
30 "x" };
31
32 const char* const family_name_prefixes[] = {
33 "d'", "de", "del", "der", "di", "la", "le", "mc", "san", "st", "ter",
34 "van", "von" };
35
36 // Returns true if |set| contains |element|, modulo a final period.
37 bool ContainsString(const char* const set[],
38 size_t set_size,
39 const base::string16& element) {
40 if (!base::IsStringASCII(element))
41 return false;
42
43 base::string16 trimmed_element;
44 base::TrimString(element, base::ASCIIToUTF16("."), &trimmed_element);
45
46 for (size_t i = 0; i < set_size; ++i) {
47 if (LowerCaseEqualsASCII(trimmed_element, set[i]))
48 return true;
49 }
50
51 return false;
52 }
53
54 // Removes common name prefixes from |name_tokens|.
55 void StripPrefixes(std::vector<base::string16>* name_tokens) {
56 std::vector<base::string16>::iterator iter = name_tokens->begin();
57 while(iter != name_tokens->end()) {
58 if (!ContainsString(name_prefixes, arraysize(name_prefixes), *iter))
59 break;
60 ++iter;
61 }
62
63 std::vector<base::string16> copy_vector;
64 copy_vector.assign(iter, name_tokens->end());
65 *name_tokens = copy_vector;
66 }
67
68 // Removes common name suffixes from |name_tokens|.
69 void StripSuffixes(std::vector<base::string16>* name_tokens) {
70 while(!name_tokens->empty()) {
71 if (!ContainsString(name_suffixes, arraysize(name_suffixes),
72 name_tokens->back())) {
73 break;
74 }
75 name_tokens->pop_back();
76 }
77 }
78
79 struct NameParts {
80 base::string16 given;
81 base::string16 middle;
82 base::string16 family;
83 };
84
85 // TODO(estade): This does Western name splitting. It should do different
86 // splitting based on the app locale.
87 NameParts SplitName(const base::string16& name) {
88 std::vector<base::string16> name_tokens;
89 Tokenize(name, base::ASCIIToUTF16(" ,"), &name_tokens);
90
91 StripPrefixes(&name_tokens);
92
93 // Don't assume "Ma" is a suffix in John Ma.
94 if (name_tokens.size() > 2)
95 StripSuffixes(&name_tokens);
96
97 NameParts parts;
98
99 if (name_tokens.empty()) {
100 // Bad things have happened; just assume the whole thing is a given name.
101 parts.given = name;
102 return parts;
103 }
104
105 // Only one token, assume given name.
106 if (name_tokens.size() == 1) {
107 parts.given = name_tokens[0];
108 return parts;
109 }
110
111 // 2 or more tokens. Grab the family, which is the last word plus any
112 // recognizable family prefixes.
113 std::vector<base::string16> reverse_family_tokens;
114 reverse_family_tokens.push_back(name_tokens.back());
115 name_tokens.pop_back();
116 while (name_tokens.size() >= 1 &&
117 ContainsString(family_name_prefixes,
118 arraysize(family_name_prefixes),
119 name_tokens.back())) {
120 reverse_family_tokens.push_back(name_tokens.back());
121 name_tokens.pop_back();
122 }
123
124 std::vector<base::string16> family_tokens(reverse_family_tokens.rbegin(),
125 reverse_family_tokens.rend());
126 parts.family = JoinString(family_tokens, base::char16(' '));
127
128 // Take the last remaining token as the middle name (if there are at least 2
129 // tokens).
130 if (name_tokens.size() >= 2) {
131 parts.middle = name_tokens.back();
132 name_tokens.pop_back();
133 }
134
135 // Remainder is given name.
136 parts.given = JoinString(name_tokens, base::char16(' '));
137
138 return parts;
139 }
140
141 } // namespace
142
19 NameInfo::NameInfo() {} 143 NameInfo::NameInfo() {}
20 144
21 NameInfo::NameInfo(const NameInfo& info) : FormGroup() { 145 NameInfo::NameInfo(const NameInfo& info) : FormGroup() {
22 *this = info; 146 *this = info;
23 } 147 }
24 148
25 NameInfo::~NameInfo() {} 149 NameInfo::~NameInfo() {}
26 150
27 NameInfo& NameInfo::operator=(const NameInfo& info) { 151 NameInfo& NameInfo::operator=(const NameInfo& info) {
28 if (this == &info) 152 if (this == &info)
29 return *this; 153 return *this;
30 154
31 first_ = info.first_; 155 given_ = info.given_;
32 middle_ = info.middle_; 156 middle_ = info.middle_;
33 last_ = info.last_; 157 family_ = info.family_;
158 full_ = info.full_;
34 return *this; 159 return *this;
35 } 160 }
36 161
37 bool NameInfo::EqualsIgnoreCase(const NameInfo& info) { 162 bool NameInfo::EqualsIgnoreCase(const NameInfo& info) {
38 return (StringToLowerASCII(first_) == StringToLowerASCII(info.first_) && 163 return (StringToLowerASCII(given_) == StringToLowerASCII(info.given_) &&
39 StringToLowerASCII(middle_) == StringToLowerASCII(info.middle_) && 164 StringToLowerASCII(middle_) == StringToLowerASCII(info.middle_) &&
40 StringToLowerASCII(last_) == StringToLowerASCII(info.last_)); 165 StringToLowerASCII(family_) == StringToLowerASCII(info.family_));
41 } 166 }
42 167
43 void NameInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { 168 void NameInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
44 supported_types->insert(NAME_FIRST); 169 supported_types->insert(NAME_FIRST);
45 supported_types->insert(NAME_MIDDLE); 170 supported_types->insert(NAME_MIDDLE);
46 supported_types->insert(NAME_LAST); 171 supported_types->insert(NAME_LAST);
47 supported_types->insert(NAME_MIDDLE_INITIAL); 172 supported_types->insert(NAME_MIDDLE_INITIAL);
48 supported_types->insert(NAME_FULL); 173 supported_types->insert(NAME_FULL);
49 } 174 }
50 175
51 base::string16 NameInfo::GetRawInfo(ServerFieldType type) const { 176 base::string16 NameInfo::GetRawInfo(ServerFieldType type) const {
52 DCHECK_EQ(NAME, AutofillType(type).group()); 177 DCHECK_EQ(NAME, AutofillType(type).group());
53 switch (type) { 178 switch (type) {
54 case NAME_FIRST: 179 case NAME_FIRST:
55 return first(); 180 return given_;
56 181
57 case NAME_MIDDLE: 182 case NAME_MIDDLE:
58 return middle(); 183 return middle_;
59 184
60 case NAME_LAST: 185 case NAME_LAST:
61 return last(); 186 return family_;
62 187
63 case NAME_MIDDLE_INITIAL: 188 case NAME_MIDDLE_INITIAL:
64 return MiddleInitial(); 189 return MiddleInitial();
65 190
66 case NAME_FULL: 191 case NAME_FULL:
67 return FullName(); 192 return FullName();
68 193
69 default: 194 default:
70 return base::string16(); 195 return base::string16();
71 } 196 }
72 } 197 }
73 198
74 void NameInfo::SetRawInfo(ServerFieldType type, const base::string16& value) { 199 void NameInfo::SetRawInfo(ServerFieldType type, const base::string16& value) {
75 DCHECK_EQ(NAME, AutofillType(type).group()); 200 DCHECK_EQ(NAME, AutofillType(type).group());
201
202 // Always clear out the full name if we're making a change.
203 if (value != GetRawInfo(type))
204 full_.clear();
205
76 switch (type) { 206 switch (type) {
77 case NAME_FIRST: 207 case NAME_FIRST:
78 first_ = value; 208 given_ = value;
79 break; 209 break;
80 210
81 case NAME_MIDDLE: 211 case NAME_MIDDLE:
82 case NAME_MIDDLE_INITIAL: 212 case NAME_MIDDLE_INITIAL:
83 middle_ = value; 213 middle_ = value;
84 break; 214 break;
85 215
86 case NAME_LAST: 216 case NAME_LAST:
87 last_ = value; 217 family_ = value;
88 break; 218 break;
89 219
90 case NAME_FULL: 220 case NAME_FULL:
221 // TODO(estade): this should just set |full_|; only SetInfo should attempt
222 // to be smart. http://crbug.com/384640
91 SetFullName(value); 223 SetFullName(value);
92 break; 224 break;
93 225
94 default: 226 default:
95 NOTREACHED(); 227 NOTREACHED();
96 } 228 }
97 } 229 }
98 230
99 base::string16 NameInfo::FullName() const { 231 base::string16 NameInfo::FullName() const {
232 if (!full_.empty())
233 return full_;
234
100 std::vector<base::string16> full_name; 235 std::vector<base::string16> full_name;
101 if (!first_.empty()) 236 if (!given_.empty())
102 full_name.push_back(first_); 237 full_name.push_back(given_);
103 238
104 if (!middle_.empty()) 239 if (!middle_.empty())
105 full_name.push_back(middle_); 240 full_name.push_back(middle_);
106 241
107 if (!last_.empty()) 242 if (!family_.empty())
108 full_name.push_back(last_); 243 full_name.push_back(family_);
109 244
110 return JoinString(full_name, ' '); 245 return JoinString(full_name, ' ');
111 } 246 }
112 247
113 base::string16 NameInfo::MiddleInitial() const { 248 base::string16 NameInfo::MiddleInitial() const {
114 if (middle_.empty()) 249 if (middle_.empty())
115 return base::string16(); 250 return base::string16();
116 251
117 base::string16 middle_name(middle()); 252 base::string16 middle_name(middle_);
118 base::string16 initial; 253 base::string16 initial;
119 initial.push_back(middle_name[0]); 254 initial.push_back(middle_name[0]);
120 return initial; 255 return initial;
121 } 256 }
122 257
123 void NameInfo::SetFullName(const base::string16& full) { 258 void NameInfo::SetFullName(const base::string16& full) {
124 // Clear the names. 259 // Hack: don't do anything if this wouldn't change the full, concatenated
125 first_ = base::string16(); 260 // name. Otherwise when unpickling data from the database, "First|Middle|"
126 middle_ = base::string16(); 261 // will get parsed as "First||Middle".
127 last_ = base::string16(); 262 // TODO(estade): we should be able to remove this when fixing the TODO in
263 // SetRawInfo. http://crbug.com/384640
264 if (FullName() == full)
265 return;
128 266
129 std::vector<base::string16> full_name_tokens; 267 full_ = full;
130 Tokenize(full, base::ASCIIToUTF16(" "), &full_name_tokens);
131 268
132 // There are four possibilities: empty; first name; first and last names; 269 // If |full| is empty, leave the other name parts alone. This might occur
133 // first, middle (possibly multiple strings) and then the last name. 270 // due to a migrated database with an empty |full_name| value.
134 if (full_name_tokens.size() > 0) { 271 if (full.empty())
135 first_ = full_name_tokens[0]; 272 return;
136 if (full_name_tokens.size() > 1) { 273
137 last_ = full_name_tokens.back(); 274 NameParts parts = SplitName(full);
138 if (full_name_tokens.size() > 2) { 275 given_ = parts.given;
139 full_name_tokens.erase(full_name_tokens.begin()); 276 middle_ = parts.middle;
140 full_name_tokens.pop_back(); 277 family_ = parts.family;
141 middle_ = JoinString(full_name_tokens, ' ');
142 }
143 }
144 }
145 } 278 }
146 279
147 EmailInfo::EmailInfo() {} 280 EmailInfo::EmailInfo() {}
148 281
149 EmailInfo::EmailInfo(const EmailInfo& info) : FormGroup() { 282 EmailInfo::EmailInfo(const EmailInfo& info) : FormGroup() {
150 *this = info; 283 *this = info;
151 } 284 }
152 285
153 EmailInfo::~EmailInfo() {} 286 EmailInfo::~EmailInfo() {}
154 287
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 return base::string16(); 336 return base::string16();
204 } 337 }
205 338
206 void CompanyInfo::SetRawInfo(ServerFieldType type, 339 void CompanyInfo::SetRawInfo(ServerFieldType type,
207 const base::string16& value) { 340 const base::string16& value) {
208 DCHECK_EQ(COMPANY_NAME, type); 341 DCHECK_EQ(COMPANY_NAME, type);
209 company_name_ = value; 342 company_name_ = value;
210 } 343 }
211 344
212 } // namespace autofill 345 } // namespace autofill
OLDNEW
« no previous file with comments | « components/autofill/core/browser/contact_info.h ('k') | components/autofill/core/browser/contact_info_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698