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

Side by Side Diff: chrome/renderer/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 format errors. Created 9 years, 11 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/form_manager.h" 5 #include "chrome/renderer/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 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 // For select-one elements copy option strings. 266 // For select-one elements copy option strings.
267 WebVector<WebElement> list_items = select_element.listItems(); 267 WebVector<WebElement> list_items = select_element.listItems();
268 option_strings->reserve(list_items.size()); 268 option_strings->reserve(list_items.size());
269 for (size_t i = 0; i < list_items.size(); ++i) { 269 for (size_t i = 0; i < list_items.size(); ++i) {
270 if (list_items[i].hasTagName("option")) 270 if (list_items[i].hasTagName("option"))
271 option_strings->push_back(list_items[i].to<WebOptionElement>().value()); 271 option_strings->push_back(list_items[i].to<WebOptionElement>().value());
272 } 272 }
273 } 273 }
274 } 274 }
275 275
276 // In HTML5, all text fields except password are text input fields to
277 // autocomplete.
278 static bool IsTextInput(const WebInputElement* element) {
Ilya Sherman 2011/01/28 08:15:52 nit: Just noticed: no need for "static" here, as i
honten.org 2011/01/29 03:43:30 Done.
279 if (!element)
280 return false;
281
282 return element->isTextField() && !element->isPasswordField();
283 }
284
276 } // namespace 285 } // namespace
277 286
278 struct FormManager::FormElement { 287 struct FormManager::FormElement {
279 WebKit::WebFormElement form_element; 288 WebKit::WebFormElement form_element;
280 std::vector<WebKit::WebFormControlElement> control_elements; 289 std::vector<WebKit::WebFormControlElement> control_elements;
281 std::vector<string16> control_values; 290 std::vector<string16> control_values;
282 }; 291 };
283 292
284 FormManager::FormManager() { 293 FormManager::FormManager() {
285 } 294 }
(...skipping 15 matching lines...) Expand all
301 field->set_name(element.nameForAutofill()); 310 field->set_name(element.nameForAutofill());
302 field->set_form_control_type(element.formControlType()); 311 field->set_form_control_type(element.formControlType());
303 312
304 if (extract_mask & EXTRACT_OPTIONS) { 313 if (extract_mask & EXTRACT_OPTIONS) {
305 // Set option strings on the field if available. 314 // Set option strings on the field if available.
306 std::vector<string16> option_strings; 315 std::vector<string16> option_strings;
307 GetOptionStringsFromElement(element, &option_strings); 316 GetOptionStringsFromElement(element, &option_strings);
308 field->set_option_strings(option_strings); 317 field->set_option_strings(option_strings);
309 } 318 }
310 319
311 if (element.formControlType() == WebString::fromUTF8("text")) { 320 const WebInputElement* input_element =
312 const WebInputElement& input_element = element.toConst<WebInputElement>(); 321 WebInputElement::toWebInputElement(&element);
313 field->set_max_length(input_element.maxLength()); 322 if (IsTextInput(input_element)) {
314 field->set_autofilled(input_element.isAutofilled()); 323 field->set_max_length(input_element->maxLength());
324 field->set_autofilled(input_element->isAutofilled());
315 } 325 }
316 326
317 if (!(extract_mask & EXTRACT_VALUE)) 327 if (!(extract_mask & EXTRACT_VALUE))
318 return; 328 return;
319 329
320 // TODO(jhawkins): In WebKit, move value() and setValue() to 330 // TODO(jhawkins): In WebKit, move value() and setValue() to
321 // WebFormControlElement. 331 // WebFormControlElement.
322 string16 value; 332 string16 value;
323 if (element.formControlType() == WebString::fromUTF8("text") || 333 if (IsTextInput(input_element) ||
324 element.formControlType() == WebString::fromUTF8("hidden")) { 334 element.formControlType() == WebString::fromUTF8("hidden")) {
325 const WebInputElement& input_element = 335 value = input_element->value();
326 element.toConst<WebInputElement>();
327 value = input_element.value();
328 } else if (element.formControlType() == WebString::fromUTF8("select-one")) { 336 } else if (element.formControlType() == WebString::fromUTF8("select-one")) {
329 // TODO(jhawkins): This is ugly. WebSelectElement::value() is a non-const 337 // TODO(jhawkins): This is ugly. WebSelectElement::value() is a non-const
330 // method. Look into fixing this on the WebKit side. 338 // method. Look into fixing this on the WebKit side.
331 WebFormControlElement& e = const_cast<WebFormControlElement&>(element); 339 WebFormControlElement& e = const_cast<WebFormControlElement&>(element);
332 WebSelectElement select_element = e.to<WebSelectElement>(); 340 WebSelectElement select_element = e.to<WebSelectElement>();
333 value = select_element.value(); 341 value = select_element.value();
334 342
335 // Convert the |select_element| value to text if requested. 343 // Convert the |select_element| value to text if requested.
336 if (extract_mask & EXTRACT_OPTION_TEXT) { 344 if (extract_mask & EXTRACT_OPTION_TEXT) {
337 WebVector<WebElement> list_items = select_element.listItems(); 345 WebVector<WebElement> list_items = select_element.listItems();
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 WebVector<WebFormControlElement> control_elements; 418 WebVector<WebFormControlElement> control_elements;
411 element.getFormControlElements(control_elements); 419 element.getFormControlElements(control_elements);
412 420
413 // A vector of bools that indicate whether each field in the form meets the 421 // A vector of bools that indicate whether each field in the form meets the
414 // requirements and thus will be in the resulting |form|. 422 // requirements and thus will be in the resulting |form|.
415 std::vector<bool> fields_extracted(control_elements.size(), false); 423 std::vector<bool> fields_extracted(control_elements.size(), false);
416 424
417 for (size_t i = 0; i < control_elements.size(); ++i) { 425 for (size_t i = 0; i < control_elements.size(); ++i) {
418 const WebFormControlElement& control_element = control_elements[i]; 426 const WebFormControlElement& control_element = control_elements[i];
419 427
428 const WebInputElement* input_element =
429 WebInputElement::toWebInputElement(&control_element);
420 if (requirements & REQUIRE_AUTOCOMPLETE && 430 if (requirements & REQUIRE_AUTOCOMPLETE &&
421 control_element.formControlType() == WebString::fromUTF8("text")) { 431 IsTextInput(input_element) && !input_element->autoComplete())
422 const WebInputElement& input_element = 432 continue;
423 control_element.toConst<WebInputElement>();
424 if (!input_element.autoComplete())
425 continue;
426 }
427 433
428 if (requirements & REQUIRE_ENABLED && !control_element.isEnabled()) 434 if (requirements & REQUIRE_ENABLED && !control_element.isEnabled())
429 continue; 435 continue;
430 436
431 // Create a new FormField, fill it out and map it to the field's name. 437 // Create a new FormField, fill it out and map it to the field's name.
432 FormField* field = new FormField; 438 FormField* field = new FormField;
433 WebFormControlElementToFormField(control_element, extract_mask, field); 439 WebFormControlElementToFormField(control_element, extract_mask, field);
434 form_fields.push_back(field); 440 form_fields.push_back(field);
435 // TODO(jhawkins): A label element is mapped to a form control element's id. 441 // TODO(jhawkins): A label element is mapped to a form control element's id.
436 // field->name() will contain the id only if the name does not exist. Add 442 // field->name() will contain the id only if the name does not exist. Add
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
624 return true; 630 return true;
625 } 631 }
626 632
627 bool FormManager::ClearFormWithNode(const WebNode& node) { 633 bool FormManager::ClearFormWithNode(const WebNode& node) {
628 FormElement* form_element = NULL; 634 FormElement* form_element = NULL;
629 if (!FindCachedFormElementWithNode(node, &form_element)) 635 if (!FindCachedFormElementWithNode(node, &form_element))
630 return false; 636 return false;
631 637
632 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { 638 for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
633 WebFormControlElement element = form_element->control_elements[i]; 639 WebFormControlElement element = form_element->control_elements[i];
634 if (element.formControlType() == WebString::fromUTF8("text")) { 640 WebInputElement* input_element =
635 641 WebInputElement::toWebInputElement(&element);
636 WebInputElement input_element = element.to<WebInputElement>(); 642 if (IsTextInput(input_element)) {
637 643
638 // We don't modify the value of disabled fields. 644 // We don't modify the value of disabled fields.
639 if (!input_element.isEnabled()) 645 if (!input_element->isEnabled())
640 continue; 646 continue;
641 647
642 input_element.setValue(string16()); 648 input_element->setValue(string16());
643 input_element.setAutofilled(false); 649 input_element->setAutofilled(false);
644 650
645 // Clearing the value in the focused node (above) can cause selection 651 // Clearing the value in the focused node (above) can cause selection
646 // to be lost. We force selection range to restore the text cursor. 652 // to be lost. We force selection range to restore the text cursor.
647 if (node == input_element) { 653 if (node == *input_element) {
648 int length = input_element.value().length(); 654 int length = input_element->value().length();
649 input_element.setSelectionRange(length, length); 655 input_element->setSelectionRange(length, length);
650 } 656 }
651 } else if (element.formControlType() == WebString::fromUTF8("select-one")) { 657 } else if (element.formControlType() == WebString::fromUTF8("select-one")) {
652 WebSelectElement select_element = element.to<WebSelectElement>(); 658 WebSelectElement select_element = element.to<WebSelectElement>();
653 select_element.setValue(form_element->control_values[i]); 659 select_element.setValue(form_element->control_values[i]);
654 } 660 }
655 } 661 }
656 662
657 return true; 663 return true;
658 } 664 }
659 665
660 bool FormManager::ClearPreviewedFormWithNode(const WebNode& node, 666 bool FormManager::ClearPreviewedFormWithNode(const WebNode& node,
661 bool was_autofilled) { 667 bool was_autofilled) {
662 FormElement* form_element = NULL; 668 FormElement* form_element = NULL;
663 if (!FindCachedFormElementWithNode(node, &form_element)) 669 if (!FindCachedFormElementWithNode(node, &form_element))
664 return false; 670 return false;
665 671
666 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { 672 for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
667 WebFormControlElement* element = &form_element->control_elements[i]; 673 WebInputElement* input_element =
668 674 WebInputElement::toWebInputElement(&form_element->control_elements[i]);
669 // Only input elements can be previewed. 675 // Only input elements can be previewed.
670 if (element->formControlType() != WebString::fromUTF8("text")) 676 if (!IsTextInput(input_element))
671 continue; 677 continue;
672 678
673 // If the input element has not been auto-filled, FormManager has not 679 // If the input element has not been auto-filled, FormManager has not
674 // previewed this field, so we have nothing to reset. 680 // previewed this field, so we have nothing to reset.
675 WebInputElement input_element = element->to<WebInputElement>(); 681 if (!input_element->isAutofilled())
676 if (!input_element.isAutofilled())
677 continue; 682 continue;
678 683
679 // There might be unrelated elements in this form which have already been 684 // There might be unrelated elements in this form which have already been
680 // auto-filled. For example, the user might have already filled the address 685 // auto-filled. For example, the user might have already filled the address
681 // part of a form and now be dealing with the credit card section. We only 686 // part of a form and now be dealing with the credit card section. We only
682 // want to reset the auto-filled status for fields that were previewed. 687 // want to reset the auto-filled status for fields that were previewed.
683 if (input_element.suggestedValue().isEmpty()) 688 if (input_element->suggestedValue().isEmpty())
684 continue; 689 continue;
685 690
686 // Clear the suggested value. For the initiating node, also restore the 691 // Clear the suggested value. For the initiating node, also restore the
687 // original value. 692 // original value.
688 input_element.setSuggestedValue(WebString()); 693 input_element->setSuggestedValue(WebString());
689 bool is_initiating_node = (node == input_element); 694 bool is_initiating_node = (node == *input_element);
690 if (is_initiating_node) { 695 if (is_initiating_node) {
691 // Call |setValue()| to force the renderer to update the field's displayed 696 // Call |setValue()| to force the renderer to update the field's displayed
692 // value. 697 // value.
693 input_element.setValue(input_element.value()); 698 input_element->setValue(input_element->value());
694 input_element.setAutofilled(was_autofilled); 699 input_element->setAutofilled(was_autofilled);
695 } else { 700 } else {
696 input_element.setAutofilled(false); 701 input_element->setAutofilled(false);
697 } 702 }
698 703
699 // Clearing the suggested value in the focused node (above) can cause 704 // Clearing the suggested value in the focused node (above) can cause
700 // selection to be lost. We force selection range to restore the text 705 // selection to be lost. We force selection range to restore the text
701 // cursor. 706 // cursor.
702 if (is_initiating_node) { 707 if (is_initiating_node) {
703 int length = input_element.value().length(); 708 int length = input_element->value().length();
704 input_element.setSelectionRange(length, length); 709 input_element->setSelectionRange(length, length);
705 } 710 }
706 } 711 }
707 712
708 return true; 713 return true;
709 } 714 }
710 715
711 void FormManager::Reset() { 716 void FormManager::Reset() {
712 STLDeleteElements(&form_elements_); 717 STLDeleteElements(&form_elements_);
713 } 718 }
714 719
715 void FormManager::ResetFrame(const WebFrame* frame) { 720 void FormManager::ResetFrame(const WebFrame* frame) {
716 FormElementList::iterator iter = form_elements_.begin(); 721 FormElementList::iterator iter = form_elements_.begin();
717 while (iter != form_elements_.end()) { 722 while (iter != form_elements_.end()) {
718 if ((*iter)->form_element.document().frame() == frame) { 723 if ((*iter)->form_element.document().frame() == frame) {
719 delete *iter; 724 delete *iter;
720 iter = form_elements_.erase(iter); 725 iter = form_elements_.erase(iter);
721 } else { 726 } else {
722 ++iter; 727 ++iter;
723 } 728 }
724 } 729 }
725 } 730 }
726 731
727 bool FormManager::FormWithNodeIsAutoFilled(const WebNode& node) { 732 bool FormManager::FormWithNodeIsAutoFilled(const WebNode& node) {
728 FormElement* form_element = NULL; 733 FormElement* form_element = NULL;
729 if (!FindCachedFormElementWithNode(node, &form_element)) 734 if (!FindCachedFormElementWithNode(node, &form_element))
730 return false; 735 return false;
731 736
732 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { 737 for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
733 WebFormControlElement element = form_element->control_elements[i]; 738 WebInputElement* input_element =
734 if (element.formControlType() != WebString::fromUTF8("text")) 739 WebInputElement::toWebInputElement(&form_element->control_elements[i]);
740 if (!IsTextInput(input_element))
735 continue; 741 continue;
736 742
737 const WebInputElement& input_element = element.to<WebInputElement>(); 743 if (input_element->isAutofilled())
738 if (input_element.isAutofilled())
739 return true; 744 return true;
740 } 745 }
741 746
742 return false; 747 return false;
743 } 748 }
744 749
745 // static 750 // static
746 string16 FormManager::InferLabelForElement( 751 string16 FormManager::InferLabelForElement(
747 const WebFormControlElement& element) { 752 const WebFormControlElement& element) {
748 // Don't scrape labels for hidden elements. 753 // Don't scrape labels for hidden elements.
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
837 if (k >= data.fields.size()) 842 if (k >= data.fields.size())
838 continue; 843 continue;
839 844
840 DCHECK_EQ(data.fields[k].name(), element_name); 845 DCHECK_EQ(data.fields[k].name(), element_name);
841 846
842 bool is_initiating_node = false; 847 bool is_initiating_node = false;
843 848
844 // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or 849 // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or
845 // REQUIRE_EMPTY, which both require text form control elements, so special- 850 // REQUIRE_EMPTY, which both require text form control elements, so special-
846 // case this type of element. 851 // case this type of element.
847 if (element->formControlType() == WebString::fromUTF8("text")) { 852 const WebInputElement* input_element =
848 const WebInputElement& input_element = 853 WebInputElement::toWebInputElement(element);
849 element->toConst<WebInputElement>(); 854 if (IsTextInput(input_element)) {
850 855
851 // TODO(jhawkins): WebKit currently doesn't handle the autocomplete 856 // TODO(jhawkins): WebKit currently doesn't handle the autocomplete
852 // attribute for select control elements, but it probably should. 857 // attribute for select control elements, but it probably should.
853 if (requirements & REQUIRE_AUTOCOMPLETE && !input_element.autoComplete()) 858 if (requirements & REQUIRE_AUTOCOMPLETE && !input_element->autoComplete())
854 continue; 859 continue;
855 860
856 is_initiating_node = (input_element == node); 861 is_initiating_node = (*input_element == node);
857 // Don't require the node that initiated the auto-fill process to be 862 // Don't require the node that initiated the auto-fill process to be
858 // empty. The user is typing in this field and we should complete the 863 // empty. The user is typing in this field and we should complete the
859 // value when the user selects a value to fill out. 864 // value when the user selects a value to fill out.
860 if (requirements & REQUIRE_EMPTY && 865 if (requirements & REQUIRE_EMPTY &&
861 !is_initiating_node && 866 !is_initiating_node &&
862 !input_element.value().isEmpty()) 867 !input_element->value().isEmpty())
863 continue; 868 continue;
864 } 869 }
865 870
866 if (requirements & REQUIRE_ENABLED && !element->isEnabled()) 871 if (requirements & REQUIRE_ENABLED && !element->isEnabled())
867 continue; 872 continue;
868 873
869 callback->Run(element, &data.fields[k], is_initiating_node); 874 callback->Run(element, &data.fields[k], is_initiating_node);
870 875
871 // We found a matching form field so move on to the next. 876 // We found a matching form field so move on to the next.
872 ++j; 877 ++j;
873 } 878 }
874 879
875 delete callback; 880 delete callback;
876 } 881 }
877 882
878 void FormManager::FillFormField(WebFormControlElement* field, 883 void FormManager::FillFormField(WebFormControlElement* field,
879 const FormField* data, 884 const FormField* data,
880 bool is_initiating_node) { 885 bool is_initiating_node) {
881 // Nothing to fill. 886 // Nothing to fill.
882 if (data->value().empty()) 887 if (data->value().empty())
883 return; 888 return;
884 889
885 if (field->formControlType() == WebString::fromUTF8("text")) { 890 WebInputElement* input_element = WebInputElement::toWebInputElement(field);
886 WebInputElement input_element = field->to<WebInputElement>(); 891 if (IsTextInput(input_element)) {
887 892
888 // If the maxlength attribute contains a negative value, maxLength() 893 // If the maxlength attribute contains a negative value, maxLength()
889 // returns the default maxlength value. 894 // returns the default maxlength value.
890 input_element.setValue(data->value().substr(0, input_element.maxLength())); 895 input_element->setValue(
891 input_element.setAutofilled(true); 896 data->value().substr(0, input_element->maxLength()));
897 input_element->setAutofilled(true);
892 if (is_initiating_node) { 898 if (is_initiating_node) {
893 int length = input_element.value().length(); 899 int length = input_element->value().length();
894 input_element.setSelectionRange(length, length); 900 input_element->setSelectionRange(length, length);
895 } 901 }
896 } else if (field->formControlType() == WebString::fromUTF8("select-one")) { 902 } else if (field->formControlType() == WebString::fromUTF8("select-one")) {
897 WebSelectElement select_element = field->to<WebSelectElement>(); 903 WebSelectElement select_element = field->to<WebSelectElement>();
898 select_element.setValue(data->value()); 904 select_element.setValue(data->value());
899 } 905 }
900 } 906 }
901 907
902 void FormManager::PreviewFormField(WebFormControlElement* field, 908 void FormManager::PreviewFormField(WebFormControlElement* field,
903 const FormField* data, 909 const FormField* data,
904 bool is_initiating_node) { 910 bool is_initiating_node) {
905 // Nothing to preview. 911 // Nothing to preview.
906 if (data->value().empty()) 912 if (data->value().empty())
907 return; 913 return;
908 914
909 // Only preview input fields. 915 // Only preview input fields.
910 if (field->formControlType() != WebString::fromUTF8("text")) 916 WebInputElement* input_element = WebInputElement::toWebInputElement(field);
917 if (!IsTextInput(input_element))
911 return; 918 return;
912 919
913 WebInputElement input_element = field->to<WebInputElement>();
914
915 // If the maxlength attribute contains a negative value, maxLength() 920 // If the maxlength attribute contains a negative value, maxLength()
916 // returns the default maxlength value. 921 // returns the default maxlength value.
917 input_element.setSuggestedValue( 922 input_element->setSuggestedValue(
918 data->value().substr(0, input_element.maxLength())); 923 data->value().substr(0, input_element->maxLength()));
919 input_element.setAutofilled(true); 924 input_element->setAutofilled(true);
920 if (is_initiating_node) 925 if (is_initiating_node)
921 input_element.setSelectionRange(0, input_element.suggestedValue().length()); 926 input_element->setSelectionRange(0,
927 input_element->suggestedValue().length());
922 } 928 }
OLDNEW
« no previous file with comments | « chrome/browser/autofill/personal_data_manager.cc ('k') | chrome/renderer/form_manager_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698