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