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 3 // found in the LICENSE file. 4 5 #include "components/autofill/core/browser/credit_card.h" 6 7 #include <stddef.h> 8 9 #include <algorithm> 10 #include <ostream> 11 #include <string> 12 13 #include "base/basictypes.h" 14 #include "base/guid.h" 15 #include "base/logging.h" 16 #include "base/strings/string16.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_split.h" 19 #include "base/strings/string_util.h" 20 #include "base/strings/utf_string_conversions.h" 21 #include "base/time/time.h" 22 #include "components/autofill/core/browser/autofill_field.h" 23 #include "components/autofill/core/browser/autofill_regexes.h" 24 #include "components/autofill/core/browser/autofill_type.h" 25 #include "components/autofill/core/browser/validation.h" 26 #include "components/autofill/core/common/form_field_data.h" 27 #include "grit/components_scaled_resources.h" 28 #include "grit/components_strings.h" 29 #include "third_party/icu/source/common/unicode/uloc.h" 30 #include "third_party/icu/source/i18n/unicode/dtfmtsym.h" 31 #include "ui/base/l10n/l10n_util.h" 32 33 namespace autofill { 34 35 namespace { 36 37 const base::char16 kCreditCardObfuscationSymbol = '*'; 38 39 // This is the maximum obfuscated symbols displayed. 40 // It is introduced to avoid rare cases where the credit card number is 41 // too large and fills the screen. 42 const size_t kMaxObfuscationSize = 20; 43 44 bool ConvertYear(const base::string16& year, int* num) { 45 // If the |year| is empty, clear the stored value. 46 if (year.empty()) { 47 *num = 0; 48 return true; 49 } 50 51 // Try parsing the |year| as a number. 52 if (base::StringToInt(year, num)) 53 return true; 54 55 *num = 0; 56 return false; 57 } 58 59 bool ConvertMonth(const base::string16& month, 60 const std::string& app_locale, 61 int* num) { 62 // If the |month| is empty, clear the stored value. 63 if (month.empty()) { 64 *num = 0; 65 return true; 66 } 67 68 // Try parsing the |month| as a number. 69 if (base::StringToInt(month, num)) 70 return true; 71 72 // If the locale is unknown, give up. 73 if (app_locale.empty()) 74 return false; 75 76 // Otherwise, try parsing the |month| as a named month, e.g. "January" or 77 // "Jan". 78 base::string16 lowercased_month = base::StringToLowerASCII(month); 79 80 UErrorCode status = U_ZERO_ERROR; 81 icu::Locale locale(app_locale.c_str()); 82 icu::DateFormatSymbols date_format_symbols(locale, status); 83 DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING || 84 status == U_USING_DEFAULT_WARNING); 85 86 int32_t num_months; 87 const icu::UnicodeString* months = date_format_symbols.getMonths(num_months); 88 for (int32_t i = 0; i < num_months; ++i) { 89 const base::string16 icu_month = base::string16(months[i].getBuffer(), 90 months[i].length()); 91 if (lowercased_month == base::StringToLowerASCII(icu_month)) { 92 *num = i + 1; // Adjust from 0-indexed to 1-indexed. 93 return true; 94 } 95 } 96 97 months = date_format_symbols.getShortMonths(num_months); 98 for (int32_t i = 0; i < num_months; ++i) { 99 const base::string16 icu_month = base::string16(months[i].getBuffer(), 100 months[i].length()); 101 if (lowercased_month == base::StringToLowerASCII(icu_month)) { 102 *num = i + 1; // Adjust from 0-indexed to 1-indexed. 103 return true; 104 } 105 } 106 107 *num = 0; 108 return false; 109 } 110 111 } // namespace 112 113 CreditCard::CreditCard(const std::string& guid, const std::string& origin) 114 : AutofillDataModel(guid, origin), 115 type_(kGenericCard), 116 expiration_month_(0), 117 expiration_year_(0) { 118 } 119 120 CreditCard::CreditCard() 121 : AutofillDataModel(base::GenerateGUID(), std::string()), 122 type_(kGenericCard), 123 expiration_month_(0), 124 expiration_year_(0) { 125 } 126 127 CreditCard::CreditCard(const CreditCard& credit_card) 128 : AutofillDataModel(std::string(), std::string()) { 129 operator=(credit_card); 130 } 131 132 CreditCard::~CreditCard() {} 133 134 // static 135 const base::string16 CreditCard::StripSeparators(const base::string16& number) { 136 base::string16 stripped; 137 base::RemoveChars(number, base::ASCIIToUTF16("- "), &stripped); 138 return stripped; 139 } 140 141 // static 142 base::string16 CreditCard::TypeForDisplay(const std::string& type) { 143 if (type == kAmericanExpressCard) 144 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX); 145 if (type == kDinersCard) 146 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DINERS); 147 if (type == kDiscoverCard) 148 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DISCOVER); 149 if (type == kJCBCard) 150 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_JCB); 151 if (type == kMasterCard) 152 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_MASTERCARD); 153 if (type == kUnionPay) 154 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_UNION_PAY); 155 if (type == kVisaCard) 156 return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_VISA); 157 158 // If you hit this DCHECK, the above list of cases needs to be updated to 159 // include a new card. 160 DCHECK_EQ(kGenericCard, type); 161 return base::string16(); 162 } 163 164 // static 165 int CreditCard::IconResourceId(const std::string& type) { 166 if (type == kAmericanExpressCard) 167 return IDR_AUTOFILL_CC_AMEX; 168 if (type == kDinersCard) 169 return IDR_AUTOFILL_CC_DINERS; 170 if (type == kDiscoverCard) 171 return IDR_AUTOFILL_CC_DISCOVER; 172 if (type == kJCBCard) 173 return IDR_AUTOFILL_CC_JCB; 174 if (type == kMasterCard) 175 return IDR_AUTOFILL_CC_MASTERCARD; 176 if (type == kUnionPay) 177 return IDR_AUTOFILL_CC_GENERIC; // Needs resource: http://crbug.com/259211 178 if (type == kVisaCard) 179 return IDR_AUTOFILL_CC_VISA; 180 181 // If you hit this DCHECK, the above list of cases needs to be updated to 182 // include a new card. 183 DCHECK_EQ(kGenericCard, type); 184 return IDR_AUTOFILL_CC_GENERIC; 185 } 186 187 // static 188 const char* CreditCard::GetCreditCardType(const base::string16& number) { 189 // Credit card number specifications taken from: 190 // http://en.wikipedia.org/wiki/Credit_card_numbers, 191 // http://en.wikipedia.org/wiki/List_of_Issuer_Identification_Numbers, 192 // http://www.discovernetwork.com/merchants/images/Merchant_Marketing_PDF.pdf, 193 // http://www.regular-expressions.info/creditcard.html, 194 // http://developer.ean.com/general_info/Valid_Credit_Card_Types, 195 // http://www.bincodes.com/, 196 // http://www.fraudpractice.com/FL-binCC.html, and 197 // http://www.beachnet.com/~hstiles/cardtype.html 198 // 199 // The last site is currently unavailable, but a cached version remains at 200 // http://web.archive.org/web/20120923111349/http://www.beachnet.com/~hstiles/cardtype.html 201 // 202 // Card Type Prefix(es) Length 203 // --------------------------------------------------------------- 204 // Visa 4 13,16 205 // American Express 34,37 15 206 // Diners Club 300-305,3095,36,38-39 14 207 // Discover Card 6011,644-649,65 16 208 // JCB 3528-3589 16 209 // MasterCard 51-55 16 210 // UnionPay 62 16-19 211 212 // Check for prefixes of length 1. 213 if (number.empty()) 214 return kGenericCard; 215 216 if (number[0] == '4') 217 return kVisaCard; 218 219 // Check for prefixes of length 2. 220 if (number.size() < 2) 221 return kGenericCard; 222 223 int first_two_digits = 0; 224 if (!base::StringToInt(number.substr(0, 2), &first_two_digits)) 225 return kGenericCard; 226 227 if (first_two_digits == 34 || first_two_digits == 37) 228 return kAmericanExpressCard; 229 230 if (first_two_digits == 36 || 231 first_two_digits == 38 || 232 first_two_digits == 39) 233 return kDinersCard; 234 235 if (first_two_digits >= 51 && first_two_digits <= 55) 236 return kMasterCard; 237 238 if (first_two_digits == 62) 239 return kUnionPay; 240 241 if (first_two_digits == 65) 242 return kDiscoverCard; 243 244 // Check for prefixes of length 3. 245 if (number.size() < 3) 246 return kGenericCard; 247 248 int first_three_digits = 0; 249 if (!base::StringToInt(number.substr(0, 3), &first_three_digits)) 250 return kGenericCard; 251 252 if (first_three_digits >= 300 && first_three_digits <= 305) 253 return kDinersCard; 254 255 if (first_three_digits >= 644 && first_three_digits <= 649) 256 return kDiscoverCard; 257 258 // Check for prefixes of length 4. 259 if (number.size() < 4) 260 return kGenericCard; 261 262 int first_four_digits = 0; 263 if (!base::StringToInt(number.substr(0, 4), &first_four_digits)) 264 return kGenericCard; 265 266 if (first_four_digits == 3095) 267 return kDinersCard; 268 269 if (first_four_digits >= 3528 && first_four_digits <= 3589) 270 return kJCBCard; 271 272 if (first_four_digits == 6011) 273 return kDiscoverCard; 274 275 return kGenericCard; 276 } 277 278 base::string16 CreditCard::GetRawInfo(ServerFieldType type) const { 279 DCHECK_EQ(CREDIT_CARD, AutofillType(type).group()); 280 switch (type) { 281 case CREDIT_CARD_NAME: 282 return name_on_card_; 283 284 case CREDIT_CARD_EXP_MONTH: 285 return ExpirationMonthAsString(); 286 287 case CREDIT_CARD_EXP_2_DIGIT_YEAR: 288 return Expiration2DigitYearAsString(); 289 290 case CREDIT_CARD_EXP_4_DIGIT_YEAR: 291 return Expiration4DigitYearAsString(); 292 293 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: { 294 base::string16 month = ExpirationMonthAsString(); 295 base::string16 year = Expiration2DigitYearAsString(); 296 if (!month.empty() && !year.empty()) 297 return month + base::ASCIIToUTF16("/") + year; 298 return base::string16(); 299 } 300 301 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: { 302 base::string16 month = ExpirationMonthAsString(); 303 base::string16 year = Expiration4DigitYearAsString(); 304 if (!month.empty() && !year.empty()) 305 return month + base::ASCIIToUTF16("/") + year; 306 return base::string16(); 307 } 308 309 case CREDIT_CARD_TYPE: 310 return TypeForDisplay(); 311 312 case CREDIT_CARD_NUMBER: 313 return number_; 314 315 case CREDIT_CARD_VERIFICATION_CODE: 316 // Chrome doesn't store credit card verification codes. 317 return base::string16(); 318 319 default: 320 // ComputeDataPresentForArray will hit this repeatedly. 321 return base::string16(); 322 } 323 } 324 325 void CreditCard::SetRawInfo(ServerFieldType type, 326 const base::string16& value) { 327 DCHECK_EQ(CREDIT_CARD, AutofillType(type).group()); 328 switch (type) { 329 case CREDIT_CARD_NAME: 330 name_on_card_ = value; 331 break; 332 333 case CREDIT_CARD_EXP_MONTH: 334 SetExpirationMonthFromString(value, std::string()); 335 break; 336 337 case CREDIT_CARD_EXP_2_DIGIT_YEAR: 338 // This is a read-only attribute. 339 break; 340 341 case CREDIT_CARD_EXP_4_DIGIT_YEAR: 342 SetExpirationYearFromString(value); 343 break; 344 345 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: 346 // This is a read-only attribute. 347 break; 348 349 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: 350 // This is a read-only attribute. 351 break; 352 353 case CREDIT_CARD_TYPE: 354 // This is a read-only attribute, determined by the credit card number. 355 break; 356 357 case CREDIT_CARD_NUMBER: { 358 // Don't change the real value if the input is an obfuscated string. 359 if (value.size() > 0 && value[0] != kCreditCardObfuscationSymbol) 360 SetNumber(value); 361 break; 362 } 363 364 case CREDIT_CARD_VERIFICATION_CODE: 365 // Chrome doesn't store the credit card verification code. 366 break; 367 368 default: 369 NOTREACHED() << "Attempting to set unknown info-type " << type; 370 break; 371 } 372 } 373 374 base::string16 CreditCard::GetInfo(const AutofillType& type, 375 const std::string& app_locale) const { 376 ServerFieldType storable_type = type.GetStorableType(); 377 if (storable_type == CREDIT_CARD_NUMBER) 378 return StripSeparators(number_); 379 380 return GetRawInfo(storable_type); 381 } 382 383 bool CreditCard::SetInfo(const AutofillType& type, 384 const base::string16& value, 385 const std::string& app_locale) { 386 ServerFieldType storable_type = type.GetStorableType(); 387 if (storable_type == CREDIT_CARD_NUMBER) 388 SetRawInfo(storable_type, StripSeparators(value)); 389 else if (storable_type == CREDIT_CARD_EXP_MONTH) 390 SetExpirationMonthFromString(value, app_locale); 391 else 392 SetRawInfo(storable_type, value); 393 394 return true; 395 } 396 397 void CreditCard::GetMatchingTypes(const base::string16& text, 398 const std::string& app_locale, 399 ServerFieldTypeSet* matching_types) const { 400 FormGroup::GetMatchingTypes(text, app_locale, matching_types); 401 402 base::string16 card_number = 403 GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale); 404 if (!card_number.empty() && StripSeparators(text) == card_number) 405 matching_types->insert(CREDIT_CARD_NUMBER); 406 407 int month; 408 if (ConvertMonth(text, app_locale, &month) && month != 0 && 409 month == expiration_month_) { 410 matching_types->insert(CREDIT_CARD_EXP_MONTH); 411 } 412 } 413 414 const base::string16 CreditCard::Label() const { 415 base::string16 label; 416 if (number().empty()) 417 return name_on_card_; // No CC number, return name only. 418 419 base::string16 obfuscated_cc_number = ObfuscatedNumber(); 420 if (!expiration_month_ || !expiration_year_) 421 return obfuscated_cc_number; // No expiration date set. 422 423 // TODO(georgey): Internationalize date. 424 base::string16 formatted_date(ExpirationMonthAsString()); 425 formatted_date.append(base::ASCIIToUTF16("/")); 426 formatted_date.append(Expiration4DigitYearAsString()); 427 428 label = l10n_util::GetStringFUTF16(IDS_CREDIT_CARD_NUMBER_PREVIEW_FORMAT, 429 obfuscated_cc_number, 430 formatted_date); 431 return label; 432 } 433 434 void CreditCard::SetInfoForMonthInputType(const base::string16& value) { 435 // Check if |text| is "yyyy-mm" format first, and check normal month format. 436 if (!autofill::MatchesPattern(value, 437 base::UTF8ToUTF16("^[0-9]{4}-[0-9]{1,2}$"))) { 438 return; 439 } 440 441 std::vector<base::string16> year_month; 442 base::SplitString(value, L'-', &year_month); 443 DCHECK_EQ((int)year_month.size(), 2); 444 int num = 0; 445 bool converted = false; 446 converted = base::StringToInt(year_month[0], &num); 447 DCHECK(converted); 448 SetExpirationYear(num); 449 converted = base::StringToInt(year_month[1], &num); 450 DCHECK(converted); 451 SetExpirationMonth(num); 452 } 453 454 base::string16 CreditCard::ObfuscatedNumber() const { 455 // If the number is shorter than four digits, there's no need to obfuscate it. 456 if (number_.size() < 4) 457 return number_; 458 459 base::string16 number = StripSeparators(number_); 460 461 // Avoid making very long obfuscated numbers. 462 size_t obfuscated_digits = std::min(kMaxObfuscationSize, number.size() - 4); 463 base::string16 result(obfuscated_digits, kCreditCardObfuscationSymbol); 464 return result.append(LastFourDigits()); 465 } 466 467 base::string16 CreditCard::LastFourDigits() const { 468 static const size_t kNumLastDigits = 4; 469 470 base::string16 number = StripSeparators(number_); 471 if (number.size() < kNumLastDigits) 472 return base::string16(); 473 474 return number.substr(number.size() - kNumLastDigits, kNumLastDigits); 475 } 476 477 base::string16 CreditCard::TypeForDisplay() const { 478 return CreditCard::TypeForDisplay(type_); 479 } 480 481 base::string16 CreditCard::TypeAndLastFourDigits() const { 482 base::string16 type = TypeForDisplay(); 483 // TODO(estade): type may be empty, we probably want to return 484 // "Card - 1234" or something in that case. 485 486 base::string16 digits = LastFourDigits(); 487 if (digits.empty()) 488 return type; 489 490 // TODO(estade): i18n. 491 return type + base::ASCIIToUTF16(" - ") + digits; 492 } 493 494 void CreditCard::operator=(const CreditCard& credit_card) { 495 if (this == &credit_card) 496 return; 497 498 number_ = credit_card.number_; 499 name_on_card_ = credit_card.name_on_card_; 500 type_ = credit_card.type_; 501 expiration_month_ = credit_card.expiration_month_; 502 expiration_year_ = credit_card.expiration_year_; 503 504 set_guid(credit_card.guid()); 505 set_origin(credit_card.origin()); 506 } 507 508 bool CreditCard::UpdateFromImportedCard(const CreditCard& imported_card, 509 const std::string& app_locale) { 510 if (this->GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale) != 511 imported_card.GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale)) { 512 return false; 513 } 514 515 // Heuristically aggregated data should never overwrite verified data. 516 // Instead, discard any heuristically aggregated credit cards that disagree 517 // with explicitly entered data, so that the UI is not cluttered with 518 // duplicate cards. 519 if (this->IsVerified() && !imported_card.IsVerified()) 520 return true; 521 522 set_origin(imported_card.origin()); 523 524 // Note that the card number is intentionally not updated, so as to preserve 525 // any formatting (i.e. separator characters). Since the card number is not 526 // updated, there is no reason to update the card type, either. 527 if (!imported_card.name_on_card_.empty()) 528 name_on_card_ = imported_card.name_on_card_; 529 530 // The expiration date for |imported_card| should always be set. 531 DCHECK(imported_card.expiration_month_ && imported_card.expiration_year_); 532 expiration_month_ = imported_card.expiration_month_; 533 expiration_year_ = imported_card.expiration_year_; 534 535 return true; 536 } 537 538 int CreditCard::Compare(const CreditCard& credit_card) const { 539 // The following CreditCard field types are the only types we store in the 540 // WebDB so far, so we're only concerned with matching these types in the 541 // credit card. 542 const ServerFieldType types[] = { CREDIT_CARD_NAME, 543 CREDIT_CARD_NUMBER, 544 CREDIT_CARD_EXP_MONTH, 545 CREDIT_CARD_EXP_4_DIGIT_YEAR }; 546 for (size_t i = 0; i < arraysize(types); ++i) { 547 int comparison = 548 GetRawInfo(types[i]).compare(credit_card.GetRawInfo(types[i])); 549 if (comparison != 0) 550 return comparison; 551 } 552 553 return 0; 554 } 555 556 bool CreditCard::operator==(const CreditCard& credit_card) const { 557 return guid() == credit_card.guid() && 558 origin() == credit_card.origin() && 559 Compare(credit_card) == 0; 560 } 561 562 bool CreditCard::operator!=(const CreditCard& credit_card) const { 563 return !operator==(credit_card); 564 } 565 566 bool CreditCard::IsEmpty(const std::string& app_locale) const { 567 ServerFieldTypeSet types; 568 GetNonEmptyTypes(app_locale, &types); 569 return types.empty(); 570 } 571 572 bool CreditCard::IsComplete() const { 573 return 574 autofill::IsValidCreditCardNumber(number_) && 575 expiration_month_ != 0 && 576 expiration_year_ != 0; 577 } 578 579 bool CreditCard::IsValid() const { 580 return autofill::IsValidCreditCardNumber(number_) && 581 autofill::IsValidCreditCardExpirationDate( 582 expiration_year_, expiration_month_, base::Time::Now()); 583 } 584 585 void CreditCard::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { 586 supported_types->insert(CREDIT_CARD_NAME); 587 supported_types->insert(CREDIT_CARD_NUMBER); 588 supported_types->insert(CREDIT_CARD_TYPE); 589 supported_types->insert(CREDIT_CARD_EXP_MONTH); 590 supported_types->insert(CREDIT_CARD_EXP_2_DIGIT_YEAR); 591 supported_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR); 592 supported_types->insert(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR); 593 supported_types->insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR); 594 } 595 596 base::string16 CreditCard::ExpirationMonthAsString() const { 597 if (expiration_month_ == 0) 598 return base::string16(); 599 600 base::string16 month = base::IntToString16(expiration_month_); 601 if (expiration_month_ >= 10) 602 return month; 603 604 base::string16 zero = base::ASCIIToUTF16("0"); 605 zero.append(month); 606 return zero; 607 } 608 609 base::string16 CreditCard::Expiration4DigitYearAsString() const { 610 if (expiration_year_ == 0) 611 return base::string16(); 612 613 return base::IntToString16(Expiration4DigitYear()); 614 } 615 616 base::string16 CreditCard::Expiration2DigitYearAsString() const { 617 if (expiration_year_ == 0) 618 return base::string16(); 619 620 return base::IntToString16(Expiration2DigitYear()); 621 } 622 623 void CreditCard::SetExpirationMonthFromString(const base::string16& text, 624 const std::string& app_locale) { 625 int month; 626 if (!ConvertMonth(text, app_locale, &month)) 627 return; 628 629 SetExpirationMonth(month); 630 } 631 632 void CreditCard::SetExpirationYearFromString(const base::string16& text) { 633 int year; 634 if (!ConvertYear(text, &year)) 635 return; 636 637 SetExpirationYear(year); 638 } 639 640 void CreditCard::SetNumber(const base::string16& number) { 641 number_ = number; 642 type_ = GetCreditCardType(StripSeparators(number_)); 643 } 644 645 void CreditCard::SetExpirationMonth(int expiration_month) { 646 if (expiration_month < 0 || expiration_month > 12) 647 return; 648 649 expiration_month_ = expiration_month; 650 } 651 652 void CreditCard::SetExpirationYear(int expiration_year) { 653 if (expiration_year != 0 && 654 (expiration_year < 2006 || expiration_year > 10000)) { 655 return; 656 } 657 658 expiration_year_ = expiration_year; 659 } 660 661 // So we can compare CreditCards with EXPECT_EQ(). 662 std::ostream& operator<<(std::ostream& os, const CreditCard& credit_card) { 663 return os 664 << base::UTF16ToUTF8(credit_card.Label()) 665 << " " 666 << credit_card.guid() 667 << " " 668 << credit_card.origin() 669 << " " 670 << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NAME)) 671 << " " 672 << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_TYPE)) 673 << " " 674 << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NUMBER)) 675 << " " 676 << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_EXP_MONTH)) 677 << " " 678 << base::UTF16ToUTF8( 679 credit_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR)); 680 } 681 682 // These values must match the values in WebKitPlatformSupportImpl in 683 // webkit/glue. We send these strings to WebKit, which then asks 684 // WebKitPlatformSupportImpl to load the image data. 685 const char* const kAmericanExpressCard = "americanExpressCC"; 686 const char* const kDinersCard = "dinersCC"; 687 const char* const kDiscoverCard = "discoverCC"; 688 const char* const kGenericCard = "genericCC"; 689 const char* const kJCBCard = "jcbCC"; 690 const char* const kMasterCard = "masterCardCC"; 691 const char* const kUnionPay = "unionPayCC"; 692 const char* const kVisaCard = "visaCC"; 693 694 } // namespace autofill 695