Home | History | Annotate | Download | only in autofill
      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 
     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 
     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|.
    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 
    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 
    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 
    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 
    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 
    241 bool IsValidState(const string16& value) {
    242   return !State::Abbreviation(value).empty() || !State::FullName(value).empty();
    243 }
    244 
    245 }  // namespace autofill
    246