Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/autofill/form_field.h" | 5 #include "chrome/browser/autofill/form_field.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
| 14 #include "base/stringprintf.h" | 14 #include "base/stringprintf.h" |
| 15 #include "base/utf_string_conversions.h" | 15 #include "base/utf_string_conversions.h" |
| 16 #include "chrome/browser/autofill/autofill_ecml.h" | |
| 16 #include "chrome/browser/autofill/address_field.h" | 17 #include "chrome/browser/autofill/address_field.h" |
| 17 #include "chrome/browser/autofill/autofill_field.h" | 18 #include "chrome/browser/autofill/autofill_field.h" |
| 18 #include "chrome/browser/autofill/autofill_scanner.h" | 19 #include "chrome/browser/autofill/autofill_scanner.h" |
| 19 #include "chrome/browser/autofill/credit_card_field.h" | 20 #include "chrome/browser/autofill/credit_card_field.h" |
| 20 #include "chrome/browser/autofill/email_field.h" | 21 #include "chrome/browser/autofill/email_field.h" |
| 21 #include "chrome/browser/autofill/field_types.h" | 22 #include "chrome/browser/autofill/field_types.h" |
| 22 #include "chrome/browser/autofill/form_structure.h" | 23 #include "chrome/browser/autofill/form_structure.h" |
| 23 #include "chrome/browser/autofill/name_field.h" | 24 #include "chrome/browser/autofill/name_field.h" |
| 24 #include "chrome/browser/autofill/phone_field.h" | 25 #include "chrome/browser/autofill/phone_field.h" |
| 25 #include "grit/autofill_resources.h" | 26 #include "grit/autofill_resources.h" |
| 26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebRegularExpression. h" | 27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebRegularExpression. h" |
| 27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" | 28 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" |
| 28 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCaseSensitivit y.h" | 29 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextCaseSensitivit y.h" |
| 29 #include "ui/base/l10n/l10n_util.h" | 30 #include "ui/base/l10n/l10n_util.h" |
| 30 | 31 |
| 31 // Field names from the ECML specification; see RFC 3106. We've | |
| 32 // made these names lowercase since we convert labels and field names to | |
| 33 // lowercase before searching. | |
| 34 | |
| 35 // shipping name/address fields | |
| 36 const char kEcmlShipToTitle[] = "ecom_shipto_postal_name_prefix"; | |
| 37 const char kEcmlShipToFirstName[] = "ecom_shipto_postal_name_first"; | |
| 38 const char kEcmlShipToMiddleName[] = "ecom_shipto_postal_name_middle"; | |
| 39 const char kEcmlShipToLastName[] = "ecom_shipto_postal_name_last"; | |
| 40 const char kEcmlShipToNameSuffix[] = "ecom_shipto_postal_name_suffix"; | |
| 41 const char kEcmlShipToCompanyName[] = "ecom_shipto_postal_company"; | |
| 42 const char kEcmlShipToAddress1[] = "ecom_shipto_postal_street_line1"; | |
| 43 const char kEcmlShipToAddress2[] = "ecom_shipto_postal_street_line2"; | |
| 44 const char kEcmlShipToAddress3[] = "ecom_shipto_postal_street_line3"; | |
| 45 const char kEcmlShipToCity[] = "ecom_shipto_postal_city"; | |
| 46 const char kEcmlShipToStateProv[] = "ecom_shipto_postal_stateprov"; | |
| 47 const char kEcmlShipToPostalCode[] = "ecom_shipto_postal_postalcode"; | |
| 48 const char kEcmlShipToCountry[] = "ecom_shipto_postal_countrycode"; | |
| 49 const char kEcmlShipToPhone[] = "ecom_shipto_telecom_phone_number"; | |
| 50 const char kEcmlShipToEmail[] = "ecom_shipto_online_email"; | |
| 51 | |
| 52 // billing name/address fields | |
| 53 const char kEcmlBillToTitle[] = "ecom_billto_postal_name_prefix"; | |
| 54 const char kEcmlBillToFirstName[] = "ecom_billto_postal_name_first"; | |
| 55 const char kEcmlBillToMiddleName[] = "ecom_billto_postal_name_middle"; | |
| 56 const char kEcmlBillToLastName[] = "ecom_billto_postal_name_last"; | |
| 57 const char kEcmlBillToNameSuffix[] = "ecom_billto_postal_name_suffix"; | |
| 58 const char kEcmlBillToCompanyName[] = "ecom_billto_postal_company"; | |
| 59 const char kEcmlBillToAddress1[] = "ecom_billto_postal_street_line1"; | |
| 60 const char kEcmlBillToAddress2[] = "ecom_billto_postal_street_line2"; | |
| 61 const char kEcmlBillToAddress3[] = "ecom_billto_postal_street_line3"; | |
| 62 const char kEcmlBillToCity[] = "ecom_billto_postal_city"; | |
| 63 const char kEcmlBillToStateProv[] = "ecom_billto_postal_stateprov"; | |
| 64 const char kEcmlBillToPostalCode[] = "ecom_billto_postal_postalcode"; | |
| 65 const char kEcmlBillToCountry[] = "ecom_billto_postal_countrycode"; | |
| 66 const char kEcmlBillToPhone[] = "ecom_billto_telecom_phone_number"; | |
| 67 const char kEcmlBillToEmail[] = "ecom_billto_online_email"; | |
| 68 | |
| 69 // credit card fields | |
| 70 const char kEcmlCardHolder[] = "ecom_payment_card_name"; | |
| 71 const char kEcmlCardType[] = "ecom_payment_card_type"; | |
| 72 const char kEcmlCardNumber[] = "ecom_payment_card_number"; | |
| 73 const char kEcmlCardVerification[] = "ecom_payment_card_verification"; | |
| 74 const char kEcmlCardExpireDay[] = "ecom_payment_card_expdate_day"; | |
| 75 const char kEcmlCardExpireMonth[] = "ecom_payment_card_expdate_month"; | |
| 76 const char kEcmlCardExpireYear[] = "ecom_payment_card_expdate_year"; | |
| 77 | |
| 78 namespace { | 32 namespace { |
| 79 | 33 |
| 80 // Checks if any of the |form|'s labels are named according to the ECML | 34 using autofill::GetEcmlPattern; |
| 81 // standard. Returns true if at least one ECML named element is found. | 35 using autofill::HasECMLField; |
| 82 bool HasECMLField(const std::vector<AutofillField*>& fields) { | |
| 83 struct EcmlField { | |
| 84 const char* name_; | |
| 85 const int length_; | |
| 86 } ecml_fields[] = { | |
| 87 #define ECML_STRING_ENTRY(x) { x, arraysize(x) - 1 }, | |
| 88 ECML_STRING_ENTRY(kEcmlShipToTitle) | |
| 89 ECML_STRING_ENTRY(kEcmlShipToFirstName) | |
| 90 ECML_STRING_ENTRY(kEcmlShipToMiddleName) | |
| 91 ECML_STRING_ENTRY(kEcmlShipToLastName) | |
| 92 ECML_STRING_ENTRY(kEcmlShipToNameSuffix) | |
| 93 ECML_STRING_ENTRY(kEcmlShipToCompanyName) | |
| 94 ECML_STRING_ENTRY(kEcmlShipToAddress1) | |
| 95 ECML_STRING_ENTRY(kEcmlShipToAddress2) | |
| 96 ECML_STRING_ENTRY(kEcmlShipToAddress3) | |
| 97 ECML_STRING_ENTRY(kEcmlShipToCity) | |
| 98 ECML_STRING_ENTRY(kEcmlShipToStateProv) | |
| 99 ECML_STRING_ENTRY(kEcmlShipToPostalCode) | |
| 100 ECML_STRING_ENTRY(kEcmlShipToCountry) | |
| 101 ECML_STRING_ENTRY(kEcmlShipToPhone) | |
| 102 ECML_STRING_ENTRY(kEcmlShipToPhone) | |
| 103 ECML_STRING_ENTRY(kEcmlShipToEmail) | |
| 104 ECML_STRING_ENTRY(kEcmlBillToTitle) | |
| 105 ECML_STRING_ENTRY(kEcmlBillToFirstName) | |
| 106 ECML_STRING_ENTRY(kEcmlBillToMiddleName) | |
| 107 ECML_STRING_ENTRY(kEcmlBillToLastName) | |
| 108 ECML_STRING_ENTRY(kEcmlBillToNameSuffix) | |
| 109 ECML_STRING_ENTRY(kEcmlBillToCompanyName) | |
| 110 ECML_STRING_ENTRY(kEcmlBillToAddress1) | |
| 111 ECML_STRING_ENTRY(kEcmlBillToAddress2) | |
| 112 ECML_STRING_ENTRY(kEcmlBillToAddress3) | |
| 113 ECML_STRING_ENTRY(kEcmlBillToCity) | |
| 114 ECML_STRING_ENTRY(kEcmlBillToStateProv) | |
| 115 ECML_STRING_ENTRY(kEcmlBillToPostalCode) | |
| 116 ECML_STRING_ENTRY(kEcmlBillToCountry) | |
| 117 ECML_STRING_ENTRY(kEcmlBillToPhone) | |
| 118 ECML_STRING_ENTRY(kEcmlBillToPhone) | |
| 119 ECML_STRING_ENTRY(kEcmlBillToEmail) | |
| 120 ECML_STRING_ENTRY(kEcmlCardHolder) | |
| 121 ECML_STRING_ENTRY(kEcmlCardType) | |
| 122 ECML_STRING_ENTRY(kEcmlCardNumber) | |
| 123 ECML_STRING_ENTRY(kEcmlCardVerification) | |
| 124 ECML_STRING_ENTRY(kEcmlCardExpireMonth) | |
| 125 ECML_STRING_ENTRY(kEcmlCardExpireYear) | |
| 126 #undef ECML_STRING_ENTRY | |
| 127 }; | |
| 128 | 36 |
| 129 const string16 ecom(ASCIIToUTF16("ecom")); | 37 bool MatchName(const AutofillField* field, const string16& pattern) { |
| 130 for (std::vector<AutofillField*>::const_iterator field = fields.begin(); | |
| 131 field != fields.end(); | |
| 132 ++field) { | |
| 133 const string16& utf16_name = (*field)->name; | |
| 134 if (StartsWith(utf16_name, ecom, true)) { | |
| 135 std::string name(UTF16ToUTF8(utf16_name)); | |
| 136 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(ecml_fields); ++i) { | |
| 137 if (base::strncasecmp(name.c_str(), ecml_fields[i].name_, | |
| 138 ecml_fields[i].length_) == 0) { | |
| 139 return true; | |
| 140 } | |
| 141 } | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 return false; | |
| 146 } | |
| 147 | |
| 148 } // namespace | |
| 149 | |
| 150 // static | |
| 151 void FormField::ParseFormFields(const std::vector<AutofillField*>& fields, | |
| 152 FieldTypeMap* field_type_map) { | |
| 153 // First, check if there is at least one form field with an ECML name. | |
| 154 // If there is, then we will match an element only if it is in the standard. | |
| 155 bool is_ecml = HasECMLField(fields); | |
| 156 | |
| 157 // Parse fields. | |
| 158 AutofillScanner scanner(fields); | |
| 159 while (!scanner.IsEnd()) { | |
| 160 scoped_ptr<FormField> form_field( | |
| 161 FormField::ParseFormField(&scanner, is_ecml)); | |
| 162 if (!form_field.get()) { | |
| 163 scanner.Advance(); | |
| 164 continue; | |
| 165 } | |
| 166 | |
| 167 bool ok = form_field->GetFieldInfo(field_type_map); | |
| 168 DCHECK(ok); | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 // static | |
| 173 bool FormField::Match(const AutofillField* field, | |
| 174 const string16& pattern, | |
| 175 bool match_label_only) { | |
| 176 if (MatchLabel(field, pattern)) | |
| 177 return true; | |
| 178 | |
| 179 // For now, we apply the same pattern to the field's label and the field's | |
| 180 // name. Matching the name is a bit of a long shot for many patterns, but | |
| 181 // it generally doesn't hurt to try. | |
| 182 if (!match_label_only && MatchName(field, pattern)) | |
| 183 return true; | |
| 184 | |
| 185 return false; | |
| 186 } | |
| 187 | |
| 188 // static | |
| 189 bool FormField::MatchName(const AutofillField* field, const string16& pattern) { | |
| 190 // TODO(jhawkins): Remove StringToLowerASCII. WebRegularExpression needs to | 38 // TODO(jhawkins): Remove StringToLowerASCII. WebRegularExpression needs to |
| 191 // be fixed to take WebTextCaseInsensitive into account. | 39 // be fixed to take WebTextCaseInsensitive into account. |
| 192 WebKit::WebRegularExpression re(WebKit::WebString(pattern), | 40 WebKit::WebRegularExpression re(WebKit::WebString(pattern), |
| 193 WebKit::WebTextCaseInsensitive); | 41 WebKit::WebTextCaseInsensitive); |
| 194 bool match = re.match( | 42 bool match = re.match( |
| 195 WebKit::WebString(StringToLowerASCII(field->name))) != -1; | 43 WebKit::WebString(StringToLowerASCII(field->name))) != -1; |
| 196 return match; | 44 return match; |
| 197 } | 45 } |
| 198 | 46 |
| 199 // static | 47 bool MatchLabel(const AutofillField* field, const string16& pattern) { |
| 200 bool FormField::MatchLabel(const AutofillField* field, | |
| 201 const string16& pattern) { | |
| 202 // TODO(jhawkins): Remove StringToLowerASCII. WebRegularExpression needs to | 48 // TODO(jhawkins): Remove StringToLowerASCII. WebRegularExpression needs to |
| 203 // be fixed to take WebTextCaseInsensitive into account. | 49 // be fixed to take WebTextCaseInsensitive into account. |
| 204 WebKit::WebRegularExpression re(WebKit::WebString(pattern), | 50 WebKit::WebRegularExpression re(WebKit::WebString(pattern), |
| 205 WebKit::WebTextCaseInsensitive); | 51 WebKit::WebTextCaseInsensitive); |
| 206 bool match = re.match( | 52 bool match = re.match( |
| 207 WebKit::WebString(StringToLowerASCII(field->label))) != -1; | 53 WebKit::WebString(StringToLowerASCII(field->label))) != -1; |
| 208 return match; | 54 return match; |
| 209 } | 55 } |
| 210 | 56 |
| 211 // static | 57 // Parses a field using the different field views we know about. |is_ecml| |
| 212 FormField* FormField::ParseFormField(AutofillScanner* scanner, bool is_ecml) { | 58 // should be true when the field conforms to the ECML specification. |
| 213 FormField *field; | 59 FormField* ParseFormField(AutofillScanner* scanner, bool is_ecml) { |
| 60 FormField* field; | |
| 214 | 61 |
| 215 field = EmailField::Parse(scanner, is_ecml); | 62 field = EmailField::Parse(scanner, is_ecml); |
| 216 if (field) | 63 if (field) |
| 217 return field; | 64 return field; |
| 218 | 65 |
| 219 // Parses both phone and fax. | 66 // Parses both phone and fax. |
| 220 field = PhoneField::Parse(scanner, is_ecml); | 67 field = PhoneField::Parse(scanner, is_ecml); |
| 221 if (field) | 68 if (field) |
| 222 return field; | 69 return field; |
| 223 | 70 |
| 224 field = AddressField::Parse(scanner, is_ecml); | 71 field = AddressField::Parse(scanner, is_ecml); |
| 225 if (field) | 72 if (field) |
| 226 return field; | 73 return field; |
| 227 | 74 |
| 228 field = CreditCardField::Parse(scanner, is_ecml); | 75 field = CreditCardField::Parse(scanner, is_ecml); |
| 229 if (field) | 76 if (field) |
| 230 return field; | 77 return field; |
| 231 | 78 |
| 232 // We search for a |NameField| last since it matches the word "name", which is | 79 // We search for a |NameField| last since it matches the word "name", which is |
| 233 // relatively general. | 80 // relatively general. |
| 234 return NameField::Parse(scanner, is_ecml); | 81 return NameField::Parse(scanner, is_ecml); |
| 235 } | 82 } |
| 236 | 83 |
| 84 } // namespace | |
| 85 | |
| 237 // static | 86 // static |
| 238 bool FormField::ParseText(AutofillScanner* scanner, const string16& pattern) { | 87 void FormField::ParseFormFields(const std::vector<AutofillField*>& fields, |
| 239 const AutofillField* field; | 88 FieldTypeMap* map) { |
| 240 return ParseText(scanner, pattern, &field); | 89 // First, check if there is at least one form field with an ECML name. |
| 90 // If there is, then we will match an element only if it is in the standard. | |
| 91 bool is_ecml = HasECMLField(fields); | |
| 92 | |
| 93 // Parse fields. | |
| 94 AutofillScanner scanner(fields); | |
| 95 while (!scanner.IsEnd()) { | |
| 96 scoped_ptr<FormField> form_field(ParseFormField(&scanner, is_ecml)); | |
| 97 if (!form_field.get()) { | |
| 98 scanner.Advance(); | |
| 99 continue; | |
| 100 } | |
| 101 | |
| 102 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 "
| |
| 103 DCHECK(ok); | |
| 104 } | |
| 241 } | 105 } |
| 242 | 106 |
| 243 // static | 107 // static |
| 244 bool FormField::ParseText(AutofillScanner* scanner, | 108 bool FormField::ParseField(AutofillScanner* scanner, |
| 245 const string16& pattern, | 109 const string16& pattern, |
| 246 const AutofillField** dest) { | 110 const AutofillField** match) { |
| 247 return ParseText(scanner, pattern, dest, false); | 111 return ParseFieldSpecifics(scanner, pattern, MATCH_ALL, match); |
| 248 } | 112 } |
| 249 | 113 |
| 250 // static | 114 // static |
| 251 bool FormField::ParseEmptyText(AutofillScanner* scanner, | 115 bool FormField::ParseFieldSpecifics(AutofillScanner* scanner, |
| 252 const AutofillField** dest) { | 116 const string16& pattern, |
| 253 return ParseLabelText(scanner, ASCIIToUTF16("^$"), dest); | 117 int match_type, |
| 254 } | 118 const AutofillField** match) { |
| 255 | |
| 256 // static | |
| 257 bool FormField::ParseLabelText(AutofillScanner* scanner, | |
| 258 const string16& pattern, | |
| 259 const AutofillField** dest) { | |
| 260 return ParseText(scanner, pattern, dest, true); | |
| 261 } | |
| 262 | |
| 263 // static | |
| 264 bool FormField::ParseText(AutofillScanner* scanner, | |
| 265 const string16& pattern, | |
| 266 const AutofillField** dest, | |
| 267 bool match_label_only) { | |
| 268 if (scanner->IsEnd()) | 119 if (scanner->IsEnd()) |
| 269 return false; | 120 return false; |
| 270 | 121 |
| 271 const AutofillField* field = scanner->Cursor(); | 122 const AutofillField* field = scanner->Cursor(); |
| 272 if (Match(field, pattern, match_label_only)) { | 123 if (Match(field, pattern, match_type)) { |
| 273 if (dest) | 124 if (match) |
| 274 *dest = field; | 125 *match = field; |
| 275 scanner->Advance(); | 126 scanner->Advance(); |
| 276 return true; | 127 return true; |
| 277 } | 128 } |
| 278 | 129 |
| 279 return false; | 130 return false; |
| 280 } | 131 } |
| 281 | 132 |
| 282 // static | 133 // static |
| 283 bool FormField::ParseLabelAndName(AutofillScanner* scanner, | 134 bool FormField::ParseEmptyLabel(AutofillScanner* scanner, |
| 284 const string16& pattern, | 135 const AutofillField** match) { |
| 285 const AutofillField** dest) { | 136 return ParseFieldSpecifics(scanner, ASCIIToUTF16("^$"), MATCH_LABEL, match); |
| 286 const AutofillField* field = scanner->Cursor(); | |
| 287 if (MatchLabel(field, pattern) && MatchName(field, pattern)) { | |
| 288 if (dest) | |
| 289 *dest = field; | |
| 290 scanner->Advance(); | |
| 291 return true; | |
| 292 } | |
| 293 | |
| 294 return false; | |
| 295 } | 137 } |
| 296 | 138 |
| 297 // static | 139 // static |
| 298 bool FormField::ParseEmpty(AutofillScanner* scanner) { | 140 bool FormField::AddClassification(const AutofillField* field, |
| 299 // TODO(jhawkins): Handle select fields. | 141 AutofillFieldType type, |
| 300 return ParseLabelAndName(scanner, ASCIIToUTF16("^$"), NULL); | 142 FieldTypeMap* map) { |
| 301 } | |
| 302 | |
| 303 // static | |
| 304 bool FormField::Add(FieldTypeMap* field_type_map, | |
| 305 const AutofillField* field, | |
| 306 AutofillFieldType type) { | |
| 307 // Several fields are optional. | 143 // Several fields are optional. |
| 308 if (!field) | 144 if (!field) |
| 309 return true; | 145 return true; |
| 310 | 146 |
| 311 // TODO(isherman): Is this the intent? | 147 return map->insert(make_pair(field->unique_name(), type)).second; |
| 312 return field_type_map->insert(make_pair(field->unique_name(), type)).second; | |
| 313 } | 148 } |
| 314 | 149 |
| 315 string16 FormField::GetEcmlPattern(const char* ecml_name) { | 150 // static |
| 316 return ASCIIToUTF16(std::string("^") + ecml_name); | 151 bool FormField::Match(const AutofillField* field, |
| 152 const string16& pattern, | |
| 153 int match_type) { | |
| 154 if ((match_type & FormField::MATCH_LABEL) && MatchLabel(field, pattern)) | |
| 155 return true; | |
| 156 | |
| 157 if ((match_type & FormField::MATCH_NAME) && MatchName(field, pattern)) | |
| 158 return true; | |
| 159 | |
| 160 return false; | |
| 317 } | 161 } |
| 318 | |
| 319 string16 FormField::GetEcmlPattern(const char* ecml_name1, | |
| 320 const char* ecml_name2, | |
| 321 char pattern_operator) { | |
| 322 return ASCIIToUTF16(StringPrintf("^%s%c^%s", | |
| 323 ecml_name1, pattern_operator, ecml_name2)); | |
| 324 } | |
| OLD | NEW |