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

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

Issue 15949025: In components/autofill, move renderer/ to content/renderer (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Response to reviews Created 7 years, 6 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
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/autofill/renderer/password_autofill_agent.h"
6
7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop.h"
10 #include "base/metrics/histogram.h"
11 #include "components/autofill/common/autofill_messages.h"
12 #include "components/autofill/common/form_field_data.h"
13 #include "components/autofill/common/password_form_fill_data.h"
14 #include "components/autofill/renderer/form_autofill_util.h"
15 #include "content/public/common/password_form.h"
16 #include "content/public/renderer/password_form_conversion_utils.h"
17 #include "content/public/renderer/render_view.h"
18 #include "third_party/WebKit/public/platform/WebVector.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFormElement.h"
23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
27 #include "ui/base/keycodes/keyboard_codes.h"
28
29 namespace autofill {
30 namespace {
31
32 // The size above which we stop triggering autocomplete.
33 static const size_t kMaximumTextSizeForAutocomplete = 1000;
34
35 // Maps element names to the actual elements to simplify form filling.
36 typedef std::map<base::string16, WebKit::WebInputElement>
37 FormInputElementMap;
38
39 // Utility struct for form lookup and autofill. When we parse the DOM to look up
40 // a form, in addition to action and origin URL's we have to compare all
41 // necessary form elements. To avoid having to look these up again when we want
42 // to fill the form, the FindFormElements function stores the pointers
43 // in a FormElements* result, referenced to ensure they are safe to use.
44 struct FormElements {
45 WebKit::WebFormElement form_element;
46 FormInputElementMap input_elements;
47 };
48
49 typedef std::vector<FormElements*> FormElementsList;
50
51 // Helper to search the given form element for the specified input elements
52 // in |data|, and add results to |result|.
53 static bool FindFormInputElements(WebKit::WebFormElement* fe,
54 const FormData& data,
55 FormElements* result) {
56 // Loop through the list of elements we need to find on the form in order to
57 // autofill it. If we don't find any one of them, abort processing this
58 // form; it can't be the right one.
59 for (size_t j = 0; j < data.fields.size(); j++) {
60 WebKit::WebVector<WebKit::WebNode> temp_elements;
61 fe->getNamedElements(data.fields[j].name, temp_elements);
62
63 // Match the first input element, if any.
64 // |getNamedElements| may return non-input elements where the names match,
65 // so the results are filtered for input elements.
66 // If more than one match is made, then we have ambiguity (due to misuse
67 // of "name" attribute) so is it considered not found.
68 bool found_input = false;
69 for (size_t i = 0; i < temp_elements.size(); ++i) {
70 if (temp_elements[i].to<WebKit::WebElement>().hasTagName("input")) {
71 // Check for a non-unique match.
72 if (found_input) {
73 found_input = false;
74 break;
75 }
76
77 // This element matched, add it to our temporary result. It's possible
78 // there are multiple matches, but for purposes of identifying the form
79 // one suffices and if some function needs to deal with multiple
80 // matching elements it can get at them through the FormElement*.
81 // Note: This assignment adds a reference to the InputElement.
82 result->input_elements[data.fields[j].name] =
83 temp_elements[i].to<WebKit::WebInputElement>();
84 found_input = true;
85 }
86 }
87
88 // A required element was not found. This is not the right form.
89 // Make sure no input elements from a partially matched form in this
90 // iteration remain in the result set.
91 // Note: clear will remove a reference from each InputElement.
92 if (!found_input) {
93 result->input_elements.clear();
94 return false;
95 }
96 }
97 return true;
98 }
99
100 // Helper to locate form elements identified by |data|.
101 void FindFormElements(WebKit::WebView* view,
102 const FormData& data,
103 FormElementsList* results) {
104 DCHECK(view);
105 DCHECK(results);
106 WebKit::WebFrame* main_frame = view->mainFrame();
107 if (!main_frame)
108 return;
109
110 GURL::Replacements rep;
111 rep.ClearQuery();
112 rep.ClearRef();
113
114 // Loop through each frame.
115 for (WebKit::WebFrame* f = main_frame; f; f = f->traverseNext(false)) {
116 WebKit::WebDocument doc = f->document();
117 if (!doc.isHTMLDocument())
118 continue;
119
120 GURL full_origin(doc.url());
121 if (data.origin != full_origin.ReplaceComponents(rep))
122 continue;
123
124 WebKit::WebVector<WebKit::WebFormElement> forms;
125 doc.forms(forms);
126
127 for (size_t i = 0; i < forms.size(); ++i) {
128 WebKit::WebFormElement fe = forms[i];
129
130 GURL full_action(f->document().completeURL(fe.action()));
131 if (full_action.is_empty()) {
132 // The default action URL is the form's origin.
133 full_action = full_origin;
134 }
135
136 // Action URL must match.
137 if (data.action != full_action.ReplaceComponents(rep))
138 continue;
139
140 scoped_ptr<FormElements> curr_elements(new FormElements);
141 if (!FindFormInputElements(&fe, data, curr_elements.get()))
142 continue;
143
144 // We found the right element.
145 // Note: this assignment adds a reference to |fe|.
146 curr_elements->form_element = fe;
147 results->push_back(curr_elements.release());
148 }
149 }
150 }
151
152 bool IsElementEditable(const WebKit::WebInputElement& element) {
153 return element.isEnabled() && !element.isReadOnly();
154 }
155
156 void FillForm(FormElements* fe, const FormData& data) {
157 if (!fe->form_element.autoComplete())
158 return;
159
160 std::map<base::string16, base::string16> data_map;
161 for (size_t i = 0; i < data.fields.size(); i++)
162 data_map[data.fields[i].name] = data.fields[i].value;
163
164 for (FormInputElementMap::iterator it = fe->input_elements.begin();
165 it != fe->input_elements.end(); ++it) {
166 WebKit::WebInputElement element = it->second;
167 // Don't fill a form that has pre-filled values distinct from the ones we
168 // want to fill with.
169 if (!element.value().isEmpty() && element.value() != data_map[it->first])
170 return;
171 }
172
173 for (FormInputElementMap::iterator it = fe->input_elements.begin();
174 it != fe->input_elements.end(); ++it) {
175 WebKit::WebInputElement element = it->second;
176 if (!IsElementEditable(element))
177 continue; // Don't fill uneditable fields.
178
179 // TODO(tkent): Check maxlength and pattern.
180 element.setValue(data_map[it->first]);
181 element.setAutofilled(true);
182 element.dispatchFormControlChangeEvent();
183 }
184 }
185
186 void SetElementAutofilled(WebKit::WebInputElement* element, bool autofilled) {
187 if (element->isAutofilled() == autofilled)
188 return;
189 element->setAutofilled(autofilled);
190 // Notify any changeEvent listeners.
191 element->dispatchFormControlChangeEvent();
192 }
193
194 bool DoUsernamesMatch(const base::string16& username1,
195 const base::string16& username2,
196 bool exact_match) {
197 if (exact_match)
198 return username1 == username2;
199 return StartsWith(username1, username2, true);
200 }
201
202 } // namespace
203
204 ////////////////////////////////////////////////////////////////////////////////
205 // PasswordAutofillAgent, public:
206
207 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view)
208 : content::RenderViewObserver(render_view),
209 disable_popup_(false),
210 usernames_usage_(NOTHING_TO_AUTOFILL),
211 web_view_(render_view->GetWebView()),
212 weak_ptr_factory_(this) {
213 }
214
215 PasswordAutofillAgent::~PasswordAutofillAgent() {
216 }
217
218 bool PasswordAutofillAgent::TextFieldDidEndEditing(
219 const WebKit::WebInputElement& element) {
220 LoginToPasswordInfoMap::const_iterator iter =
221 login_to_password_info_.find(element);
222 if (iter == login_to_password_info_.end())
223 return false;
224
225 const PasswordFormFillData& fill_data =
226 iter->second.fill_data;
227
228 // If wait_for_username is false, we should have filled when the text changed.
229 if (!fill_data.wait_for_username)
230 return false;
231
232 WebKit::WebInputElement password = iter->second.password_field;
233 if (!IsElementEditable(password))
234 return false;
235
236 WebKit::WebInputElement username = element; // We need a non-const.
237
238 // Do not set selection when ending an editing session, otherwise it can
239 // mess with focus.
240 FillUserNameAndPassword(&username, &password, fill_data, true, false);
241 return true;
242 }
243
244 bool PasswordAutofillAgent::TextDidChangeInTextField(
245 const WebKit::WebInputElement& element) {
246 LoginToPasswordInfoMap::const_iterator iter =
247 login_to_password_info_.find(element);
248 if (iter == login_to_password_info_.end())
249 return false;
250
251 // The input text is being changed, so any autofilled password is now
252 // outdated.
253 WebKit::WebInputElement username = element; // We need a non-const.
254 WebKit::WebInputElement password = iter->second.password_field;
255 SetElementAutofilled(&username, false);
256 if (password.isAutofilled()) {
257 password.setValue(base::string16());
258 SetElementAutofilled(&password, false);
259 }
260
261 // If wait_for_username is true we will fill when the username loses focus.
262 if (iter->second.fill_data.wait_for_username)
263 return false;
264
265 if (!IsElementEditable(element) ||
266 !element.isText() ||
267 !element.autoComplete()) {
268 return false;
269 }
270
271 // Don't inline autocomplete if the user is deleting, that would be confusing.
272 // But refresh the popup. Note, since this is ours, return true to signal
273 // no further processing is required.
274 if (iter->second.backspace_pressed_last) {
275 ShowSuggestionPopup(iter->second.fill_data, username);
276 return true;
277 }
278
279 WebKit::WebString name = element.nameForAutofill();
280 if (name.isEmpty())
281 return false; // If the field has no name, then we won't have values.
282
283 // Don't attempt to autofill with values that are too large.
284 if (element.value().length() > kMaximumTextSizeForAutocomplete)
285 return false;
286
287 // The caret position should have already been updated.
288 PerformInlineAutocomplete(element, password, iter->second.fill_data);
289 return true;
290 }
291
292 bool PasswordAutofillAgent::TextFieldHandlingKeyDown(
293 const WebKit::WebInputElement& element,
294 const WebKit::WebKeyboardEvent& event) {
295 // If using the new Autofill UI that lives in the browser, it will handle
296 // keypresses before this function. This is not currently an issue but if
297 // the keys handled there or here change, this issue may appear.
298
299 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(element);
300 if (iter == login_to_password_info_.end())
301 return false;
302
303 int win_key_code = event.windowsKeyCode;
304 iter->second.backspace_pressed_last =
305 (win_key_code == ui::VKEY_BACK || win_key_code == ui::VKEY_DELETE);
306 return true;
307 }
308
309 bool PasswordAutofillAgent::DidAcceptAutofillSuggestion(
310 const WebKit::WebNode& node,
311 const WebKit::WebString& value) {
312 WebKit::WebInputElement input;
313 PasswordInfo password;
314 if (!FindLoginInfo(node, &input, &password))
315 return false;
316
317 // Set the incoming |value| in the text field and |FillUserNameAndPassword|
318 // will do the rest.
319 input.setValue(value, true);
320 return FillUserNameAndPassword(&input, &password.password_field,
321 password.fill_data, true, true);
322 }
323
324 bool PasswordAutofillAgent::DidSelectAutofillSuggestion(
325 const WebKit::WebNode& node) {
326 WebKit::WebInputElement input;
327 PasswordInfo password;
328 return FindLoginInfo(node, &input, &password);
329 }
330
331 bool PasswordAutofillAgent::DidClearAutofillSelection(
332 const WebKit::WebNode& node) {
333 WebKit::WebInputElement input;
334 PasswordInfo password;
335 return FindLoginInfo(node, &input, &password);
336 }
337
338 bool PasswordAutofillAgent::ShowSuggestions(
339 const WebKit::WebInputElement& element) {
340 LoginToPasswordInfoMap::const_iterator iter =
341 login_to_password_info_.find(element);
342 if (iter == login_to_password_info_.end())
343 return false;
344
345 return ShowSuggestionPopup(iter->second.fill_data, element);
346 }
347
348 void PasswordAutofillAgent::SendPasswordForms(WebKit::WebFrame* frame,
349 bool only_visible) {
350 // Make sure that this security origin is allowed to use password manager.
351 WebKit::WebSecurityOrigin origin = frame->document().securityOrigin();
352 if (!origin.canAccessPasswordManager())
353 return;
354
355 WebKit::WebVector<WebKit::WebFormElement> forms;
356 frame->document().forms(forms);
357
358 std::vector<content::PasswordForm> password_forms;
359 for (size_t i = 0; i < forms.size(); ++i) {
360 const WebKit::WebFormElement& form = forms[i];
361
362 // If requested, ignore non-rendered forms, e.g. those styled with
363 // display:none.
364 if (only_visible && !form.hasNonEmptyBoundingBox())
365 continue;
366
367 scoped_ptr<content::PasswordForm> password_form(
368 content::CreatePasswordForm(form));
369 if (password_form.get())
370 password_forms.push_back(*password_form);
371 }
372
373 if (password_forms.empty() && !only_visible) {
374 // We need to send the PasswordFormsRendered message regardless of whether
375 // there are any forms visible, as this is also the code path that triggers
376 // showing the infobar.
377 return;
378 }
379
380 if (only_visible) {
381 Send(new AutofillHostMsg_PasswordFormsRendered(
382 routing_id(), password_forms));
383 } else {
384 Send(new AutofillHostMsg_PasswordFormsParsed(routing_id(), password_forms));
385 }
386 }
387
388 bool PasswordAutofillAgent::OnMessageReceived(const IPC::Message& message) {
389 bool handled = true;
390 IPC_BEGIN_MESSAGE_MAP(PasswordAutofillAgent, message)
391 IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordForm, OnFillPasswordForm)
392 IPC_MESSAGE_UNHANDLED(handled = false)
393 IPC_END_MESSAGE_MAP()
394 return handled;
395 }
396
397 void PasswordAutofillAgent::DidStartLoading() {
398 if (usernames_usage_ != NOTHING_TO_AUTOFILL) {
399 UMA_HISTOGRAM_ENUMERATION("PasswordManager.OtherPossibleUsernamesUsage",
400 usernames_usage_, OTHER_POSSIBLE_USERNAMES_MAX);
401 usernames_usage_ = NOTHING_TO_AUTOFILL;
402 }
403 }
404
405 void PasswordAutofillAgent::DidFinishDocumentLoad(WebKit::WebFrame* frame) {
406 // The |frame| contents have been parsed, but not yet rendered. Let the
407 // PasswordManager know that forms are loaded, even though we can't yet tell
408 // whether they're visible.
409 SendPasswordForms(frame, false);
410 }
411
412 void PasswordAutofillAgent::DidFinishLoad(WebKit::WebFrame* frame) {
413 // The |frame| contents have been rendered. Let the PasswordManager know
414 // which of the loaded frames are actually visible to the user. This also
415 // triggers the "Save password?" infobar if the user just submitted a password
416 // form.
417 SendPasswordForms(frame, true);
418 }
419
420 void PasswordAutofillAgent::FrameDetached(WebKit::WebFrame* frame) {
421 FrameClosing(frame);
422 }
423
424 void PasswordAutofillAgent::FrameWillClose(WebKit::WebFrame* frame) {
425 FrameClosing(frame);
426 }
427
428 void PasswordAutofillAgent::OnFillPasswordForm(
429 const PasswordFormFillData& form_data,
430 bool disable_popup) {
431 disable_popup_ = disable_popup;
432 if (usernames_usage_ == NOTHING_TO_AUTOFILL) {
433 if (form_data.other_possible_usernames.size())
434 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_PRESENT;
435 else if (usernames_usage_ == NOTHING_TO_AUTOFILL)
436 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT;
437 }
438
439 FormElementsList forms;
440 // We own the FormElements* in forms.
441 FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms);
442 FormElementsList::iterator iter;
443 for (iter = forms.begin(); iter != forms.end(); ++iter) {
444 scoped_ptr<FormElements> form_elements(*iter);
445
446 // If wait_for_username is true, we don't want to initially fill the form
447 // until the user types in a valid username.
448 if (!form_data.wait_for_username)
449 FillForm(form_elements.get(), form_data.basic_data);
450
451 // Attach autocomplete listener to enable selecting alternate logins.
452 // First, get pointers to username element.
453 WebKit::WebInputElement username_element =
454 form_elements->input_elements[form_data.basic_data.fields[0].name];
455
456 // Get pointer to password element. (We currently only support single
457 // password forms).
458 WebKit::WebInputElement password_element =
459 form_elements->input_elements[form_data.basic_data.fields[1].name];
460
461 // We might have already filled this form if there are two <form> elements
462 // with identical markup.
463 if (login_to_password_info_.find(username_element) !=
464 login_to_password_info_.end())
465 continue;
466
467 PasswordInfo password_info;
468 password_info.fill_data = form_data;
469 password_info.password_field = password_element;
470 login_to_password_info_[username_element] = password_info;
471
472 FormData form;
473 FormFieldData field;
474 FindFormAndFieldForInputElement(
475 username_element, &form, &field, REQUIRE_NONE);
476 Send(new AutofillHostMsg_AddPasswordFormMapping(
477 routing_id(),
478 field,
479 form_data));
480 }
481 }
482
483 ////////////////////////////////////////////////////////////////////////////////
484 // PasswordAutofillAgent, private:
485
486 void PasswordAutofillAgent::GetSuggestions(
487 const PasswordFormFillData& fill_data,
488 const base::string16& input,
489 std::vector<base::string16>* suggestions) {
490 if (StartsWith(fill_data.basic_data.fields[0].value, input, false))
491 suggestions->push_back(fill_data.basic_data.fields[0].value);
492
493 for (PasswordFormFillData::LoginCollection::const_iterator iter =
494 fill_data.additional_logins.begin();
495 iter != fill_data.additional_logins.end(); ++iter) {
496 if (StartsWith(iter->first, input, false))
497 suggestions->push_back(iter->first);
498 }
499
500 for (PasswordFormFillData::UsernamesCollection::const_iterator iter =
501 fill_data.other_possible_usernames.begin();
502 iter != fill_data.other_possible_usernames.end(); ++iter) {
503 for (size_t i = 0; i < iter->second.size(); ++i) {
504 if (StartsWith(iter->second[i], input, false)) {
505 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SHOWN;
506 suggestions->push_back(iter->second[i]);
507 }
508 }
509 }
510 }
511
512 bool PasswordAutofillAgent::ShowSuggestionPopup(
513 const PasswordFormFillData& fill_data,
514 const WebKit::WebInputElement& user_input) {
515 WebKit::WebFrame* frame = user_input.document().frame();
516 if (!frame)
517 return false;
518
519 WebKit::WebView* webview = frame->view();
520 if (!webview)
521 return false;
522
523 std::vector<base::string16> suggestions;
524 GetSuggestions(fill_data, user_input.value(), &suggestions);
525
526 if (disable_popup_) {
527 FormData form;
528 FormFieldData field;
529 FindFormAndFieldForInputElement(
530 user_input, &form, &field, REQUIRE_NONE);
531
532 WebKit::WebInputElement selected_element = user_input;
533 gfx::Rect bounding_box(selected_element.boundsInViewportSpace());
534
535 float scale = web_view_->pageScaleFactor();
536 gfx::RectF bounding_box_scaled(bounding_box.x() * scale,
537 bounding_box.y() * scale,
538 bounding_box.width() * scale,
539 bounding_box.height() * scale);
540 Send(new AutofillHostMsg_ShowPasswordSuggestions(routing_id(),
541 field,
542 bounding_box_scaled,
543 suggestions));
544 return !suggestions.empty();
545 }
546
547
548 if (suggestions.empty()) {
549 webview->hidePopups();
550 return false;
551 }
552
553 std::vector<base::string16> labels(suggestions.size());
554 std::vector<base::string16> icons(suggestions.size());
555 std::vector<int> ids(suggestions.size(),
556 WebKit::WebAutofillClient::MenuItemIDPasswordEntry);
557 webview->applyAutofillSuggestions(
558 user_input, suggestions, labels, icons, ids);
559 return true;
560 }
561
562 bool PasswordAutofillAgent::FillUserNameAndPassword(
563 WebKit::WebInputElement* username_element,
564 WebKit::WebInputElement* password_element,
565 const PasswordFormFillData& fill_data,
566 bool exact_username_match,
567 bool set_selection) {
568 base::string16 current_username = username_element->value();
569 // username and password will contain the match found if any.
570 base::string16 username;
571 base::string16 password;
572
573 // Look for any suitable matches to current field text.
574 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, current_username,
575 exact_username_match)) {
576 username = fill_data.basic_data.fields[0].value;
577 password = fill_data.basic_data.fields[1].value;
578 } else {
579 // Scan additional logins for a match.
580 PasswordFormFillData::LoginCollection::const_iterator iter;
581 for (iter = fill_data.additional_logins.begin();
582 iter != fill_data.additional_logins.end(); ++iter) {
583 if (DoUsernamesMatch(iter->first, current_username,
584 exact_username_match)) {
585 username = iter->first;
586 password = iter->second;
587 break;
588 }
589 }
590
591 // Check possible usernames.
592 if (username.empty() && password.empty()) {
593 for (PasswordFormFillData::UsernamesCollection::const_iterator iter =
594 fill_data.other_possible_usernames.begin();
595 iter != fill_data.other_possible_usernames.end(); ++iter) {
596 for (size_t i = 0; i < iter->second.size(); ++i) {
597 if (DoUsernamesMatch(iter->second[i], current_username,
598 exact_username_match)) {
599 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED;
600 username = iter->second[i];
601 password = iter->first.password;
602 break;
603 }
604 }
605 if (!username.empty() && !password.empty())
606 break;
607 }
608 }
609 }
610 if (password.empty())
611 return false; // No match was found.
612
613 // Input matches the username, fill in required values.
614 username_element->setValue(username);
615
616 if (set_selection) {
617 username_element->setSelectionRange(current_username.length(),
618 username.length());
619 }
620
621 SetElementAutofilled(username_element, true);
622 if (IsElementEditable(*password_element))
623 password_element->setValue(password);
624 SetElementAutofilled(password_element, true);
625 return true;
626 }
627
628 void PasswordAutofillAgent::PerformInlineAutocomplete(
629 const WebKit::WebInputElement& username_input,
630 const WebKit::WebInputElement& password_input,
631 const PasswordFormFillData& fill_data) {
632 DCHECK(!fill_data.wait_for_username);
633
634 // We need non-const versions of the username and password inputs.
635 WebKit::WebInputElement username = username_input;
636 WebKit::WebInputElement password = password_input;
637
638 // Don't inline autocomplete if the caret is not at the end.
639 // TODO(jcivelli): is there a better way to test the caret location?
640 if (username.selectionStart() != username.selectionEnd() ||
641 username.selectionEnd() != static_cast<int>(username.value().length())) {
642 return;
643 }
644
645 // Show the popup with the list of available usernames.
646 ShowSuggestionPopup(fill_data, username);
647
648
649 #if !defined(OS_ANDROID)
650 // Fill the user and password field with the most relevant match. Android
651 // only fills in the fields after the user clicks on the suggestion popup.
652 FillUserNameAndPassword(&username, &password, fill_data, false, true);
653 #endif
654 }
655
656 void PasswordAutofillAgent::FrameClosing(const WebKit::WebFrame* frame) {
657 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin();
658 iter != login_to_password_info_.end();) {
659 if (iter->first.document().frame() == frame)
660 login_to_password_info_.erase(iter++);
661 else
662 ++iter;
663 }
664 }
665
666 bool PasswordAutofillAgent::FindLoginInfo(const WebKit::WebNode& node,
667 WebKit::WebInputElement* found_input,
668 PasswordInfo* found_password) {
669 if (!node.isElementNode())
670 return false;
671
672 WebKit::WebElement element = node.toConst<WebKit::WebElement>();
673 if (!element.hasTagName("input"))
674 return false;
675
676 WebKit::WebInputElement input = element.to<WebKit::WebInputElement>();
677 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input);
678 if (iter == login_to_password_info_.end())
679 return false;
680
681 *found_input = input;
682 *found_password = iter->second;
683 return true;
684 }
685
686 } // namespace autofill
OLDNEW
« no previous file with comments | « components/autofill/renderer/password_autofill_agent.h ('k') | components/autofill/renderer/password_generation_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698