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