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