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

Side by Side Diff: components/autofill/content/renderer/form_autofill_util.cc

Issue 140093005: Add supports that allow Autofill to be initiated from textarea field (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update code as per review comments Created 6 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
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/content/renderer/form_autofill_util.h" 5 #include "components/autofill/content/renderer/form_autofill_util.h"
6 6
7 #include <map> 7 #include <map>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 431
432 // If we didn't find a label, check for definition list case. 432 // If we didn't find a label, check for definition list case.
433 inferred_label = InferLabelFromDefinitionList(element); 433 inferred_label = InferLabelFromDefinitionList(element);
434 if (!inferred_label.empty()) 434 if (!inferred_label.empty())
435 return inferred_label; 435 return inferred_label;
436 436
437 // If we didn't find a label, check for div table case. 437 // If we didn't find a label, check for div table case.
438 return InferLabelFromDivTable(element); 438 return InferLabelFromDivTable(element);
439 } 439 }
440 440
441 void HandleInitiatingNode(WebFormControlElement& element, bool preview) {
Ilya Sherman 2014/02/22 06:24:20 nit: Pass-by-reference is almost entirely disallow
442 WebInputElement* input_element = toWebInputElement(&element);
443 if (!IsTextInput(input_element) &&
444 !IsMonthInput(input_element) &&
445 !IsTextAreaElement(element))
446 return;
447
448 if (IsTextInput(input_element) || IsMonthInput(input_element)) {
449 if (preview) {
450 input_element->setSelectionRange(
451 input_element->value().length(),
452 input_element->suggestedValue().length());
453 } else {
454 input_element->setSelectionRange(input_element->value().length(),
455 input_element->value().length());
456 }
457 } else if (IsTextAreaElement(element)) {
458 WebTextAreaElement text_area = element.toConst<WebTextAreaElement>();
459 if (preview) {
460 text_area.setSelectionRange(text_area.value().length(),
461 text_area.suggestedValue().length());
462 } else {
463 text_area.setSelectionRange(text_area.value().length(),
464 text_area.value().length());
465 }
466 }
467 }
Ilya Sherman 2014/02/22 06:24:20 This method still makes it hard to tell that the c
468
441 // Fills |option_strings| with the values of the <option> elements present in 469 // Fills |option_strings| with the values of the <option> elements present in
442 // |select_element|. 470 // |select_element|.
443 void GetOptionStringsFromElement(const WebSelectElement& select_element, 471 void GetOptionStringsFromElement(const WebSelectElement& select_element,
444 std::vector<base::string16>* option_values, 472 std::vector<base::string16>* option_values,
445 std::vector<base::string16>* option_contents) { 473 std::vector<base::string16>* option_contents) {
446 DCHECK(!select_element.isNull()); 474 DCHECK(!select_element.isNull());
447 475
448 option_values->clear(); 476 option_values->clear();
449 option_contents->clear(); 477 option_contents->clear();
450 WebVector<WebElement> list_items = select_element.listItems(); 478 WebVector<WebElement> list_items = select_element.listItems();
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 561
534 field->setAutofilled(true); 562 field->setAutofilled(true);
535 563
536 WebInputElement* input_element = toWebInputElement(field); 564 WebInputElement* input_element = toWebInputElement(field);
537 if (IsTextInput(input_element) || IsMonthInput(input_element)) { 565 if (IsTextInput(input_element) || IsMonthInput(input_element)) {
538 // If the maxlength attribute contains a negative value, maxLength() 566 // If the maxlength attribute contains a negative value, maxLength()
539 // returns the default maxlength value. 567 // returns the default maxlength value.
540 input_element->setValue( 568 input_element->setValue(
541 data.value.substr(0, input_element->maxLength()), true); 569 data.value.substr(0, input_element->maxLength()), true);
542 if (is_initiating_node) { 570 if (is_initiating_node) {
543 int length = input_element->value().length(); 571 HandleInitiatingNode(*input_element, false);
544 input_element->setSelectionRange(length, length);
545 // Clear the current IME composition (the underline), if there is one. 572 // Clear the current IME composition (the underline), if there is one.
546 input_element->document().frame()->unmarkText(); 573 input_element->document().frame()->unmarkText();
547 } 574 }
548 } else if (IsTextAreaElement(*field)) { 575 } else if (IsTextAreaElement(*field)) {
549 WebTextAreaElement text_area = field->to<WebTextAreaElement>(); 576 WebTextAreaElement text_area = field->to<WebTextAreaElement>();
550 if (text_area.value() != data.value) { 577 if (text_area.value() != data.value) {
551 text_area.setValue(data.value); 578 text_area.setValue(data.value);
552 text_area.dispatchFormControlChangeEvent(); 579 text_area.dispatchFormControlChangeEvent();
580 if (is_initiating_node) {
581 HandleInitiatingNode(text_area, false);
582 // Clear the current IME composition (the underline), if there is one.
583 text_area.document().frame()->unmarkText();
584 }
553 } 585 }
554 } else if (IsSelectElement(*field)) { 586 } else if (IsSelectElement(*field)) {
555 WebSelectElement select_element = field->to<WebSelectElement>(); 587 WebSelectElement select_element = field->to<WebSelectElement>();
556 if (select_element.value() != data.value) { 588 if (select_element.value() != data.value) {
557 select_element.setValue(data.value); 589 select_element.setValue(data.value);
558 select_element.dispatchFormControlChangeEvent(); 590 select_element.dispatchFormControlChangeEvent();
559 } 591 }
560 } else { 592 } else {
561 DCHECK(IsCheckableElement(input_element)); 593 DCHECK(IsCheckableElement(input_element));
562 input_element->setChecked(data.is_checked, true); 594 input_element->setChecked(data.is_checked, true);
(...skipping 12 matching lines...) Expand all
575 // Preview input and textarea fields. For input fields, excludes checkboxes 607 // Preview input and textarea fields. For input fields, excludes checkboxes
576 // and radio buttons, as there is no provision for setSuggestedCheckedValue 608 // and radio buttons, as there is no provision for setSuggestedCheckedValue
577 // in WebInputElement. 609 // in WebInputElement.
578 WebInputElement* input_element = toWebInputElement(field); 610 WebInputElement* input_element = toWebInputElement(field);
579 if (IsTextInput(input_element)) { 611 if (IsTextInput(input_element)) {
580 // If the maxlength attribute contains a negative value, maxLength() 612 // If the maxlength attribute contains a negative value, maxLength()
581 // returns the default maxlength value. 613 // returns the default maxlength value.
582 input_element->setSuggestedValue( 614 input_element->setSuggestedValue(
583 data.value.substr(0, input_element->maxLength())); 615 data.value.substr(0, input_element->maxLength()));
584 input_element->setAutofilled(true); 616 input_element->setAutofilled(true);
585 if (is_initiating_node) { 617 if (is_initiating_node)
Ilya Sherman 2014/02/22 06:24:20 nit: Curly braces are still needed, since the body
586 // Select the part of the text that the user didn't type. 618 // Select the part of the text that the user didn't type.
587 input_element->setSelectionRange( 619 HandleInitiatingNode(*input_element, true);
588 input_element->value().length(), 620
589 input_element->suggestedValue().length());
590 }
591 } else if (IsTextAreaElement(*field)) { 621 } else if (IsTextAreaElement(*field)) {
592 WebTextAreaElement textarea = field->to<WebTextAreaElement>(); 622 WebTextAreaElement textarea = field->to<WebTextAreaElement>();
593 textarea.setSuggestedValue(data.value); 623 textarea.setSuggestedValue(data.value);
594 field->setAutofilled(true); 624 field->setAutofilled(true);
625 if (is_initiating_node)
Ilya Sherman 2014/02/22 06:24:20 nit: Curly braces are still needed, since the body
626 // Select the part of the text that the user didn't type.
627 HandleInitiatingNode(textarea, true);
595 } 628 }
596 } 629 }
597 630
598 std::string RetrievalMethodToString( 631 std::string RetrievalMethodToString(
599 const WebElementDescriptor::RetrievalMethod& method) { 632 const WebElementDescriptor::RetrievalMethod& method) {
600 switch (method) { 633 switch (method) {
601 case WebElementDescriptor::CSS_SELECTOR: 634 case WebElementDescriptor::CSS_SELECTOR:
602 return "CSS_SELECTOR"; 635 return "CSS_SELECTOR";
603 case WebElementDescriptor::ID: 636 case WebElementDescriptor::ID:
604 return "ID"; 637 return "ID";
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
777 field->max_length = input_element->maxLength(); 810 field->max_length = input_element->maxLength();
778 811
779 field->is_autofilled = input_element->isAutofilled(); 812 field->is_autofilled = input_element->isAutofilled();
780 field->is_focusable = input_element->isFocusable(); 813 field->is_focusable = input_element->isFocusable();
781 field->is_checkable = IsCheckableElement(input_element); 814 field->is_checkable = IsCheckableElement(input_element);
782 field->is_checked = input_element->isChecked(); 815 field->is_checked = input_element->isChecked();
783 field->should_autocomplete = input_element->autoComplete(); 816 field->should_autocomplete = input_element->autoComplete();
784 field->text_direction = input_element->directionForFormData() == "rtl" ? 817 field->text_direction = input_element->directionForFormData() == "rtl" ?
785 base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT; 818 base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
786 } else if (IsTextAreaElement(element)) { 819 } else if (IsTextAreaElement(element)) {
787 // Nothing more to do in this case. 820 const WebTextAreaElement textarea_element =
821 element.toConst<WebTextAreaElement>();
822 field->is_autofilled = element.isAutofilled();
823 field->is_focusable = element.isFocusable();
824 field->should_autocomplete = textarea_element.autoComplete();
825 field->text_direction = textarea_element.directionForFormData() == "rtl" ?
826 base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
Ilya Sherman 2014/02/22 06:24:20 Is it possible to refactor the code so that it is
788 } else if (extract_mask & EXTRACT_OPTIONS) { 827 } else if (extract_mask & EXTRACT_OPTIONS) {
789 // Set option strings on the field if available. 828 // Set option strings on the field if available.
790 DCHECK(IsSelectElement(element)); 829 DCHECK(IsSelectElement(element));
791 const WebSelectElement select_element = element.toConst<WebSelectElement>(); 830 const WebSelectElement select_element = element.toConst<WebSelectElement>();
792 GetOptionStringsFromElement(select_element, 831 GetOptionStringsFromElement(select_element,
793 &field->option_values, 832 &field->option_values,
794 &field->option_contents); 833 &field->option_contents);
795 } 834 }
796 835
797 if (!(extract_mask & EXTRACT_VALUE)) 836 if (!(extract_mask & EXTRACT_VALUE))
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
964 1003
965 // Copy the created FormFields into the resulting FormData object. 1004 // Copy the created FormFields into the resulting FormData object.
966 for (ScopedVector<FormFieldData>::const_iterator iter = form_fields.begin(); 1005 for (ScopedVector<FormFieldData>::const_iterator iter = form_fields.begin();
967 iter != form_fields.end(); ++iter) { 1006 iter != form_fields.end(); ++iter) {
968 form->fields.push_back(**iter); 1007 form->fields.push_back(**iter);
969 } 1008 }
970 1009
971 return true; 1010 return true;
972 } 1011 }
973 1012
974 bool FindFormAndFieldForInputElement(const WebInputElement& element, 1013 bool FindFormAndFieldForFormControlElement(const WebFormControlElement& element,
975 FormData* form, 1014 FormData* form,
976 FormFieldData* field, 1015 FormFieldData* field,
977 RequirementsMask requirements) { 1016 RequirementsMask requirements) {
978 if (!IsAutofillableElement(element)) 1017 if (!IsAutofillableElement(element))
979 return false; 1018 return false;
980 1019
981 const WebFormElement form_element = element.form(); 1020 const WebFormElement form_element = element.form();
982 if (form_element.isNull()) 1021 if (form_element.isNull())
983 return false; 1022 return false;
984 1023
985 ExtractMask extract_mask = 1024 ExtractMask extract_mask =
986 static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS); 1025 static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
987 return WebFormElementToFormData(form_element, 1026 return WebFormElementToFormData(form_element,
988 element, 1027 element,
989 requirements, 1028 requirements,
990 extract_mask, 1029 extract_mask,
991 form, 1030 form,
992 field); 1031 field);
993 } 1032 }
994 1033
995 void FillForm(const FormData& form, const WebInputElement& element) { 1034 void FillForm(const FormData& form, const WebFormControlElement& element) {
996 WebFormElement form_element = element.form(); 1035 WebFormElement form_element = element.form();
997 if (form_element.isNull()) 1036 if (form_element.isNull())
998 return; 1037 return;
999 1038
1000 ForEachMatchingFormField(form_element, 1039 ForEachMatchingFormField(form_element,
1001 element, 1040 element,
1002 form, 1041 form,
1003 FILTER_ALL_NON_EDITIABLE_ELEMENTS, 1042 FILTER_ALL_NON_EDITIABLE_ELEMENTS,
1004 false, /* dont force override */ 1043 false, /* dont force override */
1005 &FillFormField); 1044 &FillFormField);
(...skipping 20 matching lines...) Expand all
1026 return; 1065 return;
1027 1066
1028 ForEachMatchingFormField(form_element, 1067 ForEachMatchingFormField(form_element,
1029 WebInputElement(), 1068 WebInputElement(),
1030 form_data, 1069 form_data,
1031 FILTER_NONE, 1070 FILTER_NONE,
1032 true, /* force override */ 1071 true, /* force override */
1033 &FillFormField); 1072 &FillFormField);
1034 } 1073 }
1035 1074
1036 void PreviewForm(const FormData& form, const WebInputElement& element) { 1075 void PreviewForm(const FormData& form, const WebFormControlElement& element) {
1037 WebFormElement form_element = element.form(); 1076 WebFormElement form_element = element.form();
1038 if (form_element.isNull()) 1077 if (form_element.isNull())
1039 return; 1078 return;
1040 1079
1041 ForEachMatchingFormField(form_element, 1080 ForEachMatchingFormField(form_element,
1042 element, 1081 element,
1043 form, 1082 form,
1044 FILTER_ALL_NON_EDITIABLE_ELEMENTS, 1083 FILTER_ALL_NON_EDITIABLE_ELEMENTS,
1045 false, /* dont force override */ 1084 false, /* dont force override */
1046 &PreviewFormField); 1085 &PreviewFormField);
1047 } 1086 }
1048 1087
1049 bool ClearPreviewedFormWithElement(const WebInputElement& element, 1088 bool ClearPreviewedFormWithElement(const WebFormControlElement& element,
1050 bool was_autofilled) { 1089 bool was_autofilled) {
1051 WebFormElement form_element = element.form(); 1090 WebFormElement form_element = element.form();
1052 if (form_element.isNull()) 1091 if (form_element.isNull())
1053 return false; 1092 return false;
1054 1093
1055 std::vector<WebFormControlElement> control_elements; 1094 std::vector<WebFormControlElement> control_elements;
1056 ExtractAutofillableElements(form_element, REQUIRE_AUTOCOMPLETE, 1095 ExtractAutofillableElements(form_element, REQUIRE_AUTOCOMPLETE,
1057 &control_elements); 1096 &control_elements);
1058 for (size_t i = 0; i < control_elements.size(); ++i) { 1097 for (size_t i = 0; i < control_elements.size(); ++i) {
1059 // There might be unrelated elements in this form which have already been 1098 // There might be unrelated elements in this form which have already been
(...skipping 16 matching lines...) Expand all
1076 input_element->suggestedValue().isEmpty()) || 1115 input_element->suggestedValue().isEmpty()) ||
1077 (IsTextAreaElement(control_element) && 1116 (IsTextAreaElement(control_element) &&
1078 control_element.to<WebTextAreaElement>().suggestedValue().isEmpty())) 1117 control_element.to<WebTextAreaElement>().suggestedValue().isEmpty()))
1079 continue; 1118 continue;
1080 1119
1081 // Clear the suggested value. For the initiating node, also restore the 1120 // Clear the suggested value. For the initiating node, also restore the
1082 // original value. 1121 // original value.
1083 if (IsTextInput(input_element)) { 1122 if (IsTextInput(input_element)) {
1084 input_element->setSuggestedValue(WebString()); 1123 input_element->setSuggestedValue(WebString());
1085 bool is_initiating_node = (element == *input_element); 1124 bool is_initiating_node = (element == *input_element);
1086 if (is_initiating_node) 1125 if (is_initiating_node) {
1087 input_element->setAutofilled(was_autofilled); 1126 input_element->setAutofilled(was_autofilled);
1088 else 1127 // Clearing the suggested value in the focused node (above) can cause
1128 // selection to be lost. We force selection range to restore the text
1129 // cursor.
1130 HandleInitiatingNode(*input_element, false);
Ilya Sherman 2014/02/22 06:24:20 This change doesn't seem appropriate. Is there so
1131 }
1132 else {
Ilya Sherman 2014/02/22 06:24:20 nit: The else should be on the previous line, i.e.
1089 input_element->setAutofilled(false); 1133 input_element->setAutofilled(false);
1090
1091 // Clearing the suggested value in the focused node (above) can cause
1092 // selection to be lost. We force selection range to restore the text
1093 // cursor.
1094 if (is_initiating_node) {
1095 int length = input_element->value().length();
1096 input_element->setSelectionRange(length, length);
1097 } 1134 }
1098 } else if (IsTextAreaElement(control_element)) { 1135 } else if (IsTextAreaElement(control_element)) {
1099 WebTextAreaElement text_area = control_element.to<WebTextAreaElement>(); 1136 WebTextAreaElement text_area = control_element.to<WebTextAreaElement>();
1100 text_area.setSuggestedValue(WebString()); 1137 text_area.setSuggestedValue(WebString());
1101 bool is_initiating_node = (element == text_area); 1138 bool is_initiating_node = (element == text_area);
1102 if (is_initiating_node) 1139 if (is_initiating_node) {
1103 control_element.setAutofilled(was_autofilled); 1140 control_element.setAutofilled(was_autofilled);
1104 else 1141 HandleInitiatingNode(text_area, false);
1142 }
1143 else {
1105 control_element.setAutofilled(false); 1144 control_element.setAutofilled(false);
1145 }
1106 } 1146 }
1107 } 1147 }
1108 1148
1109 return true; 1149 return true;
1110 } 1150 }
1111 1151
1112 bool FormWithElementIsAutofilled(const WebInputElement& element) { 1152 bool FormWithElementIsAutofilled(const WebInputElement& element) {
1113 WebFormElement form_element = element.form(); 1153 WebFormElement form_element = element.form();
1114 if (form_element.isNull()) 1154 if (form_element.isNull())
1115 return false; 1155 return false;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1172 tag_is_allowed = true; 1212 tag_is_allowed = true;
1173 break; 1213 break;
1174 } 1214 }
1175 } 1215 }
1176 if (!tag_is_allowed) 1216 if (!tag_is_allowed)
1177 return false; 1217 return false;
1178 } 1218 }
1179 return true; 1219 return true;
1180 } 1220 }
1181 1221
1182 gfx::RectF GetScaledBoundingBox(float scale, WebInputElement* element) { 1222 gfx::RectF GetScaledBoundingBox(float scale, WebFormControlElement* element) {
1183 gfx::Rect bounding_box(element->boundsInViewportSpace()); 1223 gfx::Rect bounding_box(element->boundsInViewportSpace());
1184 return gfx::RectF(bounding_box.x() * scale, 1224 return gfx::RectF(bounding_box.x() * scale,
1185 bounding_box.y() * scale, 1225 bounding_box.y() * scale,
1186 bounding_box.width() * scale, 1226 bounding_box.width() * scale,
1187 bounding_box.height() * scale); 1227 bounding_box.height() * scale);
1188 } 1228 }
1189 1229
1190 } // namespace autofill 1230 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698