| Index: components/autofill/content/renderer/password_autofill_agent.cc
|
| diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
|
| index 7a9099b6aabc2e2115724c67eaa1a98b7a4542bc..93685a7b432b5fad1545c4bc1dab634a79c8345c 100644
|
| --- a/components/autofill/content/renderer/password_autofill_agent.cc
|
| +++ b/components/autofill/content/renderer/password_autofill_agent.cc
|
| @@ -5,6 +5,7 @@
|
| #include "components/autofill/content/renderer/password_autofill_agent.h"
|
|
|
| #include "base/bind.h"
|
| +#include "base/command_line.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/message_loop/message_loop.h"
|
| #include "base/metrics/histogram.h"
|
| @@ -13,6 +14,7 @@
|
| #include "components/autofill/content/renderer/form_autofill_util.h"
|
| #include "components/autofill/content/renderer/password_form_conversion_utils.h"
|
| #include "components/autofill/content/renderer/renderer_save_password_progress_logger.h"
|
| +#include "components/autofill/core/common/autofill_switches.h"
|
| #include "components/autofill/core/common/form_field_data.h"
|
| #include "components/autofill/core/common/password_form.h"
|
| #include "components/autofill/core/common/password_form_fill_data.h"
|
| @@ -119,6 +121,23 @@ bool FindFormInputElement(blink::WebFormElement* form_element,
|
| return true;
|
| }
|
|
|
| +bool ShouldFillOnAccountSelect() {
|
| + if (CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kEnableFillOnAccountSelect)) {
|
| + return true;
|
| + }
|
| +
|
| + // This is made explicit in anticiption of experimental groups being added.
|
| + if (CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kDisableFillOnAccountSelect)) {
|
| + return false;
|
| + }
|
| +
|
| + // TODO(jww): Add experimental groups check here.
|
| +
|
| + return false;
|
| +}
|
| +
|
| // Helper to search the given form element for the specified input elements in
|
| // |data|, and add results to |result|.
|
| bool FindFormInputElements(blink::WebFormElement* form_element,
|
| @@ -280,7 +299,8 @@ bool GetSuggestionsStats(const PasswordFormFillData& fill_data,
|
| // with values from |fill_data|. The |password_element| will only have the
|
| // |suggestedValue| set, and will be registered for copying that to the real
|
| // value through |registration_callback|. The function returns true when
|
| -// selected username comes from |fill_data.other_possible_usernames|.
|
| +// selected username comes from |fill_data.other_possible_usernames|. |options|
|
| +// should be a bitwise mask of FillUserNameAndPasswordOptions values.
|
| bool FillUserNameAndPassword(
|
| blink::WebInputElement* username_element,
|
| blink::WebInputElement* password_element,
|
| @@ -381,7 +401,7 @@ bool FillUserNameAndPassword(
|
| // |suggestedValue| set, and |suggestedValue| will be registered for copying to
|
| // the real value through |registration_callback|. Returns true when the
|
| // username gets selected from |other_possible_usernames|, else returns false.
|
| -bool FillFormOnPasswordRecieved(
|
| +bool FillFormOnPasswordReceived(
|
| const PasswordFormFillData& fill_data,
|
| blink::WebInputElement username_element,
|
| blink::WebInputElement password_element,
|
| @@ -396,13 +416,34 @@ bool FillFormOnPasswordRecieved(
|
| return false;
|
|
|
| bool form_contains_username_field = FillDataContainsUsername(fill_data);
|
| - // Try to set the username to the preferred name, but only if the field
|
| - // can be set and isn't prefilled.
|
| - if (form_contains_username_field &&
|
| - IsElementAutocompletable(username_element) &&
|
| - username_element.value().isEmpty()) {
|
| - // TODO(tkent): Check maxlength and pattern.
|
| - username_element.setValue(fill_data.username_field.value, true);
|
| + // If the form contains a username field, try to set the username to the
|
| + // preferred name, but only if:
|
| + // (a) The username element is autocompletable, and
|
| + // (b) The fill-on-account-select flag is not set, and
|
| + // (c) The username element isn't prefilled
|
| + //
|
| + // If (a) is true but (b) is false, then just mark the username element as
|
| + // autofilled and return so the fill step is skipped.
|
| + //
|
| + // If (a) is false but (b) is true, then the username element should not be
|
| + // autofilled, but the user should still be able to select to fill the
|
| + // password element, so the password element must be marked as autofilled and
|
| + // the fill step should also be skipped.
|
| + //
|
| + // In all other cases, do nothing.
|
| + if (form_contains_username_field) {
|
| + if (IsElementAutocompletable(username_element)) {
|
| + if (ShouldFillOnAccountSelect()) {
|
| + username_element.setAutofilled(true);
|
| + return false;
|
| + } else if (username_element.value().isEmpty()) {
|
| + // TODO(tkent): Check maxlength and pattern.
|
| + username_element.setValue(fill_data.username_field.value, true);
|
| + }
|
| + } else if (ShouldFillOnAccountSelect()) {
|
| + password_element.setAutofilled(true);
|
| + return false;
|
| + }
|
| }
|
|
|
| // Fill if we have an exact match for the username. Note that this sets
|
| @@ -514,11 +555,7 @@ bool PasswordAutofillAgent::TextFieldDidEndEditing(
|
| // Do not set selection when ending an editing session, otherwise it can
|
| // mess with focus.
|
| if (FillUserNameAndPassword(
|
| - &username,
|
| - &password,
|
| - fill_data,
|
| - true /* exact_username_match */,
|
| - false /* set_selection */,
|
| + &username, &password, fill_data, true, false,
|
| base::Bind(&PasswordValueGatekeeper::RegisterElement,
|
| base::Unretained(&gatekeeper_)))) {
|
| usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED;
|
| @@ -581,7 +618,7 @@ bool PasswordAutofillAgent::TextDidChangeInTextField(
|
| // But refresh the popup. Note, since this is ours, return true to signal
|
| // no further processing is required.
|
| if (iter->second.backspace_pressed_last) {
|
| - ShowSuggestionPopup(iter->second.fill_data, element, false);
|
| + ShowSuggestionPopup(iter->second.fill_data, element, false, false);
|
| return true;
|
| }
|
|
|
| @@ -678,11 +715,28 @@ bool PasswordAutofillAgent::DidClearAutofillSelection(
|
| return true;
|
| }
|
|
|
| +PasswordAutofillAgent::LoginToPasswordInfoMap::iterator
|
| +PasswordAutofillAgent::FindPasswordInfoForElement(
|
| + const blink::WebInputElement& element) {
|
| + const blink::WebInputElement* username_element;
|
| + if (!element.isPasswordField()) {
|
| + username_element = &element;
|
| + } else {
|
| + PasswordToLoginMap::const_iterator password_iter =
|
| + password_to_username_.find(element);
|
| + if (password_iter == password_to_username_.end())
|
| + return login_to_password_info_.end();
|
| + username_element = &password_iter->second;
|
| + }
|
| +
|
| + return login_to_password_info_.find(*username_element);
|
| +}
|
| +
|
| bool PasswordAutofillAgent::ShowSuggestions(
|
| const blink::WebInputElement& element,
|
| bool show_all) {
|
| LoginToPasswordInfoMap::const_iterator iter =
|
| - login_to_password_info_.find(element);
|
| + FindPasswordInfoForElement(element);
|
| if (iter == login_to_password_info_.end())
|
| return false;
|
|
|
| @@ -694,7 +748,13 @@ bool PasswordAutofillAgent::ShowSuggestions(
|
| !IsElementAutocompletable(iter->second.password_field))
|
| return true;
|
|
|
| - return ShowSuggestionPopup(iter->second.fill_data, element, show_all);
|
| + // Chrome should never show more than one account for a password element since
|
| + // this implies that the username element cannot be modified. Thus even if
|
| + // |show_all| is true, check if the element in question is a password element
|
| + // for the call to ShowSuggestionPopup.
|
| + return ShowSuggestionPopup(iter->second.fill_data, iter->first,
|
| + show_all && !element.isPasswordField(),
|
| + element.isPasswordField());
|
| }
|
|
|
| bool PasswordAutofillAgent::OriginCanAccessPasswordManager(
|
| @@ -1042,10 +1102,8 @@ void PasswordAutofillAgent::OnFillPasswordForm(
|
| // If wait_for_username is true, we don't want to initially fill the form
|
| // until the user types in a valid username.
|
| if (!form_data.wait_for_username &&
|
| - FillFormOnPasswordRecieved(
|
| - form_data,
|
| - username_element,
|
| - password_element,
|
| + FillFormOnPasswordReceived(
|
| + form_data, username_element, password_element,
|
| base::Bind(&PasswordValueGatekeeper::RegisterElement,
|
| base::Unretained(&gatekeeper_)))) {
|
| usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED;
|
| @@ -1079,7 +1137,8 @@ PasswordAutofillAgent::PasswordInfo::PasswordInfo()
|
| bool PasswordAutofillAgent::ShowSuggestionPopup(
|
| const PasswordFormFillData& fill_data,
|
| const blink::WebInputElement& user_input,
|
| - bool show_all) {
|
| + bool show_all,
|
| + bool show_on_password_field) {
|
| blink::WebFrame* frame = user_input.document().frame();
|
| if (!frame)
|
| return false;
|
| @@ -1094,6 +1153,12 @@ bool PasswordAutofillAgent::ShowSuggestionPopup(
|
| user_input, &form, &field, REQUIRE_NONE);
|
|
|
| blink::WebInputElement selected_element = user_input;
|
| + if (show_on_password_field) {
|
| + LoginToPasswordInfoMap::const_iterator iter =
|
| + login_to_password_info_.find(user_input);
|
| + DCHECK(iter != login_to_password_info_.end());
|
| + selected_element = iter->second.password_field;
|
| + }
|
| gfx::Rect bounding_box(selected_element.boundsInViewportSpace());
|
|
|
| LoginToPasswordInfoKeyMap::const_iterator key_it =
|
| @@ -1105,9 +1170,14 @@ bool PasswordAutofillAgent::ShowSuggestionPopup(
|
| bounding_box.y() * scale,
|
| bounding_box.width() * scale,
|
| bounding_box.height() * scale);
|
| + int options = 0;
|
| + if (show_all)
|
| + options |= ShowPasswordSuggestionsOptions::SHOW_ALL;
|
| + if (show_on_password_field)
|
| + options |= ShowPasswordSuggestionsOptions::IS_PASSWORD_FIELD;
|
| Send(new AutofillHostMsg_ShowPasswordSuggestions(
|
| routing_id(), key_it->second, field.text_direction, user_input.value(),
|
| - show_all, bounding_box_scaled));
|
| + options, bounding_box_scaled));
|
|
|
| bool suggestions_present = false;
|
| if (GetSuggestionsStats(fill_data, user_input.value(), show_all,
|
| @@ -1135,17 +1205,13 @@ void PasswordAutofillAgent::PerformInlineAutocomplete(
|
| }
|
|
|
| // Show the popup with the list of available usernames.
|
| - ShowSuggestionPopup(fill_data, username, false);
|
| + ShowSuggestionPopup(fill_data, username, false, false);
|
|
|
| #if !defined(OS_ANDROID)
|
| // Fill the user and password field with the most relevant match. Android
|
| // only fills in the fields after the user clicks on the suggestion popup.
|
| if (FillUserNameAndPassword(
|
| - &username,
|
| - &password,
|
| - fill_data,
|
| - false /* exact_username_match */,
|
| - true /* set_selection */,
|
| + &username, &password, fill_data, false, true,
|
| base::Bind(&PasswordValueGatekeeper::RegisterElement,
|
| base::Unretained(&gatekeeper_)))) {
|
| usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED;
|
| @@ -1187,7 +1253,7 @@ bool PasswordAutofillAgent::FindLoginInfo(const blink::WebNode& node,
|
| return false;
|
|
|
| blink::WebInputElement input = element.to<blink::WebInputElement>();
|
| - LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input);
|
| + LoginToPasswordInfoMap::iterator iter = FindPasswordInfoForElement(input);
|
| if (iter == login_to_password_info_.end())
|
| return false;
|
|
|
|
|