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