Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Side by Side Diff: components/autofill/core/browser/form_structure.cc

Issue 1411363003: [Autofill] Always show available data when encountering autocomplete attributes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed bug Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "components/autofill/core/browser/form_structure.h" 5 #include "components/autofill/core/browser/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/command_line.h" 10 #include "base/command_line.h"
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 } // namespace 366 } // namespace
367 367
368 FormStructure::FormStructure(const FormData& form) 368 FormStructure::FormStructure(const FormData& form)
369 : form_name_(form.name), 369 : form_name_(form.name),
370 source_url_(form.origin), 370 source_url_(form.origin),
371 target_url_(form.action), 371 target_url_(form.action),
372 autofill_count_(0), 372 autofill_count_(0),
373 active_field_count_(0), 373 active_field_count_(0),
374 upload_required_(USE_UPLOAD_RATES), 374 upload_required_(USE_UPLOAD_RATES),
375 has_author_specified_types_(false), 375 has_author_specified_types_(false),
376 has_author_specified_sections_(false),
377 was_parsed_for_autocomplete_attributes_(false),
376 has_password_field_(false), 378 has_password_field_(false),
377 is_form_tag_(form.is_form_tag) { 379 is_form_tag_(form.is_form_tag) {
378 // Copy the form fields. 380 // Copy the form fields.
379 std::map<base::string16, size_t> unique_names; 381 std::map<base::string16, size_t> unique_names;
380 for (const FormFieldData& field : form.fields) { 382 for (const FormFieldData& field : form.fields) {
381 if (!ShouldSkipField(field)) { 383 if (!ShouldSkipField(field)) {
382 // Add all supported form fields (including with empty names) to the 384 // Add all supported form fields (including with empty names) to the
383 // signature. This is a requirement for Autofill servers. 385 // signature. This is a requirement for Autofill servers.
384 form_signature_field_names_.append("&"); 386 form_signature_field_names_.append("&");
385 form_signature_field_names_.append(StripDigitsIfRequired(field.name)); 387 form_signature_field_names_.append(StripDigitsIfRequired(field.name));
(...skipping 14 matching lines...) Expand all
400 } 402 }
401 } 403 }
402 404
403 FormStructure::~FormStructure() {} 405 FormStructure::~FormStructure() {}
404 406
405 void FormStructure::DetermineHeuristicTypes() { 407 void FormStructure::DetermineHeuristicTypes() {
406 // First, try to detect field types based on each field's |autocomplete| 408 // First, try to detect field types based on each field's |autocomplete|
407 // attribute value. If there is at least one form field that specifies an 409 // attribute value. If there is at least one form field that specifies an
408 // autocomplete type hint, don't try to apply other heuristics to match fields 410 // autocomplete type hint, don't try to apply other heuristics to match fields
409 // in this form. 411 // in this form.
410 bool has_author_specified_sections; 412 if (!was_parsed_for_autocomplete_attributes_)
411 ParseFieldTypesFromAutocompleteAttributes(&has_author_specified_types_, 413 ParseFieldTypesFromAutocompleteAttributes();
412 &has_author_specified_sections);
413 414
414 if (!has_author_specified_types_) { 415 if (!has_author_specified_types_) {
415 ServerFieldTypeMap field_type_map; 416 ServerFieldTypeMap field_type_map;
416 FormField::ParseFormFields(fields_.get(), is_form_tag_, &field_type_map); 417 FormField::ParseFormFields(fields_.get(), is_form_tag_, &field_type_map);
417 for (size_t i = 0; i < field_count(); ++i) { 418 for (size_t i = 0; i < field_count(); ++i) {
418 AutofillField* field = fields_[i]; 419 AutofillField* field = fields_[i];
419 ServerFieldTypeMap::iterator iter = 420 ServerFieldTypeMap::iterator iter =
420 field_type_map.find(field->unique_name()); 421 field_type_map.find(field->unique_name());
421 if (iter != field_type_map.end()) 422 if (iter != field_type_map.end())
422 field->set_heuristic_type(iter->second); 423 field->set_heuristic_type(iter->second);
423 } 424 }
424 } 425 }
425 426
426 UpdateAutofillCount(); 427 UpdateAutofillCount();
427 IdentifySections(has_author_specified_sections); 428 IdentifySections(has_author_specified_sections_);
428 429
429 if (IsAutofillable()) { 430 if (IsAutofillable()) {
430 AutofillMetrics::LogDeveloperEngagementMetric( 431 AutofillMetrics::LogDeveloperEngagementMetric(
431 AutofillMetrics::FILLABLE_FORM_PARSED); 432 AutofillMetrics::FILLABLE_FORM_PARSED);
432 if (has_author_specified_types_) { 433 if (has_author_specified_types_) {
433 AutofillMetrics::LogDeveloperEngagementMetric( 434 AutofillMetrics::LogDeveloperEngagementMetric(
434 AutofillMetrics::FILLABLE_FORM_CONTAINS_TYPE_HINTS); 435 AutofillMetrics::FILLABLE_FORM_CONTAINS_TYPE_HINTS);
435 } 436 }
436 } 437 }
437 } 438 }
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after
702 form_signature_field_names_; 703 form_signature_field_names_;
703 704
704 return Hash64Bit(form_string); 705 return Hash64Bit(form_string);
705 } 706 }
706 707
707 bool FormStructure::ShouldSkipField(const FormFieldData& field) const { 708 bool FormStructure::ShouldSkipField(const FormFieldData& field) const {
708 return field.is_checkable; 709 return field.is_checkable;
709 } 710 }
710 711
711 bool FormStructure::IsAutofillable() const { 712 bool FormStructure::IsAutofillable() const {
712 if (autofill_count() < kRequiredAutofillFields) 713 if (autofill_count() < kRequiredFieldsForPredictionRoutines)
713 return false; 714 return false;
714 715
715 return ShouldBeParsed(); 716 return ShouldBeParsed();
716 } 717 }
717 718
718 void FormStructure::UpdateAutofillCount() { 719 void FormStructure::UpdateAutofillCount() {
719 autofill_count_ = 0; 720 autofill_count_ = 0;
720 for (const AutofillField* field : *this) { 721 for (const AutofillField* field : *this) {
721 if (field && field->IsFieldFillable()) 722 if (field && field->IsFieldFillable())
722 ++autofill_count_; 723 ++autofill_count_;
723 } 724 }
724 } 725 }
725 726
726 bool FormStructure::ShouldBeParsed() const { 727 bool FormStructure::ShouldBeParsed() const {
727 if (active_field_count() < kRequiredAutofillFields) 728 if (active_field_count() < kRequiredFieldsForPredictionRoutines &&
729 !has_author_specified_types_) {
728 return false; 730 return false;
731 }
729 732
730 // Rule out http(s)://*/search?... 733 // Rule out http(s)://*/search?...
731 // e.g. http://www.google.com/search?q=... 734 // e.g. http://www.google.com/search?q=...
732 // http://search.yahoo.com/search?p=... 735 // http://search.yahoo.com/search?p=...
733 if (target_url_.path() == "/search") 736 if (target_url_.path() == "/search")
734 return false; 737 return false;
735 738
736 bool has_text_field = false; 739 bool has_text_field = false;
737 for (const AutofillField* it : *this) { 740 for (const AutofillField* it : *this) {
738 has_text_field |= it->form_control_type != "select-one"; 741 has_text_field |= it->form_control_type != "select-one";
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
886 field_type); 889 field_type);
887 } else { 890 } else {
888 AutofillMetrics::LogOverallTypePrediction(AutofillMetrics::TYPE_MISMATCH, 891 AutofillMetrics::LogOverallTypePrediction(AutofillMetrics::TYPE_MISMATCH,
889 field_type); 892 field_type);
890 } 893 }
891 } 894 }
892 895
893 AutofillMetrics::LogNumberOfEditedAutofilledFieldsAtSubmission( 896 AutofillMetrics::LogNumberOfEditedAutofilledFieldsAtSubmission(
894 num_edited_autofilled_fields); 897 num_edited_autofilled_fields);
895 898
896 if (num_detected_field_types < kRequiredAutofillFields) { 899 if (num_detected_field_types < kRequiredFieldsForPredictionRoutines) {
897 AutofillMetrics::LogAutofillFormSubmittedState( 900 AutofillMetrics::LogAutofillFormSubmittedState(
898 AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA); 901 AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA);
899 } else { 902 } else {
900 if (did_autofill_all_possible_fields) { 903 if (did_autofill_all_possible_fields) {
901 AutofillMetrics::LogAutofillFormSubmittedState( 904 AutofillMetrics::LogAutofillFormSubmittedState(
902 AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL); 905 AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL);
903 } else if (did_autofill_some_possible_fields) { 906 } else if (did_autofill_some_possible_fields) {
904 AutofillMetrics::LogAutofillFormSubmittedState( 907 AutofillMetrics::LogAutofillFormSubmittedState(
905 AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME); 908 AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME);
906 } else if (!did_show_suggestions) { 909 } else if (!did_show_suggestions) {
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
1051 EncodeFieldForQuery(*field, encompassing_xml_element); 1054 EncodeFieldForQuery(*field, encompassing_xml_element);
1052 break; 1055 break;
1053 case FormStructure::FIELD_ASSIGNMENTS: 1056 case FormStructure::FIELD_ASSIGNMENTS:
1054 EncodeFieldForFieldAssignments(*field, encompassing_xml_element); 1057 EncodeFieldForFieldAssignments(*field, encompassing_xml_element);
1055 break; 1058 break;
1056 } 1059 }
1057 } 1060 }
1058 return true; 1061 return true;
1059 } 1062 }
1060 1063
1061 void FormStructure::ParseFieldTypesFromAutocompleteAttributes( 1064 void FormStructure::ParseFieldTypesFromAutocompleteAttributes() {
1062 bool* found_types,
1063 bool* found_sections) {
1064 const std::string kDefaultSection = "-default"; 1065 const std::string kDefaultSection = "-default";
1065 1066
1066 *found_types = false; 1067 has_author_specified_types_ = false;
1067 *found_sections = false; 1068 has_author_specified_sections_ = false;
1068 for (AutofillField* field : fields_) { 1069 for (AutofillField* field : fields_) {
1069 // To prevent potential section name collisions, add a default suffix for 1070 // To prevent potential section name collisions, add a default suffix for
1070 // other fields. Without this, 'autocomplete' attribute values 1071 // other fields. Without this, 'autocomplete' attribute values
1071 // "section--shipping street-address" and "shipping street-address" would be 1072 // "section--shipping street-address" and "shipping street-address" would be
1072 // parsed identically, given the section handling code below. We do this 1073 // parsed identically, given the section handling code below. We do this
1073 // before any validation so that fields with invalid attributes still end up 1074 // before any validation so that fields with invalid attributes still end up
1074 // in the default section. These default section names will be overridden 1075 // in the default section. These default section names will be overridden
1075 // by subsequent heuristic parsing steps if there are no author-specified 1076 // by subsequent heuristic parsing steps if there are no author-specified
1076 // section names. 1077 // section names.
1077 field->set_section(kDefaultSection); 1078 field->set_section(kDefaultSection);
(...skipping 10 matching lines...) Expand all
1088 if (autocomplete_attribute.empty() || 1089 if (autocomplete_attribute.empty() ||
1089 autocomplete_attribute == "on" || 1090 autocomplete_attribute == "on" ||
1090 autocomplete_attribute == "off") { 1091 autocomplete_attribute == "off") {
1091 continue; 1092 continue;
1092 } 1093 }
1093 1094
1094 // Any other value, even it is invalid, is considered to be a type hint. 1095 // Any other value, even it is invalid, is considered to be a type hint.
1095 // This allows a website's author to specify an attribute like 1096 // This allows a website's author to specify an attribute like
1096 // autocomplete="other" on a field to disable all Autofill heuristics for 1097 // autocomplete="other" on a field to disable all Autofill heuristics for
1097 // the form. 1098 // the form.
1098 *found_types = true; 1099 has_author_specified_types_ = true;
1099 1100
1100 // Tokenize the attribute value. Per the spec, the tokens are parsed in 1101 // Tokenize the attribute value. Per the spec, the tokens are parsed in
1101 // reverse order. 1102 // reverse order.
1102 std::vector<std::string> tokens = base::SplitString( 1103 std::vector<std::string> tokens = base::SplitString(
1103 autocomplete_attribute, " ", base::KEEP_WHITESPACE, 1104 autocomplete_attribute, " ", base::KEEP_WHITESPACE,
1104 base::SPLIT_WANT_NONEMPTY); 1105 base::SPLIT_WANT_NONEMPTY);
1105 1106
1106 // The final token must be the field type. 1107 // The final token must be the field type.
1107 // If it is not one of the known types, abort. 1108 // If it is not one of the known types, abort.
1108 DCHECK(!tokens.empty()); 1109 DCHECK(!tokens.empty());
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1151 // Prepend this section name to the suffix set in the preceding block. 1152 // Prepend this section name to the suffix set in the preceding block.
1152 section = tokens.back().substr(kSectionPrefix.size()) + section; 1153 section = tokens.back().substr(kSectionPrefix.size()) + section;
1153 tokens.pop_back(); 1154 tokens.pop_back();
1154 } 1155 }
1155 1156
1156 // No other tokens are allowed. If there are any remaining, abort. 1157 // No other tokens are allowed. If there are any remaining, abort.
1157 if (!tokens.empty()) 1158 if (!tokens.empty())
1158 continue; 1159 continue;
1159 1160
1160 if (section != kDefaultSection) { 1161 if (section != kDefaultSection) {
1161 *found_sections = true; 1162 has_author_specified_sections_ = true;
1162 field->set_section(section); 1163 field->set_section(section);
1163 } 1164 }
1164 1165
1165 // No errors encountered while parsing! 1166 // No errors encountered while parsing!
1166 // Update the |field|'s type based on what was parsed from the attribute. 1167 // Update the |field|'s type based on what was parsed from the attribute.
1167 field->SetHtmlType(field_type, mode); 1168 field->SetHtmlType(field_type, mode);
1168 } 1169 }
1170
1171 was_parsed_for_autocomplete_attributes_ = true;
1169 } 1172 }
1170 1173
1171 bool FormStructure::FillFields( 1174 bool FormStructure::FillFields(
1172 const std::vector<ServerFieldType>& types, 1175 const std::vector<ServerFieldType>& types,
1173 const InputFieldComparator& matches, 1176 const InputFieldComparator& matches,
1174 const base::Callback<base::string16(const AutofillType&)>& get_info, 1177 const base::Callback<base::string16(const AutofillType&)>& get_info,
1175 const std::string& address_language_code, 1178 const std::string& address_language_code,
1176 const std::string& app_locale) { 1179 const std::string& app_locale) {
1177 bool filled_something = false; 1180 bool filled_something = false;
1178 for (size_t i = 0; i < field_count(); ++i) { 1181 for (size_t i = 0; i < field_count(); ++i) {
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
1307 for (AutofillField* field : fields_) { 1310 for (AutofillField* field : fields_) {
1308 FieldTypeGroup field_type_group = field->Type().group(); 1311 FieldTypeGroup field_type_group = field->Type().group();
1309 if (field_type_group == CREDIT_CARD) 1312 if (field_type_group == CREDIT_CARD)
1310 field->set_section(field->section() + "-cc"); 1313 field->set_section(field->section() + "-cc");
1311 else 1314 else
1312 field->set_section(field->section() + "-default"); 1315 field->set_section(field->section() + "-default");
1313 } 1316 }
1314 } 1317 }
1315 1318
1316 } // namespace autofill 1319 } // namespace autofill
OLDNEW
« no previous file with comments | « components/autofill/core/browser/form_structure.h ('k') | components/autofill/core/browser/form_structure_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698