• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "chrome/browser/autofill/select_control_handler.h"
6 
7 #include <string>
8 
9 #include "base/basictypes.h"
10 #include "base/logging.h"
11 #include "base/string_number_conversions.h"
12 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/autofill/autofill_country.h"
14 #include "chrome/browser/autofill/autofill_profile.h"
15 #include "chrome/browser/autofill/form_group.h"
16 #include "webkit/glue/form_field.h"
17 
18 namespace {
19 
20 // TODO(jhawkins): Add more states/provinces.  See http://crbug.com/45039.
21 
22 class State {
23  public:
24   const char* name;
25   const char* abbreviation;
26 
27   static const State all_states[];
28 
29   static string16 Abbreviation(const string16& name);
30   static string16 FullName(const string16& abbreviation);
31 };
32 
33 const State State::all_states[] = {
34   { "alabama", "al" },
35   { "alaska", "ak" },
36   { "arizona", "az" },
37   { "arkansas", "ar" },
38   { "california", "ca" },
39   { "colorado", "co" },
40   { "connecticut", "ct" },
41   { "delaware", "de" },
42   { "district of columbia", "dc" },
43   { "florida", "fl" },
44   { "georgia", "ga" },
45   { "hawaii", "hi" },
46   { "idaho", "id" },
47   { "illinois", "il" },
48   { "indiana", "in" },
49   { "iowa", "ia" },
50   { "kansas", "ks" },
51   { "kentucky", "ky" },
52   { "louisiana", "la" },
53   { "maine", "me" },
54   { "maryland", "md" },
55   { "massachusetts", "ma" },
56   { "michigan", "mi" },
57   { "minnesota", "mv" },
58   { "mississippi", "ms" },
59   { "missouri", "mo" },
60   { "montana", "mt" },
61   { "nebraska", "ne" },
62   { "nevada", "nv" },
63   { "new hampshire", "nh" },
64   { "new jersey", "nj" },
65   { "new mexico", "nm" },
66   { "new york", "ny" },
67   { "north carolina", "nc" },
68   { "north dakota", "nd" },
69   { "ohio", "oh" },
70   { "oklahoma", "ok" },
71   { "oregon", "or" },
72   { "pennsylvania", "pa" },
73   { "puerto rico", "pr" },
74   { "rhode island", "ri" },
75   { "south carolina", "sc" },
76   { "south dakota", "sd" },
77   { "tennessee", "tn" },
78   { "texas", "tx" },
79   { "utah", "ut" },
80   { "vermont", "vt" },
81   { "virginia", "va" },
82   { "washington", "wa" },
83   { "west Virginia", "wv" },
84   { "wisconsin", "wi" },
85   { "wyoming", "wy" },
86   { NULL, NULL }
87 };
88 
Abbreviation(const string16 & name)89 string16 State::Abbreviation(const string16& name) {
90   for (const State *s = all_states ; s->name ; ++s)
91     if (LowerCaseEqualsASCII(name, s->name))
92       return ASCIIToUTF16(s->abbreviation);
93   return string16();
94 }
95 
FullName(const string16 & abbreviation)96 string16 State::FullName(const string16& abbreviation) {
97   for (const State *s = all_states ; s->name ; ++s)
98     if (LowerCaseEqualsASCII(abbreviation, s->abbreviation))
99       return ASCIIToUTF16(s->name);
100   return string16();
101 }
102 
103 const char* const kMonthsAbbreviated[] = {
104   NULL,  // Padding so index 1 = month 1 = January.
105   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
106   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
107 };
108 
109 const char* const kMonthsFull[] = {
110   NULL,  // Padding so index 1 = month 1 = January.
111   "January", "February", "March", "April", "May", "June",
112   "July", "August", "September", "October", "November", "December",
113 };
114 
115 const char* const kMonthsNumeric[] = {
116   NULL,  // Padding so index 1 = month 1 = January.
117   "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
118 };
119 
120 // Returns true if the value was successfully set, meaning |value| was found in
121 // the list of select options in |field|.
SetSelectControlValue(const string16 & value,webkit_glue::FormField * field)122 bool SetSelectControlValue(const string16& value,
123                            webkit_glue::FormField* field) {
124   string16 value_lowercase = StringToLowerASCII(value);
125 
126   for (std::vector<string16>::const_iterator iter =
127            field->option_strings.begin();
128        iter != field->option_strings.end(); ++iter) {
129     if (value_lowercase == StringToLowerASCII(*iter)) {
130       field->value = *iter;
131       return true;
132     }
133   }
134 
135   return false;
136 }
137 
FillStateSelectControl(const string16 & value,webkit_glue::FormField * field)138 bool FillStateSelectControl(const string16& value,
139                             webkit_glue::FormField* field) {
140   string16 abbrev, full;
141   if (value.size() < 4U) {
142     abbrev = value;
143     full = State::FullName(value);
144   } else {
145     abbrev = State::Abbreviation(value);
146     full = value;
147   }
148 
149   // Try the abbreviation name first.
150   if (!abbrev.empty() && SetSelectControlValue(abbrev, field))
151     return true;
152 
153   if (full.empty())
154     return false;
155 
156   return SetSelectControlValue(full, field);
157 }
158 
FillCountrySelectControl(const FormGroup & form_group,webkit_glue::FormField * field)159 bool FillCountrySelectControl(const FormGroup& form_group,
160                               webkit_glue::FormField* field) {
161   const AutofillProfile& profile =
162       static_cast<const AutofillProfile&>(form_group);
163   std::string country_code = profile.CountryCode();
164   std::string app_locale = AutofillCountry::ApplicationLocale();
165 
166   for (std::vector<string16>::const_iterator iter =
167            field->option_strings.begin();
168        iter != field->option_strings.end();
169        ++iter) {
170     // Canonicalize each <option> value to a country code, and compare to the
171     // target country code.
172     if (country_code == AutofillCountry::GetCountryCode(*iter, app_locale)) {
173       field->value = *iter;
174       return true;
175     }
176   }
177 
178   return false;
179 }
180 
FillExpirationMonthSelectControl(const string16 & value,webkit_glue::FormField * field)181 bool FillExpirationMonthSelectControl(const string16& value,
182                                       webkit_glue::FormField* field) {
183   int index = 0;
184   if (!base::StringToInt(value, &index) ||
185       index <= 0 ||
186       static_cast<size_t>(index) >= arraysize(kMonthsFull))
187     return false;
188 
189   bool filled =
190       SetSelectControlValue(ASCIIToUTF16(kMonthsAbbreviated[index]), field) ||
191       SetSelectControlValue(ASCIIToUTF16(kMonthsFull[index]), field) ||
192       SetSelectControlValue(ASCIIToUTF16(kMonthsNumeric[index]), field);
193   return filled;
194 }
195 
196 }  // namespace
197 
198 namespace autofill {
199 
FillSelectControl(const FormGroup & form_group,AutofillFieldType type,webkit_glue::FormField * field)200 void FillSelectControl(const FormGroup& form_group,
201                        AutofillFieldType type,
202                        webkit_glue::FormField* field) {
203   DCHECK(field);
204   DCHECK_EQ(ASCIIToUTF16("select-one"), field->form_control_type);
205 
206   string16 field_text = form_group.GetInfo(type);
207   if (field_text.empty())
208     return;
209 
210   string16 value;
211   for (size_t i = 0; i < field->option_strings.size(); ++i) {
212     if (field_text == field->option_strings[i]) {
213       // An exact match, use it.
214       value = field_text;
215       break;
216     }
217 
218     if (StringToLowerASCII(field->option_strings[i]) ==
219         StringToLowerASCII(field_text)) {
220       // A match, but not in the same case. Save it in case an exact match is
221       // not found.
222       value = field->option_strings[i];
223     }
224   }
225 
226   if (!value.empty()) {
227     field->value = value;
228     return;
229   }
230 
231   if (type == ADDRESS_HOME_STATE || type == ADDRESS_BILLING_STATE)
232     FillStateSelectControl(field_text, field);
233   else if (type == ADDRESS_HOME_COUNTRY || type == ADDRESS_BILLING_COUNTRY)
234     FillCountrySelectControl(form_group, field);
235   else if (type == CREDIT_CARD_EXP_MONTH)
236     FillExpirationMonthSelectControl(field_text, field);
237 
238   return;
239 }
240 
IsValidState(const string16 & value)241 bool IsValidState(const string16& value) {
242   return !State::Abbreviation(value).empty() || !State::FullName(value).empty();
243 }
244 
245 }  // namespace autofill
246