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

Unified Diff: components/autofill/content/renderer/password_autofill_agent.cc

Issue 2889393002: Add username field discovery heuristic. (Closed)
Patch Set: Address comments; add tests. Created 3 years, 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/autofill/content/renderer/password_autofill_agent.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 952ba4f5c471683178392788b7ddd244a945fec1..0d2a312dea5f276616a7c55e3d0474e5c7ac07c9 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <algorithm>
#include <memory>
#include <string>
#include <utility>
@@ -276,7 +277,7 @@ bool DoUsernamesMatch(const base::string16& username1,
true);
}
-// Returns |true| if the given element is editable. Otherwise, returns |false|.
+// Returns whether the given |element| is editable.
bool IsElementAutocompletable(const blink::WebInputElement& element) {
return IsElementEditable(element);
}
@@ -607,6 +608,41 @@ bool HasPasswordField(const blink::WebLocalFrame& frame) {
return false;
}
+// Returns the closest visible autocompletable non-password text element
+// preceding the |password_element| either in a form, if it belongs to one, or
+// in the |frame|.
+blink::WebInputElement FindUsernameElementPrecedingPasswordElement(
+ blink::WebFrame* frame,
+ const blink::WebInputElement& password_element) {
+ DCHECK(!password_element.IsNull());
+
+ std::vector<blink::WebFormControlElement> elements;
+ if (password_element.Form().IsNull()) {
+ elements = form_util::GetUnownedAutofillableFormFieldElements(
+ frame->GetDocument().All(), nullptr);
+ } else {
+ blink::WebVector<blink::WebFormControlElement> web_control_elements;
+ password_element.Form().GetFormControlElements(web_control_elements);
+ elements.assign(web_control_elements.begin(), web_control_elements.end());
+ }
+
+ auto iter = std::find(elements.begin(), elements.end(), password_element);
+ if (iter == elements.end())
+ return blink::WebInputElement();
+
+ for (auto begin = elements.begin(); iter != begin;) {
+ --iter;
+ const blink::WebInputElement* input = blink::ToWebInputElement(&*iter);
+ if (input && input->IsTextField() && !input->IsPasswordField() &&
+ IsElementAutocompletable(*input) &&
+ form_util::IsWebElementVisible(*input)) {
+ return *input;
+ }
+ }
+
+ return blink::WebInputElement();
+}
+
} // namespace
class PasswordAutofillAgent::FormElementObserverCallback
@@ -775,7 +811,7 @@ bool PasswordAutofillAgent::FillSuggestion(
blink::WebInputElement username_element;
blink::WebInputElement password_element;
- PasswordInfo* password_info;
+ PasswordInfo* password_info = nullptr;
if (!FindPasswordInfoForElement(*element, &username_element,
&password_element, &password_info) ||
@@ -883,33 +919,37 @@ bool PasswordAutofillAgent::FindPasswordInfoForElement(
return false;
}
+ *password_element = element;
+
WebInputToPasswordInfoMap::iterator iter =
web_input_to_password_info_.find(element);
+ if (iter == web_input_to_password_info_.end()) {
+ PasswordToLoginMap::const_iterator password_iter =
+ password_to_username_.find(element);
+ if (password_iter == password_to_username_.end()) {
+ if (web_input_to_password_info_.empty())
+ return false;
+ // Now all PasswordInfo items refer to the same set of credentials for
+ // fill, so it is ok to take any of them.
+ iter = web_input_to_password_info_.begin();
+ } else {
+ *username_element = password_iter->second;
+ }
+ }
+
if (iter != web_input_to_password_info_.end()) {
- // It's a password field without corresponding username field.
- *password_element = element;
+ // It's a password field without corresponding username field. Try to find
+ // the username field based on visibility.
+ *username_element = FindUsernameElementPrecedingPasswordElement(
+ render_frame()->GetWebFrame(), *password_element);
*password_info = &iter->second;
return true;
}
- PasswordToLoginMap::const_iterator password_iter =
- password_to_username_.find(element);
- if (password_iter == password_to_username_.end()) {
- if (web_input_to_password_info_.empty())
- return false;
-
- *password_element = element;
- // Now all PasswordInfo items refer to the same set of credentials for
- // fill, so it is ok to take any of them.
- *password_info = &web_input_to_password_info_.begin()->second;
- return true;
- }
- *username_element = password_iter->second;
- *password_element = element;
+ // Otherwise |username_element| has been set above.
kolos1 2017/05/30 05:44:55 Optional: } else { // Otherwise |username_eleme
pkalinnikov 2017/05/30 09:47:55 I will leave this as is for compactness.
}
WebInputToPasswordInfoMap::iterator iter =
web_input_to_password_info_.find(*username_element);
-
if (iter == web_input_to_password_info_.end())
return false;
« no previous file with comments | « components/autofill/content/renderer/password_autofill_agent.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698