credit_card.cc revision 3240926e260ce088908e02ac07a6cf7b0c0cbf44
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/validation.h" 25#include "components/autofill/core/common/form_field_data.h" 26#include "grit/component_strings.h" 27#include "grit/webkit_resources.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 32namespace autofill { 33 34namespace { 35 36const char16 kCreditCardObfuscationSymbol = '*'; 37 38// This is the maximum obfuscated symbols displayed. 39// It is introduced to avoid rare cases where the credit card number is 40// too large and fills the screen. 41const size_t kMaxObfuscationSize = 20; 42 43bool ConvertYear(const base::string16& year, int* num) { 44 // If the |year| is empty, clear the stored value. 45 if (year.empty()) { 46 *num = 0; 47 return true; 48 } 49 50 // Try parsing the |year| as a number. 51 if (base::StringToInt(year, num)) 52 return true; 53 54 *num = 0; 55 return false; 56} 57 58bool ConvertMonth(const base::string16& month, 59 const std::string& app_locale, 60 int* num) { 61 // If the |month| is empty, clear the stored value. 62 if (month.empty()) { 63 *num = 0; 64 return true; 65 } 66 67 // Try parsing the |month| as a number. 68 if (base::StringToInt(month, num)) 69 return true; 70 71 // If the locale is unknown, give up. 72 if (app_locale.empty()) 73 return false; 74 75 // Otherwise, try parsing the |month| as a named month, e.g. "January" or 76 // "Jan". 77 base::string16 lowercased_month = StringToLowerASCII(month); 78 79 UErrorCode status = U_ZERO_ERROR; 80 icu::Locale locale(app_locale.c_str()); 81 icu::DateFormatSymbols date_format_symbols(locale, status); 82 DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING || 83 status == U_USING_DEFAULT_WARNING); 84 85 int32_t num_months; 86 const icu::UnicodeString* months = date_format_symbols.getMonths(num_months); 87 for (int32_t i = 0; i < num_months; ++i) { 88 const base::string16 icu_month = base::string16(months[i].getBuffer(), 89 months[i].length()); 90 if (lowercased_month == StringToLowerASCII(icu_month)) { 91 *num = i + 1; // Adjust from 0-indexed to 1-indexed. 92 return true; 93 } 94 } 95 96 months = date_format_symbols.getShortMonths(num_months); 97 for (int32_t i = 0; i < num_months; ++i) { 98 const base::string16 icu_month = base::string16(months[i].getBuffer(), 99 months[i].length()); 100 if (lowercased_month == StringToLowerASCII(icu_month)) { 101 *num = i + 1; // Adjust from 0-indexed to 1-indexed. 102 return true; 103 } 104 } 105 106 *num = 0; 107 return false; 108} 109 110} // namespace 111 112CreditCard::CreditCard(const std::string& guid, const std::string& origin) 113 : AutofillDataModel(guid, origin), 114 type_(kGenericCard), 115 expiration_month_(0), 116 expiration_year_(0) { 117} 118 119CreditCard::CreditCard() 120 : AutofillDataModel(base::GenerateGUID(), std::string()), 121 type_(kGenericCard), 122 expiration_month_(0), 123 expiration_year_(0) { 124} 125 126CreditCard::CreditCard(const CreditCard& credit_card) 127 : AutofillDataModel(std::string(), std::string()) { 128 operator=(credit_card); 129} 130 131CreditCard::~CreditCard() {} 132 133// static 134const base::string16 CreditCard::StripSeparators(const base::string16& number) { 135 const char16 kSeparators[] = {'-', ' ', '\0'}; 136 base::string16 stripped; 137 RemoveChars(number, kSeparators, &stripped); 138 return stripped; 139} 140 141// static 142base::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 165int 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 188std::string 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 278base::string16 CreditCard::GetRawInfo(ServerFieldType type) const { 279 switch (type) { 280 case CREDIT_CARD_NAME: 281 return name_on_card_; 282 283 case CREDIT_CARD_EXP_MONTH: 284 return ExpirationMonthAsString(); 285 286 case CREDIT_CARD_EXP_2_DIGIT_YEAR: 287 return Expiration2DigitYearAsString(); 288 289 case CREDIT_CARD_EXP_4_DIGIT_YEAR: 290 return Expiration4DigitYearAsString(); 291 292 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: { 293 base::string16 month = ExpirationMonthAsString(); 294 base::string16 year = Expiration2DigitYearAsString(); 295 if (!month.empty() && !year.empty()) 296 return month + ASCIIToUTF16("/") + year; 297 return base::string16(); 298 } 299 300 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: { 301 base::string16 month = ExpirationMonthAsString(); 302 base::string16 year = Expiration4DigitYearAsString(); 303 if (!month.empty() && !year.empty()) 304 return month + ASCIIToUTF16("/") + year; 305 return base::string16(); 306 } 307 308 case CREDIT_CARD_TYPE: 309 return TypeForDisplay(); 310 311 case CREDIT_CARD_NUMBER: 312 return number_; 313 314 case CREDIT_CARD_VERIFICATION_CODE: 315 // Chrome doesn't store credit card verification codes. 316 return base::string16(); 317 318 default: 319 // ComputeDataPresentForArray will hit this repeatedly. 320 return base::string16(); 321 } 322} 323 324void CreditCard::SetRawInfo(ServerFieldType type, 325 const base::string16& value) { 326 switch (type) { 327 case CREDIT_CARD_NAME: 328 name_on_card_ = value; 329 break; 330 331 case CREDIT_CARD_EXP_MONTH: 332 SetExpirationMonthFromString(value, std::string()); 333 break; 334 335 case CREDIT_CARD_EXP_2_DIGIT_YEAR: 336 // This is a read-only attribute. 337 break; 338 339 case CREDIT_CARD_EXP_4_DIGIT_YEAR: 340 SetExpirationYearFromString(value); 341 break; 342 343 case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: 344 // This is a read-only attribute. 345 break; 346 347 case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: 348 // This is a read-only attribute. 349 break; 350 351 case CREDIT_CARD_TYPE: 352 // This is a read-only attribute, determined by the credit card number. 353 break; 354 355 case CREDIT_CARD_NUMBER: { 356 // Don't change the real value if the input is an obfuscated string. 357 if (value.size() > 0 && value[0] != kCreditCardObfuscationSymbol) 358 SetNumber(value); 359 break; 360 } 361 362 case CREDIT_CARD_VERIFICATION_CODE: 363 // Chrome doesn't store the credit card verification code. 364 break; 365 366 default: 367 NOTREACHED() << "Attempting to set unknown info-type " << type; 368 break; 369 } 370} 371 372base::string16 CreditCard::GetInfo(const AutofillType& type, 373 const std::string& app_locale) const { 374 if (type.server_type() == CREDIT_CARD_NUMBER) 375 return StripSeparators(number_); 376 377 return GetRawInfo(type.server_type()); 378} 379 380bool CreditCard::SetInfo(const AutofillType& type, 381 const base::string16& value, 382 const std::string& app_locale) { 383 ServerFieldType server_type = type.server_type(); 384 if (server_type == CREDIT_CARD_NUMBER) 385 SetRawInfo(server_type, StripSeparators(value)); 386 else if (server_type == CREDIT_CARD_EXP_MONTH) 387 SetExpirationMonthFromString(value, app_locale); 388 else 389 SetRawInfo(server_type, value); 390 391 return true; 392} 393 394void CreditCard::GetMatchingTypes(const base::string16& text, 395 const std::string& app_locale, 396 ServerFieldTypeSet* matching_types) const { 397 FormGroup::GetMatchingTypes(text, app_locale, matching_types); 398 399 base::string16 card_number = 400 GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale); 401 if (!card_number.empty() && StripSeparators(text) == card_number) 402 matching_types->insert(CREDIT_CARD_NUMBER); 403 404 int month; 405 if (ConvertMonth(text, app_locale, &month) && month != 0 && 406 month == expiration_month_) { 407 matching_types->insert(CREDIT_CARD_EXP_MONTH); 408 } 409} 410 411const base::string16 CreditCard::Label() const { 412 base::string16 label; 413 if (number().empty()) 414 return name_on_card_; // No CC number, return name only. 415 416 base::string16 obfuscated_cc_number = ObfuscatedNumber(); 417 if (!expiration_month_ || !expiration_year_) 418 return obfuscated_cc_number; // No expiration date set. 419 420 // TODO(georgey): Internationalize date. 421 base::string16 formatted_date(ExpirationMonthAsString()); 422 formatted_date.append(ASCIIToUTF16("/")); 423 formatted_date.append(Expiration4DigitYearAsString()); 424 425 label = l10n_util::GetStringFUTF16(IDS_CREDIT_CARD_NUMBER_PREVIEW_FORMAT, 426 obfuscated_cc_number, 427 formatted_date); 428 return label; 429} 430 431void CreditCard::SetInfoForMonthInputType(const base::string16& value) { 432 // Check if |text| is "yyyy-mm" format first, and check normal month format. 433 if (!autofill::MatchesPattern(value, UTF8ToUTF16("^[0-9]{4}-[0-9]{1,2}$"))) 434 return; 435 436 std::vector<base::string16> year_month; 437 base::SplitString(value, L'-', &year_month); 438 DCHECK_EQ((int)year_month.size(), 2); 439 int num = 0; 440 bool converted = false; 441 converted = base::StringToInt(year_month[0], &num); 442 DCHECK(converted); 443 SetExpirationYear(num); 444 converted = base::StringToInt(year_month[1], &num); 445 DCHECK(converted); 446 SetExpirationMonth(num); 447} 448 449base::string16 CreditCard::ObfuscatedNumber() const { 450 // If the number is shorter than four digits, there's no need to obfuscate it. 451 if (number_.size() < 4) 452 return number_; 453 454 base::string16 number = StripSeparators(number_); 455 456 // Avoid making very long obfuscated numbers. 457 size_t obfuscated_digits = std::min(kMaxObfuscationSize, number.size() - 4); 458 base::string16 result(obfuscated_digits, kCreditCardObfuscationSymbol); 459 return result.append(LastFourDigits()); 460} 461 462base::string16 CreditCard::LastFourDigits() const { 463 static const size_t kNumLastDigits = 4; 464 465 base::string16 number = StripSeparators(number_); 466 if (number.size() < kNumLastDigits) 467 return base::string16(); 468 469 return number.substr(number.size() - kNumLastDigits, kNumLastDigits); 470} 471 472base::string16 CreditCard::TypeForDisplay() const { 473 return CreditCard::TypeForDisplay(type_); 474} 475 476base::string16 CreditCard::TypeAndLastFourDigits() const { 477 base::string16 type = TypeForDisplay(); 478 // TODO(estade): type may be empty, we probably want to return 479 // "Card - 1234" or something in that case. 480 481 base::string16 digits = LastFourDigits(); 482 if (digits.empty()) 483 return type; 484 485 // TODO(estade): i18n. 486 return type + ASCIIToUTF16(" - ") + digits; 487} 488 489void CreditCard::operator=(const CreditCard& credit_card) { 490 if (this == &credit_card) 491 return; 492 493 number_ = credit_card.number_; 494 name_on_card_ = credit_card.name_on_card_; 495 type_ = credit_card.type_; 496 expiration_month_ = credit_card.expiration_month_; 497 expiration_year_ = credit_card.expiration_year_; 498 499 set_guid(credit_card.guid()); 500 set_origin(credit_card.origin()); 501} 502 503bool CreditCard::UpdateFromImportedCard(const CreditCard& imported_card, 504 const std::string& app_locale) { 505 if (this->GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale) != 506 imported_card.GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale)) { 507 return false; 508 } 509 510 // Heuristically aggregated data should never overwrite verified data. 511 // Instead, discard any heuristically aggregated credit cards that disagree 512 // with explicitly entered data, so that the UI is not cluttered with 513 // duplicate cards. 514 if (this->IsVerified() && !imported_card.IsVerified()) 515 return true; 516 517 set_origin(imported_card.origin()); 518 519 // Note that the card number is intentionally not updated, so as to preserve 520 // any formatting (i.e. separator characters). Since the card number is not 521 // updated, there is no reason to update the card type, either. 522 if (!imported_card.name_on_card_.empty()) 523 name_on_card_ = imported_card.name_on_card_; 524 525 // The expiration date for |imported_card| should always be set. 526 DCHECK(imported_card.expiration_month_ && imported_card.expiration_year_); 527 expiration_month_ = imported_card.expiration_month_; 528 expiration_year_ = imported_card.expiration_year_; 529 530 return true; 531} 532 533void CreditCard::FillFormField(const AutofillField& field, 534 size_t /*variant*/, 535 const std::string& app_locale, 536 FormFieldData* field_data) const { 537 DCHECK_EQ(CREDIT_CARD, field.Type().group()); 538 DCHECK(field_data); 539 540 if (field_data->form_control_type == "select-one") { 541 FillSelectControl(field.Type(), app_locale, field_data); 542 } else if (field_data->form_control_type == "month") { 543 // HTML5 input="month" consists of year-month. 544 base::string16 year = 545 GetInfo(AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale); 546 base::string16 month = 547 GetInfo(AutofillType(CREDIT_CARD_EXP_MONTH), app_locale); 548 if (!year.empty() && !month.empty()) { 549 // Fill the value only if |this| includes both year and month 550 // information. 551 field_data->value = year + ASCIIToUTF16("-") + month; 552 } 553 } else { 554 field_data->value = GetInfo(field.Type(), app_locale); 555 } 556} 557 558int CreditCard::Compare(const CreditCard& credit_card) const { 559 // The following CreditCard field types are the only types we store in the 560 // WebDB so far, so we're only concerned with matching these types in the 561 // credit card. 562 const ServerFieldType types[] = { CREDIT_CARD_NAME, 563 CREDIT_CARD_NUMBER, 564 CREDIT_CARD_EXP_MONTH, 565 CREDIT_CARD_EXP_4_DIGIT_YEAR }; 566 for (size_t i = 0; i < arraysize(types); ++i) { 567 int comparison = 568 GetRawInfo(types[i]).compare(credit_card.GetRawInfo(types[i])); 569 if (comparison != 0) 570 return comparison; 571 } 572 573 return 0; 574} 575 576bool CreditCard::operator==(const CreditCard& credit_card) const { 577 return guid() == credit_card.guid() && 578 origin() == credit_card.origin() && 579 Compare(credit_card) == 0; 580} 581 582bool CreditCard::operator!=(const CreditCard& credit_card) const { 583 return !operator==(credit_card); 584} 585 586bool CreditCard::IsEmpty(const std::string& app_locale) const { 587 ServerFieldTypeSet types; 588 GetNonEmptyTypes(app_locale, &types); 589 return types.empty(); 590} 591 592bool CreditCard::IsComplete() const { 593 return 594 autofill::IsValidCreditCardNumber(number_) && 595 expiration_month_ != 0 && 596 expiration_year_ != 0; 597} 598 599bool CreditCard::IsValid() const { 600 return autofill::IsValidCreditCardNumber(number_) && 601 autofill::IsValidCreditCardExpirationDate( 602 expiration_year_, expiration_month_, base::Time::Now()); 603} 604 605void CreditCard::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { 606 supported_types->insert(CREDIT_CARD_NAME); 607 supported_types->insert(CREDIT_CARD_NUMBER); 608 supported_types->insert(CREDIT_CARD_TYPE); 609 supported_types->insert(CREDIT_CARD_EXP_MONTH); 610 supported_types->insert(CREDIT_CARD_EXP_2_DIGIT_YEAR); 611 supported_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR); 612 supported_types->insert(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR); 613 supported_types->insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR); 614} 615 616base::string16 CreditCard::ExpirationMonthAsString() const { 617 if (expiration_month_ == 0) 618 return base::string16(); 619 620 base::string16 month = base::IntToString16(expiration_month_); 621 if (expiration_month_ >= 10) 622 return month; 623 624 base::string16 zero = ASCIIToUTF16("0"); 625 zero.append(month); 626 return zero; 627} 628 629base::string16 CreditCard::Expiration4DigitYearAsString() const { 630 if (expiration_year_ == 0) 631 return base::string16(); 632 633 return base::IntToString16(Expiration4DigitYear()); 634} 635 636base::string16 CreditCard::Expiration2DigitYearAsString() const { 637 if (expiration_year_ == 0) 638 return base::string16(); 639 640 return base::IntToString16(Expiration2DigitYear()); 641} 642 643void CreditCard::SetExpirationMonthFromString(const base::string16& text, 644 const std::string& app_locale) { 645 int month; 646 if (!ConvertMonth(text, app_locale, &month)) 647 return; 648 649 SetExpirationMonth(month); 650} 651 652void CreditCard::SetExpirationYearFromString(const base::string16& text) { 653 int year; 654 if (!ConvertYear(text, &year)) 655 return; 656 657 SetExpirationYear(year); 658} 659 660void CreditCard::SetNumber(const base::string16& number) { 661 number_ = number; 662 type_ = GetCreditCardType(StripSeparators(number_)); 663} 664 665void CreditCard::SetExpirationMonth(int expiration_month) { 666 if (expiration_month < 0 || expiration_month > 12) 667 return; 668 669 expiration_month_ = expiration_month; 670} 671 672void CreditCard::SetExpirationYear(int expiration_year) { 673 if (expiration_year != 0 && 674 (expiration_year < 2006 || expiration_year > 10000)) { 675 return; 676 } 677 678 expiration_year_ = expiration_year; 679} 680 681// So we can compare CreditCards with EXPECT_EQ(). 682std::ostream& operator<<(std::ostream& os, const CreditCard& credit_card) { 683 return os 684 << UTF16ToUTF8(credit_card.Label()) 685 << " " 686 << credit_card.guid() 687 << " " 688 << credit_card.origin() 689 << " " 690 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NAME)) 691 << " " 692 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_TYPE)) 693 << " " 694 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NUMBER)) 695 << " " 696 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_EXP_MONTH)) 697 << " " 698 << UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR)); 699} 700 701// These values must match the values in WebKitPlatformSupportImpl in 702// webkit/glue. We send these strings to WebKit, which then asks 703// WebKitPlatformSupportImpl to load the image data. 704const char* const kAmericanExpressCard = "americanExpressCC"; 705const char* const kDinersCard = "dinersCC"; 706const char* const kDiscoverCard = "discoverCC"; 707const char* const kGenericCard = "genericCC"; 708const char* const kJCBCard = "jcbCC"; 709const char* const kMasterCard = "masterCardCC"; 710const char* const kUnionPay = "unionPayCC"; 711const char* const kVisaCard = "visaCC"; 712 713} // namespace autofill 714