| 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 |