diff options
author | jhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-24 00:15:39 +0000 |
---|---|---|
committer | jhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-24 00:15:39 +0000 |
commit | 967d2f2e58b4364ef4f67ca88c9fc5e31e781381 (patch) | |
tree | c72a06eb1b1913e053522cfe45ccb234225fb145 /chrome | |
parent | 0d8a8a96caf5667356a182770f1a10505f3370aa (diff) | |
download | chromium_src-967d2f2e58b4364ef4f67ca88c9fc5e31e781381.zip chromium_src-967d2f2e58b4364ef4f67ca88c9fc5e31e781381.tar.gz chromium_src-967d2f2e58b4364ef4f67ca88c9fc5e31e781381.tar.bz2 |
AutoFill: Try harder to fill select controls with variations on states,
countries and months.
BUG=38222,46861
TEST=none
Review URL: http://codereview.chromium.org/2878052
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@53554 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/autofill/autofill_manager.cc | 18 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_manager.h | 6 | ||||
-rw-r--r-- | chrome/browser/autofill/select_control_handler.cc | 519 | ||||
-rw-r--r-- | chrome/browser/autofill/select_control_handler.h | 30 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 |
5 files changed, 572 insertions, 3 deletions
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc index ec80991..b5b28fe 100644 --- a/chrome/browser/autofill/autofill_manager.cc +++ b/chrome/browser/autofill/autofill_manager.cc @@ -11,6 +11,7 @@ #include "chrome/browser/autofill/autofill_dialog.h" #include "chrome/browser/autofill/autofill_cc_infobar_delegate.h" #include "chrome/browser/autofill/form_structure.h" +#include "chrome/browser/autofill/select_control_handler.h" #include "chrome/browser/pref_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/renderer_host/render_view_host.h" @@ -342,8 +343,7 @@ bool AutoFillManager::FillAutoFillFormData(int query_id, AutoFillType autofill_type(field->type()); if (credit_card && autofill_type.group() == AutoFillType::CREDIT_CARD) { - result.fields[i].set_value( - credit_card->GetFieldText(autofill_type)); + FillCreditCardFormField(credit_card, autofill_type, &result.fields[j]); } else if (credit_card && autofill_type.group() == AutoFillType::ADDRESS_BILLING) { FillBillingFormField(credit_card, autofill_type, &result.fields[j]); @@ -643,6 +643,18 @@ void AutoFillManager::FillBillingFormField(const CreditCard* credit_card, } } +void AutoFillManager::FillCreditCardFormField(const CreditCard* credit_card, + AutoFillType type, + webkit_glue::FormField* field) { + DCHECK(credit_card); + DCHECK(field); + + if (field->form_control_type() == ASCIIToUTF16("select-one")) + autofill::FillSelectControl(credit_card, type, field); + else + field->set_value(credit_card->GetFieldText(type)); +} + void AutoFillManager::FillFormField(const AutoFillProfile* profile, AutoFillType type, webkit_glue::FormField* field) { @@ -653,7 +665,7 @@ void AutoFillManager::FillFormField(const AutoFillProfile* profile, FillPhoneNumberField(profile, field); } else { if (field->form_control_type() == ASCIIToUTF16("select-one")) - FillSelectOneField(profile, type, field); + autofill::FillSelectControl(profile, type, field); else field->set_value(profile->GetFieldText(type)); } diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h index f6574d1..ba53fbb 100644 --- a/chrome/browser/autofill/autofill_manager.h +++ b/chrome/browser/autofill/autofill_manager.h @@ -136,6 +136,12 @@ class AutoFillManager : public RenderViewHostDelegate::AutoFill, AutoFillType type, webkit_glue::FormField* field); + // Set |field| argument's value based on |type| and contents of the + // |credit_card|. + void FillCreditCardFormField(const CreditCard* credit_card, + AutoFillType type, + webkit_glue::FormField* field); + // Set |field| argument's value based on |type| and contents of the |profile|. void FillFormField(const AutoFillProfile* profile, AutoFillType type, diff --git a/chrome/browser/autofill/select_control_handler.cc b/chrome/browser/autofill/select_control_handler.cc new file mode 100644 index 0000000..dff9d97 --- /dev/null +++ b/chrome/browser/autofill/select_control_handler.cc @@ -0,0 +1,519 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/autofill/select_control_handler.h" + +#include <string> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "base/string16.h" +#include "chrome/browser/autofill/form_group.h" +#include "webkit/glue/form_field.h" + +namespace { + +// TODO(jhawkins): Add more states/provinces. See http://crbug.com/45039. + +class State { + public: + const char* name; + const char* abbreviation; + + static const State all_states[]; + + static string16 Abbreviation(const string16& name); + static string16 FullName(const string16& abbreviation); +}; + +const State State::all_states[] = { + { "alabama", "al" }, + { "alaska", "ak" }, + { "arizona", "az" }, + { "arkansas", "ar" }, + { "california", "ca" }, + { "colorado", "co" }, + { "connecticut", "ct" }, + { "delaware", "de" }, + { "district of columbia", "dc" }, + { "florida", "fl" }, + { "georgia", "ga" }, + { "hawaii", "hi" }, + { "idaho", "id" }, + { "illinois", "il" }, + { "indiana", "in" }, + { "iowa", "ia" }, + { "kansas", "ks" }, + { "kentucky", "ky" }, + { "louisiana", "la" }, + { "maine", "me" }, + { "maryland", "md" }, + { "massachusetts", "ma" }, + { "michigan", "mi" }, + { "minnesota", "mv" }, + { "mississippi", "ms" }, + { "missouri", "mo" }, + { "montana", "mt" }, + { "nebraska", "ne" }, + { "nevada", "nv" }, + { "new hampshire", "nh" }, + { "new jersey", "nj" }, + { "new mexico", "nm" }, + { "new york", "ny" }, + { "north carolina", "nc" }, + { "north dakota", "nd" }, + { "ohio", "oh" }, + { "oklahoma", "ok" }, + { "oregon", "or" }, + { "pennsylvania", "pa" }, + { "puerto rico", "pr" }, + { "rhode island", "ri" }, + { "south carolina", "sc" }, + { "south dakota", "sd" }, + { "tennessee", "tn" }, + { "texas", "tx" }, + { "utah", "ut" }, + { "vermont", "vt" }, + { "virginia", "va" }, + { "washington", "wa" }, + { "west Virginia", "wv" }, + { "wisconsin", "wi" }, + { "wyoming", "wy" }, + { NULL, NULL } +}; + +string16 State::Abbreviation(const string16& name) { + for (const State *s = all_states ; s->name ; ++s) + if (LowerCaseEqualsASCII(name, s->name)) + return ASCIIToUTF16(s->abbreviation); + return string16(); +} + +string16 State::FullName(const string16& abbreviation) { + for (const State *s = all_states ; s->name ; ++s) + if (LowerCaseEqualsASCII(abbreviation, s->abbreviation)) + return ASCIIToUTF16(s->name); + return string16(); +} + +// Holds valid country names, their 2 letter abbreviation, and maps from +// the former to the latter +class Country { + public: + const char* name; + const char* abbreviation; + + static const Country all_countries[]; + + static string16 Abbreviation(const string16 &name); + static string16 FullName(const string16& abbreviation); +}; + +// A list of all English country names and code elements. ISO 3166. +const Country Country::all_countries[] = { + { "united states", "us" }, + { "afghanistan", "af" }, + { "aland islands", "ax" }, + { "albania", "al" }, + { "algeria", "dz" }, + { "american samoa", "as" }, + { "andorra", "ad" }, + { "angola", "ao" }, + { "anguilla", "ai" }, + { "antarctica", "aq" }, + { "antigua and barbuda", "ag" }, + { "argentina", "ar" }, + { "armenia", "am" }, + { "aruba", "aw" }, + { "australia", "au" }, + { "austria", "at" }, + { "azerbaijan", "az" }, + { "bahamas", "bs" }, + { "bahrain", "bh" }, + { "bangladesh", "bd" }, + { "barbados", "bb" }, + { "belarus", "by" }, + { "belgium", "be" }, + { "belize", "bz" }, + { "benin", "bj" }, + { "bermuda", "bm" }, + { "bhutan", "bt" }, + { "bolivia", "bo" }, + { "bosnia and herzegovina", "ba" }, + { "botswana", "bw" }, + { "bouvet island", "bv" }, + { "brazil", "br" }, + { "british indian ocean territory", "io" }, + { "brunei darussalam", "bn" }, + { "bulgaria", "bg" }, + { "burkina faso", "bf" }, + { "burundi", "bi" }, + { "cambodia", "kh" }, + { "cameroon", "cm" }, + { "canada", "ca" }, + { "cape verde", "cv" }, + { "cayman islands", "ky" }, + { "central african republic", "cf" }, + { "chad", "td" }, + { "chile", "cl" }, + { "china", "cn" }, + { "christmas island", "cx" }, + { "cocos (keeling) islands", "cc" }, + { "colombia", "co" }, + { "comoros", "km" }, + { "congo", "cg" }, + { "congo (dem. rep.)", "cd" }, + { "cook islands", "ck" }, + { "costa rica", "cr" }, + { "cote d'ivoire", "ci" }, + { "croatia", "hr" }, + { "cuba", "cu" }, + { "cyprus", "cy" }, + { "czech republic", "cz" }, + { "denmark", "dk" }, + { "djibouti", "dj" }, + { "dominica", "dm" }, + { "dominican republic", "do" }, + { "ecuador", "ec" }, + { "egypt", "eg" }, + { "el salvador", "sv" }, + { "equatorial guinea", "gq" }, + { "eritrea", "er" }, + { "estonia", "ee" }, + { "ethiopia", "et" }, + { "falkland islands (malvinas)", "fk" }, + { "faroe islands", "fo" }, + { "fiji", "fj" }, + { "finland", "fi" }, + { "france", "fr" }, + { "french guiana", "gf" }, + { "french polynesia", "pf" }, + { "gabon", "ga" }, + { "gambia", "gm" }, + { "georgia", "ge" }, + { "germany", "de" }, + { "ghana", "gh" }, + { "gibraltar", "gi" }, + { "greece", "gr" }, + { "greenland", "gl" }, + { "grenada", "gd" }, + { "guadeloupe", "gp" }, + { "guam", "gu" }, + { "guatemala", "gt" }, + { "guernsey", "cg" }, + { "guinea", "gn" }, + { "guinea-bissau", "gw" }, + { "guyana", "gy" }, + { "haiti", "ht" }, + { "heard island and mcdonald islands", "hm" }, + { "holy see (vatica city state)", "va" }, + { "honduras", "hn" }, + { "hong kong", "hk" }, + { "hungary", "hu" }, + { "iceland", "is" }, + { "india", "in" }, + { "indonesia", "id" }, + { "iran", "ir" }, + { "iraq", "iq" }, + { "ireland", "ie" }, + { "isle of man", "im" }, + { "israel", "il" }, + { "italy", "it" }, + { "ivory coast", "ci" }, + { "jamaica", "jm" }, + { "japan", "jp" }, + { "jersey", "je" }, + { "jordan", "jo" }, + { "kazakhstan", "kz" }, + { "kenya", "ke" }, + { "kiribati", "ki" }, + { "korea (north)", "kp" }, + { "korea (south)", "kr" }, + { "kuwait", "kw" }, + { "kyrgyzstan", "kg" }, + { "laos", "la" }, + { "latvia", "lv" }, + { "lebanon", "lb" }, + { "lesotho", "ls" }, + { "liberia", "lr" }, + { "libya", "ly" }, + { "liechtenstein", "li" }, + { "lithuania", "lt" }, + { "luxembourg", "lu" }, + { "macao", "mo" }, + { "macedonia", "mk" }, + { "madagascar", "mg" }, + { "malawi", "mw" }, + { "malaysia", "my" }, + { "maldives", "mv" }, + { "mali", "ml" }, + { "malta", "mt" }, + { "marshall islands", "mh" }, + { "martinique", "mq" }, + { "mauritania", "mr" }, + { "mauritius", "mu" }, + { "mayotte", "yt" }, + { "mexico", "mx" }, + { "micronesia", "fm" }, + { "moldova", "md" }, + { "monaco", "mc" }, + { "mongolia", "mn" }, + { "montserrat", "ms" }, + { "morocco", "ma" }, + { "mozambique", "mz" }, + { "myanmar", "mm" }, + { "namibia", "na" }, + { "nepal", "np" }, + { "netherlands", "nl" }, + { "netherlands antilles", "an" }, + { "new caledonia", "nc" }, + { "new zealand", "nz" }, + { "nicaragua", "ni" }, + { "niger", "ne" }, + { "nigeria", "ng" }, + { "niue", "nu" }, + { "norfolk island", "nf" }, + { "northern mariana islands", "mp" }, + { "norway", "no" }, + { "oman", "om" }, + { "pakistan", "pk" }, + { "palau", "pw" }, + { "palestine", "ps" }, + { "panama", "pa" }, + { "papua new guinea", "pg" }, + { "paraguay", "py" }, + { "peru", "pe" }, + { "philippines", "ph" }, + { "pitcairn", "pn" }, + { "poland", "pl" }, + { "portugal", "pt" }, + { "puerto rico", "pr" }, + { "qatar", "qa" }, + { "reunion", "re" }, + { "romania", "ro" }, + { "russia", "ru" }, + { "rwanda", "rw" }, + { "saint helena", "sh" }, + { "saint kitts and nevis", "kn" }, + { "saint lucia", "lc" }, + { "saint pierre and miquelon", "pm" }, + { "saint vincent and the grenadines", "vc" }, + { "samoa", "ws" }, + { "san marino", "sm" }, + { "sao tome and principe", "st" }, + { "saudi arabia", "sa" }, + { "senegal", "sn" }, + { "serbia and montenegro", "cs" }, + { "seychelles", "sc" }, + { "sierra leone", "sl" }, + { "singapore", "sg" }, + { "slovakia", "sk" }, + { "slovenia", "si" }, + { "solomon islands", "sb" }, + { "somalia", "so" }, + { "south africa", "za" }, + { "south georgia and the south sandwich islands", "gs" }, + { "spain", "es" }, + { "sri lanka", "lk" }, + { "sudan", "sd" }, + { "suriname", "sr" }, + { "svalbard and jan mayen", "sj" }, + { "swaziland", "sz" }, + { "sweden", "se" }, + { "switzerland", "ch" }, + { "syria", "sy" }, + { "taiwan", "tw" }, + { "tajikistan", "tj" }, + { "tanzania", "tz" }, + { "thailand", "th" }, + { "timor-leste", "tl" }, + { "togo", "tg" }, + { "tokelau", "tk" }, + { "tonga", "to" }, + { "trinidad and tobago", "tt" }, + { "tunisia", "tn" }, + { "turkey", "tr" }, + { "turkmenistan", "tm" }, + { "turks and caicos islands", "tc" }, + { "tuvalu", "tv" }, + { "uganda", "ug" }, + { "ukraine", "ua" }, + { "united arab emirates", "ae" }, + { "united kingdom", "gb" }, + { "u.s. minor outlying islands", "um" }, + { "uruguay", "uy" }, + { "uzbekistan", "uz" }, + { "vanuatu", "vu" }, + { "venezuela", "ve" }, + { "vietnam", "vn" }, + { "virgin islands, british", "vg" }, + { "virgin islands, u.s.", "vi" }, + { "wallis and futuna", "wf" }, + { "western sahara", "eh" }, + { "yemen", "ye" }, + { "zambia", "zm" }, + { "zimbabwe", "zw" }, + { NULL, NULL } +}; + +string16 Country::Abbreviation(const string16& name) { + for (const Country *s = all_countries ; s->name ; ++s) + if (LowerCaseEqualsASCII(name, s->name)) + return ASCIIToUTF16(s->abbreviation); + return string16(); +} + +string16 Country::FullName(const string16& abbreviation) { + for (const Country *s = all_countries ; s->name ; ++s) + if (LowerCaseEqualsASCII(abbreviation, s->abbreviation)) + return ASCIIToUTF16(s->name); + return string16(); +} + +const char* const kMonthsAbbreviated[] = { + NULL, // Padding so index 1 = month 1 = January. + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", +}; + +const char* const kMonthsFull[] = { + NULL, // Padding so index 1 = month 1 = January. + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December", +}; + +// Returns true if the value was successfully set, meaning |value| was found in +// the list of select options in |field|. +bool SetSelectControlValue(const string16& value, + webkit_glue::FormField* field) { + string16 value_lowercase = StringToLowerASCII(value); + + for (std::vector<string16>::const_iterator iter = + field->option_strings().begin(); + iter != field->option_strings().end(); ++iter) { + if (value_lowercase == StringToLowerASCII(*iter)) { + field->set_value(*iter); + return true; + } + } + + return false; +} + +bool FillStateSelectControl(const string16& value, + webkit_glue::FormField* field) { + if (value.empty()) + return false; + + string16 abbrev, full; + if (value.size() < 4U) { + abbrev = value; + full = State::FullName(value); + } else { + abbrev = State::Abbreviation(value); + full = value; + } + + // Try the abbreviation name first. + if (!abbrev.empty() && SetSelectControlValue(abbrev, field)) + return true; + + if (full.empty()) + return false; + + return SetSelectControlValue(full, field); +} + +bool FillCountrySelectControl(const string16& value, + webkit_glue::FormField* field) { + if (value.empty()) + return false; + + string16 abbrev, full; + if (value.size() < 4U) { + abbrev = value; + full = Country::FullName(value); + } else { + abbrev = Country::Abbreviation(value); + full = value; + } + + // Try the abbreviation name first. + if (!abbrev.empty() && SetSelectControlValue(abbrev, field)) + return true; + + if (full.empty()) + return false; + + return SetSelectControlValue(full, field); +} + +bool FillExpirationMonthSelectControl(const string16& value, + webkit_glue::FormField* field) { + if (value.empty()) + return false; + + if (SetSelectControlValue(value, field)) + return true; + + int index = 0; + if (!StringToInt(value, &index) || + index <= 0 || + static_cast<size_t>(index) >= arraysize(kMonthsFull)) + return false; + + bool filled = + SetSelectControlValue(ASCIIToUTF16(kMonthsAbbreviated[index]), field) || + SetSelectControlValue(ASCIIToUTF16(kMonthsFull[index]), field); + return filled; +} + +} // namespace + +namespace autofill { + +void FillSelectControl(const FormGroup* form_group, + AutoFillType type, + webkit_glue::FormField* field) { + DCHECK(form_group); + DCHECK(field); + DCHECK(field->form_control_type() == ASCIIToUTF16("select-one")); + + string16 value; + string16 field_text = form_group->GetFieldText(type); + for (size_t i = 0; i < field->option_strings().size(); ++i) { + if (form_group->GetFieldText(type) == field->option_strings()[i]) { + // An exact match, use it. + value = form_group->GetFieldText(type); + break; + } + + if (StringToLowerASCII(field->option_strings()[i]) == + StringToLowerASCII(field_text)) { + // A match, but not in the same case. Save it in case an exact match is + // not found. + value = field->option_strings()[i]; + } + } + + if (!value.empty()) { + field->set_value(value); + return; + } + + if (type.field_type() == ADDRESS_HOME_STATE || + type.field_type() == ADDRESS_BILLING_STATE) { + FillStateSelectControl(field_text, field); + } else if (type.field_type() == ADDRESS_HOME_COUNTRY || + type.field_type() == ADDRESS_BILLING_COUNTRY) { + FillCountrySelectControl(field_text, field); + } else if (type.field_type() == CREDIT_CARD_EXP_MONTH) { + FillExpirationMonthSelectControl(field_text, field); + } + + return; +} + +} // namespace autofill diff --git a/chrome/browser/autofill/select_control_handler.h b/chrome/browser/autofill/select_control_handler.h new file mode 100644 index 0000000..d434070 --- /dev/null +++ b/chrome/browser/autofill/select_control_handler.h @@ -0,0 +1,30 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_AUTOFILL_SELECT_CONTROL_HANDLER_H_ +#define CHROME_BROWSER_AUTOFILL_SELECT_CONTROL_HANDLER_H_ + +#include "chrome/browser/autofill/autofill_type.h" + +class FormGroup; + +namespace webkit_glue { +class FormField; +} // namespace webkit_glue + +namespace autofill { + +// TODO(jhawkins): This definitely needs tests. + +// Fills a select-one control with the appropriate value from |form_group|. +// Finds the matching value for field types that we know contain different +// variations of a value, e.g., (tx, TX, Texas) or credit card expiration +// months, e.g., (04, April). +void FillSelectControl(const FormGroup* form_group, + AutoFillType type, + webkit_glue::FormField* field); + +} // namespace autofill + +#endif // CHROME_BROWSER_AUTOFILL_SELECT_CONTROL_HANDLER_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 849abcf..a4087f6 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -181,6 +181,8 @@ 'browser/autofill/phone_field.h', 'browser/autofill/phone_number.cc', 'browser/autofill/phone_number.h', + 'browser/autofill/select_control_handler.cc', + 'browser/autofill/select_control_handler.h', 'browser/automation/automation_autocomplete_edit_tracker.h', 'browser/automation/automation_browser_tracker.h', 'browser/automation/extension_automation_constants.h', |