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/autofill_agent.h" | 5 #include "components/autofill/content/renderer/autofill_agent.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "base/strings/string_split.h" | 10 #include "base/strings/string_split.h" |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 for (size_t i = 0; i < strings->size(); ++i) { | 116 for (size_t i = 0; i < strings->size(); ++i) { |
117 if ((*strings)[i].length() > kMaxDataLength) | 117 if ((*strings)[i].length() > kMaxDataLength) |
118 (*strings)[i].resize(kMaxDataLength); | 118 (*strings)[i].resize(kMaxDataLength); |
119 } | 119 } |
120 } | 120 } |
121 | 121 |
122 // Extract FormData from the form element and return whether the operation was | 122 // Extract FormData from the form element and return whether the operation was |
123 // successful. | 123 // successful. |
124 bool ExtractFormDataOnSave(const WebFormElement& form_element, FormData* data) { | 124 bool ExtractFormDataOnSave(const WebFormElement& form_element, FormData* data) { |
125 return WebFormElementToFormData( | 125 return WebFormElementToFormData( |
126 form_element, WebFormControlElement(), REQUIRE_NONE, | 126 form_element, WebFormControlElement(), |
127 static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTION_TEXT), data, | 127 static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTION_TEXT), data, |
128 NULL); | 128 NULL); |
129 } | 129 } |
130 | 130 |
131 } // namespace | 131 } // namespace |
132 | 132 |
133 AutofillAgent::ShowSuggestionsOptions::ShowSuggestionsOptions() | 133 AutofillAgent::ShowSuggestionsOptions::ShowSuggestionsOptions() |
134 : autofill_on_empty_values(false), | 134 : autofill_on_empty_values(false), |
135 requires_caret_at_end(false), | 135 requires_caret_at_end(false), |
136 display_warning_if_disabled(false), | |
137 datalist_only(false), | 136 datalist_only(false), |
138 show_full_suggestion_list(false), | 137 show_full_suggestion_list(false), |
139 show_password_suggestions_only(false) { | 138 show_password_suggestions_only(false) { |
140 } | 139 } |
141 | 140 |
142 AutofillAgent::AutofillAgent(content::RenderFrame* render_frame, | 141 AutofillAgent::AutofillAgent(content::RenderFrame* render_frame, |
143 PasswordAutofillAgent* password_autofill_agent, | 142 PasswordAutofillAgent* password_autofill_agent, |
144 PasswordGenerationAgent* password_generation_agent) | 143 PasswordGenerationAgent* password_generation_agent) |
145 : content::RenderFrameObserver(render_frame), | 144 : content::RenderFrameObserver(render_frame), |
146 form_cache_(*render_frame->GetWebFrame()), | 145 form_cache_(*render_frame->GetWebFrame()), |
147 password_autofill_agent_(password_autofill_agent), | 146 password_autofill_agent_(password_autofill_agent), |
148 password_generation_agent_(password_generation_agent), | 147 password_generation_agent_(password_generation_agent), |
149 legacy_(render_frame->GetRenderView(), this), | 148 legacy_(render_frame->GetRenderView(), this), |
150 autofill_query_id_(0), | 149 autofill_query_id_(0), |
151 display_warning_if_disabled_(false), | |
152 was_query_node_autofilled_(false), | 150 was_query_node_autofilled_(false), |
153 has_shown_autofill_popup_for_current_edit_(false), | 151 has_shown_autofill_popup_for_current_edit_(false), |
154 did_set_node_text_(false), | 152 did_set_node_text_(false), |
155 ignore_text_changes_(false), | 153 ignore_text_changes_(false), |
156 is_popup_possibly_visible_(false), | 154 is_popup_possibly_visible_(false), |
157 weak_ptr_factory_(this) { | 155 weak_ptr_factory_(this) { |
158 render_frame->GetWebFrame()->setAutofillClient(this); | 156 render_frame->GetWebFrame()->setAutofillClient(this); |
159 | 157 |
160 // This owns itself, and will delete itself when |render_frame| is destructed | 158 // This owns itself, and will delete itself when |render_frame| is destructed |
161 // (same as AutofillAgent). | 159 // (same as AutofillAgent). |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
296 ::switches::kReduceSecurityForTesting); | 294 ::switches::kReduceSecurityForTesting); |
297 FormData form_data; | 295 FormData form_data; |
298 std::string error_message; | 296 std::string error_message; |
299 if (!in_flight_request_form_.isNull()) { | 297 if (!in_flight_request_form_.isNull()) { |
300 error_message = "already active."; | 298 error_message = "already active."; |
301 } else if (!is_safe && !allow_unsafe) { | 299 } else if (!is_safe && !allow_unsafe) { |
302 error_message = | 300 error_message = |
303 "must use a secure connection or --reduce-security-for-testing."; | 301 "must use a secure connection or --reduce-security-for-testing."; |
304 } else if (!WebFormElementToFormData(form, | 302 } else if (!WebFormElementToFormData(form, |
305 WebFormControlElement(), | 303 WebFormControlElement(), |
306 REQUIRE_AUTOCOMPLETE, | |
307 static_cast<ExtractMask>( | 304 static_cast<ExtractMask>( |
308 EXTRACT_VALUE | | 305 EXTRACT_VALUE | |
309 EXTRACT_OPTION_TEXT | | 306 EXTRACT_OPTION_TEXT | |
310 EXTRACT_OPTIONS), | 307 EXTRACT_OPTIONS), |
311 &form_data, | 308 &form_data, |
312 NULL)) { | 309 NULL)) { |
313 error_message = "failed to parse form."; | 310 error_message = "failed to parse form."; |
314 } | 311 } |
315 | 312 |
316 if (!error_message.empty()) { | 313 if (!error_message.empty()) { |
(...skipping 25 matching lines...) Expand all Loading... |
342 // TODO(estade): Remove this check when PageClickTracker is per-frame. | 339 // TODO(estade): Remove this check when PageClickTracker is per-frame. |
343 if (element.document().frame() != render_frame()->GetWebFrame()) | 340 if (element.document().frame() != render_frame()->GetWebFrame()) |
344 return; | 341 return; |
345 | 342 |
346 const WebInputElement* input_element = toWebInputElement(&element); | 343 const WebInputElement* input_element = toWebInputElement(&element); |
347 if (!input_element && !IsTextAreaElement(element)) | 344 if (!input_element && !IsTextAreaElement(element)) |
348 return; | 345 return; |
349 | 346 |
350 ShowSuggestionsOptions options; | 347 ShowSuggestionsOptions options; |
351 options.autofill_on_empty_values = true; | 348 options.autofill_on_empty_values = true; |
352 options.display_warning_if_disabled = true; | |
353 options.show_full_suggestion_list = element.isAutofilled(); | 349 options.show_full_suggestion_list = element.isAutofilled(); |
354 | 350 |
355 // On Android, default to showing the dropdown on field focus. | 351 // On Android, default to showing the dropdown on field focus. |
356 // On desktop, require an extra click after field focus. | 352 // On desktop, require an extra click after field focus. |
357 // See http://crbug.com/427660 | 353 // See http://crbug.com/427660 |
358 #if defined(OS_ANDROID) | 354 #if defined(OS_ANDROID) |
359 bool single_click_autofill = | 355 bool single_click_autofill = |
360 !base::CommandLine::ForCurrentProcess()->HasSwitch( | 356 !base::CommandLine::ForCurrentProcess()->HasSwitch( |
361 switches::kDisableSingleClickAutofill); | 357 switches::kDisableSingleClickAutofill); |
362 #else | 358 #else |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
424 return; | 420 return; |
425 } | 421 } |
426 } | 422 } |
427 | 423 |
428 ShowSuggestionsOptions options; | 424 ShowSuggestionsOptions options; |
429 options.requires_caret_at_end = true; | 425 options.requires_caret_at_end = true; |
430 ShowSuggestions(element, options); | 426 ShowSuggestions(element, options); |
431 | 427 |
432 FormData form; | 428 FormData form; |
433 FormFieldData field; | 429 FormFieldData field; |
434 if (FindFormAndFieldForFormControlElement(element, | 430 if (FindFormAndFieldForFormControlElement(element, &form, &field)) { |
435 &form, | |
436 &field, | |
437 REQUIRE_NONE)) { | |
438 Send(new AutofillHostMsg_TextFieldDidChange(routing_id(), form, field, | 431 Send(new AutofillHostMsg_TextFieldDidChange(routing_id(), form, field, |
439 base::TimeTicks::Now())); | 432 base::TimeTicks::Now())); |
440 } | 433 } |
441 } | 434 } |
442 | 435 |
443 void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element, | 436 void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element, |
444 const WebKeyboardEvent& event) { | 437 const WebKeyboardEvent& event) { |
445 if (password_autofill_agent_->TextFieldHandlingKeyDown(element, event)) { | 438 if (password_autofill_agent_->TextFieldHandlingKeyDown(element, event)) { |
446 element_ = element; | 439 element_ = element; |
447 return; | 440 return; |
448 } | 441 } |
449 | 442 |
450 if (event.windowsKeyCode == ui::VKEY_DOWN || | 443 if (event.windowsKeyCode == ui::VKEY_DOWN || |
451 event.windowsKeyCode == ui::VKEY_UP) { | 444 event.windowsKeyCode == ui::VKEY_UP) { |
452 ShowSuggestionsOptions options; | 445 ShowSuggestionsOptions options; |
453 options.autofill_on_empty_values = true; | 446 options.autofill_on_empty_values = true; |
454 options.requires_caret_at_end = true; | 447 options.requires_caret_at_end = true; |
455 options.display_warning_if_disabled = true; | |
456 ShowSuggestions(element, options); | 448 ShowSuggestions(element, options); |
457 } | 449 } |
458 } | 450 } |
459 | 451 |
460 void AutofillAgent::openTextDataListChooser(const WebInputElement& element) { | 452 void AutofillAgent::openTextDataListChooser(const WebInputElement& element) { |
461 ShowSuggestionsOptions options; | 453 ShowSuggestionsOptions options; |
462 options.autofill_on_empty_values = true; | 454 options.autofill_on_empty_values = true; |
463 options.datalist_only = true; | 455 options.datalist_only = true; |
464 ShowSuggestions(element, options); | 456 ShowSuggestions(element, options); |
465 } | 457 } |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
663 options.show_password_suggestions_only)) { | 655 options.show_password_suggestions_only)) { |
664 is_popup_possibly_visible_ = true; | 656 is_popup_possibly_visible_ = true; |
665 return; | 657 return; |
666 } | 658 } |
667 | 659 |
668 // Password field elements should only have suggestions shown by the password | 660 // Password field elements should only have suggestions shown by the password |
669 // autofill agent. | 661 // autofill agent. |
670 if (input_element && input_element->isPasswordField()) | 662 if (input_element && input_element->isPasswordField()) |
671 return; | 663 return; |
672 | 664 |
673 // If autocomplete is disabled at the field level, ensure that the native | 665 QueryAutofillSuggestions(element, options.datalist_only); |
674 // UI won't try to show a warning, since that may conflict with a custom | |
675 // popup. Note that we cannot use the WebKit method element.autoComplete() | |
676 // as it does not allow us to distinguish the case where autocomplete is | |
677 // disabled for *both* the element and for the form. | |
678 bool display_warning = options.display_warning_if_disabled; | |
679 if (display_warning) { | |
680 const base::string16 autocomplete_attribute = | |
681 element.getAttribute("autocomplete"); | |
682 if (LowerCaseEqualsASCII(autocomplete_attribute, "off")) | |
683 display_warning = false; | |
684 } | |
685 | |
686 QueryAutofillSuggestions(element, display_warning, options.datalist_only); | |
687 } | 666 } |
688 | 667 |
689 void AutofillAgent::QueryAutofillSuggestions( | 668 void AutofillAgent::QueryAutofillSuggestions( |
690 const WebFormControlElement& element, | 669 const WebFormControlElement& element, |
691 bool display_warning_if_disabled, | |
692 bool datalist_only) { | 670 bool datalist_only) { |
693 if (!element.document().frame()) | 671 if (!element.document().frame()) |
694 return; | 672 return; |
695 | 673 |
696 DCHECK(toWebInputElement(&element) || IsTextAreaElement(element)); | 674 DCHECK(toWebInputElement(&element) || IsTextAreaElement(element)); |
697 | 675 |
698 static int query_counter = 0; | 676 static int query_counter = 0; |
699 autofill_query_id_ = query_counter++; | 677 autofill_query_id_ = query_counter++; |
700 display_warning_if_disabled_ = display_warning_if_disabled; | |
701 | |
702 // If autocomplete is disabled at the form level, we want to see if there | |
703 // would have been any suggestions were it enabled, so that we can show a | |
704 // warning. Otherwise, we want to ignore fields that disable autocomplete, so | |
705 // that the suggestions list does not include suggestions for these form | |
706 // fields -- see comment 1 on http://crbug.com/69914 | |
707 RequirementsMask requirements = | |
708 element.autoComplete() ? REQUIRE_AUTOCOMPLETE : REQUIRE_NONE; | |
709 | |
710 // If we're ignoring autocomplete="off", always extract everything. | |
711 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | |
712 switches::kRespectAutocompleteOffForAutofill)) { | |
713 requirements = REQUIRE_NONE; | |
714 } | |
715 | 678 |
716 FormData form; | 679 FormData form; |
717 FormFieldData field; | 680 FormFieldData field; |
718 if (!FindFormAndFieldForFormControlElement(element, &form, &field, | 681 if (!FindFormAndFieldForFormControlElement(element, &form, &field)) { |
719 requirements)) { | |
720 // If we didn't find the cached form, at least let autocomplete have a shot | 682 // If we didn't find the cached form, at least let autocomplete have a shot |
721 // at providing suggestions. | 683 // at providing suggestions. |
722 WebFormControlElementToFormField(element, EXTRACT_VALUE, &field); | 684 WebFormControlElementToFormField(element, EXTRACT_VALUE, &field); |
723 } | 685 } |
724 if (datalist_only) | 686 if (datalist_only) |
725 field.should_autocomplete = false; | 687 field.should_autocomplete = false; |
726 | 688 |
727 gfx::RectF bounding_box_scaled = GetScaledBoundingBox( | 689 gfx::RectF bounding_box_scaled = GetScaledBoundingBox( |
728 render_frame()->GetRenderView()->GetWebView()->pageScaleFactor(), | 690 render_frame()->GetRenderView()->GetWebView()->pageScaleFactor(), |
729 &element_); | 691 &element_); |
730 | 692 |
731 std::vector<base::string16> data_list_values; | 693 std::vector<base::string16> data_list_values; |
732 std::vector<base::string16> data_list_labels; | 694 std::vector<base::string16> data_list_labels; |
733 const WebInputElement* input_element = toWebInputElement(&element); | 695 const WebInputElement* input_element = toWebInputElement(&element); |
734 if (input_element) { | 696 if (input_element) { |
735 // Find the datalist values and send them to the browser process. | 697 // Find the datalist values and send them to the browser process. |
736 GetDataListSuggestions(*input_element, | 698 GetDataListSuggestions(*input_element, |
737 datalist_only, | 699 datalist_only, |
738 &data_list_values, | 700 &data_list_values, |
739 &data_list_labels); | 701 &data_list_labels); |
740 TrimStringVectorForIPC(&data_list_values); | 702 TrimStringVectorForIPC(&data_list_values); |
741 TrimStringVectorForIPC(&data_list_labels); | 703 TrimStringVectorForIPC(&data_list_labels); |
742 } | 704 } |
743 | 705 |
744 is_popup_possibly_visible_ = true; | 706 is_popup_possibly_visible_ = true; |
745 Send(new AutofillHostMsg_SetDataList(routing_id(), | 707 Send(new AutofillHostMsg_SetDataList(routing_id(), |
746 data_list_values, | 708 data_list_values, |
747 data_list_labels)); | 709 data_list_labels)); |
748 | 710 |
749 Send(new AutofillHostMsg_QueryFormFieldAutofill(routing_id(), | 711 Send(new AutofillHostMsg_QueryFormFieldAutofill( |
750 autofill_query_id_, | 712 routing_id(), autofill_query_id_, form, field, bounding_box_scaled)); |
751 form, | |
752 field, | |
753 bounding_box_scaled, | |
754 display_warning_if_disabled)); | |
755 } | 713 } |
756 | 714 |
757 void AutofillAgent::FillFieldWithValue(const base::string16& value, | 715 void AutofillAgent::FillFieldWithValue(const base::string16& value, |
758 WebInputElement* node) { | 716 WebInputElement* node) { |
759 did_set_node_text_ = true; | 717 did_set_node_text_ = true; |
760 node->setEditingValue(value.substr(0, node->maxLength())); | 718 node->setEditingValue(value.substr(0, node->maxLength())); |
761 } | 719 } |
762 | 720 |
763 void AutofillAgent::PreviewFieldWithValue(const base::string16& value, | 721 void AutofillAgent::PreviewFieldWithValue(const base::string16& value, |
764 WebInputElement* node) { | 722 WebInputElement* node) { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
825 | 783 |
826 void AutofillAgent::LegacyAutofillAgent::OnDestruct() { | 784 void AutofillAgent::LegacyAutofillAgent::OnDestruct() { |
827 // No-op. Don't delete |this|. | 785 // No-op. Don't delete |this|. |
828 } | 786 } |
829 | 787 |
830 void AutofillAgent::LegacyAutofillAgent::FocusChangeComplete() { | 788 void AutofillAgent::LegacyAutofillAgent::FocusChangeComplete() { |
831 agent_->FocusChangeComplete(); | 789 agent_->FocusChangeComplete(); |
832 } | 790 } |
833 | 791 |
834 } // namespace autofill | 792 } // namespace autofill |
OLD | NEW |