Chromium Code Reviews| 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 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 239 PasswordAutofillAgent::~PasswordAutofillAgent() { | 239 PasswordAutofillAgent::~PasswordAutofillAgent() { |
| 240 } | 240 } |
| 241 | 241 |
| 242 PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper() | 242 PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper() |
| 243 : was_user_gesture_seen_(false) { | 243 : was_user_gesture_seen_(false) { |
| 244 } | 244 } |
| 245 | 245 |
| 246 PasswordAutofillAgent::PasswordValueGatekeeper::~PasswordValueGatekeeper() { | 246 PasswordAutofillAgent::PasswordValueGatekeeper::~PasswordValueGatekeeper() { |
| 247 } | 247 } |
| 248 | 248 |
| 249 void PasswordAutofillAgent::PasswordValueGatekeeper::RegisterElement( | 249 void PasswordAutofillAgent::PasswordValueGatekeeper::RegisterElementInfo( |
| 250 blink::WebInputElement* element) { | 250 PasswordInfo* element_info) { |
| 251 if (was_user_gesture_seen_) | 251 DCHECK(element_info); |
| 252 ShowValue(element); | 252 if (was_user_gesture_seen_) { |
| 253 else | 253 ShowValue(&element_info->password_field); |
| 254 elements_.push_back(*element); | 254 } else { |
| 255 elements_info_.insert(element_info); | |
| 256 } | |
| 257 } | |
| 258 | |
| 259 void PasswordAutofillAgent::PasswordValueGatekeeper::UnregisterElementInfo( | |
| 260 PasswordInfo* element_info) { | |
| 261 elements_info_.erase(element_info); | |
| 255 } | 262 } |
| 256 | 263 |
| 257 void PasswordAutofillAgent::PasswordValueGatekeeper::OnUserGesture() { | 264 void PasswordAutofillAgent::PasswordValueGatekeeper::OnUserGesture() { |
| 258 was_user_gesture_seen_ = true; | 265 was_user_gesture_seen_ = true; |
| 259 | 266 |
| 260 for (std::vector<blink::WebInputElement>::iterator it = elements_.begin(); | 267 for (std::set<PasswordInfo*>::iterator it = elements_info_.begin(); |
| 261 it != elements_.end(); | 268 it != elements_info_.end(); |
| 262 ++it) { | 269 ++it) { |
| 263 ShowValue(&(*it)); | 270 if (!(*it)->wait_for_username_change) |
|
engedy
2014/07/31 17:14:46
I would suggest keeping this logic out of Password
vabr (Chromium)
2014/08/04 15:10:07
I agree. I also realised that the callers, which n
| |
| 271 ShowValue(&(*it)->password_field); | |
| 264 } | 272 } |
| 265 | 273 |
| 266 elements_.clear(); | 274 elements_info_.clear(); |
| 267 } | 275 } |
| 268 | 276 |
| 269 void PasswordAutofillAgent::PasswordValueGatekeeper::Reset() { | 277 void PasswordAutofillAgent::PasswordValueGatekeeper::Reset() { |
| 270 was_user_gesture_seen_ = false; | 278 was_user_gesture_seen_ = false; |
| 271 elements_.clear(); | 279 elements_info_.clear(); |
| 272 } | 280 } |
| 273 | 281 |
| 274 void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue( | 282 void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue( |
| 275 blink::WebInputElement* element) { | 283 blink::WebInputElement* element) { |
| 276 if (!element->isNull() && !element->suggestedValue().isNull()) | 284 if (!element->isNull() && !element->suggestedValue().isEmpty()) |
| 277 element->setValue(element->suggestedValue(), true); | 285 element->setValue(element->suggestedValue(), true); |
| 278 } | 286 } |
| 279 | 287 |
| 280 bool PasswordAutofillAgent::TextFieldDidEndEditing( | 288 bool PasswordAutofillAgent::TextFieldDidEndEditing( |
| 281 const blink::WebInputElement& element) { | 289 const blink::WebInputElement& element) { |
| 282 LoginToPasswordInfoMap::const_iterator iter = | 290 LoginToPasswordInfoMap::const_iterator iter = |
| 283 login_to_password_info_.find(element); | 291 login_to_password_info_.find(element); |
| 284 if (iter == login_to_password_info_.end()) | 292 if (iter == login_to_password_info_.end()) |
|
engedy
2014/07/31 17:14:46
nit: I would personally add an alias here and in T
vabr (Chromium)
2014/08/04 15:10:07
Done.
| |
| 285 return false; | 293 return false; |
| 286 | 294 |
| 287 const PasswordFormFillData& fill_data = iter->second.fill_data; | 295 // Don't let autofill overwrite an explicit change made by the user. |
| 296 if (iter->second->wait_for_username_change) | |
| 297 return false; | |
| 288 | 298 |
| 289 // If wait_for_username is false, we should have filled when the text changed. | 299 // If wait_for_username is false, we should have filled when the text changed. |
| 290 if (!fill_data.wait_for_username) | 300 if (!iter->second->fill_data.wait_for_username) |
| 291 return false; | 301 return false; |
| 292 | 302 |
| 293 blink::WebInputElement password = iter->second.password_field; | 303 if (!IsElementEditable(iter->second->password_field)) |
| 294 if (!IsElementEditable(password)) | |
| 295 return false; | 304 return false; |
| 296 | 305 |
| 297 blink::WebInputElement username = element; // We need a non-const. | 306 blink::WebInputElement username = element; // We need a non-const. |
| 298 | 307 |
| 299 // Do not set selection when ending an editing session, otherwise it can | 308 // Do not set selection when ending an editing session, otherwise it can |
| 300 // mess with focus. | 309 // mess with focus. |
| 301 FillUserNameAndPassword(&username, | 310 FillUserNameAndPassword(&username, |
| 302 &password, | 311 iter->second, |
| 303 fill_data, | |
| 304 true /* exact_username_match */, | 312 true /* exact_username_match */, |
| 305 false /* set_selection */); | 313 false /* set_selection */); |
| 306 return true; | 314 return true; |
| 307 } | 315 } |
| 308 | 316 |
| 309 bool PasswordAutofillAgent::TextDidChangeInTextField( | 317 bool PasswordAutofillAgent::TextDidChangeInTextField( |
| 310 const blink::WebInputElement& element) { | 318 const blink::WebInputElement& element) { |
| 319 // TODO(vabr): Get a mutable argument instead. http://crbug.com/397083 | |
| 320 blink::WebInputElement mutable_element = element; // We need a non-const. | |
| 321 | |
| 311 if (element.isPasswordField()) { | 322 if (element.isPasswordField()) { |
| 312 // Some login forms have event handlers that put a hash of the password into | 323 // Some login forms have event handlers that put a hash of the password into |
| 313 // a hidden field and then clear the password (http://crbug.com/28910, | 324 // a hidden field and then clear the password (http://crbug.com/28910, |
| 314 // http://crbug.com/391693). This method gets called before any of those | 325 // http://crbug.com/391693). This method gets called before any of those |
| 315 // handlers run, so save away a copy of the password in case it gets lost. | 326 // handlers run, so save away a copy of the password in case it gets lost. |
| 316 // To honor the user having explicitly cleared the password, even an empty | 327 // To honor the user having explicitly cleared the password, even an empty |
| 317 // password will be saved here. | 328 // password will be saved here. |
| 318 ProvisionallySavePassword( | 329 ProvisionallySavePassword( |
| 319 element.document().frame(), element.form(), RESTRICTION_NONE); | 330 element.document().frame(), element.form(), RESTRICTION_NONE); |
| 331 | |
| 332 PasswordToLoginMap::iterator iter = password_to_username_.find(element); | |
| 333 if (iter != password_to_username_.end()) { | |
| 334 // The user changed the password after it was autofilled. Flipping the | |
| 335 // flag below to true makes sure it is not overwritten by autofill | |
| 336 // re-firing for the same username. | |
| 337 login_to_password_info_[iter->second]->wait_for_username_change = true; | |
|
engedy
2014/07/31 17:14:46
Perhaps this would be caught by tests, but we shou
vabr (Chromium)
2014/08/04 15:10:06
I'm reasonably certain that TextDidChangeInTextFie
| |
| 338 mutable_element.setAutofilled(false); | |
| 339 } | |
| 320 return false; | 340 return false; |
| 321 } | 341 } |
| 322 | 342 |
| 323 LoginToPasswordInfoMap::const_iterator iter = | 343 LoginToPasswordInfoMap::const_iterator iter = |
| 324 login_to_password_info_.find(element); | 344 login_to_password_info_.find(element); |
| 325 if (iter == login_to_password_info_.end()) | 345 if (iter == login_to_password_info_.end()) |
| 326 return false; | 346 return false; |
| 327 | 347 |
| 328 // The input text is being changed, so any autofilled password is now | 348 // The input text is being changed, so any autofilled password is now |
| 329 // outdated. | 349 // outdated. |
| 330 blink::WebInputElement username = element; // We need a non-const. | 350 mutable_element.setAutofilled(false); |
| 331 username.setAutofilled(false); | 351 iter->second->wait_for_username_change = false; |
|
engedy
2014/07/31 17:14:46
Hmm, let us discuss this logic tomorrow in person,
vabr (Chromium)
2014/08/04 15:10:07
Acknowledged.
| |
| 332 | 352 |
| 333 blink::WebInputElement password = iter->second.password_field; | 353 blink::WebInputElement password = iter->second->password_field; |
| 334 if (password.isAutofilled()) { | 354 if (password.isAutofilled()) { |
| 335 password.setValue(base::string16(), true); | 355 password.setValue(base::string16(), true); |
| 336 password.setAutofilled(false); | 356 password.setAutofilled(false); |
| 337 } | 357 } |
| 338 | 358 |
| 339 // If wait_for_username is true we will fill when the username loses focus. | 359 // If wait_for_username is true we will fill when the username loses focus. |
| 340 if (iter->second.fill_data.wait_for_username) | 360 if (iter->second->fill_data.wait_for_username) |
| 341 return false; | 361 return false; |
| 342 | 362 |
| 343 if (!element.isText() || !IsElementAutocompletable(element) || | 363 if (!element.isText() || !IsElementAutocompletable(element) || |
| 344 !IsElementAutocompletable(password)) { | 364 !IsElementAutocompletable(password)) { |
| 345 return false; | 365 return false; |
| 346 } | 366 } |
| 347 | 367 |
| 348 // Don't inline autocomplete if the user is deleting, that would be confusing. | 368 // Don't inline autocomplete if the user is deleting, that would be confusing. |
| 349 // But refresh the popup. Note, since this is ours, return true to signal | 369 // But refresh the popup. Note, since this is ours, return true to signal |
| 350 // no further processing is required. | 370 // no further processing is required. |
| 351 if (iter->second.backspace_pressed_last) { | 371 if (iter->second->backspace_pressed_last) { |
| 352 ShowSuggestionPopup(iter->second.fill_data, username, false); | 372 ShowSuggestionPopup(iter->second->fill_data, element, false); |
| 353 return true; | 373 return true; |
| 354 } | 374 } |
| 355 | 375 |
| 356 blink::WebString name = element.nameForAutofill(); | 376 blink::WebString name = element.nameForAutofill(); |
| 357 if (name.isEmpty()) | 377 if (name.isEmpty()) |
| 358 return false; // If the field has no name, then we won't have values. | 378 return false; // If the field has no name, then we won't have values. |
| 359 | 379 |
| 360 // Don't attempt to autofill with values that are too large. | 380 // Don't attempt to autofill with values that are too large. |
| 361 if (element.value().length() > kMaximumTextSizeForAutocomplete) | 381 if (element.value().length() > kMaximumTextSizeForAutocomplete) |
| 362 return false; | 382 return false; |
| 363 | 383 |
| 364 // The caret position should have already been updated. | 384 // The caret position should have already been updated. |
| 365 PerformInlineAutocomplete(element, password, iter->second.fill_data); | 385 PerformInlineAutocomplete(&mutable_element, iter->second); |
| 366 return true; | 386 return true; |
| 367 } | 387 } |
| 368 | 388 |
| 369 bool PasswordAutofillAgent::TextFieldHandlingKeyDown( | 389 bool PasswordAutofillAgent::TextFieldHandlingKeyDown( |
| 370 const blink::WebInputElement& element, | 390 const blink::WebInputElement& element, |
| 371 const blink::WebKeyboardEvent& event) { | 391 const blink::WebKeyboardEvent& event) { |
| 372 // If using the new Autofill UI that lives in the browser, it will handle | 392 // If using the new Autofill UI that lives in the browser, it will handle |
| 373 // keypresses before this function. This is not currently an issue but if | 393 // keypresses before this function. This is not currently an issue but if |
| 374 // the keys handled there or here change, this issue may appear. | 394 // the keys handled there or here change, this issue may appear. |
| 375 | 395 |
| 376 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(element); | 396 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(element); |
| 377 if (iter == login_to_password_info_.end()) | 397 if (iter == login_to_password_info_.end()) |
| 378 return false; | 398 return false; |
| 379 | 399 |
| 380 int win_key_code = event.windowsKeyCode; | 400 int win_key_code = event.windowsKeyCode; |
| 381 iter->second.backspace_pressed_last = | 401 iter->second->backspace_pressed_last = |
| 382 (win_key_code == ui::VKEY_BACK || win_key_code == ui::VKEY_DELETE); | 402 (win_key_code == ui::VKEY_BACK || win_key_code == ui::VKEY_DELETE); |
| 383 return true; | 403 return true; |
| 384 } | 404 } |
| 385 | 405 |
| 386 bool PasswordAutofillAgent::FillSuggestion( | 406 bool PasswordAutofillAgent::FillSuggestion( |
| 387 const blink::WebNode& node, | 407 const blink::WebNode& node, |
| 388 const blink::WebString& username, | 408 const blink::WebString& username, |
| 389 const blink::WebString& password) { | 409 const blink::WebString& password) { |
| 390 blink::WebInputElement username_element; | 410 blink::WebInputElement username_element; |
| 391 PasswordInfo password_info; | 411 PasswordInfo* password_info; |
| 392 | 412 |
| 393 if (!FindLoginInfo(node, &username_element, &password_info) || | 413 if (!FindLoginInfo(node, &username_element, &password_info) || |
| 394 !IsElementAutocompletable(username_element) || | 414 !IsElementAutocompletable(username_element) || |
| 395 !IsElementAutocompletable(password_info.password_field)) { | 415 !IsElementAutocompletable(password_info->password_field)) { |
| 396 return false; | 416 return false; |
| 397 } | 417 } |
| 398 | 418 |
| 399 base::string16 current_username = username_element.value(); | 419 if (username_element.value() != username_element.value()) |
| 420 password_info->wait_for_username_change = false; | |
| 400 username_element.setValue(username, true); | 421 username_element.setValue(username, true); |
| 401 username_element.setAutofilled(true); | 422 username_element.setAutofilled(true); |
| 402 username_element.setSelectionRange(username.length(), username.length()); | 423 username_element.setSelectionRange(username.length(), username.length()); |
| 403 | 424 |
| 404 password_info.password_field.setValue(password, true); | 425 password_info->password_field.setValue(password, true); |
| 405 password_info.password_field.setAutofilled(true); | 426 password_info->password_field.setAutofilled(true); |
| 406 | 427 |
| 407 return true; | 428 return true; |
| 408 } | 429 } |
| 409 | 430 |
| 410 bool PasswordAutofillAgent::PreviewSuggestion( | 431 bool PasswordAutofillAgent::PreviewSuggestion( |
| 411 const blink::WebNode& node, | 432 const blink::WebNode& node, |
| 412 const blink::WebString& username, | 433 const blink::WebString& username, |
| 413 const blink::WebString& password) { | 434 const blink::WebString& password) { |
| 414 blink::WebInputElement username_element; | 435 blink::WebInputElement username_element; |
| 415 PasswordInfo password_info; | 436 PasswordInfo* password_info; |
| 416 | 437 |
| 417 if (!FindLoginInfo(node, &username_element, &password_info) || | 438 if (!FindLoginInfo(node, &username_element, &password_info) || |
| 418 !IsElementAutocompletable(username_element) || | 439 !IsElementAutocompletable(username_element) || |
| 419 !IsElementAutocompletable(password_info.password_field)) { | 440 !IsElementAutocompletable(password_info->password_field)) { |
| 420 return false; | 441 return false; |
| 421 } | 442 } |
| 422 | 443 |
| 423 was_username_autofilled_ = username_element.isAutofilled(); | 444 was_username_autofilled_ = username_element.isAutofilled(); |
| 424 username_selection_start_ = username_element.selectionStart(); | 445 username_selection_start_ = username_element.selectionStart(); |
| 425 username_element.setSuggestedValue(username); | 446 username_element.setSuggestedValue(username); |
| 426 username_element.setAutofilled(true); | 447 username_element.setAutofilled(true); |
| 427 username_element.setSelectionRange( | 448 username_element.setSelectionRange( |
| 428 username_selection_start_, | 449 username_selection_start_, |
| 429 username_element.suggestedValue().length()); | 450 username_element.suggestedValue().length()); |
| 430 | 451 |
| 431 was_password_autofilled_ = password_info.password_field.isAutofilled(); | 452 was_password_autofilled_ = password_info->password_field.isAutofilled(); |
| 432 password_info.password_field.setSuggestedValue(password); | 453 password_info->password_field.setSuggestedValue(password); |
| 433 password_info.password_field.setAutofilled(true); | 454 password_info->password_field.setAutofilled(true); |
| 434 | 455 |
| 435 return true; | 456 return true; |
| 436 } | 457 } |
| 437 | 458 |
| 438 bool PasswordAutofillAgent::DidClearAutofillSelection( | 459 bool PasswordAutofillAgent::DidClearAutofillSelection( |
| 439 const blink::WebNode& node) { | 460 const blink::WebNode& node) { |
| 440 blink::WebInputElement username_element; | 461 blink::WebInputElement username_element; |
| 441 PasswordInfo password_info; | 462 PasswordInfo* password_info; |
| 442 if (!FindLoginInfo(node, &username_element, &password_info)) | 463 if (!FindLoginInfo(node, &username_element, &password_info)) |
| 443 return false; | 464 return false; |
| 444 | 465 |
| 445 ClearPreview(&username_element, &password_info.password_field); | 466 ClearPreview(&username_element, &password_info->password_field); |
| 446 return true; | 467 return true; |
| 447 } | 468 } |
| 448 | 469 |
| 449 bool PasswordAutofillAgent::ShowSuggestions( | 470 bool PasswordAutofillAgent::ShowSuggestions( |
| 450 const blink::WebInputElement& element, | 471 const blink::WebInputElement& element, |
| 451 bool show_all) { | 472 bool show_all) { |
| 452 LoginToPasswordInfoMap::const_iterator iter = | 473 LoginToPasswordInfoMap::const_iterator iter = |
| 453 login_to_password_info_.find(element); | 474 login_to_password_info_.find(element); |
| 454 if (iter == login_to_password_info_.end()) | 475 if (iter == login_to_password_info_.end()) |
| 455 return false; | 476 return false; |
| 456 | 477 |
| 457 // If autocomplete='off' is set on the form elements, no suggestion dialog | 478 // If autocomplete='off' is set on the form elements, no suggestion dialog |
| 458 // should be shown. However, return |true| to indicate that this is a known | 479 // should be shown. However, return |true| to indicate that this is a known |
| 459 // password form and that the request to show suggestions has been handled (as | 480 // password form and that the request to show suggestions has been handled (as |
| 460 // a no-op). | 481 // a no-op). |
| 461 if (!IsElementAutocompletable(element) || | 482 if (!IsElementAutocompletable(element) || |
| 462 !IsElementAutocompletable(iter->second.password_field)) | 483 !IsElementAutocompletable(iter->second->password_field)) |
| 463 return true; | 484 return true; |
| 464 | 485 |
| 465 return ShowSuggestionPopup(iter->second.fill_data, element, show_all); | 486 return ShowSuggestionPopup(iter->second->fill_data, element, show_all); |
| 466 } | 487 } |
| 467 | 488 |
| 468 bool PasswordAutofillAgent::OriginCanAccessPasswordManager( | 489 bool PasswordAutofillAgent::OriginCanAccessPasswordManager( |
| 469 const blink::WebSecurityOrigin& origin) { | 490 const blink::WebSecurityOrigin& origin) { |
| 470 return origin.canAccessPasswordManager(); | 491 return origin.canAccessPasswordManager(); |
| 471 } | 492 } |
| 472 | 493 |
| 473 void PasswordAutofillAgent::OnDynamicFormsSeen(blink::WebFrame* frame) { | 494 void PasswordAutofillAgent::OnDynamicFormsSeen(blink::WebFrame* frame) { |
| 474 SendPasswordForms(frame, false /* only_visible */); | 495 SendPasswordForms(frame, false /* only_visible */); |
| 475 } | 496 } |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 789 // Attach autocomplete listener to enable selecting alternate logins. | 810 // Attach autocomplete listener to enable selecting alternate logins. |
| 790 // First, get pointers to username element. | 811 // First, get pointers to username element. |
| 791 blink::WebInputElement username_element = | 812 blink::WebInputElement username_element = |
| 792 form_elements->input_elements[form_data.basic_data.fields[0].name]; | 813 form_elements->input_elements[form_data.basic_data.fields[0].name]; |
| 793 | 814 |
| 794 // Get pointer to password element. (We currently only support single | 815 // Get pointer to password element. (We currently only support single |
| 795 // password forms). | 816 // password forms). |
| 796 blink::WebInputElement password_element = | 817 blink::WebInputElement password_element = |
| 797 form_elements->input_elements[form_data.basic_data.fields[1].name]; | 818 form_elements->input_elements[form_data.basic_data.fields[1].name]; |
| 798 | 819 |
| 799 // If wait_for_username is true, we don't want to initially fill the form | |
| 800 // until the user types in a valid username. | |
| 801 if (!form_data.wait_for_username) | |
| 802 FillFormOnPasswordRecieved(form_data, username_element, password_element); | |
| 803 | |
| 804 // We might have already filled this form if there are two <form> elements | 820 // We might have already filled this form if there are two <form> elements |
| 805 // with identical markup. | 821 // with identical markup. |
| 806 if (login_to_password_info_.find(username_element) != | 822 if (login_to_password_info_.find(username_element) != |
| 807 login_to_password_info_.end()) | 823 login_to_password_info_.end()) |
| 808 continue; | 824 continue; |
| 809 | 825 |
| 810 PasswordInfo password_info; | 826 scoped_ptr<PasswordInfo> password_info(new PasswordInfo); |
| 811 password_info.fill_data = form_data; | 827 password_info->fill_data = form_data; |
| 812 password_info.password_field = password_element; | 828 password_info->password_field = password_element; |
| 813 login_to_password_info_[username_element] = password_info; | 829 login_to_password_info_[username_element] = password_info.get(); |
| 830 password_to_username_[password_element] = username_element; | |
| 831 // If wait_for_username is true, we don't want to initially fill the form | |
| 832 // until the user types in a valid username. | |
| 833 if (!form_data.wait_for_username) | |
| 834 FillFormOnPasswordRecieved(&username_element, password_info.get()); | |
| 835 password_infos_[username_element.document().frame()].push_back( | |
| 836 make_linked_ptr(password_info.release())); | |
| 814 | 837 |
| 815 FormData form; | 838 FormData form; |
| 816 FormFieldData field; | 839 FormFieldData field; |
| 817 FindFormAndFieldForFormControlElement( | 840 FindFormAndFieldForFormControlElement( |
| 818 username_element, &form, &field, REQUIRE_NONE); | 841 username_element, &form, &field, REQUIRE_NONE); |
| 819 Send(new AutofillHostMsg_AddPasswordFormMapping( | 842 Send(new AutofillHostMsg_AddPasswordFormMapping( |
| 820 routing_id(), field, form_data)); | 843 routing_id(), field, form_data)); |
| 821 } | 844 } |
| 822 } | 845 } |
| 823 | 846 |
| 824 void PasswordAutofillAgent::OnSetLoggingState(bool active) { | 847 void PasswordAutofillAgent::OnSetLoggingState(bool active) { |
| 825 logging_state_active_ = active; | 848 logging_state_active_ = active; |
| 826 } | 849 } |
| 827 | 850 |
| 828 //////////////////////////////////////////////////////////////////////////////// | 851 //////////////////////////////////////////////////////////////////////////////// |
| 829 // PasswordAutofillAgent, private: | 852 // PasswordAutofillAgent, private: |
| 830 | 853 |
| 854 PasswordAutofillAgent::PasswordInfo::PasswordInfo() | |
| 855 : backspace_pressed_last(false), wait_for_username_change(false) { | |
| 856 } | |
| 857 | |
| 831 void PasswordAutofillAgent::GetSuggestions( | 858 void PasswordAutofillAgent::GetSuggestions( |
| 832 const PasswordFormFillData& fill_data, | 859 const PasswordFormFillData& fill_data, |
| 833 const base::string16& input, | 860 const base::string16& input, |
| 834 std::vector<base::string16>* suggestions, | 861 std::vector<base::string16>* suggestions, |
| 835 std::vector<base::string16>* realms, | 862 std::vector<base::string16>* realms, |
| 836 bool show_all) { | 863 bool show_all) { |
| 837 if (show_all || | 864 if (show_all || |
| 838 StartsWith(fill_data.basic_data.fields[0].value, input, false)) { | 865 StartsWith(fill_data.basic_data.fields[0].value, input, false)) { |
| 839 suggestions->push_back(fill_data.basic_data.fields[0].value); | 866 suggestions->push_back(fill_data.basic_data.fields[0].value); |
| 840 realms->push_back(base::UTF8ToUTF16(fill_data.preferred_realm)); | 867 realms->push_back(base::UTF8ToUTF16(fill_data.preferred_realm)); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 894 gfx::RectF bounding_box_scaled(bounding_box.x() * scale, | 921 gfx::RectF bounding_box_scaled(bounding_box.x() * scale, |
| 895 bounding_box.y() * scale, | 922 bounding_box.y() * scale, |
| 896 bounding_box.width() * scale, | 923 bounding_box.width() * scale, |
| 897 bounding_box.height() * scale); | 924 bounding_box.height() * scale); |
| 898 Send(new AutofillHostMsg_ShowPasswordSuggestions( | 925 Send(new AutofillHostMsg_ShowPasswordSuggestions( |
| 899 routing_id(), field, bounding_box_scaled, suggestions, realms)); | 926 routing_id(), field, bounding_box_scaled, suggestions, realms)); |
| 900 return !suggestions.empty(); | 927 return !suggestions.empty(); |
| 901 } | 928 } |
| 902 | 929 |
| 903 void PasswordAutofillAgent::FillFormOnPasswordRecieved( | 930 void PasswordAutofillAgent::FillFormOnPasswordRecieved( |
| 904 const PasswordFormFillData& fill_data, | 931 blink::WebInputElement* username_element, |
| 905 blink::WebInputElement username_element, | 932 PasswordInfo* password_info) { |
| 906 blink::WebInputElement password_element) { | 933 blink::WebInputElement* password_element = &password_info->password_field; |
| 907 // Do not fill if the password field is in an iframe. | 934 // Do not fill if the password field is in an iframe. |
| 908 DCHECK(password_element.document().frame()); | 935 DCHECK(password_element->document().frame()); |
| 909 if (password_element.document().frame()->parent()) | 936 if (password_element->document().frame()->parent()) |
| 910 return; | 937 return; |
| 911 | 938 |
| 912 if (!ShouldIgnoreAutocompleteOffForPasswordFields() && | 939 if (!ShouldIgnoreAutocompleteOffForPasswordFields() && |
| 913 !username_element.form().autoComplete()) | 940 !username_element->form().autoComplete()) |
| 914 return; | 941 return; |
| 915 | 942 |
| 916 // If we can't modify the password, don't try to set the username | 943 // If we can't modify the password, don't try to set the username |
| 917 if (!IsElementAutocompletable(password_element)) | 944 if (!IsElementAutocompletable(*password_element)) |
| 918 return; | 945 return; |
| 919 | 946 |
| 920 // Try to set the username to the preferred name, but only if the field | 947 // Try to set the username to the preferred name, but only if the field |
| 921 // can be set and isn't prefilled. | 948 // can be set and isn't prefilled. |
| 922 if (IsElementAutocompletable(username_element) && | 949 if (IsElementAutocompletable(*username_element) && |
| 923 username_element.value().isEmpty()) { | 950 username_element->value().isEmpty()) { |
| 924 // TODO(tkent): Check maxlength and pattern. | 951 // TODO(tkent): Check maxlength and pattern. |
| 925 username_element.setValue(fill_data.basic_data.fields[0].value, true); | 952 username_element->setValue( |
| 953 password_info->fill_data.basic_data.fields[0].value, true); | |
| 926 } | 954 } |
| 927 | 955 |
| 928 // Fill if we have an exact match for the username. Note that this sets | 956 // Fill if we have an exact match for the username. Note that this sets |
| 929 // username to autofilled. | 957 // username to autofilled. |
| 930 FillUserNameAndPassword(&username_element, | 958 FillUserNameAndPassword(username_element, |
| 931 &password_element, | 959 password_info, |
| 932 fill_data, | |
| 933 true /* exact_username_match */, | 960 true /* exact_username_match */, |
| 934 false /* set_selection */); | 961 false /* set_selection */); |
| 935 } | 962 } |
| 936 | 963 |
| 937 bool PasswordAutofillAgent::FillUserNameAndPassword( | 964 bool PasswordAutofillAgent::FillUserNameAndPassword( |
| 938 blink::WebInputElement* username_element, | 965 blink::WebInputElement* username_element, |
| 939 blink::WebInputElement* password_element, | 966 PasswordInfo* password_info, |
| 940 const PasswordFormFillData& fill_data, | |
| 941 bool exact_username_match, | 967 bool exact_username_match, |
| 942 bool set_selection) { | 968 bool set_selection) { |
| 969 blink::WebInputElement password_element = password_info->password_field; | |
| 970 const PasswordFormFillData& fill_data = password_info->fill_data; | |
| 943 base::string16 current_username = username_element->value(); | 971 base::string16 current_username = username_element->value(); |
| 944 // username and password will contain the match found if any. | 972 // username and password will contain the match found if any. |
| 945 base::string16 username; | 973 base::string16 username; |
| 946 base::string16 password; | 974 base::string16 password; |
| 947 | 975 |
| 948 // Look for any suitable matches to current field text. | 976 // Look for any suitable matches to current field text. |
| 949 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, | 977 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, |
| 950 current_username, | 978 current_username, |
| 951 exact_username_match)) { | 979 exact_username_match)) { |
| 952 username = fill_data.basic_data.fields[0].value; | 980 username = fill_data.basic_data.fields[0].value; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 985 } | 1013 } |
| 986 } | 1014 } |
| 987 } | 1015 } |
| 988 if (password.empty()) | 1016 if (password.empty()) |
| 989 return false; // No match was found. | 1017 return false; // No match was found. |
| 990 | 1018 |
| 991 // TODO(tkent): Check maxlength and pattern for both username and password | 1019 // TODO(tkent): Check maxlength and pattern for both username and password |
| 992 // fields. | 1020 // fields. |
| 993 | 1021 |
| 994 // Don't fill username if password can't be set. | 1022 // Don't fill username if password can't be set. |
| 995 if (!IsElementAutocompletable(*password_element)) { | 1023 if (!IsElementAutocompletable(password_element)) { |
| 996 return false; | 1024 return false; |
| 997 } | 1025 } |
| 998 | 1026 |
| 999 // Input matches the username, fill in required values. | 1027 // Input matches the username, fill in required values. |
| 1000 if (IsElementAutocompletable(*username_element)) { | 1028 if (IsElementAutocompletable(*username_element)) { |
| 1001 username_element->setValue(username, true); | 1029 username_element->setValue(username, true); |
| 1002 username_element->setAutofilled(true); | 1030 username_element->setAutofilled(true); |
| 1003 | 1031 |
| 1004 if (set_selection) { | 1032 if (set_selection) { |
| 1005 username_element->setSelectionRange(current_username.length(), | 1033 username_element->setSelectionRange(current_username.length(), |
| 1006 username.length()); | 1034 username.length()); |
| 1007 } | 1035 } |
| 1008 } else if (current_username != username) { | 1036 } else if (current_username != username) { |
| 1009 // If the username can't be filled and it doesn't match a saved password | 1037 // If the username can't be filled and it doesn't match a saved password |
| 1010 // as is, don't autofill a password. | 1038 // as is, don't autofill a password. |
| 1011 return false; | 1039 return false; |
| 1012 } | 1040 } |
| 1013 | 1041 |
| 1014 // Wait to fill in the password until a user gesture occurs. This is to make | 1042 // Wait to fill in the password until a user gesture occurs. This is to make |
| 1015 // sure that we do not fill in the DOM with a password until we believe the | 1043 // sure that we do not fill in the DOM with a password until we believe the |
| 1016 // user is intentionally interacting with the page. | 1044 // user is intentionally interacting with the page. |
| 1017 password_element->setSuggestedValue(password); | 1045 password_element.setSuggestedValue(password); |
| 1018 gatekeeper_.RegisterElement(password_element); | 1046 gatekeeper_.RegisterElementInfo(password_info); |
| 1019 | 1047 |
| 1020 password_element->setAutofilled(true); | 1048 password_element.setAutofilled(true); |
| 1021 return true; | 1049 return true; |
| 1022 } | 1050 } |
| 1023 | 1051 |
| 1024 void PasswordAutofillAgent::PerformInlineAutocomplete( | 1052 void PasswordAutofillAgent::PerformInlineAutocomplete( |
| 1025 const blink::WebInputElement& username_input, | 1053 blink::WebInputElement* username, |
| 1026 const blink::WebInputElement& password_input, | 1054 PasswordInfo* password_info) { |
| 1027 const PasswordFormFillData& fill_data) { | 1055 DCHECK(!password_info->fill_data.wait_for_username); |
| 1028 DCHECK(!fill_data.wait_for_username); | |
| 1029 | 1056 |
| 1030 // We need non-const versions of the username and password inputs. | 1057 blink::WebInputElement password = password_info->password_field; |
| 1031 blink::WebInputElement username = username_input; | |
| 1032 blink::WebInputElement password = password_input; | |
| 1033 | 1058 |
| 1034 // Don't inline autocomplete if the caret is not at the end. | 1059 // Don't inline autocomplete if the caret is not at the end. |
| 1035 // TODO(jcivelli): is there a better way to test the caret location? | 1060 // TODO(jcivelli): is there a better way to test the caret location? |
| 1036 if (username.selectionStart() != username.selectionEnd() || | 1061 if (username->selectionStart() != username->selectionEnd() || |
| 1037 username.selectionEnd() != static_cast<int>(username.value().length())) { | 1062 username->selectionEnd() != |
| 1063 static_cast<int>(username->value().length())) { | |
| 1038 return; | 1064 return; |
| 1039 } | 1065 } |
| 1040 | 1066 |
| 1041 // Show the popup with the list of available usernames. | 1067 // Show the popup with the list of available usernames. |
| 1042 ShowSuggestionPopup(fill_data, username, false); | 1068 ShowSuggestionPopup(password_info->fill_data, *username, false); |
| 1043 | 1069 |
| 1044 #if !defined(OS_ANDROID) | 1070 #if !defined(OS_ANDROID) |
| 1045 // Fill the user and password field with the most relevant match. Android | 1071 // Fill the user and password field with the most relevant match. Android |
| 1046 // only fills in the fields after the user clicks on the suggestion popup. | 1072 // only fills in the fields after the user clicks on the suggestion popup. |
| 1047 FillUserNameAndPassword(&username, | 1073 FillUserNameAndPassword(username, |
| 1048 &password, | 1074 password_info, |
| 1049 fill_data, | |
| 1050 false /* exact_username_match */, | 1075 false /* exact_username_match */, |
| 1051 true /* set_selection */); | 1076 true /* set_selection */); |
| 1052 #endif | 1077 #endif |
| 1053 } | 1078 } |
| 1054 | 1079 |
| 1055 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { | 1080 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { |
| 1056 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); | 1081 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); |
| 1057 iter != login_to_password_info_.end();) { | 1082 iter != login_to_password_info_.end();) { |
| 1058 if (iter->first.document().frame() == frame) | 1083 if (iter->first.document().frame() == frame) { |
| 1084 password_to_username_.erase(iter->second->password_field); | |
| 1085 gatekeeper_.UnregisterElementInfo(iter->second); | |
| 1059 login_to_password_info_.erase(iter++); | 1086 login_to_password_info_.erase(iter++); |
| 1060 else | 1087 } else { |
| 1061 ++iter; | 1088 ++iter; |
| 1089 } | |
| 1062 } | 1090 } |
| 1091 password_infos_.erase(frame); | |
| 1063 for (FrameToPasswordFormMap::iterator iter = | 1092 for (FrameToPasswordFormMap::iterator iter = |
| 1064 provisionally_saved_forms_.begin(); | 1093 provisionally_saved_forms_.begin(); |
| 1065 iter != provisionally_saved_forms_.end();) { | 1094 iter != provisionally_saved_forms_.end();) { |
| 1066 if (iter->first == frame) | 1095 if (iter->first == frame) |
| 1067 provisionally_saved_forms_.erase(iter++); | 1096 provisionally_saved_forms_.erase(iter++); |
| 1068 else | 1097 else |
| 1069 ++iter; | 1098 ++iter; |
| 1070 } | 1099 } |
| 1071 } | 1100 } |
| 1072 | 1101 |
| 1073 bool PasswordAutofillAgent::FindLoginInfo(const blink::WebNode& node, | 1102 bool PasswordAutofillAgent::FindLoginInfo(const blink::WebNode& node, |
| 1074 blink::WebInputElement* found_input, | 1103 blink::WebInputElement* found_input, |
| 1075 PasswordInfo* found_password) { | 1104 PasswordInfo** found_password) { |
| 1076 if (!node.isElementNode()) | 1105 if (!node.isElementNode()) |
| 1077 return false; | 1106 return false; |
| 1078 | 1107 |
| 1079 blink::WebElement element = node.toConst<blink::WebElement>(); | 1108 blink::WebElement element = node.toConst<blink::WebElement>(); |
| 1080 if (!element.hasHTMLTagName("input")) | 1109 if (!element.hasHTMLTagName("input")) |
| 1081 return false; | 1110 return false; |
| 1082 | 1111 |
| 1083 blink::WebInputElement input = element.to<blink::WebInputElement>(); | 1112 blink::WebInputElement input = element.to<blink::WebInputElement>(); |
| 1084 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input); | 1113 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input); |
| 1085 if (iter == login_to_password_info_.end()) | 1114 if (iter == login_to_password_info_.end()) |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 1112 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); | 1141 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); |
| 1113 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && | 1142 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && |
| 1114 password_form->password_value.empty() && | 1143 password_form->password_value.empty() && |
| 1115 password_form->new_password_value.empty())) { | 1144 password_form->new_password_value.empty())) { |
| 1116 return; | 1145 return; |
| 1117 } | 1146 } |
| 1118 provisionally_saved_forms_[frame].reset(password_form.release()); | 1147 provisionally_saved_forms_[frame].reset(password_form.release()); |
| 1119 } | 1148 } |
| 1120 | 1149 |
| 1121 } // namespace autofill | 1150 } // namespace autofill |
| OLD | NEW |