OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |