credit_card.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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_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
33namespace autofill {
34
35namespace {
36
37const 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.
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 = 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
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  base::string16 stripped;
137  base::RemoveChars(number, base::ASCIIToUTF16("- "), &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
188const 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
278base::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
325void 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
374base::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
383bool 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
397void 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
414const 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
434void 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
454base::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
467base::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
477base::string16 CreditCard::TypeForDisplay() const {
478  return CreditCard::TypeForDisplay(type_);
479}
480
481base::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
494void 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
508bool 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
538int 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
556bool 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
562bool CreditCard::operator!=(const CreditCard& credit_card) const {
563  return !operator==(credit_card);
564}
565
566bool CreditCard::IsEmpty(const std::string& app_locale) const {
567  ServerFieldTypeSet types;
568  GetNonEmptyTypes(app_locale, &types);
569  return types.empty();
570}
571
572bool CreditCard::IsComplete() const {
573  return
574      autofill::IsValidCreditCardNumber(number_) &&
575      expiration_month_ != 0 &&
576      expiration_year_ != 0;
577}
578
579bool CreditCard::IsValid() const {
580  return autofill::IsValidCreditCardNumber(number_) &&
581         autofill::IsValidCreditCardExpirationDate(
582             expiration_year_, expiration_month_, base::Time::Now());
583}
584
585void 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
596base::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
609base::string16 CreditCard::Expiration4DigitYearAsString() const {
610  if (expiration_year_ == 0)
611    return base::string16();
612
613  return base::IntToString16(Expiration4DigitYear());
614}
615
616base::string16 CreditCard::Expiration2DigitYearAsString() const {
617  if (expiration_year_ == 0)
618    return base::string16();
619
620  return base::IntToString16(Expiration2DigitYear());
621}
622
623void 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
632void CreditCard::SetExpirationYearFromString(const base::string16& text) {
633  int year;
634  if (!ConvertYear(text, &year))
635    return;
636
637  SetExpirationYear(year);
638}
639
640void CreditCard::SetNumber(const base::string16& number) {
641  number_ = number;
642  type_ = GetCreditCardType(StripSeparators(number_));
643}
644
645void CreditCard::SetExpirationMonth(int expiration_month) {
646  if (expiration_month < 0 || expiration_month > 12)
647    return;
648
649  expiration_month_ = expiration_month;
650}
651
652void 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().
662std::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.
685const char* const kAmericanExpressCard = "americanExpressCC";
686const char* const kDinersCard = "dinersCC";
687const char* const kDiscoverCard = "discoverCC";
688const char* const kGenericCard = "genericCC";
689const char* const kJCBCard = "jcbCC";
690const char* const kMasterCard = "masterCardCC";
691const char* const kUnionPay = "unionPayCC";
692const char* const kVisaCard = "visaCC";
693
694}  // namespace autofill
695