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

Side by Side Diff: chrome/renderer/autofill_helper.cc

Issue 6151011: Introduce RenderView::Observer interface so that RenderView doesn't have to k... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "chrome/renderer/autofill_helper.h" 5 #include "chrome/renderer/autofill_helper.h"
6 6
7 #include "app/keyboard_codes.h" 7 #include "app/keyboard_codes.h"
8 #include "app/l10n_util.h" 8 #include "app/l10n_util.h"
9 #include "base/utf_string_conversions.h" 9 #include "base/utf_string_conversions.h"
10 #include "chrome/common/chrome_constants.h" 10 #include "chrome/common/chrome_constants.h"
11 #include "chrome/common/render_messages.h"
11 #include "chrome/renderer/form_manager.h" 12 #include "chrome/renderer/form_manager.h"
12 #include "chrome/renderer/render_view.h" 13 #include "chrome/renderer/password_autocomplete_manager.h"
13 #include "grit/generated_resources.h" 14 #include "grit/generated_resources.h"
14 #include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" 15 #include "third_party/WebKit/WebKit/chromium/public/WebDocument.h"
15 #include "third_party/WebKit/WebKit/chromium/public/WebFormControlElement.h" 16 #include "third_party/WebKit/WebKit/chromium/public/WebFormControlElement.h"
16 #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" 17 #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
17 #include "third_party/WebKit/WebKit/chromium/public/WebInputElement.h" 18 #include "third_party/WebKit/WebKit/chromium/public/WebInputElement.h"
18 #include "third_party/WebKit/WebKit/chromium/public/WebView.h" 19 #include "third_party/WebKit/WebKit/chromium/public/WebView.h"
19 #include "webkit/glue/form_data.h" 20 #include "webkit/glue/form_data.h"
20 #include "webkit/glue/form_field.h" 21 #include "webkit/glue/form_field.h"
21 #include "webkit/glue/password_form.h" 22 #include "webkit/glue/password_form.h"
22 23
23 using WebKit::WebFormControlElement; 24 using WebKit::WebFormControlElement;
24 using WebKit::WebFormElement; 25 using WebKit::WebFormElement;
25 using WebKit::WebFrame; 26 using WebKit::WebFrame;
26 using WebKit::WebInputElement; 27 using WebKit::WebInputElement;
27 using WebKit::WebKeyboardEvent; 28 using WebKit::WebKeyboardEvent;
28 using WebKit::WebNode; 29 using WebKit::WebNode;
29 using WebKit::WebString; 30 using WebKit::WebString;
30 31
31 namespace { 32 namespace {
32 33
33 // The size above which we stop triggering autofill for an input text field 34 // The size above which we stop triggering autofill for an input text field
34 // (so to avoid sending long strings through IPC). 35 // (so to avoid sending long strings through IPC).
35 const size_t kMaximumTextSizeForAutoFill = 1000; 36 const size_t kMaximumTextSizeForAutoFill = 1000;
36 37
37 } // namespace 38 } // namespace
38 39
39 AutoFillHelper::AutoFillHelper(RenderView* render_view) 40 AutoFillHelper::AutoFillHelper(
40 : render_view_(render_view), 41 RenderView* render_view,
42 PasswordAutocompleteManager* password_autocomplete_manager)
43 : RenderView::Observer(render_view),
44 password_autocomplete_manager_(password_autocomplete_manager),
41 autofill_query_id_(0), 45 autofill_query_id_(0),
42 autofill_action_(AUTOFILL_NONE), 46 autofill_action_(AUTOFILL_NONE),
43 display_warning_if_disabled_(false), 47 display_warning_if_disabled_(false),
44 was_query_node_autofilled_(false), 48 was_query_node_autofilled_(false),
45 suggestions_clear_index_(-1), 49 suggestions_clear_index_(-1),
46 suggestions_options_index_(-1) { 50 suggestions_options_index_(-1),
51 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
47 } 52 }
48 53
49 void AutoFillHelper::RemoveAutocompleteSuggestion(const WebString& name, 54 bool AutoFillHelper::OnMessageReceived(const IPC::Message& message) {
50 const WebString& value) { 55 bool handled = true;
56 IPC_BEGIN_MESSAGE_MAP(AutoFillHelper, message)
57 IPC_MESSAGE_HANDLER(ViewMsg_AutoFillSuggestionsReturned,
58 OnSuggestionsReturned)
59 IPC_MESSAGE_HANDLER(ViewMsg_AutoFillFormDataFilled, OnFormDataFilled)
60 IPC_MESSAGE_UNHANDLED(handled = false)
61 IPC_END_MESSAGE_MAP()
62 return handled;
63 }
64
65 void AutoFillHelper::DidFinishDocumentLoad(WebKit::WebFrame* frame) {
66 // The document has now been fully loaded. Scan for forms to be sent up to
67 // the browser.
68 form_manager_.ExtractForms(frame);
69 SendForms(frame);
70 }
71
72 void AutoFillHelper::FrameDetached(WebKit::WebFrame* frame) {
73 form_manager_.ResetFrame(frame);
74 }
75
76 void AutoFillHelper::FrameWillClose(WebKit::WebFrame* frame) {
77 form_manager_.ResetFrame(frame);
78 }
79
80 void AutoFillHelper::FrameTranslated(WebKit::WebFrame* frame) {
81 // The page is translated, so try to extract the form data again.
82 DidFinishDocumentLoad(frame);
83 }
84
85 bool AutoFillHelper::InputElementClicked(const WebInputElement& element,
86 bool was_focused,
87 bool is_focused) {
88 if (was_focused)
89 ShowSuggestions(element, true, false, true);
90 return false;
91 }
92
93 void AutoFillHelper::didAcceptAutoFillSuggestion(const WebKit::WebNode& node,
94 const WebKit::WebString& value,
95 const WebKit::WebString& label,
96 int unique_id,
97 unsigned index) {
98 if (suggestions_options_index_ != -1 &&
99 index == static_cast<unsigned>(suggestions_options_index_)) {
100 // User selected 'AutoFill Options'.
101 Send(new ViewHostMsg_ShowAutoFillDialog(routing_id()));
102 } else if (suggestions_clear_index_ != -1 &&
103 index == static_cast<unsigned>(suggestions_clear_index_)) {
104 // User selected 'Clear form'.
105 form_manager_.ClearFormWithNode(node);
106 } else if (!unique_id) {
107 // User selected an Autocomplete entry, so we fill directly.
108 WebInputElement element = node.toConst<WebInputElement>();
109
110 string16 substring = value;
111 substring = substring.substr(0, element.maxLength());
112 element.setValue(substring);
113
114 WebFrame* webframe = node.document().frame();
115 if (webframe)
116 webframe->notifiyPasswordListenerOfAutocomplete(element);
117 } else {
118 // Fill the values for the whole form.
119 FillAutoFillFormData(node, unique_id, AUTOFILL_FILL);
120 }
121
122 suggestions_clear_index_ = -1;
123 suggestions_options_index_ = -1;
124 }
125
126 void AutoFillHelper::didSelectAutoFillSuggestion(const WebKit::WebNode& node,
127 const WebKit::WebString& value,
128 const WebKit::WebString& label,
129 int unique_id) {
130 DCHECK_GE(unique_id, 0);
131
132 didClearAutoFillSelection(node);
133 FillAutoFillFormData(node, unique_id, AUTOFILL_PREVIEW);
134 }
135
136 void AutoFillHelper::didClearAutoFillSelection(const WebKit::WebNode& node) {
137 form_manager_.ClearPreviewedFormWithNode(node, was_query_node_autofilled_);
138 }
139
140 void AutoFillHelper::didAcceptAutocompleteSuggestion(
141 const WebKit::WebInputElement& user_element) {
142 bool result = password_autocomplete_manager_->FillPassword(user_element);
143 // Since this user name was selected from a suggestion list, we should always
144 // have password for it.
145 DCHECK(result);
146 }
147
148 void AutoFillHelper::removeAutocompleteSuggestion(
149 const WebKit::WebString& name,
150 const WebKit::WebString& value) {
51 // The index of clear & options will have shifted down. 151 // The index of clear & options will have shifted down.
52 if (suggestions_clear_index_ != -1) 152 if (suggestions_clear_index_ != -1)
53 suggestions_clear_index_--; 153 suggestions_clear_index_--;
54 if (suggestions_options_index_ != -1) 154 if (suggestions_options_index_ != -1)
55 suggestions_options_index_--; 155 suggestions_options_index_--;
56 156
57 render_view_->Send(new ViewHostMsg_RemoveAutocompleteEntry( 157 Send(new ViewHostMsg_RemoveAutocompleteEntry(routing_id(), name, value));
58 render_view_->routing_id(), name, value));
59 } 158 }
60 159
61 void AutoFillHelper::SuggestionsReceived(int query_id, 160 void AutoFillHelper::textFieldDidEndEditing(
62 const std::vector<string16>& values, 161 const WebKit::WebInputElement& element) {
63 const std::vector<string16>& labels, 162 password_autocomplete_manager_->TextFieldDidEndEditing(element);
64 const std::vector<string16>& icons, 163 }
65 const std::vector<int>& unique_ids) { 164
66 WebKit::WebView* web_view = render_view_->webview(); 165 void AutoFillHelper::textFieldDidChange(
166 const WebKit::WebInputElement& element) {
167 // We post a task for doing the AutoFill as the caret position is not set
168 // properly at this point (http://bugs.webkit.org/show_bug.cgi?id=16976) and
169 // it is needed to trigger autofill.
170 method_factory_.RevokeAll();
171 MessageLoop::current()->PostTask(
172 FROM_HERE,
173 method_factory_.NewRunnableMethod(
174 &AutoFillHelper::TextFieldDidChangeImpl, element));
175 }
176
177 void AutoFillHelper::TextFieldDidChangeImpl(
178 const WebKit::WebInputElement& element) {
179 if (password_autocomplete_manager_->TextDidChangeInTextField(element))
180 return;
181
182 ShowSuggestions(element, false, true, false);
183 }
184
185 void AutoFillHelper::textFieldDidReceiveKeyDown(
186 const WebKit::WebInputElement& element,
187 const WebKit::WebKeyboardEvent& event) {
188 password_autocomplete_manager_->TextFieldHandlingKeyDown(element, event);
189
190 if (event.windowsKeyCode == app::VKEY_DOWN ||
191 event.windowsKeyCode == app::VKEY_UP)
192 ShowSuggestions(element, true, true, true);
193 }
194
195 void AutoFillHelper::OnSuggestionsReturned(
196 int query_id,
197 const std::vector<string16>& values,
198 const std::vector<string16>& labels,
199 const std::vector<string16>& icons,
200 const std::vector<int>& unique_ids) {
201 WebKit::WebView* web_view = render_view()->webview();
67 if (!web_view || query_id != autofill_query_id_) 202 if (!web_view || query_id != autofill_query_id_)
68 return; 203 return;
69 204
70 if (values.empty()) { 205 if (values.empty()) {
71 // No suggestions, any popup currently showing is obsolete. 206 // No suggestions, any popup currently showing is obsolete.
72 web_view->hidePopups(); 207 web_view->hidePopups();
73 return; 208 return;
74 } 209 }
75 210
76 std::vector<string16> v(values); 211 std::vector<string16> v(values);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 suggestions_options_index_ = v.size() - 1; 259 suggestions_options_index_ = v.size() - 1;
125 separator_index = values.size(); 260 separator_index = values.size();
126 } 261 }
127 262
128 // Send to WebKit for display. 263 // Send to WebKit for display.
129 if (!v.empty() && autofill_query_node_.hasNonEmptyBoundingBox()) { 264 if (!v.empty() && autofill_query_node_.hasNonEmptyBoundingBox()) {
130 web_view->applyAutoFillSuggestions( 265 web_view->applyAutoFillSuggestions(
131 autofill_query_node_, v, l, i, ids, separator_index); 266 autofill_query_node_, v, l, i, ids, separator_index);
132 } 267 }
133 268
134 render_view_->Send(new ViewHostMsg_DidShowAutoFillSuggestions( 269 Send(new ViewHostMsg_DidShowAutoFillSuggestions(routing_id()));
135 render_view_->routing_id()));
136 } 270 }
137 271
138 void AutoFillHelper::FormDataFilled(int query_id, 272 void AutoFillHelper::OnFormDataFilled(
139 const webkit_glue::FormData& form) { 273 int query_id, const webkit_glue::FormData& form) {
140 if (!render_view_->webview() || query_id != autofill_query_id_) 274 if (!render_view()->webview() || query_id != autofill_query_id_)
141 return; 275 return;
142 276
143 switch (autofill_action_) { 277 switch (autofill_action_) {
144 case AUTOFILL_FILL: 278 case AUTOFILL_FILL:
145 form_manager_.FillForm(form, autofill_query_node_); 279 form_manager_.FillForm(form, autofill_query_node_);
146 break; 280 break;
147 case AUTOFILL_PREVIEW: 281 case AUTOFILL_PREVIEW:
148 form_manager_.PreviewForm(form, autofill_query_node_); 282 form_manager_.PreviewForm(form, autofill_query_node_);
149 break; 283 break;
150 default: 284 default:
151 NOTREACHED(); 285 NOTREACHED();
152 } 286 }
153 autofill_action_ = AUTOFILL_NONE; 287 autofill_action_ = AUTOFILL_NONE;
154 render_view_->Send(new ViewHostMsg_DidFillAutoFillFormData( 288 Send(new ViewHostMsg_DidFillAutoFillFormData(routing_id()));
155 render_view_->routing_id()));
156 }
157
158 void AutoFillHelper::DidSelectAutoFillSuggestion(const WebNode& node,
159 int unique_id) {
160 DCHECK_GE(unique_id, 0);
161
162 DidClearAutoFillSelection(node);
163 FillAutoFillFormData(node, unique_id, AUTOFILL_PREVIEW);
164 }
165
166 void AutoFillHelper::DidAcceptAutoFillSuggestion(const WebNode& node,
167 const WebString& value,
168 int unique_id,
169 unsigned index) {
170 if (suggestions_options_index_ != -1 &&
171 index == static_cast<unsigned>(suggestions_options_index_)) {
172 // User selected 'AutoFill Options'.
173 render_view_->Send(new ViewHostMsg_ShowAutoFillDialog(
174 render_view_->routing_id()));
175 } else if (suggestions_clear_index_ != -1 &&
176 index == static_cast<unsigned>(suggestions_clear_index_)) {
177 // User selected 'Clear form'.
178 form_manager_.ClearFormWithNode(node);
179 } else if (!unique_id) {
180 // User selected an Autocomplete entry, so we fill directly.
181 WebInputElement element = node.toConst<WebInputElement>();
182
183 string16 substring = value;
184 substring = substring.substr(0, element.maxLength());
185 element.setValue(substring);
186
187 WebFrame* webframe = node.document().frame();
188 if (webframe)
189 webframe->notifiyPasswordListenerOfAutocomplete(element);
190 } else {
191 // Fill the values for the whole form.
192 FillAutoFillFormData(node, unique_id, AUTOFILL_FILL);
193 }
194
195 suggestions_clear_index_ = -1;
196 suggestions_options_index_ = -1;
197 }
198
199 void AutoFillHelper::DidClearAutoFillSelection(const WebNode& node) {
200 form_manager_.ClearPreviewedFormWithNode(node, was_query_node_autofilled_);
201 }
202
203 void AutoFillHelper::FrameContentsAvailable(WebFrame* frame) {
204 form_manager_.ExtractForms(frame);
205 SendForms(frame);
206 }
207
208 void AutoFillHelper::FrameWillClose(WebFrame* frame) {
209 form_manager_.ResetFrame(frame);
210 }
211
212 void AutoFillHelper::FrameDetached(WebFrame* frame) {
213 form_manager_.ResetFrame(frame);
214 }
215
216 void AutoFillHelper::TextDidChangeInTextField(const WebInputElement& element) {
217 ShowSuggestions(element, false, true, false);
218 }
219
220 void AutoFillHelper::KeyDownInTextField(const WebInputElement& element,
221 const WebKeyboardEvent& event) {
222 if (event.windowsKeyCode == app::VKEY_DOWN ||
223 event.windowsKeyCode == app::VKEY_UP)
224 ShowSuggestions(element, true, true, true);
225 }
226
227 bool AutoFillHelper::InputElementClicked(const WebInputElement& element,
228 bool was_focused,
229 bool is_focused) {
230 if (was_focused)
231 ShowSuggestions(element, true, false, true);
232 return false;
233 } 289 }
234 290
235 void AutoFillHelper::ShowSuggestions(const WebInputElement& element, 291 void AutoFillHelper::ShowSuggestions(const WebInputElement& element,
236 bool autofill_on_empty_values, 292 bool autofill_on_empty_values,
237 bool requires_caret_at_end, 293 bool requires_caret_at_end,
238 bool display_warning_if_disabled) { 294 bool display_warning_if_disabled) {
239 if (!element.isEnabledFormControl() || !element.isTextField() || 295 if (!element.isEnabledFormControl() || !element.isTextField() ||
240 element.isPasswordField() || element.isReadOnly() || 296 element.isPasswordField() || element.isReadOnly() ||
241 !element.autoComplete()) 297 !element.autoComplete())
242 return; 298 return;
(...skipping 23 matching lines...) Expand all
266 static int query_counter = 0; 322 static int query_counter = 0;
267 autofill_query_id_ = query_counter++; 323 autofill_query_id_ = query_counter++;
268 autofill_query_node_ = node; 324 autofill_query_node_ = node;
269 display_warning_if_disabled_ = display_warning_if_disabled; 325 display_warning_if_disabled_ = display_warning_if_disabled;
270 326
271 webkit_glue::FormData form; 327 webkit_glue::FormData form;
272 webkit_glue::FormField field; 328 webkit_glue::FormField field;
273 if (!FindFormAndFieldForNode(node, &form, &field)) 329 if (!FindFormAndFieldForNode(node, &form, &field))
274 return; 330 return;
275 331
276 render_view_->Send(new ViewHostMsg_QueryFormFieldAutoFill( 332 Send(new ViewHostMsg_QueryFormFieldAutoFill(
277 render_view_->routing_id(), autofill_query_id_, form, field)); 333 routing_id(), autofill_query_id_, form, field));
278 } 334 }
279 335
280 void AutoFillHelper::FillAutoFillFormData(const WebNode& node, 336 void AutoFillHelper::FillAutoFillFormData(const WebNode& node,
281 int unique_id, 337 int unique_id,
282 AutoFillAction action) { 338 AutoFillAction action) {
283 static int query_counter = 0; 339 static int query_counter = 0;
284 autofill_query_id_ = query_counter++; 340 autofill_query_id_ = query_counter++;
285 341
286 webkit_glue::FormData form; 342 webkit_glue::FormData form;
287 webkit_glue::FormField field; 343 webkit_glue::FormField field;
288 if (!FindFormAndFieldForNode(node, &form, &field)) 344 if (!FindFormAndFieldForNode(node, &form, &field))
289 return; 345 return;
290 346
291 autofill_action_ = action; 347 autofill_action_ = action;
292 was_query_node_autofilled_ = field.is_autofilled(); 348 was_query_node_autofilled_ = field.is_autofilled();
293 render_view_->Send(new ViewHostMsg_FillAutoFillFormData( 349 Send(new ViewHostMsg_FillAutoFillFormData(
294 render_view_->routing_id(), autofill_query_id_, form, field, unique_id)); 350 routing_id(), autofill_query_id_, form, field, unique_id));
295 } 351 }
296 352
297 void AutoFillHelper::SendForms(WebFrame* frame) { 353 void AutoFillHelper::SendForms(WebFrame* frame) {
298 // TODO(jhawkins): Use FormManager once we have strict ordering of form 354 // TODO(jhawkins): Use FormManager once we have strict ordering of form
299 // control elements in the cache. 355 // control elements in the cache.
300 WebKit::WebVector<WebFormElement> web_forms; 356 WebKit::WebVector<WebFormElement> web_forms;
301 frame->forms(web_forms); 357 frame->forms(web_forms);
302 358
303 std::vector<webkit_glue::FormData> forms; 359 std::vector<webkit_glue::FormData> forms;
304 for (size_t i = 0; i < web_forms.size(); ++i) { 360 for (size_t i = 0; i < web_forms.size(); ++i) {
305 const WebFormElement& web_form = web_forms[i]; 361 const WebFormElement& web_form = web_forms[i];
306 362
307 webkit_glue::FormData form; 363 webkit_glue::FormData form;
308 if (FormManager::WebFormElementToFormData( 364 if (FormManager::WebFormElementToFormData(
309 web_form, FormManager::REQUIRE_NONE, 365 web_form, FormManager::REQUIRE_NONE,
310 FormManager::EXTRACT_NONE, &form)) { 366 FormManager::EXTRACT_NONE, &form)) {
311 forms.push_back(form); 367 forms.push_back(form);
312 } 368 }
313 } 369 }
314 370
315 if (!forms.empty()) { 371 if (!forms.empty())
316 render_view_->Send(new ViewHostMsg_FormsSeen(render_view_->routing_id(), 372 Send(new ViewHostMsg_FormsSeen(routing_id(), forms));
317 forms));
318 }
319 } 373 }
320 374
321 bool AutoFillHelper::FindFormAndFieldForNode(const WebNode& node, 375 bool AutoFillHelper::FindFormAndFieldForNode(const WebNode& node,
322 webkit_glue::FormData* form, 376 webkit_glue::FormData* form,
323 webkit_glue::FormField* field) { 377 webkit_glue::FormField* field) {
324 const WebInputElement& element = node.toConst<WebInputElement>(); 378 const WebInputElement& element = node.toConst<WebInputElement>();
325 if (!form_manager_.FindFormWithFormControlElement(element, 379 if (!form_manager_.FindFormWithFormControlElement(element,
326 FormManager::REQUIRE_NONE, 380 FormManager::REQUIRE_NONE,
327 form)) 381 form))
328 return false; 382 return false;
329 383
330 FormManager::WebFormControlElementToFormField(element, 384 FormManager::WebFormControlElementToFormField(element,
331 FormManager::EXTRACT_VALUE, 385 FormManager::EXTRACT_VALUE,
332 field); 386 field);
333 387
334 // WebFormControlElementToFormField does not scrape the DOM for the field 388 // WebFormControlElementToFormField does not scrape the DOM for the field
335 // label, so find the label here. 389 // label, so find the label here.
336 // TODO(jhawkins): Add form and field identities so we can use the cached form 390 // TODO(jhawkins): Add form and field identities so we can use the cached form
337 // data in FormManager. 391 // data in FormManager.
338 field->set_label(FormManager::LabelForElement(element)); 392 field->set_label(FormManager::LabelForElement(element));
339 393
340 return true; 394 return true;
341 } 395 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698