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