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

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

Powered by Google App Engine
This is Rietveld 408576698