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

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

Issue 208453002: Add "previewing on hover" support for password field. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 9 months 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/password_autofill_agent.h" 5 #include "components/autofill/content/renderer/password_autofill_agent.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h" 8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h" 9 #include "base/message_loop/message_loop.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 211
212 } // namespace 212 } // namespace
213 213
214 //////////////////////////////////////////////////////////////////////////////// 214 ////////////////////////////////////////////////////////////////////////////////
215 // PasswordAutofillAgent, public: 215 // PasswordAutofillAgent, public:
216 216
217 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view) 217 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view)
218 : content::RenderViewObserver(render_view), 218 : content::RenderViewObserver(render_view),
219 usernames_usage_(NOTHING_TO_AUTOFILL), 219 usernames_usage_(NOTHING_TO_AUTOFILL),
220 web_view_(render_view->GetWebView()), 220 web_view_(render_view->GetWebView()),
221 was_password_autofilled_(false),
221 weak_ptr_factory_(this) { 222 weak_ptr_factory_(this) {
222 } 223 }
223 224
224 PasswordAutofillAgent::~PasswordAutofillAgent() {} 225 PasswordAutofillAgent::~PasswordAutofillAgent() {}
225 226
226 PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper() 227 PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper()
227 : was_user_gesture_seen_(false) {} 228 : was_user_gesture_seen_(false) {}
228 229
229 PasswordAutofillAgent::PasswordValueGatekeeper::~PasswordValueGatekeeper() {} 230 PasswordAutofillAgent::PasswordValueGatekeeper::~PasswordValueGatekeeper() {}
230 231
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 328
328 // Don't attempt to autofill with values that are too large. 329 // Don't attempt to autofill with values that are too large.
329 if (element.value().length() > kMaximumTextSizeForAutocomplete) 330 if (element.value().length() > kMaximumTextSizeForAutocomplete)
330 return false; 331 return false;
331 332
332 // The caret position should have already been updated. 333 // The caret position should have already been updated.
333 PerformInlineAutocomplete(element, password, iter->second.fill_data); 334 PerformInlineAutocomplete(element, password, iter->second.fill_data);
334 return true; 335 return true;
335 } 336 }
336 337
338 bool PasswordAutofillAgent::WasPasswordAutofilled() {
339 return was_password_autofilled_;
340 }
341
337 bool PasswordAutofillAgent::TextFieldHandlingKeyDown( 342 bool PasswordAutofillAgent::TextFieldHandlingKeyDown(
338 const blink::WebInputElement& element, 343 const blink::WebInputElement& element,
339 const blink::WebKeyboardEvent& event) { 344 const blink::WebKeyboardEvent& event) {
340 // If using the new Autofill UI that lives in the browser, it will handle 345 // If using the new Autofill UI that lives in the browser, it will handle
341 // keypresses before this function. This is not currently an issue but if 346 // keypresses before this function. This is not currently an issue but if
342 // the keys handled there or here change, this issue may appear. 347 // the keys handled there or here change, this issue may appear.
343 348
344 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(element); 349 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(element);
345 if (iter == login_to_password_info_.end()) 350 if (iter == login_to_password_info_.end())
346 return false; 351 return false;
347 352
348 int win_key_code = event.windowsKeyCode; 353 int win_key_code = event.windowsKeyCode;
349 iter->second.backspace_pressed_last = 354 iter->second.backspace_pressed_last =
350 (win_key_code == ui::VKEY_BACK || win_key_code == ui::VKEY_DELETE); 355 (win_key_code == ui::VKEY_BACK || win_key_code == ui::VKEY_DELETE);
351 return true; 356 return true;
352 } 357 }
353 358
359 bool PasswordAutofillAgent::DidSelectAutofillSuggestion(
360 const blink::WebNode& node,
361 const blink::WebString& username) {
362 blink::WebInputElement input;
363 PasswordInfo password;
364 if (!FindLoginInfo(node, &input, &password))
365 return false;
366
367 // Set the incoming |username| as the suggested value for the text field and
368 // |PreviewUserNameAndPassword| will do the rest.
369 input.setSuggestedValue(username);
370 return PreviewUserNameAndPassword(&input, &password.password_field,
371 password.fill_data,
372 true /* exact_username_match */,
373 true /* set_selection */);
374 }
375
354 bool PasswordAutofillAgent::DidAcceptAutofillSuggestion( 376 bool PasswordAutofillAgent::DidAcceptAutofillSuggestion(
355 const blink::WebNode& node, 377 const blink::WebNode& node,
356 const blink::WebString& username) { 378 const blink::WebString& username) {
357 blink::WebInputElement input; 379 blink::WebInputElement input;
358 PasswordInfo password; 380 PasswordInfo password;
359 if (!FindLoginInfo(node, &input, &password)) 381 if (!FindLoginInfo(node, &input, &password))
360 return false; 382 return false;
361 383
362 // Set the incoming |username| in the text field and |FillUserNameAndPassword| 384 // Set the incoming |username| in the text field and |FillUserNameAndPassword|
363 // will do the rest. 385 // will do the rest.
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 username_element.setValue(fill_data.basic_data.fields[0].value, true); 765 username_element.setValue(fill_data.basic_data.fields[0].value, true);
744 } 766 }
745 767
746 // Fill if we have an exact match for the username. Note that this sets 768 // Fill if we have an exact match for the username. Note that this sets
747 // username to autofilled. 769 // username to autofilled.
748 FillUserNameAndPassword(&username_element, &password_element, fill_data, 770 FillUserNameAndPassword(&username_element, &password_element, fill_data,
749 true /* exact_username_match */, 771 true /* exact_username_match */,
750 false /* set_selection */); 772 false /* set_selection */);
751 } 773 }
752 774
753 bool PasswordAutofillAgent::FillUserNameAndPassword( 775 std::vector<base::string16> PasswordAutofillAgent::FindUserNameAndPassword(
754 blink::WebInputElement* username_element, 776 base::string16 current_username,
755 blink::WebInputElement* password_element,
756 const PasswordFormFillData& fill_data, 777 const PasswordFormFillData& fill_data,
757 bool exact_username_match, 778 bool exact_username_match) {
758 bool set_selection) { 779 std::vector<base::string16> username_and_password;
Ilya Sherman 2014/03/21 22:35:19 Please use out-parameters named "string16* usernam
ziran.sun 2014/03/25 18:25:26 Done.
759 base::string16 current_username = username_element->value();
760 // username and password will contain the match found if any.
761 base::string16 username;
762 base::string16 password;
763
764 // Look for any suitable matches to current field text. 780 // Look for any suitable matches to current field text.
765 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, current_username, 781 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, current_username,
766 exact_username_match)) { 782 exact_username_match)) {
767 username = fill_data.basic_data.fields[0].value; 783 username_and_password.push_back(fill_data.basic_data.fields[0].value);
768 password = fill_data.basic_data.fields[1].value; 784 username_and_password.push_back(fill_data.basic_data.fields[1].value);
769 } else { 785 } else {
770 // Scan additional logins for a match. 786 // Scan additional logins for a match.
771 PasswordFormFillData::LoginCollection::const_iterator iter; 787 PasswordFormFillData::LoginCollection::const_iterator iter;
772 for (iter = fill_data.additional_logins.begin(); 788 for (iter = fill_data.additional_logins.begin();
773 iter != fill_data.additional_logins.end(); ++iter) { 789 iter != fill_data.additional_logins.end(); ++iter) {
774 if (DoUsernamesMatch(iter->first, current_username, 790 if (DoUsernamesMatch(iter->first, current_username,
775 exact_username_match)) { 791 exact_username_match)) {
776 username = iter->first; 792 username_and_password.push_back(iter->first);
777 password = iter->second.password; 793 username_and_password.push_back(iter->second.password);
778 break; 794 break;
779 } 795 }
780 } 796 }
781
782 // Check possible usernames. 797 // Check possible usernames.
783 if (username.empty() && password.empty()) { 798 if (username_and_password.size() == 0) {
784 for (PasswordFormFillData::UsernamesCollection::const_iterator iter = 799 for (PasswordFormFillData::UsernamesCollection::const_iterator iter =
785 fill_data.other_possible_usernames.begin(); 800 fill_data.other_possible_usernames.begin();
786 iter != fill_data.other_possible_usernames.end(); ++iter) { 801 iter != fill_data.other_possible_usernames.end(); ++iter) {
787 for (size_t i = 0; i < iter->second.size(); ++i) { 802 for (size_t i = 0; i < iter->second.size(); ++i) {
788 if (DoUsernamesMatch(iter->second[i], current_username, 803 if (DoUsernamesMatch(iter->second[i], current_username,
789 exact_username_match)) { 804 exact_username_match)) {
790 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED; 805 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED;
791 username = iter->second[i]; 806 username_and_password.push_back(iter->second[i]);
792 password = iter->first.password; 807 username_and_password.push_back(iter->first.password);
793 break; 808 break;
794 } 809 }
795 } 810 }
796 if (!username.empty() && !password.empty()) 811 if (username_and_password.size() == 2)
797 break; 812 break;
798 } 813 }
799 } 814 }
800 } 815 }
801 if (password.empty()) 816 return username_and_password;
817 }
818
819 bool PasswordAutofillAgent::FillUserNameAndPassword(
820 blink::WebInputElement* username_element,
821 blink::WebInputElement* password_element,
822 const PasswordFormFillData& fill_data,
823 bool exact_username_match,
824 bool set_selection) {
825 base::string16 current_username = username_element->value();
826 // username and password will contain the match found if any.
827 std::vector<base::string16> username_and_password =
828 FindUserNameAndPassword (current_username,
829 fill_data,
830 exact_username_match);
831
832 if(username_and_password.size() < 2)
802 return false; // No match was found. 833 return false; // No match was found.
803 834
835 // username and password contain the match found.
836 base::string16 username = username_and_password[0];
837 base::string16 password = username_and_password[1];
838
804 // TODO(tkent): Check maxlength and pattern for both username and password 839 // TODO(tkent): Check maxlength and pattern for both username and password
805 // fields. 840 // fields.
806 841
807 // Don't fill username if password can't be set. 842 // Don't fill username if password can't be set.
808 if (!IsElementAutocompletable(*password_element)) { 843 if (!IsElementAutocompletable(*password_element)) {
809 return false; 844 return false;
810 } 845 }
811 846
812 // Input matches the username, fill in required values. 847 // Input matches the username, fill in required values.
813 if (IsElementAutocompletable(*username_element)) { 848 if (IsElementAutocompletable(*username_element)) {
814 username_element->setValue(username, true); 849 username_element->setValue(username, true);
815 SetElementAutofilled(username_element, true); 850 SetElementAutofilled(username_element, true);
816 851
817 if (set_selection) { 852 if (set_selection) {
818 username_element->setSelectionRange(current_username.length(), 853 username_element->setSelectionRange(current_username.length(),
819 username.length()); 854 username.length());
820 } 855 }
821 } else if (current_username != username) { 856 } else if (current_username != username) {
822 // If the username can't be filled and it doesn't match a saved password 857 // If the username can't be filled and it doesn't match a saved password
823 // as is, don't autofill a password. 858 // as is, don't autofill a password.
824 return false; 859 return false;
825 } 860 }
826 861
862 was_password_autofilled_ = password_element->isAutofilled();
827 // TODO(vabr): The "gatekeeper" feature is currently disabled on mobile. 863 // TODO(vabr): The "gatekeeper" feature is currently disabled on mobile.
828 // http://crbug.com/345510#c13 864 // http://crbug.com/345510#c13
829 #if !defined(OS_ANDROID) || !defined(OS_IOS) 865 #if !defined(OS_ANDROID) || !defined(OS_IOS)
830 // Wait to fill in the password until a user gesture occurs. This is to make 866 // Wait to fill in the password until a user gesture occurs. This is to make
831 // sure that we do not fill in the DOM with a password until we believe the 867 // sure that we do not fill in the DOM with a password until we believe the
832 // user is intentionally interacting with the page. 868 // user is intentionally interacting with the page.
833 password_element->setSuggestedValue(password); 869 password_element->setSuggestedValue(password);
834 gatekeeper_.RegisterElement(password_element); 870 gatekeeper_.RegisterElement(password_element);
835 #else 871 #else
836 password_element->setValue(password); 872 password_element->setValue(password);
837 #endif 873 #endif
838 874
839 // Note: Don't call SetElementAutofilled() here, as that dispatches an 875 // Note: Don't call SetElementAutofilled() here, as that dispatches an
840 // onChange event in JavaScript, which is not appropriate for the password 876 // onChange event in JavaScript, which is not appropriate for the password
841 // element if a user gesture has not yet occured. 877 // element if a user gesture has not yet occured.
842 password_element->setAutofilled(true); 878 password_element->setAutofilled(true);
843 return true; 879 return true;
844 } 880 }
845 881
882 bool PasswordAutofillAgent::PreviewUserNameAndPassword(
883 blink::WebInputElement* username_element,
884 blink::WebInputElement* password_element,
885 const PasswordFormFillData& fill_data,
886 bool exact_username_match,
887 bool set_selection) {
888 base::string16 current_username = username_element->suggestedValue();
889 std::vector<base::string16> username_and_password =
890 FindUserNameAndPassword (current_username,
891 fill_data,
892 exact_username_match);
893
894 if (username_and_password.size() < 2)
895 return false; // No match was found.
896
897 // TODO(tkent): Check maxlength and pattern for both username and password
898 // fields.
899
900 // Don't preview username if password can't be set.
901 if (!IsElementAutocompletable(*password_element)) {
902 return false;
903 }
904
905 base::string16 username = username_and_password[0];
906 base::string16 password = username_and_password[1];
907
908 // Input matches the username, preview required values.
909 if (IsElementAutocompletable(*username_element)) {
910 username_element->setSuggestedValue(username);
911 username_element->setAutofilled(true);
912
913 if (set_selection) {
914 username_element->setSelectionRange(current_username.length(),
915 username.length());
Ilya Sherman 2014/03/21 22:35:19 This will always set an empty selection, right? T
ziran.sun 2014/03/25 18:25:26 I tried to replace current_username.length() with
916 }
917 } else if (current_username != username) {
918 return false;
919 }
920
921 was_password_autofilled_ = password_element->isAutofilled();
922 password_element->setSuggestedValue(password);
923 password_element->setAutofilled(true);
924 return true;
925 }
926
846 void PasswordAutofillAgent::PerformInlineAutocomplete( 927 void PasswordAutofillAgent::PerformInlineAutocomplete(
847 const blink::WebInputElement& username_input, 928 const blink::WebInputElement& username_input,
848 const blink::WebInputElement& password_input, 929 const blink::WebInputElement& password_input,
849 const PasswordFormFillData& fill_data) { 930 const PasswordFormFillData& fill_data) {
850 DCHECK(!fill_data.wait_for_username); 931 DCHECK(!fill_data.wait_for_username);
851 932
852 // We need non-const versions of the username and password inputs. 933 // We need non-const versions of the username and password inputs.
853 blink::WebInputElement username = username_input; 934 blink::WebInputElement username = username_input;
854 blink::WebInputElement password = password_input; 935 blink::WebInputElement password = password_input;
855 936
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
905 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input); 986 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input);
906 if (iter == login_to_password_info_.end()) 987 if (iter == login_to_password_info_.end())
907 return false; 988 return false;
908 989
909 *found_input = input; 990 *found_input = input;
910 *found_password = iter->second; 991 *found_password = iter->second;
911 return true; 992 return true;
912 } 993 }
913 994
914 } // namespace autofill 995 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698