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