OLD | NEW |
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/credit_card_field.h" | 5 #include "components/autofill/core/browser/credit_card_field.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
11 #include "base/strings/string16.h" | 11 #include "base/strings/string16.h" |
12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.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/time/time.h" | 15 #include "base/time/time.h" |
15 #include "components/autofill/core/browser/autofill_field.h" | 16 #include "components/autofill/core/browser/autofill_field.h" |
16 #include "components/autofill/core/browser/autofill_regex_constants.h" | 17 #include "components/autofill/core/browser/autofill_regex_constants.h" |
17 #include "components/autofill/core/browser/autofill_scanner.h" | 18 #include "components/autofill/core/browser/autofill_scanner.h" |
18 #include "components/autofill/core/browser/field_types.h" | 19 #include "components/autofill/core/browser/field_types.h" |
19 #include "components/autofill/core/common/autofill_regexes.h" | 20 #include "components/autofill/core/common/autofill_regexes.h" |
20 #include "grit/components_strings.h" | 21 #include "grit/components_strings.h" |
21 #include "ui/base/l10n/l10n_util.h" | 22 #include "ui/base/l10n/l10n_util.h" |
22 | 23 |
23 namespace autofill { | 24 namespace autofill { |
24 | 25 |
25 namespace { | 26 namespace { |
26 | 27 |
27 // Credit card numbers are at most 19 digits in length. | 28 // Credit card numbers are at most 19 digits in length. |
28 // [Ref: http://en.wikipedia.org/wiki/Bank_card_number] | 29 // [Ref: http://en.wikipedia.org/wiki/Bank_card_number] |
29 const size_t kMaxValidCardNumberSize = 19; | 30 const size_t kMaxValidCardNumberSize = 19; |
30 | 31 |
31 // Look for the vector |regex_needles| in |haystack|. Returns true if a | 32 // Look for the vector |regex_needles| in |haystack|. Returns true if a |
32 // consecutive section of |haystack| matches |regex_needles|. | 33 // consecutive section of |haystack| matches |regex_needles|. |
33 bool FindConsecutiveStrings(const std::vector<std::string>& regex_needles, | 34 bool FindConsecutiveStrings(const std::vector<base::string16>& regex_needles, |
34 const std::vector<base::string16>& haystack) { | 35 const std::vector<base::string16>& haystack) { |
35 if (regex_needles.empty() || | 36 if (regex_needles.empty() || |
36 haystack.empty() || | 37 haystack.empty() || |
37 (haystack.size() < regex_needles.size())) | 38 (haystack.size() < regex_needles.size())) |
38 return false; | 39 return false; |
39 | 40 |
40 for (size_t i = 0; i < haystack.size() - regex_needles.size() + 1; ++i) { | 41 for (size_t i = 0; i < haystack.size() - regex_needles.size() + 1; ++i) { |
41 for (size_t j = 0; j < regex_needles.size(); ++j) { | 42 for (size_t j = 0; j < regex_needles.size(); ++j) { |
42 if (!MatchesPattern(haystack[i + j], regex_needles[j])) | 43 if (!MatchesPattern(haystack[i + j], regex_needles[j])) |
43 break; | 44 break; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 | 84 |
84 // Credit card fields can appear in many different orders. | 85 // Credit card fields can appear in many different orders. |
85 // We loop until no more credit card related fields are found, see |break| at | 86 // We loop until no more credit card related fields are found, see |break| at |
86 // the bottom of the loop. | 87 // the bottom of the loop. |
87 for (int fields = 0; !scanner->IsEnd(); ++fields) { | 88 for (int fields = 0; !scanner->IsEnd(); ++fields) { |
88 // Ignore gift card fields. | 89 // Ignore gift card fields. |
89 if (IsGiftCardField(scanner)) | 90 if (IsGiftCardField(scanner)) |
90 break; | 91 break; |
91 | 92 |
92 if (!credit_card_field->cardholder_) { | 93 if (!credit_card_field->cardholder_) { |
93 if (ParseField(scanner, kNameOnCardRe, &credit_card_field->cardholder_)) { | 94 if (ParseField(scanner, |
| 95 base::UTF8ToUTF16(kNameOnCardRe), |
| 96 &credit_card_field->cardholder_)) { |
94 continue; | 97 continue; |
95 } | 98 } |
96 | 99 |
97 // Sometimes the cardholder field is just labeled "name". Unfortunately | 100 // Sometimes the cardholder field is just labeled "name". Unfortunately |
98 // this is a dangerously generic word to search for, since it will often | 101 // this is a dangerously generic word to search for, since it will often |
99 // match a name (not cardholder name) field before or after credit card | 102 // match a name (not cardholder name) field before or after credit card |
100 // fields. So we search for "name" only when we've already parsed at | 103 // fields. So we search for "name" only when we've already parsed at |
101 // least one other credit card field and haven't yet parsed the | 104 // least one other credit card field and haven't yet parsed the |
102 // expiration date (which usually appears at the end). | 105 // expiration date (which usually appears at the end). |
103 if (fields > 0 && !credit_card_field->expiration_month_ && | 106 if (fields > 0 && |
104 ParseField(scanner, kNameOnCardContextualRe, | 107 !credit_card_field->expiration_month_ && |
| 108 ParseField(scanner, |
| 109 base::UTF8ToUTF16(kNameOnCardContextualRe), |
105 &credit_card_field->cardholder_)) { | 110 &credit_card_field->cardholder_)) { |
106 continue; | 111 continue; |
107 } | 112 } |
108 } | 113 } |
109 | 114 |
110 // Check for a credit card type (Visa, MasterCard, etc.) field. | 115 // Check for a credit card type (Visa, MasterCard, etc.) field. |
111 // All CC type fields encountered so far have been of type select. | 116 // All CC type fields encountered so far have been of type select. |
112 if (!credit_card_field->type_ && LikelyCardTypeSelectField(scanner)) { | 117 if (!credit_card_field->type_ && LikelyCardTypeSelectField(scanner)) { |
113 credit_card_field->type_ = scanner->Cursor(); | 118 credit_card_field->type_ = scanner->Cursor(); |
114 scanner->Advance(); | 119 scanner->Advance(); |
115 continue; | 120 continue; |
116 } | 121 } |
117 | 122 |
118 // We look for a card security code before we look for a credit card number | 123 // We look for a card security code before we look for a credit card number |
119 // and match the general term "number". The security code has a plethora of | 124 // and match the general term "number". The security code has a plethora of |
120 // names; we've seen "verification #", "verification number", "card | 125 // names; we've seen "verification #", "verification number", "card |
121 // identification number", and others listed in the regex pattern used | 126 // identification number", and others listed in the regex pattern used |
122 // below. | 127 // below. |
123 // Note: Some sites use type="tel" or type="number" for numerical inputs. | 128 // Note: Some sites use type="tel" or type="number" for numerical inputs. |
124 const int kMatchNumAndTel = MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE; | 129 const int kMatchNumAndTel = MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE; |
125 if (!credit_card_field->verification_ && | 130 if (!credit_card_field->verification_ && |
126 ParseFieldSpecifics(scanner, | 131 ParseFieldSpecifics(scanner, |
127 kCardCvcRe, | 132 base::UTF8ToUTF16(kCardCvcRe), |
128 kMatchNumAndTel | MATCH_PASSWORD, | 133 kMatchNumAndTel | MATCH_PASSWORD, |
129 &credit_card_field->verification_)) { | 134 &credit_card_field->verification_)) { |
130 continue; | 135 continue; |
131 } | 136 } |
132 | 137 |
133 AutofillField* current_number_field; | 138 AutofillField* current_number_field; |
134 if (ParseFieldSpecifics(scanner, | 139 if (ParseFieldSpecifics(scanner, |
135 kCardNumberRe, | 140 base::UTF8ToUTF16(kCardNumberRe), |
136 kMatchNumAndTel, | 141 kMatchNumAndTel, |
137 ¤t_number_field)) { | 142 ¤t_number_field)) { |
138 // Avoid autofilling any credit card number field having very low or high | 143 // Avoid autofilling any credit card number field having very low or high |
139 // |start_index| on the HTML form. | 144 // |start_index| on the HTML form. |
140 size_t start_index = 0; | 145 size_t start_index = 0; |
141 if (!credit_card_field->numbers_.empty()) { | 146 if (!credit_card_field->numbers_.empty()) { |
142 size_t last_number_field_size = | 147 size_t last_number_field_size = |
143 credit_card_field->numbers_.back()->credit_card_number_offset() + | 148 credit_card_field->numbers_.back()->credit_card_number_offset() + |
144 credit_card_field->numbers_.back()->max_length; | 149 credit_card_field->numbers_.back()->max_length; |
145 | 150 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 return false; | 207 return false; |
203 | 208 |
204 AutofillField* field = scanner->Cursor(); | 209 AutofillField* field = scanner->Cursor(); |
205 if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT)) | 210 if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT)) |
206 return false; | 211 return false; |
207 | 212 |
208 if (field->option_values.size() < 12 || field->option_values.size() > 13) | 213 if (field->option_values.size() < 12 || field->option_values.size() > 13) |
209 return false; | 214 return false; |
210 | 215 |
211 // Filter out years. | 216 // Filter out years. |
212 const char kNumericalYearRe[] = "[1-9][0-9][0-9][0-9]"; | 217 const base::string16 kNumericalYearRe = |
| 218 base::ASCIIToUTF16("[1-9][0-9][0-9][0-9]"); |
213 for (const auto& value : field->option_values) { | 219 for (const auto& value : field->option_values) { |
214 if (MatchesPattern(value, kNumericalYearRe)) | 220 if (MatchesPattern(value, kNumericalYearRe)) |
215 return false; | 221 return false; |
216 } | 222 } |
217 for (const auto& value : field->option_contents) { | 223 for (const auto& value : field->option_contents) { |
218 if (MatchesPattern(value, kNumericalYearRe)) | 224 if (MatchesPattern(value, kNumericalYearRe)) |
219 return false; | 225 return false; |
220 } | 226 } |
221 | 227 |
222 // Look for numerical months. | 228 // Look for numerical months. |
223 const char kNumericalMonthRe[] = "12"; | 229 const base::string16 kNumericalMonthRe = base::ASCIIToUTF16("12"); |
224 if (MatchesPattern(field->option_values.back(), kNumericalMonthRe) || | 230 if (MatchesPattern(field->option_values.back(), kNumericalMonthRe) || |
225 MatchesPattern(field->option_contents.back(), kNumericalMonthRe)) { | 231 MatchesPattern(field->option_contents.back(), kNumericalMonthRe)) { |
226 return true; | 232 return true; |
227 } | 233 } |
228 | 234 |
229 // Maybe do more matches here. e.g. look for (translated) December. | 235 // Maybe do more matches here. e.g. look for (translated) December. |
230 | 236 |
231 // Unsure? Return false. | 237 // Unsure? Return false. |
232 return false; | 238 return false; |
233 } | 239 } |
234 | 240 |
235 // static | 241 // static |
236 bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner) { | 242 bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner) { |
237 if (scanner->IsEnd()) | 243 if (scanner->IsEnd()) |
238 return false; | 244 return false; |
239 | 245 |
240 AutofillField* field = scanner->Cursor(); | 246 AutofillField* field = scanner->Cursor(); |
241 if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT)) | 247 if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT)) |
242 return false; | 248 return false; |
243 | 249 |
244 const base::Time time_now = base::Time::Now(); | 250 const base::Time time_now = base::Time::Now(); |
245 base::Time::Exploded time_exploded; | 251 base::Time::Exploded time_exploded; |
246 time_now.UTCExplode(&time_exploded); | 252 time_now.UTCExplode(&time_exploded); |
247 | 253 |
248 const int kYearsToMatch = 3; | 254 const int kYearsToMatch = 3; |
249 std::vector<std::string> years_to_check; | 255 std::vector<base::string16> years_to_check; |
250 for (int year = time_exploded.year; | 256 for (int year = time_exploded.year; |
251 year < time_exploded.year + kYearsToMatch; | 257 year < time_exploded.year + kYearsToMatch; |
252 ++year) { | 258 ++year) { |
253 years_to_check.push_back(base::IntToString(year)); | 259 years_to_check.push_back(base::IntToString16(year)); |
254 } | 260 } |
255 return (FindConsecutiveStrings(years_to_check, field->option_values) || | 261 return (FindConsecutiveStrings(years_to_check, field->option_values) || |
256 FindConsecutiveStrings(years_to_check, field->option_contents)); | 262 FindConsecutiveStrings(years_to_check, field->option_contents)); |
257 } | 263 } |
258 | 264 |
259 // static | 265 // static |
260 bool CreditCardField::LikelyCardTypeSelectField(AutofillScanner* scanner) { | 266 bool CreditCardField::LikelyCardTypeSelectField(AutofillScanner* scanner) { |
261 if (scanner->IsEnd()) | 267 if (scanner->IsEnd()) |
262 return false; | 268 return false; |
263 | 269 |
264 AutofillField* field = scanner->Cursor(); | 270 AutofillField* field = scanner->Cursor(); |
265 if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT)) | 271 if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT)) |
266 return false; | 272 return false; |
267 | 273 |
268 return AutofillField::FindValueInSelectControl( | 274 return AutofillField::FindValueInSelectControl( |
269 *field, l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_VISA), | 275 *field, l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_VISA), |
270 nullptr) || | 276 nullptr) || |
271 AutofillField::FindValueInSelectControl( | 277 AutofillField::FindValueInSelectControl( |
272 *field, l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_MASTERCARD), | 278 *field, l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_MASTERCARD), |
273 nullptr); | 279 nullptr); |
274 } | 280 } |
275 | 281 |
276 // static | 282 // static |
277 bool CreditCardField::IsGiftCardField(AutofillScanner* scanner) { | 283 bool CreditCardField::IsGiftCardField(AutofillScanner* scanner) { |
278 if (scanner->IsEnd()) | 284 if (scanner->IsEnd()) |
279 return false; | 285 return false; |
280 | 286 |
281 size_t saved_cursor = scanner->SaveCursor(); | 287 size_t saved_cursor = scanner->SaveCursor(); |
282 if (ParseField(scanner, kDebitCardRe, nullptr)) { | 288 if (ParseField(scanner, base::UTF8ToUTF16(kDebitCardRe), nullptr)) { |
283 scanner->RewindTo(saved_cursor); | 289 scanner->RewindTo(saved_cursor); |
284 return false; | 290 return false; |
285 } | 291 } |
286 if (ParseField(scanner, kDebitGiftCardRe, nullptr)) { | 292 if (ParseField(scanner, base::UTF8ToUTF16(kDebitGiftCardRe), nullptr)) { |
287 scanner->RewindTo(saved_cursor); | 293 scanner->RewindTo(saved_cursor); |
288 return false; | 294 return false; |
289 } | 295 } |
290 | 296 |
291 return ParseField(scanner, kGiftCardRe, nullptr); | 297 return ParseField(scanner, base::UTF8ToUTF16(kGiftCardRe), nullptr); |
292 } | 298 } |
293 | 299 |
294 CreditCardField::CreditCardField() | 300 CreditCardField::CreditCardField() |
295 : cardholder_(nullptr), | 301 : cardholder_(nullptr), |
296 cardholder_last_(nullptr), | 302 cardholder_last_(nullptr), |
297 type_(nullptr), | 303 type_(nullptr), |
298 verification_(nullptr), | 304 verification_(nullptr), |
299 expiration_month_(nullptr), | 305 expiration_month_(nullptr), |
300 expiration_year_(nullptr), | 306 expiration_year_(nullptr), |
301 expiration_date_(nullptr), | 307 expiration_date_(nullptr), |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 return true; | 369 return true; |
364 } | 370 } |
365 expiration_month_ = nullptr; | 371 expiration_month_ = nullptr; |
366 expiration_year_ = nullptr; | 372 expiration_year_ = nullptr; |
367 } | 373 } |
368 | 374 |
369 // If that fails, do a general regex search. | 375 // If that fails, do a general regex search. |
370 scanner->RewindTo(month_year_saved_cursor); | 376 scanner->RewindTo(month_year_saved_cursor); |
371 const int kMatchTelAndSelect = MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_SELECT; | 377 const int kMatchTelAndSelect = MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_SELECT; |
372 if (ParseFieldSpecifics(scanner, | 378 if (ParseFieldSpecifics(scanner, |
373 kExpirationMonthRe, | 379 base::UTF8ToUTF16(kExpirationMonthRe), |
374 kMatchTelAndSelect, | 380 kMatchTelAndSelect, |
375 &expiration_month_) && | 381 &expiration_month_) && |
376 ParseFieldSpecifics(scanner, | 382 ParseFieldSpecifics(scanner, |
377 kExpirationYearRe, | 383 base::UTF8ToUTF16(kExpirationYearRe), |
378 kMatchTelAndSelect, | 384 kMatchTelAndSelect, |
379 &expiration_year_)) { | 385 &expiration_year_)) { |
380 return true; | 386 return true; |
381 } | 387 } |
382 | 388 |
383 // If that fails, look for just MM/YY(YY). | 389 // If that fails, look for just MM/YY(YY). |
384 scanner->RewindTo(month_year_saved_cursor); | 390 scanner->RewindTo(month_year_saved_cursor); |
385 if (ParseFieldSpecifics(scanner, | 391 if (ParseFieldSpecifics(scanner, |
386 "^mm$", | 392 base::ASCIIToUTF16("^mm$"), |
387 kMatchTelAndSelect, | 393 kMatchTelAndSelect, |
388 &expiration_month_) && | 394 &expiration_month_) && |
389 ParseFieldSpecifics(scanner, | 395 ParseFieldSpecifics(scanner, |
390 "^(yy|yyyy)$", | 396 base::ASCIIToUTF16("^(yy|yyyy)$"), |
391 kMatchTelAndSelect, | 397 kMatchTelAndSelect, |
392 &expiration_year_)) { | 398 &expiration_year_)) { |
393 return true; | 399 return true; |
394 } | 400 } |
395 | 401 |
396 // If that fails, try to parse a combined expiration field. | 402 // If that fails, try to parse a combined expiration field. |
397 // We allow <select> fields, because they're used e.g. on qvc.com. | 403 // We allow <select> fields, because they're used e.g. on qvc.com. |
398 scanner->RewindTo(month_year_saved_cursor); | 404 scanner->RewindTo(month_year_saved_cursor); |
399 | 405 |
400 // Bail out if the field cannot fit a 2-digit year expiration date. | 406 // Bail out if the field cannot fit a 2-digit year expiration date. |
401 const int current_field_max_length = scanner->Cursor()->max_length; | 407 const int current_field_max_length = scanner->Cursor()->max_length; |
402 if (!FieldCanFitDataForFieldType(current_field_max_length, | 408 if (!FieldCanFitDataForFieldType(current_field_max_length, |
403 CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR)) { | 409 CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR)) { |
404 return false; | 410 return false; |
405 } | 411 } |
406 | 412 |
407 // Try to look for a 2-digit year expiration date. | 413 // Try to look for a 2-digit year expiration date. |
408 if (ParseFieldSpecifics(scanner, | 414 if (ParseFieldSpecifics(scanner, |
409 kExpirationDate2DigitYearRe, | 415 base::UTF8ToUTF16(kExpirationDate2DigitYearRe), |
410 kMatchTelAndSelect, | 416 kMatchTelAndSelect, |
411 &expiration_date_)) { | 417 &expiration_date_)) { |
412 exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR; | 418 exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR; |
413 expiration_month_ = nullptr; | 419 expiration_month_ = nullptr; |
414 return true; | 420 return true; |
415 } | 421 } |
416 | 422 |
417 // Try to look for a generic expiration date field. (2 or 4 digit year) | 423 // Try to look for a generic expiration date field. (2 or 4 digit year) |
418 if (ParseFieldSpecifics(scanner, | 424 if (ParseFieldSpecifics(scanner, |
419 kExpirationDateRe, | 425 base::UTF8ToUTF16(kExpirationDateRe), |
420 kMatchTelAndSelect, | 426 kMatchTelAndSelect, |
421 &expiration_date_)) { | 427 &expiration_date_)) { |
422 // If such a field exists, but it cannot fit a 4-digit year expiration | 428 // If such a field exists, but it cannot fit a 4-digit year expiration |
423 // date, then the likely possibility is that it is a 2-digit year expiration | 429 // date, then the likely possibility is that it is a 2-digit year expiration |
424 // date. | 430 // date. |
425 if (!FieldCanFitDataForFieldType(current_field_max_length, | 431 if (!FieldCanFitDataForFieldType(current_field_max_length, |
426 CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR)) { | 432 CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR)) { |
427 exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR; | 433 exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR; |
428 } | 434 } |
429 expiration_month_ = nullptr; | 435 expiration_month_ = nullptr; |
430 return true; | 436 return true; |
431 } | 437 } |
432 | 438 |
433 // Try to look for a 4-digit year expiration date. | 439 // Try to look for a 4-digit year expiration date. |
434 if (FieldCanFitDataForFieldType(current_field_max_length, | 440 if (FieldCanFitDataForFieldType(current_field_max_length, |
435 CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) && | 441 CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) && |
436 ParseFieldSpecifics(scanner, | 442 ParseFieldSpecifics(scanner, |
437 kExpirationDate4DigitYearRe, | 443 base::UTF8ToUTF16(kExpirationDate4DigitYearRe), |
438 kMatchTelAndSelect, | 444 kMatchTelAndSelect, |
439 &expiration_date_)) { | 445 &expiration_date_)) { |
440 expiration_month_ = nullptr; | 446 expiration_month_ = nullptr; |
441 return true; | 447 return true; |
442 } | 448 } |
443 | 449 |
444 return false; | 450 return false; |
445 } | 451 } |
446 | 452 |
447 ServerFieldType CreditCardField::GetExpirationYearType() const { | 453 ServerFieldType CreditCardField::GetExpirationYearType() const { |
448 return (expiration_date_ | 454 return (expiration_date_ |
449 ? exp_year_type_ | 455 ? exp_year_type_ |
450 : ((expiration_year_ && expiration_year_->max_length == 2) | 456 : ((expiration_year_ && expiration_year_->max_length == 2) |
451 ? CREDIT_CARD_EXP_2_DIGIT_YEAR | 457 ? CREDIT_CARD_EXP_2_DIGIT_YEAR |
452 : CREDIT_CARD_EXP_4_DIGIT_YEAR)); | 458 : CREDIT_CARD_EXP_4_DIGIT_YEAR)); |
453 } | 459 } |
454 | 460 |
455 } // namespace autofill | 461 } // namespace autofill |
OLD | NEW |