Chromium Code Reviews| Index: chrome/browser/autofill/form_field.cc |
| diff --git a/chrome/browser/autofill/form_field.cc b/chrome/browser/autofill/form_field.cc |
| index 926d3409a746e8d02d2f319a3f2cb99da3cefb38..708211da01f2c7a89e61d1606655b45b02d055be 100644 |
| --- a/chrome/browser/autofill/form_field.cc |
| +++ b/chrome/browser/autofill/form_field.cc |
| @@ -13,6 +13,7 @@ |
| #include "base/string_util.h" |
| #include "base/stringprintf.h" |
| #include "base/utf_string_conversions.h" |
| +#include "chrome/browser/autofill/autofill_ecml.h" |
| #include "chrome/browser/autofill/address_field.h" |
| #include "chrome/browser/autofill/autofill_field.h" |
| #include "chrome/browser/autofill/autofill_scanner.h" |
| @@ -28,165 +29,12 @@ |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCaseSensitivity.h" |
| #include "ui/base/l10n/l10n_util.h" |
| -// Field names from the ECML specification; see RFC 3106. We've |
| -// made these names lowercase since we convert labels and field names to |
| -// lowercase before searching. |
| - |
| -// shipping name/address fields |
| -const char kEcmlShipToTitle[] = "ecom_shipto_postal_name_prefix"; |
| -const char kEcmlShipToFirstName[] = "ecom_shipto_postal_name_first"; |
| -const char kEcmlShipToMiddleName[] = "ecom_shipto_postal_name_middle"; |
| -const char kEcmlShipToLastName[] = "ecom_shipto_postal_name_last"; |
| -const char kEcmlShipToNameSuffix[] = "ecom_shipto_postal_name_suffix"; |
| -const char kEcmlShipToCompanyName[] = "ecom_shipto_postal_company"; |
| -const char kEcmlShipToAddress1[] = "ecom_shipto_postal_street_line1"; |
| -const char kEcmlShipToAddress2[] = "ecom_shipto_postal_street_line2"; |
| -const char kEcmlShipToAddress3[] = "ecom_shipto_postal_street_line3"; |
| -const char kEcmlShipToCity[] = "ecom_shipto_postal_city"; |
| -const char kEcmlShipToStateProv[] = "ecom_shipto_postal_stateprov"; |
| -const char kEcmlShipToPostalCode[] = "ecom_shipto_postal_postalcode"; |
| -const char kEcmlShipToCountry[] = "ecom_shipto_postal_countrycode"; |
| -const char kEcmlShipToPhone[] = "ecom_shipto_telecom_phone_number"; |
| -const char kEcmlShipToEmail[] = "ecom_shipto_online_email"; |
| - |
| -// billing name/address fields |
| -const char kEcmlBillToTitle[] = "ecom_billto_postal_name_prefix"; |
| -const char kEcmlBillToFirstName[] = "ecom_billto_postal_name_first"; |
| -const char kEcmlBillToMiddleName[] = "ecom_billto_postal_name_middle"; |
| -const char kEcmlBillToLastName[] = "ecom_billto_postal_name_last"; |
| -const char kEcmlBillToNameSuffix[] = "ecom_billto_postal_name_suffix"; |
| -const char kEcmlBillToCompanyName[] = "ecom_billto_postal_company"; |
| -const char kEcmlBillToAddress1[] = "ecom_billto_postal_street_line1"; |
| -const char kEcmlBillToAddress2[] = "ecom_billto_postal_street_line2"; |
| -const char kEcmlBillToAddress3[] = "ecom_billto_postal_street_line3"; |
| -const char kEcmlBillToCity[] = "ecom_billto_postal_city"; |
| -const char kEcmlBillToStateProv[] = "ecom_billto_postal_stateprov"; |
| -const char kEcmlBillToPostalCode[] = "ecom_billto_postal_postalcode"; |
| -const char kEcmlBillToCountry[] = "ecom_billto_postal_countrycode"; |
| -const char kEcmlBillToPhone[] = "ecom_billto_telecom_phone_number"; |
| -const char kEcmlBillToEmail[] = "ecom_billto_online_email"; |
| - |
| -// credit card fields |
| -const char kEcmlCardHolder[] = "ecom_payment_card_name"; |
| -const char kEcmlCardType[] = "ecom_payment_card_type"; |
| -const char kEcmlCardNumber[] = "ecom_payment_card_number"; |
| -const char kEcmlCardVerification[] = "ecom_payment_card_verification"; |
| -const char kEcmlCardExpireDay[] = "ecom_payment_card_expdate_day"; |
| -const char kEcmlCardExpireMonth[] = "ecom_payment_card_expdate_month"; |
| -const char kEcmlCardExpireYear[] = "ecom_payment_card_expdate_year"; |
| - |
| namespace { |
| -// Checks if any of the |form|'s labels are named according to the ECML |
| -// standard. Returns true if at least one ECML named element is found. |
| -bool HasECMLField(const std::vector<AutofillField*>& fields) { |
| - struct EcmlField { |
| - const char* name_; |
| - const int length_; |
| - } ecml_fields[] = { |
| -#define ECML_STRING_ENTRY(x) { x, arraysize(x) - 1 }, |
| - ECML_STRING_ENTRY(kEcmlShipToTitle) |
| - ECML_STRING_ENTRY(kEcmlShipToFirstName) |
| - ECML_STRING_ENTRY(kEcmlShipToMiddleName) |
| - ECML_STRING_ENTRY(kEcmlShipToLastName) |
| - ECML_STRING_ENTRY(kEcmlShipToNameSuffix) |
| - ECML_STRING_ENTRY(kEcmlShipToCompanyName) |
| - ECML_STRING_ENTRY(kEcmlShipToAddress1) |
| - ECML_STRING_ENTRY(kEcmlShipToAddress2) |
| - ECML_STRING_ENTRY(kEcmlShipToAddress3) |
| - ECML_STRING_ENTRY(kEcmlShipToCity) |
| - ECML_STRING_ENTRY(kEcmlShipToStateProv) |
| - ECML_STRING_ENTRY(kEcmlShipToPostalCode) |
| - ECML_STRING_ENTRY(kEcmlShipToCountry) |
| - ECML_STRING_ENTRY(kEcmlShipToPhone) |
| - ECML_STRING_ENTRY(kEcmlShipToPhone) |
| - ECML_STRING_ENTRY(kEcmlShipToEmail) |
| - ECML_STRING_ENTRY(kEcmlBillToTitle) |
| - ECML_STRING_ENTRY(kEcmlBillToFirstName) |
| - ECML_STRING_ENTRY(kEcmlBillToMiddleName) |
| - ECML_STRING_ENTRY(kEcmlBillToLastName) |
| - ECML_STRING_ENTRY(kEcmlBillToNameSuffix) |
| - ECML_STRING_ENTRY(kEcmlBillToCompanyName) |
| - ECML_STRING_ENTRY(kEcmlBillToAddress1) |
| - ECML_STRING_ENTRY(kEcmlBillToAddress2) |
| - ECML_STRING_ENTRY(kEcmlBillToAddress3) |
| - ECML_STRING_ENTRY(kEcmlBillToCity) |
| - ECML_STRING_ENTRY(kEcmlBillToStateProv) |
| - ECML_STRING_ENTRY(kEcmlBillToPostalCode) |
| - ECML_STRING_ENTRY(kEcmlBillToCountry) |
| - ECML_STRING_ENTRY(kEcmlBillToPhone) |
| - ECML_STRING_ENTRY(kEcmlBillToPhone) |
| - ECML_STRING_ENTRY(kEcmlBillToEmail) |
| - ECML_STRING_ENTRY(kEcmlCardHolder) |
| - ECML_STRING_ENTRY(kEcmlCardType) |
| - ECML_STRING_ENTRY(kEcmlCardNumber) |
| - ECML_STRING_ENTRY(kEcmlCardVerification) |
| - ECML_STRING_ENTRY(kEcmlCardExpireMonth) |
| - ECML_STRING_ENTRY(kEcmlCardExpireYear) |
| -#undef ECML_STRING_ENTRY |
| - }; |
| - |
| - const string16 ecom(ASCIIToUTF16("ecom")); |
| - for (std::vector<AutofillField*>::const_iterator field = fields.begin(); |
| - field != fields.end(); |
| - ++field) { |
| - const string16& utf16_name = (*field)->name; |
| - if (StartsWith(utf16_name, ecom, true)) { |
| - std::string name(UTF16ToUTF8(utf16_name)); |
| - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(ecml_fields); ++i) { |
| - if (base::strncasecmp(name.c_str(), ecml_fields[i].name_, |
| - ecml_fields[i].length_) == 0) { |
| - return true; |
| - } |
| - } |
| - } |
| - } |
| - |
| - return false; |
| -} |
| - |
| -} // namespace |
| - |
| -// static |
| -void FormField::ParseFormFields(const std::vector<AutofillField*>& fields, |
| - FieldTypeMap* field_type_map) { |
| - // First, check if there is at least one form field with an ECML name. |
| - // If there is, then we will match an element only if it is in the standard. |
| - bool is_ecml = HasECMLField(fields); |
| +using autofill::GetEcmlPattern; |
| +using autofill::HasECMLField; |
| - // Parse fields. |
| - AutofillScanner scanner(fields); |
| - while (!scanner.IsEnd()) { |
| - scoped_ptr<FormField> form_field( |
| - FormField::ParseFormField(&scanner, is_ecml)); |
| - if (!form_field.get()) { |
| - scanner.Advance(); |
| - continue; |
| - } |
| - |
| - bool ok = form_field->GetFieldInfo(field_type_map); |
| - DCHECK(ok); |
| - } |
| -} |
| - |
| -// static |
| -bool FormField::Match(const AutofillField* field, |
| - const string16& pattern, |
| - bool match_label_only) { |
| - if (MatchLabel(field, pattern)) |
| - return true; |
| - |
| - // For now, we apply the same pattern to the field's label and the field's |
| - // name. Matching the name is a bit of a long shot for many patterns, but |
| - // it generally doesn't hurt to try. |
| - if (!match_label_only && MatchName(field, pattern)) |
| - return true; |
| - |
| - return false; |
| -} |
| - |
| -// static |
| -bool FormField::MatchName(const AutofillField* field, const string16& pattern) { |
| +bool MatchName(const AutofillField* field, const string16& pattern) { |
| // TODO(jhawkins): Remove StringToLowerASCII. WebRegularExpression needs to |
| // be fixed to take WebTextCaseInsensitive into account. |
| WebKit::WebRegularExpression re(WebKit::WebString(pattern), |
| @@ -196,9 +44,7 @@ bool FormField::MatchName(const AutofillField* field, const string16& pattern) { |
| return match; |
| } |
| -// static |
| -bool FormField::MatchLabel(const AutofillField* field, |
| - const string16& pattern) { |
| +bool MatchLabel(const AutofillField* field, const string16& pattern) { |
| // TODO(jhawkins): Remove StringToLowerASCII. WebRegularExpression needs to |
| // be fixed to take WebTextCaseInsensitive into account. |
| WebKit::WebRegularExpression re(WebKit::WebString(pattern), |
| @@ -208,9 +54,10 @@ bool FormField::MatchLabel(const AutofillField* field, |
| return match; |
| } |
| -// static |
| -FormField* FormField::ParseFormField(AutofillScanner* scanner, bool is_ecml) { |
| - FormField *field; |
| +// Parses a field using the different field views we know about. |is_ecml| |
| +// should be true when the field conforms to the ECML specification. |
| +FormField* ParseFormField(AutofillScanner* scanner, bool is_ecml) { |
| + FormField* field; |
| field = EmailField::Parse(scanner, is_ecml); |
| if (field) |
| @@ -234,44 +81,48 @@ FormField* FormField::ParseFormField(AutofillScanner* scanner, bool is_ecml) { |
| return NameField::Parse(scanner, is_ecml); |
| } |
| -// static |
| -bool FormField::ParseText(AutofillScanner* scanner, const string16& pattern) { |
| - const AutofillField* field; |
| - return ParseText(scanner, pattern, &field); |
| -} |
| +} // namespace |
| // static |
| -bool FormField::ParseText(AutofillScanner* scanner, |
| - const string16& pattern, |
| - const AutofillField** dest) { |
| - return ParseText(scanner, pattern, dest, false); |
| -} |
| +void FormField::ParseFormFields(const std::vector<AutofillField*>& fields, |
| + FieldTypeMap* map) { |
| + // First, check if there is at least one form field with an ECML name. |
| + // If there is, then we will match an element only if it is in the standard. |
| + bool is_ecml = HasECMLField(fields); |
| -// static |
| -bool FormField::ParseEmptyText(AutofillScanner* scanner, |
| - const AutofillField** dest) { |
| - return ParseLabelText(scanner, ASCIIToUTF16("^$"), dest); |
| + // Parse fields. |
| + AutofillScanner scanner(fields); |
| + while (!scanner.IsEnd()) { |
| + scoped_ptr<FormField> form_field(ParseFormField(&scanner, is_ecml)); |
| + if (!form_field.get()) { |
| + scanner.Advance(); |
| + continue; |
| + } |
| + |
| + bool ok = form_field->ClassifyField(map); |
|
Ilya Sherman
2011/05/19 05:44:16
This line parses really oddly, since form_field ca
dhollowa
2011/05/19 17:53:08
Yes, it requires the reader to understand that a "
|
| + DCHECK(ok); |
| + } |
| } |
| // static |
| -bool FormField::ParseLabelText(AutofillScanner* scanner, |
| - const string16& pattern, |
| - const AutofillField** dest) { |
| - return ParseText(scanner, pattern, dest, true); |
| +bool FormField::ParseField(AutofillScanner* scanner, |
| + const string16& pattern, |
| + const AutofillField** match) { |
| + return ParseFieldSpecifics(scanner, pattern, MATCH_ALL, match); |
| } |
| // static |
| -bool FormField::ParseText(AutofillScanner* scanner, |
| - const string16& pattern, |
| - const AutofillField** dest, |
| - bool match_label_only) { |
| +bool FormField::ParseFieldSpecifics(AutofillScanner* scanner, |
| + const string16& pattern, |
| + int match_type, |
| + const AutofillField** match) { |
| if (scanner->IsEnd()) |
| return false; |
| const AutofillField* field = scanner->Cursor(); |
| - if (Match(field, pattern, match_label_only)) { |
| - if (dest) |
| - *dest = field; |
| + if (Match(field, pattern, match_type)) { |
| + if (match) |
| + *match = field; |
| scanner->Advance(); |
| return true; |
| } |
| @@ -280,45 +131,31 @@ bool FormField::ParseText(AutofillScanner* scanner, |
| } |
| // static |
| -bool FormField::ParseLabelAndName(AutofillScanner* scanner, |
| - const string16& pattern, |
| - const AutofillField** dest) { |
| - const AutofillField* field = scanner->Cursor(); |
| - if (MatchLabel(field, pattern) && MatchName(field, pattern)) { |
| - if (dest) |
| - *dest = field; |
| - scanner->Advance(); |
| - return true; |
| - } |
| - |
| - return false; |
| +bool FormField::ParseEmptyLabel(AutofillScanner* scanner, |
| + const AutofillField** match) { |
| + return ParseFieldSpecifics(scanner, ASCIIToUTF16("^$"), MATCH_LABEL, match); |
| } |
| // static |
| -bool FormField::ParseEmpty(AutofillScanner* scanner) { |
| - // TODO(jhawkins): Handle select fields. |
| - return ParseLabelAndName(scanner, ASCIIToUTF16("^$"), NULL); |
| -} |
| - |
| -// static |
| -bool FormField::Add(FieldTypeMap* field_type_map, |
| - const AutofillField* field, |
| - AutofillFieldType type) { |
| +bool FormField::AddClassification(const AutofillField* field, |
| + AutofillFieldType type, |
| + FieldTypeMap* map) { |
| // Several fields are optional. |
| if (!field) |
| return true; |
| - // TODO(isherman): Is this the intent? |
| - return field_type_map->insert(make_pair(field->unique_name(), type)).second; |
| + return map->insert(make_pair(field->unique_name(), type)).second; |
| } |
| -string16 FormField::GetEcmlPattern(const char* ecml_name) { |
| - return ASCIIToUTF16(std::string("^") + ecml_name); |
| -} |
| +// static |
| +bool FormField::Match(const AutofillField* field, |
| + const string16& pattern, |
| + int match_type) { |
| + if ((match_type & FormField::MATCH_LABEL) && MatchLabel(field, pattern)) |
| + return true; |
| -string16 FormField::GetEcmlPattern(const char* ecml_name1, |
| - const char* ecml_name2, |
| - char pattern_operator) { |
| - return ASCIIToUTF16(StringPrintf("^%s%c^%s", |
| - ecml_name1, pattern_operator, ecml_name2)); |
| + if ((match_type & FormField::MATCH_NAME) && MatchName(field, pattern)) |
| + return true; |
| + |
| + return false; |
| } |