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