OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/browser/autofill/address_field.h" | 5 #include "chrome/browser/autofill/address_field.h" |
6 | 6 |
| 7 #include "app/l10n_util.h" |
7 #include "base/logging.h" | 8 #include "base/logging.h" |
8 #include "base/scoped_ptr.h" | 9 #include "base/scoped_ptr.h" |
9 #include "base/string16.h" | 10 #include "base/string16.h" |
10 #include "base/string_util.h" | 11 #include "base/string_util.h" |
11 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
12 #include "chrome/browser/autofill/autofill_field.h" | 13 #include "chrome/browser/autofill/autofill_field.h" |
| 14 #include "grit/autofill_resources.h" |
13 | 15 |
14 bool AddressField::GetFieldInfo(FieldTypeMap* field_type_map) const { | 16 bool AddressField::GetFieldInfo(FieldTypeMap* field_type_map) const { |
15 AutoFillFieldType address_company; | 17 AutoFillFieldType address_company; |
16 AutoFillFieldType address_line1; | 18 AutoFillFieldType address_line1; |
17 AutoFillFieldType address_line2; | 19 AutoFillFieldType address_line2; |
18 AutoFillFieldType address_appt_num; | 20 AutoFillFieldType address_appt_num; |
19 AutoFillFieldType address_city; | 21 AutoFillFieldType address_city; |
20 AutoFillFieldType address_state; | 22 AutoFillFieldType address_state; |
21 AutoFillFieldType address_zip; | 23 AutoFillFieldType address_zip; |
22 AutoFillFieldType address_country; | 24 AutoFillFieldType address_country; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 | 85 |
84 scoped_ptr<AddressField> address_field(new AddressField); | 86 scoped_ptr<AddressField> address_field(new AddressField); |
85 std::vector<AutoFillField*>::const_iterator q = *iter; | 87 std::vector<AutoFillField*>::const_iterator q = *iter; |
86 string16 pattern; | 88 string16 pattern; |
87 | 89 |
88 // The ECML standard uses 2 letter country codes. So we will | 90 // The ECML standard uses 2 letter country codes. So we will |
89 // have to remember that this is an ECML form, for when we fill | 91 // have to remember that this is an ECML form, for when we fill |
90 // it out. | 92 // it out. |
91 address_field->is_ecml_ = is_ecml; | 93 address_field->is_ecml_ = is_ecml; |
92 | 94 |
| 95 string16 attention_ignored = |
| 96 l10n_util::GetStringUTF16(IDS_AUTOFILL_ATTENTION_IGNORED_RE); |
| 97 string16 region_ignored = |
| 98 l10n_util::GetStringUTF16(IDS_AUTOFILL_REGION_IGNORED_RE); |
| 99 |
93 // Allow address fields to appear in any order. | 100 // Allow address fields to appear in any order. |
94 while (true) { | 101 while (true) { |
95 if (ParseCompany(&q, is_ecml, address_field.get()) || | 102 if (ParseCompany(&q, is_ecml, address_field.get()) || |
96 ParseAddressLines(&q, is_ecml, address_field.get()) || | 103 ParseAddressLines(&q, is_ecml, address_field.get()) || |
97 ParseCity(&q, is_ecml, address_field.get()) || | 104 ParseCity(&q, is_ecml, address_field.get()) || |
98 ParseState(&q, is_ecml, address_field.get()) || | 105 ParseState(&q, is_ecml, address_field.get()) || |
99 ParseZipCode(&q, is_ecml, address_field.get()) || | 106 ParseZipCode(&q, is_ecml, address_field.get()) || |
100 ParseCountry(&q, is_ecml, address_field.get())) { | 107 ParseCountry(&q, is_ecml, address_field.get())) { |
101 continue; | 108 continue; |
102 } else if (ParseText(&q, ASCIIToUTF16("attention|attn.")) || | 109 } else if (ParseText(&q, attention_ignored) || |
103 ParseText(&q, ASCIIToUTF16("province|region|other"))) { | 110 ParseText(&q, region_ignored)) { |
104 // We ignore the following: | 111 // We ignore the following: |
105 // * Attention. | 112 // * Attention. |
106 // * Province/Region/Other. | 113 // * Province/Region/Other. |
107 continue; | 114 continue; |
108 } else if (*q != **iter && ParseEmpty(&q)) { | 115 } else if (*q != **iter && ParseEmpty(&q)) { |
109 // Ignore non-labeled fields within an address; the page | 116 // Ignore non-labeled fields within an address; the page |
110 // MapQuest Driving Directions North America.html contains such a field. | 117 // MapQuest Driving Directions North America.html contains such a field. |
111 // We only ignore such fields after we've parsed at least one other field; | 118 // We only ignore such fields after we've parsed at least one other field; |
112 // otherwise we'd effectively parse address fields before other field | 119 // otherwise we'd effectively parse address fields before other field |
113 // types after any non-labeled fields, and we want email address fields to | 120 // types after any non-labeled fields, and we want email address fields to |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 std::vector<AutoFillField*>::const_iterator* iter, | 173 std::vector<AutoFillField*>::const_iterator* iter, |
167 bool is_ecml, AddressField* address_field) { | 174 bool is_ecml, AddressField* address_field) { |
168 if (address_field->company_ && !address_field->company_->IsEmpty()) | 175 if (address_field->company_ && !address_field->company_->IsEmpty()) |
169 return false; | 176 return false; |
170 | 177 |
171 string16 pattern; | 178 string16 pattern; |
172 if (is_ecml) | 179 if (is_ecml) |
173 pattern = GetEcmlPattern(kEcmlShipToCompanyName, | 180 pattern = GetEcmlPattern(kEcmlShipToCompanyName, |
174 kEcmlBillToCompanyName, '|'); | 181 kEcmlBillToCompanyName, '|'); |
175 else | 182 else |
176 pattern = ASCIIToUTF16("company|business name"); | 183 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_COMPANY_RE); |
177 | 184 |
178 if (!ParseText(iter, pattern, &address_field->company_)) | 185 if (!ParseText(iter, pattern, &address_field->company_)) |
179 return false; | 186 return false; |
180 | 187 |
181 return true; | 188 return true; |
182 } | 189 } |
183 | 190 |
184 // static | 191 // static |
185 bool AddressField::ParseAddressLines( | 192 bool AddressField::ParseAddressLines( |
186 std::vector<AutoFillField*>::const_iterator* iter, | 193 std::vector<AutoFillField*>::const_iterator* iter, |
187 bool is_ecml, AddressField* address_field) { | 194 bool is_ecml, AddressField* address_field) { |
188 // We only match the string "address" in page text, not in element names, | 195 // We only match the string "address" in page text, not in element names, |
189 // because sometimes every element in a group of address fields will have | 196 // because sometimes every element in a group of address fields will have |
190 // a name containing the string "address"; for example, on the page | 197 // a name containing the string "address"; for example, on the page |
191 // Kohl's - Register Billing Address.html the text element labeled "city" | 198 // Kohl's - Register Billing Address.html the text element labeled "city" |
192 // has the name "BILL_TO_ADDRESS<>city". We do match address labels | 199 // has the name "BILL_TO_ADDRESS<>city". We do match address labels |
193 // such as "address1", which appear as element names on various pages (eg | 200 // such as "address1", which appear as element names on various pages (eg |
194 // AmericanGirl-Registration.html, BloomingdalesBilling.html, | 201 // AmericanGirl-Registration.html, BloomingdalesBilling.html, |
195 // EBay Registration Enter Information.html). | 202 // EBay Registration Enter Information.html). |
196 if (address_field->address1_) | 203 if (address_field->address1_) |
197 return false; | 204 return false; |
198 | 205 |
199 string16 pattern; | 206 string16 pattern; |
200 if (is_ecml) { | 207 if (is_ecml) { |
201 pattern = GetEcmlPattern(kEcmlShipToAddress1, | 208 pattern = GetEcmlPattern(kEcmlShipToAddress1, kEcmlBillToAddress1, '|'); |
202 kEcmlBillToAddress1, '|'); | |
203 if (!ParseText(iter, pattern, &address_field->address1_)) | 209 if (!ParseText(iter, pattern, &address_field->address1_)) |
204 return false; | 210 return false; |
205 } else { | 211 } else { |
206 pattern = | 212 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_1_RE); |
207 ASCIIToUTF16("address.?line|address1|addr1|street"); | 213 string16 label_pattern = |
208 string16 label_pattern = ASCIIToUTF16("address"); | 214 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_1_LABEL_RE); |
209 | 215 |
210 if (!ParseText(iter, pattern, &address_field->address1_)) | 216 if (!ParseText(iter, pattern, &address_field->address1_)) |
211 if (!ParseLabelText(iter, label_pattern, &address_field->address1_)) | 217 if (!ParseLabelText(iter, label_pattern, &address_field->address1_)) |
212 return false; | 218 return false; |
213 } | 219 } |
214 | 220 |
215 // Optionally parse more address lines, which may have empty labels. | 221 // Optionally parse more address lines, which may have empty labels. |
216 // Some pages have 3 address lines (eg SharperImageModifyAccount.html) | 222 // Some pages have 3 address lines (eg SharperImageModifyAccount.html) |
217 // Some pages even have 4 address lines (e.g. uk/ShoesDirect2.html)! | 223 // Some pages even have 4 address lines (e.g. uk/ShoesDirect2.html)! |
218 if (is_ecml) { | 224 if (is_ecml) { |
219 pattern = GetEcmlPattern(kEcmlShipToAddress2, | 225 pattern = GetEcmlPattern(kEcmlShipToAddress2, kEcmlBillToAddress2, '|'); |
220 kEcmlBillToAddress2, '|'); | |
221 if (!ParseEmptyText(iter, &address_field->address2_)) | 226 if (!ParseEmptyText(iter, &address_field->address2_)) |
222 ParseText(iter, pattern, &address_field->address2_); | 227 ParseText(iter, pattern, &address_field->address2_); |
223 } else { | 228 } else { |
224 pattern = ASCIIToUTF16("address.?line2|address2|addr2|street|suite|unit"); | 229 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_2_RE); |
225 string16 label_pattern = ASCIIToUTF16("address"); | 230 string16 label_pattern = |
| 231 l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_1_LABEL_RE); |
226 if (!ParseEmptyText(iter, &address_field->address2_)) | 232 if (!ParseEmptyText(iter, &address_field->address2_)) |
227 if (!ParseText(iter, pattern, &address_field->address2_)) | 233 if (!ParseText(iter, pattern, &address_field->address2_)) |
228 ParseLabelText(iter, label_pattern, &address_field->address2_); | 234 ParseLabelText(iter, label_pattern, &address_field->address2_); |
229 } | 235 } |
230 | 236 |
231 // Try for a third line, which we will promptly discard. | 237 // Try for a third line, which we will promptly discard. |
232 if (address_field->address2_ != NULL) { | 238 if (address_field->address2_ != NULL) { |
233 if (is_ecml) { | 239 if (is_ecml) { |
234 pattern = GetEcmlPattern(kEcmlShipToAddress3, | 240 pattern = GetEcmlPattern(kEcmlShipToAddress3, kEcmlBillToAddress3, '|'); |
235 kEcmlBillToAddress3, '|'); | |
236 ParseText(iter, pattern); | 241 ParseText(iter, pattern); |
237 } else { | 242 } else { |
238 pattern = ASCIIToUTF16("address.?line3|address3|addr3|street|line3"); | 243 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_3_RE); |
239 if (!ParseEmptyText(iter, NULL)) | 244 if (!ParseEmptyText(iter, NULL)) |
240 ParseText(iter, pattern, NULL); | 245 ParseText(iter, pattern, NULL); |
241 } | 246 } |
242 } | 247 } |
243 | 248 |
244 return true; | 249 return true; |
245 } | 250 } |
246 | 251 |
247 // static | 252 // static |
248 bool AddressField::ParseCountry( | 253 bool AddressField::ParseCountry( |
249 std::vector<AutoFillField*>::const_iterator* iter, | 254 std::vector<AutoFillField*>::const_iterator* iter, |
250 bool is_ecml, AddressField* address_field) { | 255 bool is_ecml, AddressField* address_field) { |
251 // Parse a country. The occasional page (e.g. | 256 // Parse a country. The occasional page (e.g. |
252 // Travelocity_New Member Information1.html) calls this a "location". | 257 // Travelocity_New Member Information1.html) calls this a "location". |
253 // Note: ECML standard uses 2 letter country code (ISO 3166) | 258 // Note: ECML standard uses 2 letter country code (ISO 3166) |
254 if (address_field->country_ && !address_field->country_->IsEmpty()) | 259 if (address_field->country_ && !address_field->country_->IsEmpty()) |
255 return false; | 260 return false; |
256 | 261 |
257 string16 pattern; | 262 string16 pattern; |
258 if (is_ecml) | 263 if (is_ecml) |
259 pattern = GetEcmlPattern(kEcmlShipToCountry, kEcmlBillToCountry, '|'); | 264 pattern = GetEcmlPattern(kEcmlShipToCountry, kEcmlBillToCountry, '|'); |
260 else | 265 else |
261 pattern = ASCIIToUTF16("country|location"); | 266 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_COUNTRY_RE); |
262 | 267 |
263 if (!ParseText(iter, pattern, &address_field->country_)) | 268 if (!ParseText(iter, pattern, &address_field->country_)) |
264 return false; | 269 return false; |
265 | 270 |
266 return true; | 271 return true; |
267 } | 272 } |
268 | 273 |
269 // static | 274 // static |
270 bool AddressField::ParseZipCode( | 275 bool AddressField::ParseZipCode( |
271 std::vector<AutoFillField*>::const_iterator* iter, | 276 std::vector<AutoFillField*>::const_iterator* iter, |
272 bool is_ecml, AddressField* address_field) { | 277 bool is_ecml, AddressField* address_field) { |
273 // Parse a zip code. On some UK pages (e.g. The China Shop2.html) this | 278 // Parse a zip code. On some UK pages (e.g. The China Shop2.html) this |
274 // is called a "post code". | 279 // is called a "post code". |
275 // | 280 // |
276 // HACK: Just for the MapQuest driving directions page we match the | 281 // HACK: Just for the MapQuest driving directions page we match the |
277 // exact name "1z", which MapQuest uses to label its zip code field. | 282 // exact name "1z", which MapQuest uses to label its zip code field. |
278 // Hopefully before long we'll be smart enough to find the zip code | 283 // Hopefully before long we'll be smart enough to find the zip code |
279 // on that page automatically. | 284 // on that page automatically. |
280 if (address_field->zip_) | 285 if (address_field->zip_) |
281 return false; | 286 return false; |
282 | 287 |
283 // We may be out of fields. | 288 // We may be out of fields. |
284 if (!**iter) | 289 if (!**iter) |
285 return false; | 290 return false; |
286 | 291 |
287 string16 pattern; | 292 string16 pattern; |
288 if (is_ecml) { | 293 if (is_ecml) { |
289 pattern = GetEcmlPattern(kEcmlShipToPostalCode, | 294 pattern = GetEcmlPattern(kEcmlShipToPostalCode, kEcmlBillToPostalCode, '|'); |
290 kEcmlBillToPostalCode, '|'); | |
291 } else { | 295 } else { |
292 pattern = ASCIIToUTF16("zip|postal|post code|pcode|^1z$"); | 296 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_ZIP_CODE_RE); |
293 } | 297 } |
294 | 298 |
295 AddressType tempType; | 299 AddressType tempType; |
296 string16 name = (**iter)->name(); | 300 string16 name = (**iter)->name(); |
297 | 301 |
298 // Note: comparisons using the ecml compliant name as a prefix must be used in | 302 // Note: comparisons using the ecml compliant name as a prefix must be used in |
299 // order to accommodate Google Checkout. See FormFieldSet::GetEcmlPattern for | 303 // order to accommodate Google Checkout. See FormFieldSet::GetEcmlPattern for |
300 // more detail. | 304 // more detail. |
301 string16 bill_to_postal_code_field(ASCIIToUTF16(kEcmlBillToPostalCode)); | 305 string16 bill_to_postal_code_field(ASCIIToUTF16(kEcmlBillToPostalCode)); |
302 if (StartsWith(name, bill_to_postal_code_field, false)) { | 306 if (StartsWith(name, bill_to_postal_code_field, false)) { |
303 tempType = kBillingAddress; | 307 tempType = kBillingAddress; |
304 } else if (StartsWith(name, bill_to_postal_code_field, false)) { | 308 } else if (StartsWith(name, bill_to_postal_code_field, false)) { |
305 tempType = kShippingAddress; | 309 tempType = kShippingAddress; |
306 } else { | 310 } else { |
307 tempType = kGenericAddress; | 311 tempType = kGenericAddress; |
308 } | 312 } |
309 | 313 |
310 if (!ParseText(iter, pattern, &address_field->zip_)) | 314 if (!ParseText(iter, pattern, &address_field->zip_)) |
311 return false; | 315 return false; |
312 | 316 |
313 address_field->type_ = tempType; | 317 address_field->type_ = tempType; |
314 if (!is_ecml) { | 318 if (!is_ecml) { |
315 // Look for a zip+4, whose field name will also often contain | 319 // Look for a zip+4, whose field name will also often contain |
316 // the substring "zip". | 320 // the substring "zip". |
317 ParseText(iter, ASCIIToUTF16("zip|^-$"), &address_field->zip4_); | 321 ParseText(iter, |
| 322 l10n_util::GetStringUTF16(IDS_AUTOFILL_ZIP_4_RE), |
| 323 &address_field->zip4_); |
318 } | 324 } |
319 | 325 |
320 return true; | 326 return true; |
321 } | 327 } |
322 | 328 |
323 // static | 329 // static |
324 bool AddressField::ParseCity( | 330 bool AddressField::ParseCity( |
325 std::vector<AutoFillField*>::const_iterator* iter, | 331 std::vector<AutoFillField*>::const_iterator* iter, |
326 bool is_ecml, AddressField* address_field) { | 332 bool is_ecml, AddressField* address_field) { |
327 // Parse a city name. Some UK pages (e.g. The China Shop2.html) use | 333 // Parse a city name. Some UK pages (e.g. The China Shop2.html) use |
328 // the term "town". | 334 // the term "town". |
329 if (address_field->city_) | 335 if (address_field->city_) |
330 return false; | 336 return false; |
331 | 337 |
332 string16 pattern; | 338 string16 pattern; |
333 if (is_ecml) | 339 if (is_ecml) |
334 pattern = GetEcmlPattern(kEcmlShipToCity, kEcmlBillToCity, '|'); | 340 pattern = GetEcmlPattern(kEcmlShipToCity, kEcmlBillToCity, '|'); |
335 else | 341 else |
336 pattern = ASCIIToUTF16("city|town"); | 342 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CITY_RE); |
337 | 343 |
338 if (!ParseText(iter, pattern, &address_field->city_)) | 344 if (!ParseText(iter, pattern, &address_field->city_)) |
339 return false; | 345 return false; |
340 | 346 |
341 return true; | 347 return true; |
342 } | 348 } |
343 | 349 |
344 // static | 350 // static |
345 bool AddressField::ParseState( | 351 bool AddressField::ParseState( |
346 std::vector<AutoFillField*>::const_iterator* iter, | 352 std::vector<AutoFillField*>::const_iterator* iter, |
347 bool is_ecml, AddressField* address_field) { | 353 bool is_ecml, AddressField* address_field) { |
348 if (address_field->state_) | 354 if (address_field->state_) |
349 return false; | 355 return false; |
350 | 356 |
351 string16 pattern; | 357 string16 pattern; |
352 if (is_ecml) | 358 if (is_ecml) |
353 pattern = GetEcmlPattern(kEcmlShipToStateProv, kEcmlBillToStateProv, '|'); | 359 pattern = GetEcmlPattern(kEcmlShipToStateProv, kEcmlBillToStateProv, '|'); |
354 else | 360 else |
355 pattern = ASCIIToUTF16("state|county"); | 361 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_STATE_RE); |
356 | 362 |
357 if (!ParseText(iter, pattern, &address_field->state_)) | 363 if (!ParseText(iter, pattern, &address_field->state_)) |
358 return false; | 364 return false; |
359 | 365 |
360 return true; | 366 return true; |
361 } | 367 } |
362 | 368 |
363 AddressType AddressField::AddressTypeFromText(const string16 &text) { | 369 AddressType AddressField::AddressTypeFromText(const string16 &text) { |
364 if (text.find(ASCIIToUTF16("same as")) != string16::npos || | 370 if (text.find(l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_TYPE_SAME_AS_RE)) |
365 text.find(ASCIIToUTF16("use my")) != string16::npos) | 371 != string16::npos || |
| 372 text.find(l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_TYPE_USE_MY_RE)) |
| 373 != string16::npos) |
366 // This text could be a checkbox label such as "same as my billing | 374 // This text could be a checkbox label such as "same as my billing |
367 // address" or "use my shipping address". | 375 // address" or "use my shipping address". |
368 // ++ It would help if we generally skipped all text that appears | 376 // ++ It would help if we generally skipped all text that appears |
369 // after a check box. | 377 // after a check box. |
370 return kGenericAddress; | 378 return kGenericAddress; |
371 | 379 |
372 // Not all pages say "billing address" and "shipping address" explicitly; | 380 // Not all pages say "billing address" and "shipping address" explicitly; |
373 // for example, Craft Catalog1.html has "Bill-to Address" and | 381 // for example, Craft Catalog1.html has "Bill-to Address" and |
374 // "Ship-to Address". | 382 // "Ship-to Address". |
375 size_t bill = text.rfind(ASCIIToUTF16("bill")); | 383 size_t bill = text.rfind( |
376 size_t ship = text.rfind(ASCIIToUTF16("ship")); | 384 l10n_util::GetStringUTF16(IDS_AUTOFILL_BILLING_DESIGNATOR_RE)); |
| 385 size_t ship = text.rfind( |
| 386 l10n_util::GetStringUTF16(IDS_AUTOFILL_SHIPPING_DESIGNATOR_RE)); |
377 | 387 |
378 if (bill == string16::npos && ship == string16::npos) | 388 if (bill == string16::npos && ship == string16::npos) |
379 return kGenericAddress; | 389 return kGenericAddress; |
380 | 390 |
381 if (bill != string16::npos && ship == string16::npos) | 391 if (bill != string16::npos && ship == string16::npos) |
382 return kBillingAddress; | 392 return kBillingAddress; |
383 | 393 |
384 if (bill == string16::npos && ship != string16::npos) | 394 if (bill == string16::npos && ship != string16::npos) |
385 return kShippingAddress; | 395 return kShippingAddress; |
386 | 396 |
387 if (bill > ship) | 397 if (bill > ship) |
388 return kBillingAddress; | 398 return kBillingAddress; |
389 | 399 |
390 return kShippingAddress; | 400 return kShippingAddress; |
391 } | 401 } |
OLD | NEW |