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

Side by Side Diff: chrome/browser/autofill/form_structure.cc

Issue 11415221: Add support for autofilling radio buttons and checkboxes. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Remove extra line change in autofill_scanner.cc Created 8 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/command_line.h" 10 #include "base/command_line.h"
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 return UNKNOWN_TYPE; 220 return UNKNOWN_TYPE;
221 } 221 }
222 222
223 } // namespace 223 } // namespace
224 224
225 FormStructure::FormStructure(const FormData& form) 225 FormStructure::FormStructure(const FormData& form)
226 : form_name_(form.name), 226 : form_name_(form.name),
227 source_url_(form.origin), 227 source_url_(form.origin),
228 target_url_(form.action), 228 target_url_(form.action),
229 autofill_count_(0), 229 autofill_count_(0),
230 checkable_field_count_(0),
230 upload_required_(USE_UPLOAD_RATES), 231 upload_required_(USE_UPLOAD_RATES),
231 server_experiment_id_("no server response"), 232 server_experiment_id_("no server response"),
232 has_author_specified_types_(false) { 233 has_author_specified_types_(false) {
233 // Copy the form fields. 234 // Copy the form fields.
234 std::map<string16, size_t> unique_names; 235 std::map<string16, size_t> unique_names;
235 for (std::vector<FormFieldData>::const_iterator field = 236 for (std::vector<FormFieldData>::const_iterator field =
236 form.fields.begin(); 237 form.fields.begin();
237 field != form.fields.end(); field++) { 238 field != form.fields.end(); field++) {
238 // Add all supported form fields (including with empty names) to the 239 // Skipping checkable elements when flag is not set, else these fields will
239 // signature. This is a requirement for Autofill servers. 240 // interfere with existing field signatures with Autofill servers.
240 form_signature_field_names_.append("&"); 241 // TODO(ramankk): Add checkable elements only on whitelisted pages
241 form_signature_field_names_.append(UTF16ToUTF8(field->name)); 242 if (!field->is_checkable ||
243 CommandLine::ForCurrentProcess()->HasSwitch(
244 switches::kEnableExperimentalFormFilling)) {
245 // Add all supported form fields (including with empty names) to the
246 // signature. This is a requirement for Autofill servers.
247 form_signature_field_names_.append("&");
248 form_signature_field_names_.append(UTF16ToUTF8(field->name));
249 }
242 250
243 // Generate a unique name for this field by appending a counter to the name. 251 // Generate a unique name for this field by appending a counter to the name.
244 // Make sure to prepend the counter with a non-numeric digit so that we are 252 // Make sure to prepend the counter with a non-numeric digit so that we are
245 // guaranteed to avoid collisions. 253 // guaranteed to avoid collisions.
246 if (!unique_names.count(field->name)) 254 if (!unique_names.count(field->name))
247 unique_names[field->name] = 1; 255 unique_names[field->name] = 1;
248 else 256 else
249 ++unique_names[field->name]; 257 ++unique_names[field->name];
250 string16 unique_name = field->name + ASCIIToUTF16("_") + 258 string16 unique_name = field->name + ASCIIToUTF16("_") +
251 base::IntToString16(unique_names[field->name]); 259 base::IntToString16(unique_names[field->name]);
252 fields_.push_back(new AutofillField(*field, unique_name)); 260 fields_.push_back(new AutofillField(*field, unique_name));
261
262 if (field->is_checkable)
263 ++checkable_field_count_;
253 } 264 }
254 265
255 std::string method = UTF16ToUTF8(form.method); 266 std::string method = UTF16ToUTF8(form.method);
256 if (StringToLowerASCII(method) == kFormMethodPost) { 267 if (StringToLowerASCII(method) == kFormMethodPost) {
257 method_ = POST; 268 method_ = POST;
258 } else { 269 } else {
259 // Either the method is 'get', or we don't know. In this case we default 270 // Either the method is 'get', or we don't know. In this case we default
260 // to GET. 271 // to GET.
261 method_ = GET; 272 method_ = GET;
262 } 273 }
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 return true; 410 return true;
400 } 411 }
401 412
402 // static 413 // static
403 void FormStructure::ParseQueryResponse(const std::string& response_xml, 414 void FormStructure::ParseQueryResponse(const std::string& response_xml,
404 const std::vector<FormStructure*>& forms, 415 const std::vector<FormStructure*>& forms,
405 const AutofillMetrics& metric_logger) { 416 const AutofillMetrics& metric_logger) {
406 metric_logger.LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_RECEIVED); 417 metric_logger.LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_RECEIVED);
407 418
408 // Parse the field types from the server response to the query. 419 // Parse the field types from the server response to the query.
409 std::vector<AutofillFieldType> field_types; 420 std::vector<AutofillServerFieldInfo> field_infos;
410 UploadRequired upload_required; 421 UploadRequired upload_required;
411 std::string experiment_id; 422 std::string experiment_id;
412 AutofillQueryXmlParser parse_handler(&field_types, &upload_required, 423 AutofillQueryXmlParser parse_handler(&field_infos, &upload_required,
413 &experiment_id); 424 &experiment_id);
414 buzz::XmlParser parser(&parse_handler); 425 buzz::XmlParser parser(&parse_handler);
415 parser.Parse(response_xml.c_str(), response_xml.length(), true); 426 parser.Parse(response_xml.c_str(), response_xml.length(), true);
416 if (!parse_handler.succeeded()) 427 if (!parse_handler.succeeded())
417 return; 428 return;
418 429
419 metric_logger.LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_PARSED); 430 metric_logger.LogServerQueryMetric(AutofillMetrics::QUERY_RESPONSE_PARSED);
420 metric_logger.LogServerExperimentIdForQuery(experiment_id); 431 metric_logger.LogServerExperimentIdForQuery(experiment_id);
421 432
422 bool heuristics_detected_fillable_field = false; 433 bool heuristics_detected_fillable_field = false;
423 bool query_response_overrode_heuristics = false; 434 bool query_response_overrode_heuristics = false;
424 435
425 // Copy the field types into the actual form. 436 // Copy the field types into the actual form.
426 std::vector<AutofillFieldType>::iterator current_type = field_types.begin(); 437 std::vector<AutofillServerFieldInfo>::iterator current_info =
438 field_infos.begin();
427 for (std::vector<FormStructure*>::const_iterator iter = forms.begin(); 439 for (std::vector<FormStructure*>::const_iterator iter = forms.begin();
428 iter != forms.end(); ++iter) { 440 iter != forms.end(); ++iter) {
429 FormStructure* form = *iter; 441 FormStructure* form = *iter;
430 form->upload_required_ = upload_required; 442 form->upload_required_ = upload_required;
431 form->server_experiment_id_ = experiment_id; 443 form->server_experiment_id_ = experiment_id;
432 444
433 for (std::vector<AutofillField*>::iterator field = form->fields_.begin(); 445 for (std::vector<AutofillField*>::iterator field = form->fields_.begin();
434 field != form->fields_.end(); ++field, ++current_type) { 446 field != form->fields_.end(); ++field, ++current_info) {
435 // In some cases *successful* response does not return all the fields. 447 // In some cases *successful* response does not return all the fields.
436 // Quit the update of the types then. 448 // Quit the update of the types then.
437 if (current_type == field_types.end()) 449 if (current_info == field_infos.end())
438 break; 450 break;
439 451
440 // UNKNOWN_TYPE is reserved for use by the client. 452 // UNKNOWN_TYPE is reserved for use by the client.
441 DCHECK_NE(*current_type, UNKNOWN_TYPE); 453 DCHECK_NE(current_info->field_type, UNKNOWN_TYPE);
442 454
443 AutofillFieldType heuristic_type = (*field)->type(); 455 AutofillFieldType heuristic_type = (*field)->type();
444 if (heuristic_type != UNKNOWN_TYPE) 456 if (heuristic_type != UNKNOWN_TYPE)
445 heuristics_detected_fillable_field = true; 457 heuristics_detected_fillable_field = true;
446 458
447 (*field)->set_server_type(*current_type); 459 (*field)->set_server_type(current_info->field_type);
448 if (heuristic_type != (*field)->type()) 460 if (heuristic_type != (*field)->type())
449 query_response_overrode_heuristics = true; 461 query_response_overrode_heuristics = true;
462
463 // Copy default value into the field if available.
464 if (!current_info->default_value.empty())
465 (*field)->set_default_value(current_info->default_value);
450 } 466 }
451 467
452 form->UpdateAutofillCount(); 468 form->UpdateAutofillCount();
453 form->IdentifySections(false); 469 form->IdentifySections(false);
454 } 470 }
455 471
456 AutofillMetrics::ServerQueryMetric metric; 472 AutofillMetrics::ServerQueryMetric metric;
457 if (query_response_overrode_heuristics) { 473 if (query_response_overrode_heuristics) {
458 if (heuristics_detected_fillable_field) { 474 if (heuristics_detected_fillable_field) {
459 metric = AutofillMetrics::QUERY_RESPONSE_OVERRODE_LOCAL_HEURISTICS; 475 metric = AutofillMetrics::QUERY_RESPONSE_OVERRODE_LOCAL_HEURISTICS;
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 } 560 }
545 } 561 }
546 562
547 bool FormStructure::ShouldBeParsed(bool require_method_post) const { 563 bool FormStructure::ShouldBeParsed(bool require_method_post) const {
548 // TODO(ramankk): Remove this check once we have better way of identifying the 564 // TODO(ramankk): Remove this check once we have better way of identifying the
549 // cases to trigger experimental form filling. 565 // cases to trigger experimental form filling.
550 if (CommandLine::ForCurrentProcess()->HasSwitch( 566 if (CommandLine::ForCurrentProcess()->HasSwitch(
551 switches::kEnableExperimentalFormFilling)) 567 switches::kEnableExperimentalFormFilling))
552 return true; 568 return true;
553 569
554 if (field_count() < kRequiredFillableFields) 570 // Ignore counting checkable elements towards minimum number of elements
571 // required to parse. This avoids trying to crowdsource forms with few text
572 // or select elements.
Ilya Sherman 2012/12/17 22:33:27 Please add test coverage for this.
Raman Kakilate 2012/12/18 01:54:04 Done.
573 if (field_count() - checkable_field_count() < kRequiredFillableFields)
Ilya Sherman 2012/12/17 22:33:27 nit: Please add parentheses around the difference
Raman Kakilate 2012/12/18 01:54:04 Done.
555 return false; 574 return false;
556 575
557 // Rule out http(s)://*/search?... 576 // Rule out http(s)://*/search?...
558 // e.g. http://www.google.com/search?q=... 577 // e.g. http://www.google.com/search?q=...
559 // http://search.yahoo.com/search?p=... 578 // http://search.yahoo.com/search?p=...
560 if (target_url_.path() == "/search") 579 if (target_url_.path() == "/search")
561 return false; 580 return false;
562 581
563 // Make sure there as at least one text field. 582 // Make sure there as at least one text field.
564 bool has_text_field = false; 583 bool has_text_field = false;
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
806 825
807 AutofillField* FormStructure::field(size_t index) { 826 AutofillField* FormStructure::field(size_t index) {
808 return const_cast<AutofillField*>( 827 return const_cast<AutofillField*>(
809 static_cast<const FormStructure*>(this)->field(index)); 828 static_cast<const FormStructure*>(this)->field(index));
810 } 829 }
811 830
812 size_t FormStructure::field_count() const { 831 size_t FormStructure::field_count() const {
813 return fields_.size(); 832 return fields_.size();
814 } 833 }
815 834
835 size_t FormStructure::checkable_field_count() const {
836 return checkable_field_count_;
837 }
838
816 std::string FormStructure::server_experiment_id() const { 839 std::string FormStructure::server_experiment_id() const {
817 return server_experiment_id_; 840 return server_experiment_id_;
818 } 841 }
819 842
820 FormData FormStructure::ToFormData() const { 843 FormData FormStructure::ToFormData() const {
821 // |data.user_submitted| will always be false. 844 // |data.user_submitted| will always be false.
822 FormData data; 845 FormData data;
823 data.name = form_name_; 846 data.name = form_name_;
824 data.origin = source_url_; 847 data.origin = source_url_;
825 data.action = target_url_; 848 data.action = target_url_;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
877 // Do not send requests for forms with more than this many fields, as they are 900 // Do not send requests for forms with more than this many fields, as they are
878 // near certainly not valid/auto-fillable. 901 // near certainly not valid/auto-fillable.
879 const size_t kMaxFieldsOnTheForm = 48; 902 const size_t kMaxFieldsOnTheForm = 48;
880 if (field_count() > kMaxFieldsOnTheForm) 903 if (field_count() > kMaxFieldsOnTheForm)
881 return false; 904 return false;
882 905
883 // Add the child nodes for the form fields. 906 // Add the child nodes for the form fields.
884 for (size_t index = 0; index < field_count(); ++index) { 907 for (size_t index = 0; index < field_count(); ++index) {
885 const AutofillField* field = fields_[index]; 908 const AutofillField* field = fields_[index];
886 if (request_type == FormStructure::UPLOAD) { 909 if (request_type == FormStructure::UPLOAD) {
910 // Don't upload checkable fields.
911 if (field->is_checkable)
912 continue;
913
887 FieldTypeSet types = field->possible_types(); 914 FieldTypeSet types = field->possible_types();
888 // |types| could be empty in unit-tests only. 915 // |types| could be empty in unit-tests only.
889 for (FieldTypeSet::iterator field_type = types.begin(); 916 for (FieldTypeSet::iterator field_type = types.begin();
890 field_type != types.end(); ++field_type) { 917 field_type != types.end(); ++field_type) {
891 buzz::XmlElement *field_element = new buzz::XmlElement( 918 buzz::XmlElement *field_element = new buzz::XmlElement(
892 buzz::QName(kXMLElementField)); 919 buzz::QName(kXMLElementField));
893 920
894 field_element->SetAttr(buzz::QName(kAttributeSignature), 921 field_element->SetAttr(buzz::QName(kAttributeSignature),
895 field->FieldSignature()); 922 field->FieldSignature());
896 field_element->SetAttr(buzz::QName(kAttributeAutofillType), 923 field_element->SetAttr(buzz::QName(kAttributeAutofillType),
897 base::IntToString(*field_type)); 924 base::IntToString(*field_type));
898 encompassing_xml_element->AddElement(field_element); 925 encompassing_xml_element->AddElement(field_element);
899 } 926 }
900 } else { 927 } else {
928 // Skip putting checkable fields in the request if the flag is not set.
929 if (field->is_checkable &&
930 !CommandLine::ForCurrentProcess()->HasSwitch(
931 switches::kEnableExperimentalFormFilling))
932 continue;
933
901 buzz::XmlElement *field_element = new buzz::XmlElement( 934 buzz::XmlElement *field_element = new buzz::XmlElement(
902 buzz::QName(kXMLElementField)); 935 buzz::QName(kXMLElementField));
903 field_element->SetAttr(buzz::QName(kAttributeSignature), 936 field_element->SetAttr(buzz::QName(kAttributeSignature),
904 field->FieldSignature()); 937 field->FieldSignature());
905 encompassing_xml_element->AddElement(field_element); 938 encompassing_xml_element->AddElement(field_element);
906 } 939 }
907 } 940 }
908 return true; 941 return true;
909 } 942 }
910 943
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
1071 for (std::vector<AutofillField*>::iterator field = fields_.begin(); 1104 for (std::vector<AutofillField*>::iterator field = fields_.begin();
1072 field != fields_.end(); ++field) { 1105 field != fields_.end(); ++field) {
1073 AutofillType::FieldTypeGroup field_type_group = 1106 AutofillType::FieldTypeGroup field_type_group =
1074 AutofillType((*field)->type()).group(); 1107 AutofillType((*field)->type()).group();
1075 if (field_type_group == AutofillType::CREDIT_CARD) 1108 if (field_type_group == AutofillType::CREDIT_CARD)
1076 (*field)->set_section((*field)->section() + "-cc"); 1109 (*field)->set_section((*field)->section() + "-cc");
1077 else 1110 else
1078 (*field)->set_section((*field)->section() + "-default"); 1111 (*field)->set_section((*field)->section() + "-default");
1079 } 1112 }
1080 } 1113 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698