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

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

Issue 753393004: Add flag for single click autofill (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years 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/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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698