 Chromium Code Reviews
 Chromium Code Reviews Issue 548953002:
  [Password Manager] Modified to support saving passwords on forms without username fields.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 548953002:
  [Password Manager] Modified to support saving passwords on forms without username fields.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| 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 a4720aac19665b6e35defecf4fae38e7aa9e7432..480bfc617eb95ca620779cf045b0eeb3c9a37899 100644 | 
| --- a/components/autofill/content/renderer/password_autofill_agent.cc | 
| +++ b/components/autofill/content/renderer/password_autofill_agent.cc | 
| @@ -67,10 +67,13 @@ typedef std::vector<FormElements*> FormElementsList; | 
| static bool FindFormInputElements(blink::WebFormElement* fe, | 
| const FormData& data, | 
| FormElements* result) { | 
| + const bool username_is_present = !data.fields[0].name.empty(); | 
| + | 
| // Loop through the list of elements we need to find on the form in order to | 
| // autofill it. If we don't find any one of them, abort processing this | 
| // form; it can't be the right one. | 
| - for (size_t j = 0; j < data.fields.size(); j++) { | 
| + // First field is the username, skip it if not present. | 
| + for (size_t j = (username_is_present ? 0 : 1); j < data.fields.size(); ++j) { | 
| 
vabr (Chromium)
2014/09/26 12:32:39
Sorry for causing this with the typo in my comment
 | 
| blink::WebVector<blink::WebNode> temp_elements; | 
| fe->getNamedElements(data.fields[j].name, temp_elements); | 
| @@ -218,6 +221,10 @@ void LogHTMLForm(SavePasswordProgressLogger* logger, | 
| GURL(form.action().utf8())); | 
| } | 
| +bool FillDataContainsUsername(const PasswordFormFillData& fill_data) { | 
| + return !fill_data.basic_data.fields[0].name.empty(); | 
| +} | 
| + | 
| } // namespace | 
| //////////////////////////////////////////////////////////////////////////////// | 
| @@ -802,13 +809,22 @@ void PasswordAutofillAgent::OnFillPasswordForm( | 
| scoped_ptr<FormElements> form_elements(*iter); | 
| // Attach autocomplete listener to enable selecting alternate logins. | 
| - // First, get pointers to username element. | 
| - blink::WebInputElement username_element = | 
| - form_elements->input_elements[form_data.basic_data.fields[0].name]; | 
| + blink::WebInputElement username_element, password_element; | 
| + | 
| + // Check whether the password form has a username input field. | 
| + bool form_contains_username_field = FillDataContainsUsername(form_data); | 
| + if (form_contains_username_field) { | 
| + username_element = | 
| + form_elements->input_elements[form_data.basic_data.fields[0].name]; | 
| + } | 
| + | 
| + // No password field, bail out. | 
| + if (form_data.basic_data.fields[1].name.empty()) | 
| + break; | 
| // Get pointer to password element. (We currently only support single | 
| // password forms). | 
| - blink::WebInputElement password_element = | 
| + password_element = | 
| form_elements->input_elements[form_data.basic_data.fields[1].name]; | 
| // If wait_for_username is true, we don't want to initially fill the form | 
| @@ -830,8 +846,11 @@ void PasswordAutofillAgent::OnFillPasswordForm( | 
| FormData form; | 
| FormFieldData field; | 
| - FindFormAndFieldForFormControlElement( | 
| - username_element, &form, &field, REQUIRE_NONE); | 
| + if (form_contains_username_field) { | 
| + FindFormAndFieldForFormControlElement( | 
| + username_element, &form, &field, REQUIRE_NONE); | 
| + } | 
| + | 
| Send(new AutofillHostMsg_AddPasswordFormMapping( | 
| routing_id(), field, form_data)); | 
| } | 
| @@ -929,8 +948,9 @@ void PasswordAutofillAgent::FillFormOnPasswordRecieved( | 
| if (password_element.document().frame()->parent()) | 
| return; | 
| + bool form_contains_username_field = FillDataContainsUsername(fill_data); | 
| if (!ShouldIgnoreAutocompleteOffForPasswordFields() && | 
| - !username_element.form().autoComplete()) | 
| + form_contains_username_field && !username_element.form().autoComplete()) | 
| return; | 
| // If we can't modify the password, don't try to set the username | 
| @@ -939,7 +959,8 @@ void PasswordAutofillAgent::FillFormOnPasswordRecieved( | 
| // Try to set the username to the preferred name, but only if the field | 
| // can be set and isn't prefilled. | 
| - if (IsElementAutocompletable(username_element) && | 
| + if (form_contains_username_field && | 
| + IsElementAutocompletable(username_element) && | 
| username_element.value().isEmpty()) { | 
| // TODO(tkent): Check maxlength and pattern. | 
| username_element.setValue(fill_data.basic_data.fields[0].value, true); | 
| @@ -960,15 +981,19 @@ bool PasswordAutofillAgent::FillUserNameAndPassword( | 
| const PasswordFormFillData& fill_data, | 
| bool exact_username_match, | 
| bool set_selection) { | 
| - base::string16 current_username = username_element->value(); | 
| - // username and password will contain the match found if any. | 
| - base::string16 username; | 
| - base::string16 password; | 
| - | 
| // Don't fill username if password can't be set. | 
| if (!IsElementAutocompletable(*password_element)) | 
| return false; | 
| + base::string16 current_username; | 
| + if (!username_element->isNull()) { | 
| + current_username = username_element->value(); | 
| + } | 
| + | 
| + // username and password will contain the match found if any. | 
| + base::string16 username; | 
| + base::string16 password; | 
| + | 
| // Look for any suitable matches to current field text. | 
| if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, | 
| current_username, | 
| @@ -1016,7 +1041,8 @@ bool PasswordAutofillAgent::FillUserNameAndPassword( | 
| // fields. | 
| // Input matches the username, fill in required values. | 
| - if (IsElementAutocompletable(*username_element)) { | 
| + if (!username_element->isNull() && | 
| + IsElementAutocompletable(*username_element)) { | 
| username_element->setValue(username, true); | 
| username_element->setAutofilled(true); | 
| @@ -1074,7 +1100,9 @@ void PasswordAutofillAgent::PerformInlineAutocomplete( | 
| void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { | 
| for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); | 
| iter != login_to_password_info_.end();) { | 
| - if (iter->first.document().frame() == frame) { | 
| + // There may not be a username field, so get the frame from the password | 
| + // field. | 
| + if (iter->second.password_field.document().frame() == frame) { | 
| password_to_username_.erase(iter->second.password_field); | 
| login_to_password_info_.erase(iter++); | 
| } else { |