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

Side by Side Diff: chrome/renderer/autofill/form_manager.cc

Issue 6033010: Support autocompletion for HTMl5 tags:"email", "month" and "tel". (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Fix merge error. Created 9 years, 10 months 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/renderer/autofill/form_manager.h" 5 #include "chrome/renderer/autofill/form_manager.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/scoped_vector.h" 8 #include "base/scoped_vector.h"
9 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "base/stl_util-inl.h" 10 #include "base/stl_util-inl.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 45
46 // The number of fields required by AutoFill. Ideally we could send the forms 46 // The number of fields required by AutoFill. Ideally we could send the forms
47 // to AutoFill no matter how many fields are in the forms; however, finding the 47 // to AutoFill no matter how many fields are in the forms; however, finding the
48 // label for each field is a costly operation and we can't spare the cycles if 48 // label for each field is a costly operation and we can't spare the cycles if
49 // it's not necessary. 49 // it's not necessary.
50 const size_t kRequiredAutoFillFields = 3; 50 const size_t kRequiredAutoFillFields = 3;
51 51
52 // The maximum length allowed for form data. 52 // The maximum length allowed for form data.
53 const size_t kMaxDataLength = 1024; 53 const size_t kMaxDataLength = 1024;
54 54
55 // TODO(isherman): Replace calls to this with IsTextInput() once 55 // In HTML5, all text fields except password are text input fields to
56 // http://codereview.chromium.org/6033010/ lands. 56 // autocomplete.
57 bool IsTextElement(const WebFormControlElement& element) { 57 bool IsTextInput(const WebInputElement* element) {
58 return element.formControlType() == WebString::fromUTF8("text"); 58 if (!element)
59 return false;
60
61 return element->isTextField() && !element->isPasswordField();
59 } 62 }
60 63
61 bool IsSelectElement(const WebFormControlElement& element) { 64 bool IsSelectElement(const WebFormControlElement& element) {
62 return element.formControlType() == ASCIIToUTF16("select-one"); 65 return element.formControlType() == ASCIIToUTF16("select-one");
63 } 66 }
64 67
65 bool IsOptionElement(const WebElement& element) { 68 bool IsOptionElement(const WebElement& element) {
66 return element.hasTagName("option"); 69 return element.hasTagName("option");
67 } 70 }
68 71
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 ExtractMask extract_mask, 331 ExtractMask extract_mask,
329 FormField* field) { 332 FormField* field) {
330 DCHECK(field); 333 DCHECK(field);
331 334
332 // The label is not officially part of a WebFormControlElement; however, the 335 // The label is not officially part of a WebFormControlElement; however, the
333 // labels for all form control elements are scraped from the DOM and set in 336 // labels for all form control elements are scraped from the DOM and set in
334 // WebFormElementToFormData. 337 // WebFormElementToFormData.
335 field->set_name(element.nameForAutofill()); 338 field->set_name(element.nameForAutofill());
336 field->set_form_control_type(element.formControlType()); 339 field->set_form_control_type(element.formControlType());
337 340
338 if (IsTextElement(element)) { 341 const WebInputElement* input_element = toWebInputElement(&element);
342 if (IsTextInput(input_element)) {
339 const WebInputElement& input_element = element.toConst<WebInputElement>(); 343 const WebInputElement& input_element = element.toConst<WebInputElement>();
340 field->set_max_length(input_element.maxLength()); 344 field->set_max_length(input_element.maxLength());
341 field->set_autofilled(input_element.isAutofilled()); 345 field->set_autofilled(input_element.isAutofilled());
342 } else if (extract_mask & EXTRACT_OPTIONS) { 346 } else if (extract_mask & EXTRACT_OPTIONS) {
343 // Set option strings on the field if available. 347 // Set option strings on the field if available.
344 std::vector<string16> option_strings; 348 std::vector<string16> option_strings;
345 GetOptionStringsFromElement(element, &option_strings); 349 GetOptionStringsFromElement(element, &option_strings);
346 field->set_option_strings(option_strings); 350 field->set_option_strings(option_strings);
347 } 351 }
348 352
349 if (!(extract_mask & EXTRACT_VALUE)) 353 if (!(extract_mask & EXTRACT_VALUE))
350 return; 354 return;
351 355
352 string16 value; 356 string16 value;
353 if (IsTextElement(element) || 357 if (IsTextInput(input_element) ||
354 element.formControlType() == WebString::fromUTF8("hidden")) { 358 element.formControlType() == WebString::fromUTF8("hidden")) {
355 const WebInputElement& input_element = element.toConst<WebInputElement>(); 359 value = input_element->value();
356 value = input_element.value();
357 } else if (IsSelectElement(element)) { 360 } else if (IsSelectElement(element)) {
358 const WebSelectElement select_element = element.toConst<WebSelectElement>(); 361 const WebSelectElement select_element = element.toConst<WebSelectElement>();
359 value = select_element.value(); 362 value = select_element.value();
360 363
361 // Convert the |select_element| value to text if requested. 364 // Convert the |select_element| value to text if requested.
362 if (extract_mask & EXTRACT_OPTION_TEXT) { 365 if (extract_mask & EXTRACT_OPTION_TEXT) {
363 WebVector<WebElement> list_items = select_element.listItems(); 366 WebVector<WebElement> list_items = select_element.listItems();
364 for (size_t i = 0; i < list_items.size(); ++i) { 367 for (size_t i = 0; i < list_items.size(); ++i) {
365 if (IsOptionElement(list_items[i])) { 368 if (IsOptionElement(list_items[i])) {
366 const WebOptionElement option_element = 369 const WebOptionElement option_element =
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
437 WebVector<WebFormControlElement> control_elements; 440 WebVector<WebFormControlElement> control_elements;
438 element.getFormControlElements(control_elements); 441 element.getFormControlElements(control_elements);
439 442
440 // A vector of bools that indicate whether each field in the form meets the 443 // A vector of bools that indicate whether each field in the form meets the
441 // requirements and thus will be in the resulting |form|. 444 // requirements and thus will be in the resulting |form|.
442 std::vector<bool> fields_extracted(control_elements.size(), false); 445 std::vector<bool> fields_extracted(control_elements.size(), false);
443 446
444 for (size_t i = 0; i < control_elements.size(); ++i) { 447 for (size_t i = 0; i < control_elements.size(); ++i) {
445 const WebFormControlElement& control_element = control_elements[i]; 448 const WebFormControlElement& control_element = control_elements[i];
446 449
447 if (requirements & REQUIRE_AUTOCOMPLETE && IsTextElement(control_element)) { 450 const WebInputElement* input_element = toWebInputElement(&control_element);
448 const WebInputElement& input_element = 451 if (requirements & REQUIRE_AUTOCOMPLETE && IsTextInput(input_element) &&
449 control_element.toConst<WebInputElement>(); 452 !input_element->autoComplete())
450 if (!input_element.autoComplete()) 453 continue;
451 continue;
452 }
453 454
454 if (requirements & REQUIRE_ENABLED && !control_element.isEnabled()) 455 if (requirements & REQUIRE_ENABLED && !control_element.isEnabled())
455 continue; 456 continue;
456 457
457 // Create a new FormField, fill it out and map it to the field's name. 458 // Create a new FormField, fill it out and map it to the field's name.
458 FormField* field = new FormField; 459 FormField* field = new FormField;
459 WebFormControlElementToFormField(control_element, extract_mask, field); 460 WebFormControlElementToFormField(control_element, extract_mask, field);
460 form_fields.push_back(field); 461 form_fields.push_back(field);
461 // TODO(jhawkins): A label element is mapped to a form control element's id. 462 // TODO(jhawkins): A label element is mapped to a form control element's id.
462 // field->name() will contain the id only if the name does not exist. Add 463 // field->name() will contain the id only if the name does not exist. Add
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
647 return true; 648 return true;
648 } 649 }
649 650
650 bool FormManager::ClearFormWithNode(const WebNode& node) { 651 bool FormManager::ClearFormWithNode(const WebNode& node) {
651 FormElement* form_element = NULL; 652 FormElement* form_element = NULL;
652 if (!FindCachedFormElementWithNode(node, &form_element)) 653 if (!FindCachedFormElementWithNode(node, &form_element))
653 return false; 654 return false;
654 655
655 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { 656 for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
656 WebFormControlElement element = form_element->control_elements[i]; 657 WebFormControlElement element = form_element->control_elements[i];
657 if (IsTextElement(element)) { 658 WebInputElement* input_element = toWebInputElement(&element);
658 WebInputElement input_element = element.to<WebInputElement>(); 659 if (IsTextInput(input_element)) {
659 660
660 // We don't modify the value of disabled fields. 661 // We don't modify the value of disabled fields.
661 if (!input_element.isEnabled()) 662 if (!input_element->isEnabled())
662 continue; 663 continue;
663 664
664 input_element.setValue(string16()); 665 input_element->setValue(string16());
665 input_element.setAutofilled(false); 666 input_element->setAutofilled(false);
666 667
667 // Clearing the value in the focused node (above) can cause selection 668 // Clearing the value in the focused node (above) can cause selection
668 // to be lost. We force selection range to restore the text cursor. 669 // to be lost. We force selection range to restore the text cursor.
669 if (node == input_element) { 670 if (node == *input_element) {
670 int length = input_element.value().length(); 671 int length = input_element->value().length();
671 input_element.setSelectionRange(length, length); 672 input_element->setSelectionRange(length, length);
672 } 673 }
673 } else if (IsSelectElement(element)) { 674 } else if (IsSelectElement(element)) {
674 WebSelectElement select_element = element.to<WebSelectElement>(); 675 WebSelectElement select_element = element.to<WebSelectElement>();
675 select_element.setValue(form_element->control_values[i]); 676 select_element.setValue(form_element->control_values[i]);
676 } 677 }
677 } 678 }
678 679
679 return true; 680 return true;
680 } 681 }
681 682
682 bool FormManager::ClearPreviewedFormWithNode(const WebNode& node, 683 bool FormManager::ClearPreviewedFormWithNode(const WebNode& node,
683 bool was_autofilled) { 684 bool was_autofilled) {
684 FormElement* form_element = NULL; 685 FormElement* form_element = NULL;
685 if (!FindCachedFormElementWithNode(node, &form_element)) 686 if (!FindCachedFormElementWithNode(node, &form_element))
686 return false; 687 return false;
687 688
688 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { 689 for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
689 WebFormControlElement* element = &form_element->control_elements[i]; 690 WebInputElement* input_element =
690 691 toWebInputElement(&form_element->control_elements[i]);
691 // Only text input elements can be previewed. 692 // Only text input elements can be previewed.
692 if (!IsTextElement(*element)) 693 if (!IsTextInput(input_element))
693 continue; 694 continue;
694 695
695 // If the input element has not been auto-filled, FormManager has not 696 // If the input element has not been auto-filled, FormManager has not
696 // previewed this field, so we have nothing to reset. 697 // previewed this field, so we have nothing to reset.
697 WebInputElement input_element = element->to<WebInputElement>(); 698 if (!input_element->isAutofilled())
698 if (!input_element.isAutofilled())
699 continue; 699 continue;
700 700
701 // There might be unrelated elements in this form which have already been 701 // There might be unrelated elements in this form which have already been
702 // auto-filled. For example, the user might have already filled the address 702 // auto-filled. For example, the user might have already filled the address
703 // part of a form and now be dealing with the credit card section. We only 703 // part of a form and now be dealing with the credit card section. We only
704 // want to reset the auto-filled status for fields that were previewed. 704 // want to reset the auto-filled status for fields that were previewed.
705 if (input_element.suggestedValue().isEmpty()) 705 if (input_element->suggestedValue().isEmpty())
706 continue; 706 continue;
707 707
708 // Clear the suggested value. For the initiating node, also restore the 708 // Clear the suggested value. For the initiating node, also restore the
709 // original value. 709 // original value.
710 input_element.setSuggestedValue(WebString()); 710 input_element->setSuggestedValue(WebString());
711 bool is_initiating_node = (node == input_element); 711 bool is_initiating_node = (node == *input_element);
712 if (is_initiating_node) { 712 if (is_initiating_node) {
713 // Call |setValue()| to force the renderer to update the field's displayed 713 // Call |setValue()| to force the renderer to update the field's displayed
714 // value. 714 // value.
715 input_element.setValue(input_element.value()); 715 input_element->setValue(input_element->value());
716 input_element.setAutofilled(was_autofilled); 716 input_element->setAutofilled(was_autofilled);
717 } else { 717 } else {
718 input_element.setAutofilled(false); 718 input_element->setAutofilled(false);
719 } 719 }
720 720
721 // Clearing the suggested value in the focused node (above) can cause 721 // Clearing the suggested value in the focused node (above) can cause
722 // selection to be lost. We force selection range to restore the text 722 // selection to be lost. We force selection range to restore the text
723 // cursor. 723 // cursor.
724 if (is_initiating_node) { 724 if (is_initiating_node) {
725 int length = input_element.value().length(); 725 int length = input_element->value().length();
726 input_element.setSelectionRange(length, length); 726 input_element->setSelectionRange(length, length);
727 } 727 }
728 } 728 }
729 729
730 return true; 730 return true;
731 } 731 }
732 732
733 void FormManager::Reset() { 733 void FormManager::Reset() {
734 form_elements_.reset(); 734 form_elements_.reset();
735 } 735 }
736 736
737 void FormManager::ResetFrame(const WebFrame* frame) { 737 void FormManager::ResetFrame(const WebFrame* frame) {
738 FormElementList::iterator iter = form_elements_.begin(); 738 FormElementList::iterator iter = form_elements_.begin();
739 while (iter != form_elements_.end()) { 739 while (iter != form_elements_.end()) {
740 if ((*iter)->form_element.document().frame() == frame) 740 if ((*iter)->form_element.document().frame() == frame)
741 iter = form_elements_.erase(iter); 741 iter = form_elements_.erase(iter);
742 else 742 else
743 ++iter; 743 ++iter;
744 } 744 }
745 } 745 }
746 746
747 bool FormManager::FormWithNodeIsAutoFilled(const WebNode& node) { 747 bool FormManager::FormWithNodeIsAutoFilled(const WebNode& node) {
748 FormElement* form_element = NULL; 748 FormElement* form_element = NULL;
749 if (!FindCachedFormElementWithNode(node, &form_element)) 749 if (!FindCachedFormElementWithNode(node, &form_element))
750 return false; 750 return false;
751 751
752 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { 752 for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
753 WebFormControlElement element = form_element->control_elements[i]; 753 WebInputElement* input_element =
754 if (!IsTextElement(element)) 754 toWebInputElement(&form_element->control_elements[i]);
755 if (!IsTextInput(input_element))
755 continue; 756 continue;
756 757
757 const WebInputElement& input_element = element.to<WebInputElement>(); 758 if (input_element->isAutofilled())
758 if (input_element.isAutofilled())
759 return true; 759 return true;
760 } 760 }
761 761
762 return false; 762 return false;
763 } 763 }
764 764
765 bool FormManager::FindCachedFormElementWithNode(const WebNode& node, 765 bool FormManager::FindCachedFormElementWithNode(const WebNode& node,
766 FormElement** form_element) { 766 FormElement** form_element) {
767 for (FormElementList::const_iterator form_iter = form_elements_.begin(); 767 for (FormElementList::const_iterator form_iter = form_elements_.begin();
768 form_iter != form_elements_.end(); ++form_iter) { 768 form_iter != form_elements_.end(); ++form_iter) {
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
829 if (k >= data.fields.size()) 829 if (k >= data.fields.size())
830 continue; 830 continue;
831 831
832 DCHECK_EQ(data.fields[k].name(), element_name); 832 DCHECK_EQ(data.fields[k].name(), element_name);
833 833
834 bool is_initiating_node = false; 834 bool is_initiating_node = false;
835 835
836 // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or 836 // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or
837 // REQUIRE_EMPTY, which both require text form control elements, so special- 837 // REQUIRE_EMPTY, which both require text form control elements, so special-
838 // case this type of element. 838 // case this type of element.
839 if (IsTextElement(*element)) { 839 const WebInputElement* input_element = toWebInputElement(element);
840 const WebInputElement& input_element = 840 if (IsTextInput(input_element)) {
841 element->toConst<WebInputElement>();
842 841
843 // TODO(jhawkins): WebKit currently doesn't handle the autocomplete 842 // TODO(jhawkins): WebKit currently doesn't handle the autocomplete
844 // attribute for select control elements, but it probably should. 843 // attribute for select control elements, but it probably should.
845 if (requirements & REQUIRE_AUTOCOMPLETE && !input_element.autoComplete()) 844 if (requirements & REQUIRE_AUTOCOMPLETE && !input_element->autoComplete())
846 continue; 845 continue;
847 846
848 is_initiating_node = (input_element == node); 847 is_initiating_node = (*input_element == node);
849 // Don't require the node that initiated the auto-fill process to be 848 // Don't require the node that initiated the auto-fill process to be
850 // empty. The user is typing in this field and we should complete the 849 // empty. The user is typing in this field and we should complete the
851 // value when the user selects a value to fill out. 850 // value when the user selects a value to fill out.
852 if (requirements & REQUIRE_EMPTY && 851 if (requirements & REQUIRE_EMPTY &&
853 !is_initiating_node && 852 !is_initiating_node &&
854 !input_element.value().isEmpty()) 853 !input_element->value().isEmpty())
855 continue; 854 continue;
856 } 855 }
857 856
858 if (requirements & REQUIRE_ENABLED && !element->isEnabled()) 857 if (requirements & REQUIRE_ENABLED && !element->isEnabled())
859 continue; 858 continue;
860 859
861 callback->Run(element, &data.fields[k], is_initiating_node); 860 callback->Run(element, &data.fields[k], is_initiating_node);
862 861
863 // We found a matching form field so move on to the next. 862 // We found a matching form field so move on to the next.
864 ++j; 863 ++j;
865 } 864 }
866 865
867 delete callback; 866 delete callback;
868 } 867 }
869 868
870 void FormManager::FillFormField(WebFormControlElement* field, 869 void FormManager::FillFormField(WebFormControlElement* field,
871 const FormField* data, 870 const FormField* data,
872 bool is_initiating_node) { 871 bool is_initiating_node) {
873 // Nothing to fill. 872 // Nothing to fill.
874 if (data->value().empty()) 873 if (data->value().empty())
875 return; 874 return;
876 875
877 if (IsTextElement(*field)) { 876 WebInputElement* input_element = toWebInputElement(field);
878 WebInputElement input_element = field->to<WebInputElement>(); 877 if (IsTextInput(input_element)) {
879 878
880 // If the maxlength attribute contains a negative value, maxLength() 879 // If the maxlength attribute contains a negative value, maxLength()
881 // returns the default maxlength value. 880 // returns the default maxlength value.
882 input_element.setValue(data->value().substr(0, input_element.maxLength())); 881 input_element->setValue(
883 input_element.setAutofilled(true); 882 data->value().substr(0, input_element->maxLength()));
883 input_element->setAutofilled(true);
884 if (is_initiating_node) { 884 if (is_initiating_node) {
885 int length = input_element.value().length(); 885 int length = input_element->value().length();
886 input_element.setSelectionRange(length, length); 886 input_element->setSelectionRange(length, length);
887 } 887 }
888 } else if (IsSelectElement(*field)) { 888 } else if (IsSelectElement(*field)) {
889 WebSelectElement select_element = field->to<WebSelectElement>(); 889 WebSelectElement select_element = field->to<WebSelectElement>();
890 select_element.setValue(data->value()); 890 select_element.setValue(data->value());
891 } 891 }
892 } 892 }
893 893
894 void FormManager::PreviewFormField(WebFormControlElement* field, 894 void FormManager::PreviewFormField(WebFormControlElement* field,
895 const FormField* data, 895 const FormField* data,
896 bool is_initiating_node) { 896 bool is_initiating_node) {
897 // Nothing to preview. 897 // Nothing to preview.
898 if (data->value().empty()) 898 if (data->value().empty())
899 return; 899 return;
900 900
901 // Only preview input fields. 901 // Only preview input fields.
902 if (!IsTextElement(*field)) 902 WebInputElement* input_element = toWebInputElement(field);
903 if (!IsTextInput(input_element))
903 return; 904 return;
904 905
905 WebInputElement input_element = field->to<WebInputElement>();
906
907 // If the maxlength attribute contains a negative value, maxLength() 906 // If the maxlength attribute contains a negative value, maxLength()
908 // returns the default maxlength value. 907 // returns the default maxlength value.
909 input_element.setSuggestedValue( 908 input_element->setSuggestedValue(
910 data->value().substr(0, input_element.maxLength())); 909 data->value().substr(0, input_element->maxLength()));
911 input_element.setAutofilled(true); 910 input_element->setAutofilled(true);
912 if (is_initiating_node) 911 if (is_initiating_node)
913 input_element.setSelectionRange(0, input_element.suggestedValue().length()); 912 input_element->setSelectionRange(0,
913 input_element->suggestedValue().length());
914 } 914 }
915 915
916 } // namespace autofill 916 } // namespace autofill
OLDNEW
« no previous file with comments | « chrome/browser/autofill/personal_data_manager.cc ('k') | chrome/renderer/autofill/form_manager_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698