| 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 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 | 112 |
| 113 // Limit the size of the strings in the vector. | 113 // Limit the size of the strings in the vector. |
| 114 for (size_t i = 0; i < strings->size(); ++i) { | 114 for (size_t i = 0; i < strings->size(); ++i) { |
| 115 if ((*strings)[i].length() > kMaxDataLength) | 115 if ((*strings)[i].length() > kMaxDataLength) |
| 116 (*strings)[i].resize(kMaxDataLength); | 116 (*strings)[i].resize(kMaxDataLength); |
| 117 } | 117 } |
| 118 } | 118 } |
| 119 | 119 |
| 120 } // namespace | 120 } // namespace |
| 121 | 121 |
| 122 AutofillAgent::ShowSuggestionsOptions::ShowSuggestionsOptions() |
| 123 : autofill_on_empty_values(false), |
| 124 requires_caret_at_end(false), |
| 125 display_warning_if_disabled(false), |
| 126 datalist_only(false), |
| 127 show_full_suggestion_list(false), |
| 128 show_password_suggestions_only(false) { |
| 129 } |
| 130 |
| 122 AutofillAgent::AutofillAgent(content::RenderView* render_view, | 131 AutofillAgent::AutofillAgent(content::RenderView* render_view, |
| 123 PasswordAutofillAgent* password_autofill_agent, | 132 PasswordAutofillAgent* password_autofill_agent, |
| 124 PasswordGenerationAgent* password_generation_agent) | 133 PasswordGenerationAgent* password_generation_agent) |
| 125 : content::RenderViewObserver(render_view), | 134 : content::RenderViewObserver(render_view), |
| 126 password_autofill_agent_(password_autofill_agent), | 135 password_autofill_agent_(password_autofill_agent), |
| 127 password_generation_agent_(password_generation_agent), | 136 password_generation_agent_(password_generation_agent), |
| 128 autofill_query_id_(0), | 137 autofill_query_id_(0), |
| 129 web_view_(render_view->GetWebView()), | 138 web_view_(render_view->GetWebView()), |
| 130 display_warning_if_disabled_(false), | 139 display_warning_if_disabled_(false), |
| 131 was_query_node_autofilled_(false), | 140 was_query_node_autofilled_(false), |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 const WebFormElement& form) { | 266 const WebFormElement& form) { |
| 258 // Disallow the dialog over non-https or broken https, except when the | 267 // Disallow the dialog over non-https or broken https, except when the |
| 259 // ignore SSL flag is passed. See http://crbug.com/272512. | 268 // ignore SSL flag is passed. See http://crbug.com/272512. |
| 260 // TODO(palmer): this should be moved to the browser process after frames | 269 // TODO(palmer): this should be moved to the browser process after frames |
| 261 // get their own processes. | 270 // get their own processes. |
| 262 GURL url(form.document().url()); | 271 GURL url(form.document().url()); |
| 263 content::SSLStatus ssl_status = | 272 content::SSLStatus ssl_status = |
| 264 render_view()->GetSSLStatusOfFrame(form.document().frame()); | 273 render_view()->GetSSLStatusOfFrame(form.document().frame()); |
| 265 bool is_safe = url.SchemeIs(url::kHttpsScheme) && | 274 bool is_safe = url.SchemeIs(url::kHttpsScheme) && |
| 266 !net::IsCertStatusError(ssl_status.cert_status); | 275 !net::IsCertStatusError(ssl_status.cert_status); |
| 267 bool allow_unsafe = CommandLine::ForCurrentProcess()->HasSwitch( | 276 bool allow_unsafe = base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 268 ::switches::kReduceSecurityForTesting); | 277 ::switches::kReduceSecurityForTesting); |
| 269 | 278 |
| 270 FormData form_data; | 279 FormData form_data; |
| 271 std::string error_message; | 280 std::string error_message; |
| 272 if (!in_flight_request_form_.isNull()) { | 281 if (!in_flight_request_form_.isNull()) { |
| 273 error_message = "already active."; | 282 error_message = "already active."; |
| 274 } else if (!is_safe && !allow_unsafe) { | 283 } else if (!is_safe && !allow_unsafe) { |
| 275 error_message = | 284 error_message = |
| 276 "must use a secure connection or --reduce-security-for-testing."; | 285 "must use a secure connection or --reduce-security-for-testing."; |
| 277 } else if (!WebFormElementToFormData(form, | 286 } else if (!WebFormElementToFormData(form, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 ignore_text_changes_ = ignore; | 318 ignore_text_changes_ = ignore; |
| 310 } | 319 } |
| 311 | 320 |
| 312 void AutofillAgent::FormControlElementClicked( | 321 void AutofillAgent::FormControlElementClicked( |
| 313 const WebFormControlElement& element, | 322 const WebFormControlElement& element, |
| 314 bool was_focused) { | 323 bool was_focused) { |
| 315 const WebInputElement* input_element = toWebInputElement(&element); | 324 const WebInputElement* input_element = toWebInputElement(&element); |
| 316 if (!input_element && !IsTextAreaElement(element)) | 325 if (!input_element && !IsTextAreaElement(element)) |
| 317 return; | 326 return; |
| 318 | 327 |
| 319 bool show_full_suggestion_list = element.isAutofilled() || was_focused; | 328 ShowSuggestionsOptions options; |
| 320 bool show_password_suggestions_only = !was_focused; | 329 options.autofill_on_empty_values = true; |
| 330 options.display_warning_if_disabled = true; |
| 331 options.show_full_suggestion_list = element.isAutofilled(); |
| 321 | 332 |
| 322 // TODO(gcasto): Remove after crbug.com/430318 has been fixed. | 333 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 323 bool show_suggestions = true; | 334 switches::kEnableSingleClickAutofill)) { |
| 335 // Show full suggestions when clicking on an already-focused form field. On |
| 336 // the initial click (not focused yet), only show password suggestions. |
| 324 #if defined(OS_ANDROID) | 337 #if defined(OS_ANDROID) |
| 325 show_suggestions = was_focused; | 338 // TODO(gcasto): Remove after crbug.com/430318 has been fixed. |
| 339 if (!was_focused) |
| 340 return; |
| 326 #endif | 341 #endif |
| 327 | 342 |
| 328 if (show_suggestions) { | 343 options.show_full_suggestion_list = |
| 329 ShowSuggestions(element, | 344 options.show_full_suggestion_list || was_focused; |
| 330 true, | 345 options.show_password_suggestions_only = !was_focused; |
| 331 false, | |
| 332 true, | |
| 333 false, | |
| 334 show_full_suggestion_list, | |
| 335 show_password_suggestions_only); | |
| 336 } | 346 } |
| 347 ShowSuggestions(element, options); |
| 337 } | 348 } |
| 338 | 349 |
| 339 void AutofillAgent::textFieldDidEndEditing(const WebInputElement& element) { | 350 void AutofillAgent::textFieldDidEndEditing(const WebInputElement& element) { |
| 340 password_autofill_agent_->TextFieldDidEndEditing(element); | 351 password_autofill_agent_->TextFieldDidEndEditing(element); |
| 341 has_shown_autofill_popup_for_current_edit_ = false; | 352 has_shown_autofill_popup_for_current_edit_ = false; |
| 342 Send(new AutofillHostMsg_DidEndTextFieldEditing(routing_id())); | 353 Send(new AutofillHostMsg_DidEndTextFieldEditing(routing_id())); |
| 343 } | 354 } |
| 344 | 355 |
| 345 void AutofillAgent::textFieldDidChange(const WebFormControlElement& element) { | 356 void AutofillAgent::textFieldDidChange(const WebFormControlElement& element) { |
| 346 if (ignore_text_changes_) | 357 if (ignore_text_changes_) |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 is_popup_possibly_visible_ = true; | 389 is_popup_possibly_visible_ = true; |
| 379 return; | 390 return; |
| 380 } | 391 } |
| 381 | 392 |
| 382 if (password_autofill_agent_->TextDidChangeInTextField(*input_element)) { | 393 if (password_autofill_agent_->TextDidChangeInTextField(*input_element)) { |
| 383 element_ = element; | 394 element_ = element; |
| 384 return; | 395 return; |
| 385 } | 396 } |
| 386 } | 397 } |
| 387 | 398 |
| 388 ShowSuggestions(element, false, true, false, false, false, false); | 399 ShowSuggestionsOptions options; |
| 400 options.requires_caret_at_end = true; |
| 401 ShowSuggestions(element, options); |
| 389 | 402 |
| 390 FormData form; | 403 FormData form; |
| 391 FormFieldData field; | 404 FormFieldData field; |
| 392 if (FindFormAndFieldForFormControlElement(element, | 405 if (FindFormAndFieldForFormControlElement(element, |
| 393 &form, | 406 &form, |
| 394 &field, | 407 &field, |
| 395 REQUIRE_NONE)) { | 408 REQUIRE_NONE)) { |
| 396 Send(new AutofillHostMsg_TextFieldDidChange(routing_id(), form, field, | 409 Send(new AutofillHostMsg_TextFieldDidChange(routing_id(), form, field, |
| 397 base::TimeTicks::Now())); | 410 base::TimeTicks::Now())); |
| 398 } | 411 } |
| 399 } | 412 } |
| 400 | 413 |
| 401 void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element, | 414 void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element, |
| 402 const WebKeyboardEvent& event) { | 415 const WebKeyboardEvent& event) { |
| 403 if (password_autofill_agent_->TextFieldHandlingKeyDown(element, event)) { | 416 if (password_autofill_agent_->TextFieldHandlingKeyDown(element, event)) { |
| 404 element_ = element; | 417 element_ = element; |
| 405 return; | 418 return; |
| 406 } | 419 } |
| 407 | 420 |
| 408 if (event.windowsKeyCode == ui::VKEY_DOWN || | 421 if (event.windowsKeyCode == ui::VKEY_DOWN || |
| 409 event.windowsKeyCode == ui::VKEY_UP) | 422 event.windowsKeyCode == ui::VKEY_UP) { |
| 410 ShowSuggestions(element, true, true, true, false, false, false); | 423 ShowSuggestionsOptions options; |
| 424 options.autofill_on_empty_values = true; |
| 425 options.requires_caret_at_end = true; |
| 426 options.display_warning_if_disabled = true; |
| 427 ShowSuggestions(element, options); |
| 428 } |
| 411 } | 429 } |
| 412 | 430 |
| 413 void AutofillAgent::openTextDataListChooser(const WebInputElement& element) { | 431 void AutofillAgent::openTextDataListChooser(const WebInputElement& element) { |
| 414 ShowSuggestions(element, true, false, false, true, false, false); | 432 ShowSuggestionsOptions options; |
| 433 options.autofill_on_empty_values = true; |
| 434 options.datalist_only = true; |
| 435 ShowSuggestions(element, options); |
| 415 } | 436 } |
| 416 | 437 |
| 417 void AutofillAgent::firstUserGestureObserved() { | 438 void AutofillAgent::firstUserGestureObserved() { |
| 418 password_autofill_agent_->FirstUserGestureObserved(); | 439 password_autofill_agent_->FirstUserGestureObserved(); |
| 419 } | 440 } |
| 420 | 441 |
| 421 void AutofillAgent::AcceptDataListSuggestion( | 442 void AutofillAgent::AcceptDataListSuggestion( |
| 422 const base::string16& suggested_value) { | 443 const base::string16& suggested_value) { |
| 423 WebInputElement* input_element = toWebInputElement(&element_); | 444 WebInputElement* input_element = toWebInputElement(&element_); |
| 424 DCHECK(input_element); | 445 DCHECK(input_element); |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 WebConsoleMessage console_message = WebConsoleMessage( | 576 WebConsoleMessage console_message = WebConsoleMessage( |
| 556 WebConsoleMessage::LevelLog, WebString(prefix + message)); | 577 WebConsoleMessage::LevelLog, WebString(prefix + message)); |
| 557 in_flight_request_form_.document().frame()->addMessageToConsole( | 578 in_flight_request_form_.document().frame()->addMessageToConsole( |
| 558 console_message); | 579 console_message); |
| 559 } | 580 } |
| 560 | 581 |
| 561 in_flight_request_form_.reset(); | 582 in_flight_request_form_.reset(); |
| 562 } | 583 } |
| 563 | 584 |
| 564 void AutofillAgent::ShowSuggestions(const WebFormControlElement& element, | 585 void AutofillAgent::ShowSuggestions(const WebFormControlElement& element, |
| 565 bool autofill_on_empty_values, | 586 const ShowSuggestionsOptions& options) { |
| 566 bool requires_caret_at_end, | |
| 567 bool display_warning_if_disabled, | |
| 568 bool datalist_only, | |
| 569 bool show_full_suggestion_list, | |
| 570 bool show_password_suggestions_only) { | |
| 571 if (!element.isEnabled() || element.isReadOnly()) | 587 if (!element.isEnabled() || element.isReadOnly()) |
| 572 return; | 588 return; |
| 573 if (!datalist_only && !element.suggestedValue().isEmpty()) | 589 if (!options.datalist_only && !element.suggestedValue().isEmpty()) |
| 574 return; | 590 return; |
| 575 | 591 |
| 576 const WebInputElement* input_element = toWebInputElement(&element); | 592 const WebInputElement* input_element = toWebInputElement(&element); |
| 577 if (input_element) { | 593 if (input_element) { |
| 578 if (!input_element->isTextField() || input_element->isPasswordField()) | 594 if (!input_element->isTextField() || input_element->isPasswordField()) |
| 579 return; | 595 return; |
| 580 if (!datalist_only && !input_element->suggestedValue().isEmpty()) | 596 if (!options.datalist_only && !input_element->suggestedValue().isEmpty()) |
| 581 return; | 597 return; |
| 582 } else { | 598 } else { |
| 583 DCHECK(IsTextAreaElement(element)); | 599 DCHECK(IsTextAreaElement(element)); |
| 584 if (!element.toConst<WebTextAreaElement>().suggestedValue().isEmpty()) | 600 if (!element.toConst<WebTextAreaElement>().suggestedValue().isEmpty()) |
| 585 return; | 601 return; |
| 586 } | 602 } |
| 587 | 603 |
| 588 // Don't attempt to autofill with values that are too large or if filling | 604 // Don't attempt to autofill with values that are too large or if filling |
| 589 // criteria are not met. | 605 // criteria are not met. |
| 590 WebString value = element.editingValue(); | 606 WebString value = element.editingValue(); |
| 591 if (!datalist_only && | 607 if (!options.datalist_only && |
| 592 (value.length() > kMaxDataLength || | 608 (value.length() > kMaxDataLength || |
| 593 (!autofill_on_empty_values && value.isEmpty()) || | 609 (!options.autofill_on_empty_values && value.isEmpty()) || |
| 594 (requires_caret_at_end && | 610 (options.requires_caret_at_end && |
| 595 (element.selectionStart() != element.selectionEnd() || | 611 (element.selectionStart() != element.selectionEnd() || |
| 596 element.selectionEnd() != static_cast<int>(value.length()))))) { | 612 element.selectionEnd() != static_cast<int>(value.length()))))) { |
| 597 // Any popup currently showing is obsolete. | 613 // Any popup currently showing is obsolete. |
| 598 HidePopup(); | 614 HidePopup(); |
| 599 return; | 615 return; |
| 600 } | 616 } |
| 601 | 617 |
| 602 element_ = element; | 618 element_ = element; |
| 603 if (IsAutofillableInputElement(input_element) && | 619 if (IsAutofillableInputElement(input_element) && |
| 604 (password_autofill_agent_->ShowSuggestions(*input_element, | 620 (password_autofill_agent_->ShowSuggestions( |
| 605 show_full_suggestion_list) || | 621 *input_element, options.show_full_suggestion_list) || |
| 606 show_password_suggestions_only)) { | 622 options.show_password_suggestions_only)) { |
| 607 is_popup_possibly_visible_ = true; | 623 is_popup_possibly_visible_ = true; |
| 608 return; | 624 return; |
| 609 } | 625 } |
| 610 | 626 |
| 611 // If autocomplete is disabled at the field level, ensure that the native | 627 // If autocomplete is disabled at the field level, ensure that the native |
| 612 // UI won't try to show a warning, since that may conflict with a custom | 628 // UI won't try to show a warning, since that may conflict with a custom |
| 613 // popup. Note that we cannot use the WebKit method element.autoComplete() | 629 // popup. Note that we cannot use the WebKit method element.autoComplete() |
| 614 // as it does not allow us to distinguish the case where autocomplete is | 630 // as it does not allow us to distinguish the case where autocomplete is |
| 615 // disabled for *both* the element and for the form. | 631 // disabled for *both* the element and for the form. |
| 616 const base::string16 autocomplete_attribute = | 632 bool display_warning = options.display_warning_if_disabled; |
| 617 element.getAttribute("autocomplete"); | 633 if (display_warning) { |
| 618 if (LowerCaseEqualsASCII(autocomplete_attribute, "off")) | 634 const base::string16 autocomplete_attribute = |
| 619 display_warning_if_disabled = false; | 635 element.getAttribute("autocomplete"); |
| 636 if (LowerCaseEqualsASCII(autocomplete_attribute, "off")) |
| 637 display_warning = false; |
| 638 } |
| 620 | 639 |
| 621 QueryAutofillSuggestions(element, | 640 QueryAutofillSuggestions(element, display_warning, options.datalist_only); |
| 622 display_warning_if_disabled, | |
| 623 datalist_only); | |
| 624 } | 641 } |
| 625 | 642 |
| 626 void AutofillAgent::QueryAutofillSuggestions( | 643 void AutofillAgent::QueryAutofillSuggestions( |
| 627 const WebFormControlElement& element, | 644 const WebFormControlElement& element, |
| 628 bool display_warning_if_disabled, | 645 bool display_warning_if_disabled, |
| 629 bool datalist_only) { | 646 bool datalist_only) { |
| 630 if (!element.document().frame()) | 647 if (!element.document().frame()) |
| 631 return; | 648 return; |
| 632 | 649 |
| 633 DCHECK(toWebInputElement(&element) || IsTextAreaElement(element)); | 650 DCHECK(toWebInputElement(&element) || IsTextAreaElement(element)); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 745 ProcessForms(*frame); | 762 ProcessForms(*frame); |
| 746 password_autofill_agent_->OnDynamicFormsSeen(frame); | 763 password_autofill_agent_->OnDynamicFormsSeen(frame); |
| 747 if (password_generation_agent_) | 764 if (password_generation_agent_) |
| 748 password_generation_agent_->OnDynamicFormsSeen(frame); | 765 password_generation_agent_->OnDynamicFormsSeen(frame); |
| 749 return; | 766 return; |
| 750 } | 767 } |
| 751 } | 768 } |
| 752 } | 769 } |
| 753 | 770 |
| 754 } // namespace autofill | 771 } // namespace autofill |
| OLD | NEW |