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/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 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
157 curr_elements->form_element = fe; | 157 curr_elements->form_element = fe; |
158 results->push_back(curr_elements.release()); | 158 results->push_back(curr_elements.release()); |
159 } | 159 } |
160 } | 160 } |
161 } | 161 } |
162 | 162 |
163 bool IsElementEditable(const WebKit::WebInputElement& element) { | 163 bool IsElementEditable(const WebKit::WebInputElement& element) { |
164 return element.isEnabled() && !element.isReadOnly(); | 164 return element.isEnabled() && !element.isReadOnly(); |
165 } | 165 } |
166 | 166 |
167 void FillForm(FormElements* fe, const FormData& data) { | |
168 if (!fe->form_element.autoComplete()) | |
169 return; | |
170 | |
171 std::map<base::string16, base::string16> data_map; | |
172 for (size_t i = 0; i < data.fields.size(); i++) | |
173 data_map[data.fields[i].name] = data.fields[i].value; | |
174 | |
175 for (FormInputElementMap::iterator it = fe->input_elements.begin(); | |
176 it != fe->input_elements.end(); ++it) { | |
177 WebKit::WebInputElement element = it->second; | |
178 // Don't fill a form that has pre-filled values distinct from the ones we | |
179 // want to fill with. | |
180 if (!element.value().isEmpty() && element.value() != data_map[it->first]) | |
181 return; | |
182 | |
183 // Don't fill forms with uneditable fields or fields with autocomplete | |
184 // disabled. | |
185 if (!IsElementEditable(element) || !element.autoComplete()) | |
186 return; | |
187 } | |
188 | |
189 for (FormInputElementMap::iterator it = fe->input_elements.begin(); | |
190 it != fe->input_elements.end(); ++it) { | |
191 WebKit::WebInputElement element = it->second; | |
192 | |
193 // TODO(tkent): Check maxlength and pattern. | |
194 element.setValue(data_map[it->first]); | |
195 element.setAutofilled(true); | |
196 element.dispatchFormControlChangeEvent(); | |
197 } | |
198 } | |
199 | |
200 void SetElementAutofilled(WebKit::WebInputElement* element, bool autofilled) { | 167 void SetElementAutofilled(WebKit::WebInputElement* element, bool autofilled) { |
201 if (element->isAutofilled() == autofilled) | 168 if (element->isAutofilled() == autofilled) |
202 return; | 169 return; |
203 element->setAutofilled(autofilled); | 170 element->setAutofilled(autofilled); |
204 // Notify any changeEvent listeners. | 171 // Notify any changeEvent listeners. |
205 element->dispatchFormControlChangeEvent(); | 172 element->dispatchFormControlChangeEvent(); |
206 } | 173 } |
207 | 174 |
208 bool DoUsernamesMatch(const base::string16& username1, | 175 bool DoUsernamesMatch(const base::string16& username1, |
209 const base::string16& username2, | 176 const base::string16& username2, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 return false; | 210 return false; |
244 | 211 |
245 WebKit::WebInputElement password = iter->second.password_field; | 212 WebKit::WebInputElement password = iter->second.password_field; |
246 if (!IsElementEditable(password)) | 213 if (!IsElementEditable(password)) |
247 return false; | 214 return false; |
248 | 215 |
249 WebKit::WebInputElement username = element; // We need a non-const. | 216 WebKit::WebInputElement username = element; // We need a non-const. |
250 | 217 |
251 // Do not set selection when ending an editing session, otherwise it can | 218 // Do not set selection when ending an editing session, otherwise it can |
252 // mess with focus. | 219 // mess with focus. |
253 FillUserNameAndPassword(&username, &password, fill_data, true, false); | 220 FillUserNameAndPassword(&username, &password, fill_data, |
221 true /* exact_username_match */, | |
222 false /* set_selection */); | |
254 return true; | 223 return true; |
255 } | 224 } |
256 | 225 |
257 bool PasswordAutofillAgent::TextDidChangeInTextField( | 226 bool PasswordAutofillAgent::TextDidChangeInTextField( |
258 const WebKit::WebInputElement& element) { | 227 const WebKit::WebInputElement& element) { |
259 LoginToPasswordInfoMap::const_iterator iter = | 228 LoginToPasswordInfoMap::const_iterator iter = |
260 login_to_password_info_.find(element); | 229 login_to_password_info_.find(element); |
261 if (iter == login_to_password_info_.end()) | 230 if (iter == login_to_password_info_.end()) |
262 return false; | 231 return false; |
263 | 232 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
324 const WebKit::WebString& value) { | 293 const WebKit::WebString& value) { |
325 WebKit::WebInputElement input; | 294 WebKit::WebInputElement input; |
326 PasswordInfo password; | 295 PasswordInfo password; |
327 if (!FindLoginInfo(node, &input, &password)) | 296 if (!FindLoginInfo(node, &input, &password)) |
328 return false; | 297 return false; |
329 | 298 |
330 // Set the incoming |value| in the text field and |FillUserNameAndPassword| | 299 // Set the incoming |value| in the text field and |FillUserNameAndPassword| |
331 // will do the rest. | 300 // will do the rest. |
332 input.setValue(value, true); | 301 input.setValue(value, true); |
333 return FillUserNameAndPassword(&input, &password.password_field, | 302 return FillUserNameAndPassword(&input, &password.password_field, |
334 password.fill_data, true, true); | 303 password.fill_data, |
304 true /* exact_username_match */, | |
305 true /* set_selection */); | |
335 } | 306 } |
336 | 307 |
337 bool PasswordAutofillAgent::DidClearAutofillSelection( | 308 bool PasswordAutofillAgent::DidClearAutofillSelection( |
338 const WebKit::WebNode& node) { | 309 const WebKit::WebNode& node) { |
339 WebKit::WebInputElement input; | 310 WebKit::WebInputElement input; |
340 PasswordInfo password; | 311 PasswordInfo password; |
341 return FindLoginInfo(node, &input, &password); | 312 return FindLoginInfo(node, &input, &password); |
342 } | 313 } |
343 | 314 |
344 bool PasswordAutofillAgent::ShowSuggestions( | 315 bool PasswordAutofillAgent::ShowSuggestions( |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
509 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT; | 480 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT; |
510 } | 481 } |
511 | 482 |
512 FormElementsList forms; | 483 FormElementsList forms; |
513 // We own the FormElements* in forms. | 484 // We own the FormElements* in forms. |
514 FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms); | 485 FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms); |
515 FormElementsList::iterator iter; | 486 FormElementsList::iterator iter; |
516 for (iter = forms.begin(); iter != forms.end(); ++iter) { | 487 for (iter = forms.begin(); iter != forms.end(); ++iter) { |
517 scoped_ptr<FormElements> form_elements(*iter); | 488 scoped_ptr<FormElements> form_elements(*iter); |
518 | 489 |
519 // If wait_for_username is true, we don't want to initially fill the form | |
520 // until the user types in a valid username. | |
521 if (!form_data.wait_for_username) | |
522 FillForm(form_elements.get(), form_data.basic_data); | |
523 | |
524 // Attach autocomplete listener to enable selecting alternate logins. | 490 // Attach autocomplete listener to enable selecting alternate logins. |
525 // First, get pointers to username element. | 491 // First, get pointers to username element. |
526 WebKit::WebInputElement username_element = | 492 WebKit::WebInputElement username_element = |
527 form_elements->input_elements[form_data.basic_data.fields[0].name]; | 493 form_elements->input_elements[form_data.basic_data.fields[0].name]; |
528 | 494 |
529 // Get pointer to password element. (We currently only support single | 495 // Get pointer to password element. (We currently only support single |
530 // password forms). | 496 // password forms). |
531 WebKit::WebInputElement password_element = | 497 WebKit::WebInputElement password_element = |
532 form_elements->input_elements[form_data.basic_data.fields[1].name]; | 498 form_elements->input_elements[form_data.basic_data.fields[1].name]; |
533 | 499 |
500 // If wait_for_username is true, we don't want to initially fill the form | |
501 // until the user types in a valid username. | |
502 if (!form_data.wait_for_username) { | |
503 FillFormOnPasswordRecieved(form_data, form_elements->form_element, | |
504 username_element, password_element); | |
505 } | |
506 | |
534 // We might have already filled this form if there are two <form> elements | 507 // We might have already filled this form if there are two <form> elements |
535 // with identical markup. | 508 // with identical markup. |
536 if (login_to_password_info_.find(username_element) != | 509 if (login_to_password_info_.find(username_element) != |
537 login_to_password_info_.end()) | 510 login_to_password_info_.end()) |
538 continue; | 511 continue; |
539 | 512 |
540 PasswordInfo password_info; | 513 PasswordInfo password_info; |
541 password_info.fill_data = form_data; | 514 password_info.fill_data = form_data; |
542 password_info.password_field = password_element; | 515 password_info.password_field = password_element; |
543 login_to_password_info_[username_element] = password_info; | 516 login_to_password_info_[username_element] = password_info; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
618 bounding_box.width() * scale, | 591 bounding_box.width() * scale, |
619 bounding_box.height() * scale); | 592 bounding_box.height() * scale); |
620 Send(new AutofillHostMsg_ShowPasswordSuggestions(routing_id(), | 593 Send(new AutofillHostMsg_ShowPasswordSuggestions(routing_id(), |
621 field, | 594 field, |
622 bounding_box_scaled, | 595 bounding_box_scaled, |
623 suggestions, | 596 suggestions, |
624 realms)); | 597 realms)); |
625 return !suggestions.empty(); | 598 return !suggestions.empty(); |
626 } | 599 } |
627 | 600 |
601 void PasswordAutofillAgent::FillFormOnPasswordRecieved( | |
602 const PasswordFormFillData& fill_data, | |
603 const WebKit::WebFormElement& form_element, | |
604 WebKit::WebInputElement username_element, | |
605 WebKit::WebInputElement password_element) { | |
606 if (!form_element.autoComplete()) | |
607 return; | |
608 | |
609 // If we can't modify the password, don't try to set the username | |
610 if (!IsElementEditable(password_element) || !password_element.autoComplete()) | |
611 return; | |
612 | |
613 // Try and set the username to the preferred name, but only if the field | |
614 // can be set and isn't prefilled. | |
615 if (IsElementEditable(username_element) && | |
616 username_element.autoComplete() && | |
617 username_element.value().isEmpty()) { | |
618 username_element.setValue(fill_data.basic_data.fields[0].value); | |
619 } | |
620 | |
621 // Fill if we have an exact match for the username. Note that this sets | |
622 // username to autofilled. | |
623 FillUserNameAndPassword(&username_element, &password_element, fill_data, | |
624 true /* exact_username_match */, | |
625 false /* set_selection */); | |
626 } | |
627 | |
628 bool PasswordAutofillAgent::FillUserNameAndPassword( | 628 bool PasswordAutofillAgent::FillUserNameAndPassword( |
629 WebKit::WebInputElement* username_element, | 629 WebKit::WebInputElement* username_element, |
630 WebKit::WebInputElement* password_element, | 630 WebKit::WebInputElement* password_element, |
631 const PasswordFormFillData& fill_data, | 631 const PasswordFormFillData& fill_data, |
632 bool exact_username_match, | 632 bool exact_username_match, |
633 bool set_selection) { | 633 bool set_selection) { |
634 base::string16 current_username = username_element->value(); | 634 base::string16 current_username = username_element->value(); |
635 // username and password will contain the match found if any. | 635 // username and password will contain the match found if any. |
636 base::string16 username; | 636 base::string16 username; |
637 base::string16 password; | 637 base::string16 password; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
678 | 678 |
679 // Input matches the username, fill in required values. | 679 // Input matches the username, fill in required values. |
680 username_element->setValue(username); | 680 username_element->setValue(username); |
681 | 681 |
682 if (set_selection) { | 682 if (set_selection) { |
683 username_element->setSelectionRange(current_username.length(), | 683 username_element->setSelectionRange(current_username.length(), |
684 username.length()); | 684 username.length()); |
685 } | 685 } |
686 | 686 |
687 SetElementAutofilled(username_element, true); | 687 SetElementAutofilled(username_element, true); |
688 if (IsElementEditable(*password_element)) | 688 if (IsElementEditable(*password_element)) { |
689 // TODO(tkent): Check maxlength and pattern | |
Ilya Sherman
2013/11/05 01:25:12
This should apply to the username element as well,
Garrett Casto
2013/11/05 01:56:39
Done.
| |
689 password_element->setValue(password); | 690 password_element->setValue(password); |
691 } | |
690 SetElementAutofilled(password_element, true); | 692 SetElementAutofilled(password_element, true); |
691 return true; | 693 return true; |
692 } | 694 } |
693 | 695 |
694 void PasswordAutofillAgent::PerformInlineAutocomplete( | 696 void PasswordAutofillAgent::PerformInlineAutocomplete( |
695 const WebKit::WebInputElement& username_input, | 697 const WebKit::WebInputElement& username_input, |
696 const WebKit::WebInputElement& password_input, | 698 const WebKit::WebInputElement& password_input, |
697 const PasswordFormFillData& fill_data) { | 699 const PasswordFormFillData& fill_data) { |
698 DCHECK(!fill_data.wait_for_username); | 700 DCHECK(!fill_data.wait_for_username); |
699 | 701 |
700 // We need non-const versions of the username and password inputs. | 702 // We need non-const versions of the username and password inputs. |
701 WebKit::WebInputElement username = username_input; | 703 WebKit::WebInputElement username = username_input; |
702 WebKit::WebInputElement password = password_input; | 704 WebKit::WebInputElement password = password_input; |
703 | 705 |
704 // Don't inline autocomplete if the caret is not at the end. | 706 // Don't inline autocomplete if the caret is not at the end. |
705 // TODO(jcivelli): is there a better way to test the caret location? | 707 // TODO(jcivelli): is there a better way to test the caret location? |
706 if (username.selectionStart() != username.selectionEnd() || | 708 if (username.selectionStart() != username.selectionEnd() || |
707 username.selectionEnd() != static_cast<int>(username.value().length())) { | 709 username.selectionEnd() != static_cast<int>(username.value().length())) { |
708 return; | 710 return; |
709 } | 711 } |
710 | 712 |
711 // Show the popup with the list of available usernames. | 713 // Show the popup with the list of available usernames. |
712 ShowSuggestionPopup(fill_data, username); | 714 ShowSuggestionPopup(fill_data, username); |
713 | 715 |
714 | 716 |
715 #if !defined(OS_ANDROID) | 717 #if !defined(OS_ANDROID) |
716 // Fill the user and password field with the most relevant match. Android | 718 // Fill the user and password field with the most relevant match. Android |
717 // only fills in the fields after the user clicks on the suggestion popup. | 719 // only fills in the fields after the user clicks on the suggestion popup. |
718 FillUserNameAndPassword(&username, &password, fill_data, false, true); | 720 FillUserNameAndPassword(&username, &password, fill_data, |
721 false /* exact_username_match */, | |
722 true /* set_selection */); | |
719 #endif | 723 #endif |
720 } | 724 } |
721 | 725 |
722 void PasswordAutofillAgent::FrameClosing(const WebKit::WebFrame* frame) { | 726 void PasswordAutofillAgent::FrameClosing(const WebKit::WebFrame* frame) { |
723 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); | 727 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); |
724 iter != login_to_password_info_.end();) { | 728 iter != login_to_password_info_.end();) { |
725 if (iter->first.document().frame() == frame) | 729 if (iter->first.document().frame() == frame) |
726 login_to_password_info_.erase(iter++); | 730 login_to_password_info_.erase(iter++); |
727 else | 731 else |
728 ++iter; | 732 ++iter; |
(...skipping 14 matching lines...) Expand all Loading... | |
743 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input); | 747 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input); |
744 if (iter == login_to_password_info_.end()) | 748 if (iter == login_to_password_info_.end()) |
745 return false; | 749 return false; |
746 | 750 |
747 *found_input = input; | 751 *found_input = input; |
748 *found_password = iter->second; | 752 *found_password = iter->second; |
749 return true; | 753 return true; |
750 } | 754 } |
751 | 755 |
752 } // namespace autofill | 756 } // namespace autofill |
OLD | NEW |