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