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

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

Powered by Google App Engine
This is Rietveld 408576698