autofill_data_model.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// found in the LICENSE file.
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "components/autofill/core/browser/autofill_data_model.h"
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/basictypes.h"
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/logging.h"
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/strings/string_util.h"
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "components/autofill/core/browser/autofill_country.h"
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "components/autofill/core/browser/autofill_field.h"
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "components/autofill/core/browser/state_names.h"
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "components/autofill/core/browser/validation.h"
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "components/autofill/core/common/form_field_data.h"
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "googleurl/src/gurl.h"
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "grit/component_strings.h"
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace autofill {
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace {
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const char* const kMonthsAbbreviated[] = {
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  NULL,  // Padding so index 1 = month 1 = January.
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
28e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)};
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
30e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)const char* const kMonthsFull[] = {
31e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)  NULL,  // Padding so index 1 = month 1 = January.
325d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)  "January", "February", "March", "April", "May", "June",
331e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)  "July", "August", "September", "October", "November", "December",
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
35c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const char* const kMonthsNumeric[] = {
37d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)  NULL,  // Padding so index 1 = month 1 = January.
38d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)  "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
401e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
415267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)// Returns true if the value was successfully set, meaning |value| was found in
425267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)// the list of select options in |field|.
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool SetSelectControlValue(const base::string16& value,
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                           FormFieldData* field) {
455267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)  base::string16 value_lowercase = StringToLowerASCII(value);
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  DCHECK_EQ(field->option_values.size(), field->option_contents.size());
483c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch  for (size_t i = 0; i < field->option_values.size(); ++i) {
4902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    if (value_lowercase == StringToLowerASCII(field->option_values[i]) ||
503c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch        value_lowercase == StringToLowerASCII(field->option_contents[i])) {
51e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)      field->value = field->option_values[i];
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      return true;
533c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch    }
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
563c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch  return false;
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
58d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
59d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)bool FillStateSelectControl(const base::string16& value,
6002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch                            FormFieldData* field) {
613c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch  base::string16 full, abbreviation;
623c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch  state_names::GetNameAndAbbreviation(value, &full, &abbreviation);
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // Try the abbreviation first.
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  if (!abbreviation.empty() && SetSelectControlValue(abbreviation, field))
66c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    return true;
67
68  return !full.empty() && SetSelectControlValue(full, field);
69}
70
71bool FillExpirationMonthSelectControl(const base::string16& value,
72                                      FormFieldData* field) {
73  int index = 0;
74  if (!base::StringToInt(value, &index) ||
75      index <= 0 ||
76      static_cast<size_t>(index) >= arraysize(kMonthsFull))
77    return false;
78
79  bool filled =
80      SetSelectControlValue(ASCIIToUTF16(kMonthsAbbreviated[index]), field) ||
81      SetSelectControlValue(ASCIIToUTF16(kMonthsFull[index]), field) ||
82      SetSelectControlValue(ASCIIToUTF16(kMonthsNumeric[index]), field);
83  return filled;
84}
85
86// Try to fill a credit card type |value| (Visa, MasterCard, etc.) into the
87// given |field|.
88bool FillCreditCardTypeSelectControl(const base::string16& value,
89                                     FormFieldData* field) {
90  // Try stripping off spaces.
91  base::string16 value_stripped;
92  RemoveChars(StringToLowerASCII(value), kWhitespaceUTF16, &value_stripped);
93
94  for (size_t i = 0; i < field->option_values.size(); ++i) {
95    base::string16 option_value_lowercase;
96    RemoveChars(StringToLowerASCII(field->option_values[i]), kWhitespaceUTF16,
97                &option_value_lowercase);
98    base::string16 option_contents_lowercase;
99    RemoveChars(StringToLowerASCII(field->option_contents[i]), kWhitespaceUTF16,
100                &option_contents_lowercase);
101
102    // Perform a case-insensitive comparison; but fill the form with the
103    // original text, not the lowercased version.
104    if (value_stripped == option_value_lowercase ||
105        value_stripped == option_contents_lowercase) {
106      field->value = field->option_values[i];
107      return true;
108    }
109  }
110
111  // For American Express, also try filling as "AmEx".
112  if (value == l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX))
113    return FillCreditCardTypeSelectControl(ASCIIToUTF16("AmEx"), field);
114
115  return false;
116}
117
118}  // namespace
119
120AutofillDataModel::AutofillDataModel(const std::string& guid,
121                                     const std::string& origin)
122    : guid_(guid),
123      origin_(origin) {}
124AutofillDataModel::~AutofillDataModel() {}
125
126void AutofillDataModel::FillSelectControl(AutofillFieldType type,
127                                          const std::string& app_locale,
128                                          FormFieldData* field) const {
129  DCHECK(field);
130  DCHECK_EQ("select-one", field->form_control_type);
131  DCHECK_EQ(field->option_values.size(), field->option_contents.size());
132
133  base::string16 field_text = GetInfo(type, app_locale);
134  base::string16 field_text_lower = StringToLowerASCII(field_text);
135  if (field_text.empty())
136    return;
137
138  base::string16 value;
139  for (size_t i = 0; i < field->option_values.size(); ++i) {
140    if (field_text == field->option_values[i] ||
141        field_text == field->option_contents[i]) {
142      // An exact match, use it.
143      value = field->option_values[i];
144      break;
145    }
146
147    if (field_text_lower == StringToLowerASCII(field->option_values[i]) ||
148        field_text_lower == StringToLowerASCII(field->option_contents[i])) {
149      // A match, but not in the same case. Save it in case an exact match is
150      // not found.
151      value = field->option_values[i];
152    }
153  }
154
155  if (!value.empty()) {
156    field->value = value;
157    return;
158  }
159
160  if (type == ADDRESS_HOME_STATE || type == ADDRESS_BILLING_STATE) {
161    FillStateSelectControl(field_text, field);
162  } else if (type == ADDRESS_HOME_COUNTRY || type == ADDRESS_BILLING_COUNTRY) {
163    FillCountrySelectControl(app_locale, field);
164  } else if (type == CREDIT_CARD_EXP_MONTH) {
165    FillExpirationMonthSelectControl(field_text, field);
166  } else if (type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
167    // Attempt to fill the year as a 2-digit year.  This compensates for the
168    // fact that our heuristics do not always correctly detect when a website
169    // requests a 2-digit rather than a 4-digit year.
170    FillSelectControl(CREDIT_CARD_EXP_2_DIGIT_YEAR, app_locale, field);
171  } else if (type == CREDIT_CARD_TYPE) {
172    FillCreditCardTypeSelectControl(field_text, field);
173  }
174}
175
176bool AutofillDataModel::FillCountrySelectControl(
177    const std::string& app_locale,
178    FormFieldData* field_data) const {
179  return false;
180}
181
182bool AutofillDataModel::IsVerified() const {
183  return !origin_.empty() && !GURL(origin_).is_valid();
184}
185
186}  // namespace autofill
187