credit_card.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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
38namespace autofill {
39
40namespace {
41
42const base::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.
47const size_t kMaxObfuscationSize = 20;
48
49bool 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
64bool 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
118CreditCard::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
125CreditCard::CreditCard()
126    : AutofillDataModel(base::GenerateGUID(), std::string()),
127      type_(kGenericCard),
128      expiration_month_(0),
129      expiration_year_(0) {
130}
131
132CreditCard::CreditCard(const CreditCard& credit_card)
133    : AutofillDataModel(std::string(), std::string()) {
134  operator=(credit_card);
135}
136
137CreditCard::~CreditCard() {}
138
139// static
140const 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
148base::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
171int 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
201std::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
291base::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 + base::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 + base::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
338void 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
387base::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
396bool 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
410void 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
427const 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(base::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
447void 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,
450                                base::UTF8ToUTF16("^[0-9]{4}-[0-9]{1,2}$"))) {
451    return;
452  }
453
454  std::vector<base::string16> year_month;
455  base::SplitString(value, L'-', &year_month);
456  DCHECK_EQ((int)year_month.size(), 2);
457  int num = 0;
458  bool converted = false;
459  converted = base::StringToInt(year_month[0], &num);
460  DCHECK(converted);
461  SetExpirationYear(num);
462  converted = base::StringToInt(year_month[1], &num);
463  DCHECK(converted);
464  SetExpirationMonth(num);
465}
466
467base::string16 CreditCard::ObfuscatedNumber() const {
468  // If the number is shorter than four digits, there's no need to obfuscate it.
469  if (number_.size() < 4)
470    return number_;
471
472  base::string16 number = StripSeparators(number_);
473
474  // Avoid making very long obfuscated numbers.
475  size_t obfuscated_digits = std::min(kMaxObfuscationSize, number.size() - 4);
476  base::string16 result(obfuscated_digits, kCreditCardObfuscationSymbol);
477  return result.append(LastFourDigits());
478}
479
480base::string16 CreditCard::LastFourDigits() const {
481  static const size_t kNumLastDigits = 4;
482
483  base::string16 number = StripSeparators(number_);
484  if (number.size() < kNumLastDigits)
485    return base::string16();
486
487  return number.substr(number.size() - kNumLastDigits, kNumLastDigits);
488}
489
490base::string16 CreditCard::TypeForDisplay() const {
491  return CreditCard::TypeForDisplay(type_);
492}
493
494base::string16 CreditCard::TypeAndLastFourDigits() const {
495  base::string16 type = TypeForDisplay();
496  // TODO(estade): type may be empty, we probably want to return
497  // "Card - 1234" or something in that case.
498
499  base::string16 digits = LastFourDigits();
500  if (digits.empty())
501    return type;
502
503  // TODO(estade): i18n.
504  return type + base::ASCIIToUTF16(" - ") + digits;
505}
506
507void CreditCard::operator=(const CreditCard& credit_card) {
508  if (this == &credit_card)
509    return;
510
511  number_ = credit_card.number_;
512  name_on_card_ = credit_card.name_on_card_;
513  type_ = credit_card.type_;
514  expiration_month_ = credit_card.expiration_month_;
515  expiration_year_ = credit_card.expiration_year_;
516
517  set_guid(credit_card.guid());
518  set_origin(credit_card.origin());
519}
520
521bool CreditCard::UpdateFromImportedCard(const CreditCard& imported_card,
522                                        const std::string& app_locale) {
523  if (this->GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale) !=
524          imported_card.GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale)) {
525    return false;
526  }
527
528  // Heuristically aggregated data should never overwrite verified data.
529  // Instead, discard any heuristically aggregated credit cards that disagree
530  // with explicitly entered data, so that the UI is not cluttered with
531  // duplicate cards.
532  if (this->IsVerified() && !imported_card.IsVerified())
533    return true;
534
535  set_origin(imported_card.origin());
536
537  // Note that the card number is intentionally not updated, so as to preserve
538  // any formatting (i.e. separator characters).  Since the card number is not
539  // updated, there is no reason to update the card type, either.
540  if (!imported_card.name_on_card_.empty())
541    name_on_card_ = imported_card.name_on_card_;
542
543  // The expiration date for |imported_card| should always be set.
544  DCHECK(imported_card.expiration_month_ && imported_card.expiration_year_);
545  expiration_month_ = imported_card.expiration_month_;
546  expiration_year_ = imported_card.expiration_year_;
547
548  return true;
549}
550
551int CreditCard::Compare(const CreditCard& credit_card) const {
552  // The following CreditCard field types are the only types we store in the
553  // WebDB so far, so we're only concerned with matching these types in the
554  // credit card.
555  const ServerFieldType types[] = { CREDIT_CARD_NAME,
556                                    CREDIT_CARD_NUMBER,
557                                    CREDIT_CARD_EXP_MONTH,
558                                    CREDIT_CARD_EXP_4_DIGIT_YEAR };
559  for (size_t i = 0; i < arraysize(types); ++i) {
560    int comparison =
561        GetRawInfo(types[i]).compare(credit_card.GetRawInfo(types[i]));
562    if (comparison != 0)
563      return comparison;
564  }
565
566  return 0;
567}
568
569bool CreditCard::operator==(const CreditCard& credit_card) const {
570  return guid() == credit_card.guid() &&
571         origin() == credit_card.origin() &&
572         Compare(credit_card) == 0;
573}
574
575bool CreditCard::operator!=(const CreditCard& credit_card) const {
576  return !operator==(credit_card);
577}
578
579bool CreditCard::IsEmpty(const std::string& app_locale) const {
580  ServerFieldTypeSet types;
581  GetNonEmptyTypes(app_locale, &types);
582  return types.empty();
583}
584
585bool CreditCard::IsComplete() const {
586  return
587      autofill::IsValidCreditCardNumber(number_) &&
588      expiration_month_ != 0 &&
589      expiration_year_ != 0;
590}
591
592bool CreditCard::IsValid() const {
593  return autofill::IsValidCreditCardNumber(number_) &&
594         autofill::IsValidCreditCardExpirationDate(
595             expiration_year_, expiration_month_, base::Time::Now());
596}
597
598void CreditCard::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
599  supported_types->insert(CREDIT_CARD_NAME);
600  supported_types->insert(CREDIT_CARD_NUMBER);
601  supported_types->insert(CREDIT_CARD_TYPE);
602  supported_types->insert(CREDIT_CARD_EXP_MONTH);
603  supported_types->insert(CREDIT_CARD_EXP_2_DIGIT_YEAR);
604  supported_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR);
605  supported_types->insert(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
606  supported_types->insert(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR);
607}
608
609base::string16 CreditCard::ExpirationMonthAsString() const {
610  if (expiration_month_ == 0)
611    return base::string16();
612
613  base::string16 month = base::IntToString16(expiration_month_);
614  if (expiration_month_ >= 10)
615    return month;
616
617  base::string16 zero = base::ASCIIToUTF16("0");
618  zero.append(month);
619  return zero;
620}
621
622base::string16 CreditCard::Expiration4DigitYearAsString() const {
623  if (expiration_year_ == 0)
624    return base::string16();
625
626  return base::IntToString16(Expiration4DigitYear());
627}
628
629base::string16 CreditCard::Expiration2DigitYearAsString() const {
630  if (expiration_year_ == 0)
631    return base::string16();
632
633  return base::IntToString16(Expiration2DigitYear());
634}
635
636void CreditCard::SetExpirationMonthFromString(const base::string16& text,
637                                              const std::string& app_locale) {
638  int month;
639  if (!ConvertMonth(text, app_locale, &month))
640    return;
641
642  SetExpirationMonth(month);
643}
644
645void CreditCard::SetExpirationYearFromString(const base::string16& text) {
646  int year;
647  if (!ConvertYear(text, &year))
648    return;
649
650  SetExpirationYear(year);
651}
652
653void CreditCard::SetNumber(const base::string16& number) {
654  number_ = number;
655  type_ = GetCreditCardType(StripSeparators(number_));
656}
657
658void CreditCard::SetExpirationMonth(int expiration_month) {
659  if (expiration_month < 0 || expiration_month > 12)
660    return;
661
662  expiration_month_ = expiration_month;
663}
664
665void CreditCard::SetExpirationYear(int expiration_year) {
666  if (expiration_year != 0 &&
667      (expiration_year < 2006 || expiration_year > 10000)) {
668    return;
669  }
670
671  expiration_year_ = expiration_year;
672}
673
674// So we can compare CreditCards with EXPECT_EQ().
675std::ostream& operator<<(std::ostream& os, const CreditCard& credit_card) {
676  return os
677      << base::UTF16ToUTF8(credit_card.Label())
678      << " "
679      << credit_card.guid()
680      << " "
681      << credit_card.origin()
682      << " "
683      << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NAME))
684      << " "
685      << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_TYPE))
686      << " "
687      << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_NUMBER))
688      << " "
689      << base::UTF16ToUTF8(credit_card.GetRawInfo(CREDIT_CARD_EXP_MONTH))
690      << " "
691      << base::UTF16ToUTF8(
692             credit_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
693}
694
695// These values must match the values in WebKitPlatformSupportImpl in
696// webkit/glue. We send these strings to WebKit, which then asks
697// WebKitPlatformSupportImpl to load the image data.
698const char* const kAmericanExpressCard = "americanExpressCC";
699const char* const kDinersCard = "dinersCC";
700const char* const kDiscoverCard = "discoverCC";
701const char* const kGenericCard = "genericCC";
702const char* const kJCBCard = "jcbCC";
703const char* const kMasterCard = "masterCardCC";
704const char* const kUnionPay = "unionPayCC";
705const char* const kVisaCard = "visaCC";
706
707}  // namespace autofill
708