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_structure.h" | 5 #include "chrome/browser/autofill/form_structure.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 if (autocomplete_type == ASCIIToUTF16("cc-exp-year")) { | 214 if (autocomplete_type == ASCIIToUTF16("cc-exp-year")) { |
215 if (field.max_length == 2) | 215 if (field.max_length == 2) |
216 *autofill_type = CREDIT_CARD_EXP_2_DIGIT_YEAR; | 216 *autofill_type = CREDIT_CARD_EXP_2_DIGIT_YEAR; |
217 else | 217 else |
218 *autofill_type = CREDIT_CARD_EXP_4_DIGIT_YEAR; | 218 *autofill_type = CREDIT_CARD_EXP_4_DIGIT_YEAR; |
219 return true; | 219 return true; |
220 } | 220 } |
221 | 221 |
222 if (autocomplete_type == ASCIIToUTF16("cc-exp")) { | 222 if (autocomplete_type == ASCIIToUTF16("cc-exp")) { |
223 // TODO(isherman): Choose variant based on HTML5 validation regex. | 223 // TODO(isherman): Choose variant based on HTML5 validation regex. |
224 *autofill_type = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR; | 224 *autofill_type = CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR; |
225 return true; | 225 return true; |
226 } | 226 } |
227 | 227 |
228 return false; | 228 return false; |
229 } | 229 } |
230 | 230 |
231 // Classifies each field in |fields| based upon its |autocompletetype| | |
232 // attribute, if the attribute is available. The association is stored into | |
233 // |map|. Returns |true| if the attribute is available (and non-empty) for at | |
234 // least one field. | |
235 bool ParseAutocompletetypeAttributes(const std::vector<AutofillField*>& fields, | |
236 FieldTypeMap* map) { | |
237 bool found_attribute = false; | |
238 for (std::vector<AutofillField*>::const_iterator field = fields.begin(); | |
239 field != fields.end(); ++field) { | |
240 if ((*field)->autocomplete_type.empty()) | |
241 continue; | |
242 | |
243 found_attribute = true; | |
244 std::vector<string16> types; | |
245 Tokenize((*field)->autocomplete_type, ASCIIToUTF16(" "), &types); | |
246 | |
247 // TODO(isherman): Handle sections: http://crbug.com/92121 | |
248 for (std::vector<string16>::const_iterator type = types.begin(); | |
249 type != types.end(); ++type) { | |
250 AutofillFieldType autofill_type = UNKNOWN_TYPE; | |
251 if (ConvertToAutofillFieldType(**field, *type, &autofill_type)) { | |
252 map->insert(make_pair((*field)->unique_name(), autofill_type)); | |
253 break; | |
254 } | |
255 } | |
256 } | |
257 | |
258 return found_attribute; | |
259 } | |
260 | |
261 } // namespace | 231 } // namespace |
262 | 232 |
263 FormStructure::FormStructure(const FormData& form) | 233 FormStructure::FormStructure(const FormData& form) |
264 : form_name_(form.name), | 234 : form_name_(form.name), |
265 source_url_(form.origin), | 235 source_url_(form.origin), |
266 target_url_(form.action), | 236 target_url_(form.action), |
267 autofill_count_(0), | 237 autofill_count_(0), |
268 upload_required_(USE_UPLOAD_RATES), | 238 upload_required_(USE_UPLOAD_RATES), |
269 server_experiment_id_("no server response"), | 239 server_experiment_id_("no server response"), |
270 has_author_specified_types_(false) { | 240 has_author_specified_types_(false) { |
(...skipping 18 matching lines...) Expand all Loading... |
289 } else { | 259 } else { |
290 // Either the method is 'get', or we don't know. In this case we default | 260 // Either the method is 'get', or we don't know. In this case we default |
291 // to GET. | 261 // to GET. |
292 method_ = GET; | 262 method_ = GET; |
293 } | 263 } |
294 } | 264 } |
295 | 265 |
296 FormStructure::~FormStructure() {} | 266 FormStructure::~FormStructure() {} |
297 | 267 |
298 void FormStructure::DetermineHeuristicTypes() { | 268 void FormStructure::DetermineHeuristicTypes() { |
299 autofill_count_ = 0; | |
300 | |
301 FieldTypeMap field_type_map; | |
302 | |
303 // First, try to detect field types based on the fields' |autocompletetype| | 269 // First, try to detect field types based on the fields' |autocompletetype| |
304 // attributes. If there is at least one form field with this attribute, don't | 270 // attributes. If there is at least one form field with this attribute, don't |
305 // try to apply other heuristics to match fields in this form. | 271 // try to apply other heuristics to match fields in this form. |
306 has_author_specified_types_ = | 272 bool found_sections; |
307 ParseAutocompletetypeAttributes(fields_.get(), &field_type_map); | 273 ParseAutocompletetypeAttributes(&has_author_specified_types_, |
308 if (!has_author_specified_types_) | 274 &found_sections); |
| 275 |
| 276 if (!has_author_specified_types_) { |
| 277 FieldTypeMap field_type_map; |
309 FormField::ParseFormFields(fields_.get(), &field_type_map); | 278 FormField::ParseFormFields(fields_.get(), &field_type_map); |
| 279 for (size_t index = 0; index < field_count(); index++) { |
| 280 AutofillField* field = fields_[index]; |
| 281 FieldTypeMap::iterator iter = field_type_map.find(field->unique_name()); |
| 282 if (iter != field_type_map.end()) |
| 283 field->set_heuristic_type(iter->second); |
| 284 } |
| 285 } |
310 | 286 |
311 for (size_t index = 0; index < field_count(); index++) { | 287 UpdateAutofillCount(); |
312 AutofillField* field = fields_[index]; | |
313 FieldTypeMap::iterator iter = field_type_map.find(field->unique_name()); | |
314 | 288 |
315 AutofillFieldType heuristic_autofill_type; | 289 if (!found_sections) |
316 if (iter == field_type_map.end()) { | 290 IdentifySections(); |
317 heuristic_autofill_type = UNKNOWN_TYPE; | |
318 } else { | |
319 heuristic_autofill_type = iter->second; | |
320 ++autofill_count_; | |
321 } | |
322 | 291 |
323 field->set_heuristic_type(heuristic_autofill_type); | 292 // Ensure that credit card and address fields are in separate sections. |
| 293 // This simplifies the section-aware logic in autofill_manager.cc. |
| 294 for (std::vector<AutofillField*>::iterator field = fields_->begin(); |
| 295 field != fields_->end(); ++field) { |
| 296 AutofillType::FieldTypeGroup field_type_group = |
| 297 AutofillType((*field)->type()).group(); |
| 298 if (field_type_group == AutofillType::CREDIT_CARD) |
| 299 (*field)->set_section((*field)->section() + ASCIIToUTF16("-cc")); |
| 300 else |
| 301 (*field)->set_section((*field)->section() + ASCIIToUTF16("-default")); |
324 } | 302 } |
325 } | 303 } |
326 | 304 |
327 bool FormStructure::EncodeUploadRequest( | 305 bool FormStructure::EncodeUploadRequest( |
328 const FieldTypeSet& available_field_types, | 306 const FieldTypeSet& available_field_types, |
329 bool form_was_autofilled, | 307 bool form_was_autofilled, |
330 std::string* encoded_xml) const { | 308 std::string* encoded_xml) const { |
331 if (!ShouldBeCrowdsourced()) { | 309 if (!ShouldBeCrowdsourced()) { |
332 NOTREACHED(); | 310 NOTREACHED(); |
333 return false; | 311 return false; |
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
845 } else { | 823 } else { |
846 buzz::XmlElement *field_element = new buzz::XmlElement( | 824 buzz::XmlElement *field_element = new buzz::XmlElement( |
847 buzz::QName(kXMLElementField)); | 825 buzz::QName(kXMLElementField)); |
848 field_element->SetAttr(buzz::QName(kAttributeSignature), | 826 field_element->SetAttr(buzz::QName(kAttributeSignature), |
849 field->FieldSignature()); | 827 field->FieldSignature()); |
850 encompassing_xml_element->AddElement(field_element); | 828 encompassing_xml_element->AddElement(field_element); |
851 } | 829 } |
852 } | 830 } |
853 return true; | 831 return true; |
854 } | 832 } |
| 833 |
| 834 void FormStructure::ParseAutocompletetypeAttributes(bool* found_attribute, |
| 835 bool* found_sections) { |
| 836 *found_attribute = false; |
| 837 *found_sections = false; |
| 838 for (std::vector<AutofillField*>::iterator field = fields_->begin(); |
| 839 field != fields_->end(); ++field) { |
| 840 if ((*field)->autocomplete_type.empty()) |
| 841 continue; |
| 842 |
| 843 *found_attribute = true; |
| 844 std::vector<string16> types; |
| 845 Tokenize((*field)->autocomplete_type, ASCIIToUTF16(" "), &types); |
| 846 |
| 847 // Look for a named section. |
| 848 const string16 kSectionPrefix = ASCIIToUTF16("section-"); |
| 849 if (!types.empty() && StartsWith(types.front(), kSectionPrefix, true)) { |
| 850 *found_sections = true; |
| 851 (*field)->set_section(types.front().substr(kSectionPrefix.size())); |
| 852 } |
| 853 |
| 854 // Look for specified types. |
| 855 for (std::vector<string16>::const_iterator type = types.begin(); |
| 856 type != types.end(); ++type) { |
| 857 AutofillFieldType autofill_type = UNKNOWN_TYPE; |
| 858 if (ConvertToAutofillFieldType(**field, *type, &autofill_type)) { |
| 859 (*field)->set_heuristic_type(autofill_type); |
| 860 break; |
| 861 } |
| 862 } |
| 863 } |
| 864 } |
| 865 |
| 866 void FormStructure::IdentifySections() { |
| 867 if (fields_.empty()) |
| 868 return; |
| 869 |
| 870 // Name sections after the first field in the section. |
| 871 string16 current_section = fields_->front()->unique_name(); |
| 872 |
| 873 // Keep track of the types we've seen in this section. |
| 874 std::set<AutofillFieldType> seen_types; |
| 875 AutofillFieldType previous_type = UNKNOWN_TYPE; |
| 876 |
| 877 for (std::vector<AutofillField*>::iterator field = fields_->begin(); |
| 878 field != fields_->end(); ++field) { |
| 879 const AutofillFieldType current_type = |
| 880 AutofillType::GetEquivalentFieldType((*field)->type()); |
| 881 |
| 882 bool already_saw_current_type = seen_types.count(current_type) > 0; |
| 883 |
| 884 // Forms often ask for multiple phone numbers -- e.g. both a daytime and |
| 885 // evening phone number. Our phone and fax number detection is also |
| 886 // generally a little off. Hence, ignore both field types as a signal here. |
| 887 AutofillType::FieldTypeGroup current_type_group = |
| 888 AutofillType(current_type).group(); |
| 889 if (current_type_group == AutofillType::PHONE_HOME || |
| 890 current_type_group == AutofillType::PHONE_FAX) |
| 891 already_saw_current_type = false; |
| 892 |
| 893 // Some forms have adjacent fields of the same type. Two common examples: |
| 894 // * Forms with two email fields, where the second is meant to "confirm" |
| 895 // the first. |
| 896 // * Forms with a <select> menu for states in some countries, and a |
| 897 // freeform <input> field for states in other countries. (Usually, only |
| 898 // one of these two will be visible for any given choice of country.) |
| 899 // Generally, adjacent fields of the same type belong in the same logical |
| 900 // section. |
| 901 if (current_type == previous_type) |
| 902 already_saw_current_type = false; |
| 903 |
| 904 previous_type = current_type; |
| 905 |
| 906 if (current_type != UNKNOWN_TYPE && already_saw_current_type) { |
| 907 // We reached the end of a section, so start a new section. |
| 908 seen_types.clear(); |
| 909 current_section = (*field)->unique_name(); |
| 910 } |
| 911 |
| 912 seen_types.insert(current_type); |
| 913 (*field)->set_section(current_section); |
| 914 } |
| 915 } |
OLD | NEW |