| 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 |