[email protected] | c4a9e93 | 2011-03-05 04:05:55 | [diff] [blame] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 5 | #include "chrome/renderer/autofill/autofill_agent.h" |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 6 | |
[email protected] | 8704f89b | 2011-04-15 00:30:05 | [diff] [blame] | 7 | #include "base/message_loop.h" |
[email protected] | 2377cafe | 2010-10-27 01:19:08 | [diff] [blame] | 8 | #include "base/utf_string_conversions.h" |
[email protected] | 19d6e1e8 | 2011-01-26 05:08:58 | [diff] [blame] | 9 | #include "chrome/common/autofill_messages.h" |
[email protected] | 2377cafe | 2010-10-27 01:19:08 | [diff] [blame] | 10 | #include "chrome/common/chrome_constants.h" |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 11 | #include "chrome/renderer/autofill/password_autofill_manager.h" |
[email protected] | 6091604 | 2011-03-19 00:43:36 | [diff] [blame] | 12 | #include "content/renderer/render_view.h" |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 13 | #include "grit/generated_resources.h" |
[email protected] | 8bd0fe6 | 2011-01-17 06:44:37 | [diff] [blame] | 14 | #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" |
| 15 | #include "third_party/WebKit/Source/WebKit/chromium/public/WebFormControlElement.h" |
| 16 | #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
| 17 | #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h" |
[email protected] | a22f7e0 | 2011-02-09 07:15:35 | [diff] [blame] | 18 | #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" |
[email protected] | 8bd0fe6 | 2011-01-17 06:44:37 | [diff] [blame] | 19 | #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
[email protected] | b6d8126 | 2011-01-13 17:36:09 | [diff] [blame] | 20 | #include "ui/base/keycodes/keyboard_codes.h" |
[email protected] | c051a1b | 2011-01-21 23:30:17 | [diff] [blame] | 21 | #include "ui/base/l10n/l10n_util.h" |
[email protected] | 6a8ddba5 | 2010-09-05 04:38:06 | [diff] [blame] | 22 | #include "webkit/glue/form_data.h" |
| 23 | #include "webkit/glue/form_field.h" |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 24 | #include "webkit/glue/password_form.h" |
| 25 | |
| 26 | using WebKit::WebFormControlElement; |
| 27 | using WebKit::WebFormElement; |
| 28 | using WebKit::WebFrame; |
| 29 | using WebKit::WebInputElement; |
[email protected] | 7aab84b | 2010-11-20 01:04:26 | [diff] [blame] | 30 | using WebKit::WebKeyboardEvent; |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 31 | using WebKit::WebNode; |
| 32 | using WebKit::WebString; |
[email protected] | 2a5b173 | 2011-04-01 23:55:55 | [diff] [blame] | 33 | using webkit_glue::FormData; |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 34 | |
[email protected] | e47aec5 | 2010-08-12 00:50:30 | [diff] [blame] | 35 | namespace { |
| 36 | |
| 37 | // The size above which we stop triggering autofill for an input text field |
| 38 | // (so to avoid sending long strings through IPC). |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 39 | const size_t kMaximumTextSizeForAutofill = 1000; |
[email protected] | e47aec5 | 2010-08-12 00:50:30 | [diff] [blame] | 40 | |
| 41 | } // namespace |
| 42 | |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 43 | namespace autofill { |
| 44 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 45 | AutofillAgent::AutofillAgent( |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 46 | RenderView* render_view, |
[email protected] | c4a9e93 | 2011-03-05 04:05:55 | [diff] [blame] | 47 | PasswordAutofillManager* password_autofill_manager) |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 48 | : RenderViewObserver(render_view), |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 49 | password_autofill_manager_(password_autofill_manager), |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 50 | autofill_query_id_(0), |
| 51 | autofill_action_(AUTOFILL_NONE), |
[email protected] | 6bcd58a | 2010-11-25 02:31:20 | [diff] [blame] | 52 | display_warning_if_disabled_(false), |
[email protected] | d77ddc806 | 2010-11-24 01:14:06 | [diff] [blame] | 53 | was_query_node_autofilled_(false), |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 54 | suggestions_clear_index_(-1), |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 55 | suggestions_options_index_(-1), |
| 56 | ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
[email protected] | 2a5b173 | 2011-04-01 23:55:55 | [diff] [blame] | 57 | render_view->webview()->setAutoFillClient(this); |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 58 | } |
| 59 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 60 | AutofillAgent::~AutofillAgent() {} |
[email protected] | d2f05d0 | 2011-01-27 18:51:01 | [diff] [blame] | 61 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 62 | bool AutofillAgent::OnMessageReceived(const IPC::Message& message) { |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 63 | bool handled = true; |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 64 | IPC_BEGIN_MESSAGE_MAP(AutofillAgent, message) |
| 65 | IPC_MESSAGE_HANDLER(AutofillMsg_SuggestionsReturned, OnSuggestionsReturned) |
| 66 | IPC_MESSAGE_HANDLER(AutofillMsg_FormDataFilled, OnFormDataFilled) |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 67 | IPC_MESSAGE_UNHANDLED(handled = false) |
| 68 | IPC_END_MESSAGE_MAP() |
| 69 | return handled; |
| 70 | } |
| 71 | |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 72 | void AutofillAgent::DidFinishDocumentLoad(WebFrame* frame) { |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 73 | // The document has now been fully loaded. Scan for forms to be sent up to |
| 74 | // the browser. |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 75 | std::vector<webkit_glue::FormData> forms; |
| 76 | form_manager_.ExtractForms(frame, &forms); |
| 77 | |
| 78 | if (!forms.empty()) |
| 79 | Send(new AutofillHostMsg_FormsSeen(routing_id(), forms)); |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 80 | } |
| 81 | |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 82 | void AutofillAgent::FrameDetached(WebFrame* frame) { |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 83 | form_manager_.ResetFrame(frame); |
| 84 | } |
| 85 | |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 86 | void AutofillAgent::FrameWillClose(WebFrame* frame) { |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 87 | form_manager_.ResetFrame(frame); |
| 88 | } |
| 89 | |
[email protected] | 2a5b173 | 2011-04-01 23:55:55 | [diff] [blame] | 90 | void AutofillAgent::WillSubmitForm(WebFrame* frame, |
| 91 | const WebFormElement& form) { |
| 92 | FormData form_data; |
| 93 | if (FormManager::WebFormElementToFormData( |
| 94 | form, |
| 95 | FormManager::REQUIRE_AUTOCOMPLETE, |
| 96 | static_cast<FormManager::ExtractMask>( |
| 97 | FormManager::EXTRACT_VALUE | FormManager::EXTRACT_OPTION_TEXT), |
| 98 | &form_data)) { |
| 99 | Send(new AutofillHostMsg_FormSubmitted(routing_id(), form_data)); |
| 100 | } |
| 101 | } |
| 102 | |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 103 | void AutofillAgent::FrameTranslated(WebFrame* frame) { |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 104 | // The page is translated, so try to extract the form data again. |
| 105 | DidFinishDocumentLoad(frame); |
| 106 | } |
| 107 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 108 | bool AutofillAgent::InputElementClicked(const WebInputElement& element, |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 109 | bool was_focused, |
| 110 | bool is_focused) { |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 111 | if (was_focused) |
| 112 | ShowSuggestions(element, true, false, true); |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 113 | |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 114 | return false; |
| 115 | } |
| 116 | |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 117 | void AutofillAgent::didAcceptAutoFillSuggestion(const WebNode& node, |
| 118 | const WebString& value, |
| 119 | const WebString& label, |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 120 | int unique_id, |
| 121 | unsigned index) { |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 122 | if (password_autofill_manager_->DidAcceptAutofillSuggestion(node, value)) |
[email protected] | b43c135 | 2011-03-04 23:55:34 | [diff] [blame] | 123 | return; |
| 124 | |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 125 | if (suggestions_options_index_ != -1 && |
| 126 | index == static_cast<unsigned>(suggestions_options_index_)) { |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 127 | // User selected 'Autofill Options'. |
| 128 | Send(new AutofillHostMsg_ShowAutofillDialog(routing_id())); |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 129 | } else if (suggestions_clear_index_ != -1 && |
| 130 | index == static_cast<unsigned>(suggestions_clear_index_)) { |
| 131 | // User selected 'Clear form'. |
| 132 | form_manager_.ClearFormWithNode(node); |
| 133 | } else if (!unique_id) { |
| 134 | // User selected an Autocomplete entry, so we fill directly. |
| 135 | WebInputElement element = node.toConst<WebInputElement>(); |
| 136 | |
| 137 | string16 substring = value; |
| 138 | substring = substring.substr(0, element.maxLength()); |
[email protected] | 3b3b94d | 2011-03-10 09:52:20 | [diff] [blame] | 139 | element.setValue(substring, true); |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 140 | |
| 141 | WebFrame* webframe = node.document().frame(); |
| 142 | if (webframe) |
| 143 | webframe->notifiyPasswordListenerOfAutocomplete(element); |
| 144 | } else { |
| 145 | // Fill the values for the whole form. |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 146 | FillAutofillFormData(node, unique_id, AUTOFILL_FILL); |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 147 | } |
| 148 | |
| 149 | suggestions_clear_index_ = -1; |
| 150 | suggestions_options_index_ = -1; |
| 151 | } |
| 152 | |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 153 | void AutofillAgent::didSelectAutoFillSuggestion(const WebNode& node, |
| 154 | const WebString& value, |
| 155 | const WebString& label, |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 156 | int unique_id) { |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 157 | DCHECK_GE(unique_id, 0); |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 158 | if (password_autofill_manager_->DidSelectAutofillSuggestion(node)) |
[email protected] | fc1964a | 2011-01-20 19:33:07 | [diff] [blame] | 159 | return; |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 160 | |
| 161 | didClearAutoFillSelection(node); |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 162 | FillAutofillFormData(node, unique_id, AUTOFILL_PREVIEW); |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 163 | } |
| 164 | |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 165 | void AutofillAgent::didClearAutoFillSelection(const WebNode& node) { |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 166 | form_manager_.ClearPreviewedFormWithNode(node, was_query_node_autofilled_); |
| 167 | } |
| 168 | |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 169 | void AutofillAgent::removeAutocompleteSuggestion(const WebString& name, |
| 170 | const WebString& value) { |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 171 | // The index of clear & options will have shifted down. |
| 172 | if (suggestions_clear_index_ != -1) |
| 173 | suggestions_clear_index_--; |
| 174 | if (suggestions_options_index_ != -1) |
| 175 | suggestions_options_index_--; |
| 176 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 177 | Send(new AutofillHostMsg_RemoveAutocompleteEntry(routing_id(), name, value)); |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 178 | } |
| 179 | |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 180 | void AutofillAgent::textFieldDidEndEditing(const WebInputElement& element) { |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 181 | password_autofill_manager_->TextFieldDidEndEditing(element); |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 182 | } |
| 183 | |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 184 | void AutofillAgent::textFieldDidChange(const WebInputElement& element) { |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 185 | // We post a task for doing the Autofill as the caret position is not set |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 186 | // properly at this point (http://bugs.webkit.org/show_bug.cgi?id=16976) and |
| 187 | // it is needed to trigger autofill. |
| 188 | method_factory_.RevokeAll(); |
| 189 | MessageLoop::current()->PostTask( |
| 190 | FROM_HERE, |
| 191 | method_factory_.NewRunnableMethod( |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 192 | &AutofillAgent::TextFieldDidChangeImpl, element)); |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 193 | } |
| 194 | |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 195 | void AutofillAgent::TextFieldDidChangeImpl(const WebInputElement& element) { |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 196 | if (password_autofill_manager_->TextDidChangeInTextField(element)) |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 197 | return; |
| 198 | |
| 199 | ShowSuggestions(element, false, true, false); |
| 200 | } |
| 201 | |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 202 | void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element, |
| 203 | const WebKeyboardEvent& event) { |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 204 | if (password_autofill_manager_->TextFieldHandlingKeyDown(element, event)) |
[email protected] | fc1964a | 2011-01-20 19:33:07 | [diff] [blame] | 205 | return; |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 206 | |
| 207 | if (event.windowsKeyCode == ui::VKEY_DOWN || |
| 208 | event.windowsKeyCode == ui::VKEY_UP) |
| 209 | ShowSuggestions(element, true, true, true); |
| 210 | } |
| 211 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 212 | void AutofillAgent::OnSuggestionsReturned(int query_id, |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 213 | const std::vector<string16>& values, |
| 214 | const std::vector<string16>& labels, |
| 215 | const std::vector<string16>& icons, |
| 216 | const std::vector<int>& unique_ids) { |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 217 | WebKit::WebView* web_view = render_view()->webview(); |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 218 | if (!web_view || query_id != autofill_query_id_) |
| 219 | return; |
| 220 | |
[email protected] | 4313847 | 2010-08-17 22:45:45 | [diff] [blame] | 221 | if (values.empty()) { |
| 222 | // No suggestions, any popup currently showing is obsolete. |
| 223 | web_view->hidePopups(); |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 224 | return; |
[email protected] | 4313847 | 2010-08-17 22:45:45 | [diff] [blame] | 225 | } |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 226 | |
| 227 | std::vector<string16> v(values); |
| 228 | std::vector<string16> l(labels); |
[email protected] | a53e0683 | 2010-07-28 22:46:41 | [diff] [blame] | 229 | std::vector<string16> i(icons); |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 230 | std::vector<int> ids(unique_ids); |
| 231 | int separator_index = -1; |
| 232 | |
[email protected] | e417b1a | 2010-11-29 23:34:18 | [diff] [blame] | 233 | if (ids[0] < 0 && ids.size() > 1) { |
[email protected] | 1866d06 | 2010-11-16 06:19:56 | [diff] [blame] | 234 | // If we received a warning instead of suggestions from autofill but regular |
| 235 | // suggestions from autocomplete, don't show the autofill warning. |
| 236 | v.erase(v.begin()); |
| 237 | l.erase(l.begin()); |
| 238 | i.erase(i.begin()); |
| 239 | ids.erase(ids.begin()); |
| 240 | } |
| 241 | |
[email protected] | 6bcd58a | 2010-11-25 02:31:20 | [diff] [blame] | 242 | // If we were about to show a warning and we shouldn't, don't. |
| 243 | if (ids[0] < 0 && !display_warning_if_disabled_) |
| 244 | return; |
| 245 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 246 | // Only include "Autofill Options" special menu item if we have Autofill |
[email protected] | 4f03a2d3 | 2010-12-01 01:49:36 | [diff] [blame] | 247 | // items, identified by |unique_ids| having at least one valid value. |
| 248 | bool has_autofill_item = false; |
| 249 | for (size_t i = 0; i < ids.size(); ++i) { |
| 250 | if (ids[i] > 0) { |
| 251 | has_autofill_item = true; |
| 252 | break; |
| 253 | } |
| 254 | } |
| 255 | |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 256 | // The form has been auto-filled, so give the user the chance to clear the |
| 257 | // form. Append the 'Clear form' menu item. |
[email protected] | 4f03a2d3 | 2010-12-01 01:49:36 | [diff] [blame] | 258 | if (has_autofill_item && |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 259 | form_manager_.FormWithNodeIsAutofilled(autofill_query_node_)) { |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 260 | v.push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM)); |
| 261 | l.push_back(string16()); |
[email protected] | a53e0683 | 2010-07-28 22:46:41 | [diff] [blame] | 262 | i.push_back(string16()); |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 263 | ids.push_back(0); |
| 264 | suggestions_clear_index_ = v.size() - 1; |
[email protected] | 1866d06 | 2010-11-16 06:19:56 | [diff] [blame] | 265 | separator_index = v.size() - 1; |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 266 | } |
| 267 | |
[email protected] | 4f03a2d3 | 2010-12-01 01:49:36 | [diff] [blame] | 268 | if (has_autofill_item) { |
[email protected] | 2377cafe | 2010-10-27 01:19:08 | [diff] [blame] | 269 | // Append the 'Chrome Autofill options' menu item; |
| 270 | v.push_back(l10n_util::GetStringFUTF16(IDS_AUTOFILL_OPTIONS_POPUP, |
| 271 | WideToUTF16(chrome::kBrowserAppName))); |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 272 | l.push_back(string16()); |
[email protected] | a53e0683 | 2010-07-28 22:46:41 | [diff] [blame] | 273 | i.push_back(string16()); |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 274 | ids.push_back(0); |
| 275 | suggestions_options_index_ = v.size() - 1; |
| 276 | separator_index = values.size(); |
| 277 | } |
| 278 | |
| 279 | // Send to WebKit for display. |
[email protected] | 3b2ff66 | 2011-02-24 00:50:14 | [diff] [blame] | 280 | if (!v.empty() && !autofill_query_node_.isNull() && |
[email protected] | 0dcec959 | 2011-03-25 07:55:02 | [diff] [blame] | 281 | autofill_query_node_.isFocusable()) { |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 282 | web_view->applyAutoFillSuggestions( |
[email protected] | a53e0683 | 2010-07-28 22:46:41 | [diff] [blame] | 283 | autofill_query_node_, v, l, i, ids, separator_index); |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 284 | } |
[email protected] | 468327f | 2010-10-04 20:02:29 | [diff] [blame] | 285 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 286 | Send(new AutofillHostMsg_DidShowAutofillSuggestions(routing_id())); |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 287 | } |
| 288 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 289 | void AutofillAgent::OnFormDataFilled(int query_id, |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 290 | const webkit_glue::FormData& form) { |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 291 | if (!render_view()->webview() || query_id != autofill_query_id_) |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 292 | return; |
| 293 | |
| 294 | switch (autofill_action_) { |
| 295 | case AUTOFILL_FILL: |
| 296 | form_manager_.FillForm(form, autofill_query_node_); |
| 297 | break; |
| 298 | case AUTOFILL_PREVIEW: |
[email protected] | e7d8b51 | 2010-11-01 16:09:05 | [diff] [blame] | 299 | form_manager_.PreviewForm(form, autofill_query_node_); |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 300 | break; |
| 301 | default: |
| 302 | NOTREACHED(); |
| 303 | } |
| 304 | autofill_action_ = AUTOFILL_NONE; |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 305 | Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id())); |
[email protected] | e47aec5 | 2010-08-12 00:50:30 | [diff] [blame] | 306 | } |
| 307 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 308 | void AutofillAgent::ShowSuggestions(const WebInputElement& element, |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 309 | bool autofill_on_empty_values, |
| 310 | bool requires_caret_at_end, |
| 311 | bool display_warning_if_disabled) { |
[email protected] | ee8d79f | 2011-03-14 20:15:18 | [diff] [blame] | 312 | if (!element.isEnabled() || element.isReadOnly() || !element.autoComplete() || |
[email protected] | 6244581 | 2011-05-03 22:41:32 | [diff] [blame] | 313 | !element.isTextField() || element.isPasswordField() || |
| 314 | !element.suggestedValue().isEmpty()) |
[email protected] | dc9144f | 2010-11-16 02:18:28 | [diff] [blame] | 315 | return; |
[email protected] | dc9144f | 2010-11-16 02:18:28 | [diff] [blame] | 316 | |
[email protected] | 1866d06 | 2010-11-16 06:19:56 | [diff] [blame] | 317 | // If the field has no name, then we won't have values. |
| 318 | if (element.nameForAutofill().isEmpty()) |
[email protected] | e47aec5 | 2010-08-12 00:50:30 | [diff] [blame] | 319 | return; |
| 320 | |
| 321 | // Don't attempt to autofill with values that are too large. |
| 322 | WebString value = element.value(); |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 323 | if (value.length() > kMaximumTextSizeForAutofill) |
[email protected] | e47aec5 | 2010-08-12 00:50:30 | [diff] [blame] | 324 | return; |
| 325 | |
| 326 | if (!autofill_on_empty_values && value.isEmpty()) |
| 327 | return; |
| 328 | |
| 329 | if (requires_caret_at_end && |
| 330 | (element.selectionStart() != element.selectionEnd() || |
[email protected] | 1866d06 | 2010-11-16 06:19:56 | [diff] [blame] | 331 | element.selectionEnd() != static_cast<int>(value.length()))) |
[email protected] | e47aec5 | 2010-08-12 00:50:30 | [diff] [blame] | 332 | return; |
[email protected] | e47aec5 | 2010-08-12 00:50:30 | [diff] [blame] | 333 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 334 | QueryAutofillSuggestions(element, display_warning_if_disabled); |
[email protected] | 77bb0da | 2010-11-20 01:55:30 | [diff] [blame] | 335 | } |
| 336 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 337 | void AutofillAgent::QueryAutofillSuggestions(const WebNode& node, |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 338 | bool display_warning_if_disabled) { |
[email protected] | 77bb0da | 2010-11-20 01:55:30 | [diff] [blame] | 339 | static int query_counter = 0; |
| 340 | autofill_query_id_ = query_counter++; |
| 341 | autofill_query_node_ = node; |
[email protected] | 6bcd58a | 2010-11-25 02:31:20 | [diff] [blame] | 342 | display_warning_if_disabled_ = display_warning_if_disabled; |
[email protected] | 77bb0da | 2010-11-20 01:55:30 | [diff] [blame] | 343 | |
[email protected] | 3bb80e4 | 2010-11-29 22:27:16 | [diff] [blame] | 344 | webkit_glue::FormData form; |
[email protected] | 77bb0da | 2010-11-20 01:55:30 | [diff] [blame] | 345 | webkit_glue::FormField field; |
[email protected] | 7837be6 | 2011-01-18 23:45:08 | [diff] [blame] | 346 | if (!FindFormAndFieldForNode(node, &form, &field)) { |
| 347 | // If we didn't find the cached form, at least let autocomplete have a shot |
| 348 | // at providing suggestions. |
| 349 | FormManager::WebFormControlElementToFormField( |
| 350 | node.toConst<WebFormControlElement>(), FormManager::EXTRACT_VALUE, |
| 351 | &field); |
| 352 | } |
[email protected] | 77bb0da | 2010-11-20 01:55:30 | [diff] [blame] | 353 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 354 | Send(new AutofillHostMsg_QueryFormFieldAutofill( |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 355 | routing_id(), autofill_query_id_, form, field)); |
[email protected] | e47aec5 | 2010-08-12 00:50:30 | [diff] [blame] | 356 | } |
| 357 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 358 | void AutofillAgent::FillAutofillFormData(const WebNode& node, |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 359 | int unique_id, |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 360 | AutofillAction action) { |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 361 | static int query_counter = 0; |
| 362 | autofill_query_id_ = query_counter++; |
| 363 | |
| 364 | webkit_glue::FormData form; |
[email protected] | 3bb80e4 | 2010-11-29 22:27:16 | [diff] [blame] | 365 | webkit_glue::FormField field; |
| 366 | if (!FindFormAndFieldForNode(node, &form, &field)) |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 367 | return; |
| 368 | |
| 369 | autofill_action_ = action; |
[email protected] | e2aaa81 | 2011-03-08 18:46:04 | [diff] [blame] | 370 | was_query_node_autofilled_ = field.is_autofilled; |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 371 | Send(new AutofillHostMsg_FillAutofillFormData( |
[email protected] | 676126f7 | 2011-01-15 00:03:51 | [diff] [blame] | 372 | routing_id(), autofill_query_id_, form, field, unique_id)); |
[email protected] | 679f128f | 2010-07-22 22:57:44 | [diff] [blame] | 373 | } |
| 374 | |
[email protected] | 663bd9e | 2011-03-21 01:07:01 | [diff] [blame] | 375 | bool AutofillAgent::FindFormAndFieldForNode(const WebNode& node, |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 376 | webkit_glue::FormData* form, |
| 377 | webkit_glue::FormField* field) { |
[email protected] | 3bb80e4 | 2010-11-29 22:27:16 | [diff] [blame] | 378 | const WebInputElement& element = node.toConst<WebInputElement>(); |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 379 | if (!form_manager_.FindFormWithFormControlElement(element, form)) |
[email protected] | 3bb80e4 | 2010-11-29 22:27:16 | [diff] [blame] | 380 | return false; |
| 381 | |
| 382 | FormManager::WebFormControlElementToFormField(element, |
| 383 | FormManager::EXTRACT_VALUE, |
| 384 | field); |
| 385 | |
| 386 | // WebFormControlElementToFormField does not scrape the DOM for the field |
| 387 | // label, so find the label here. |
[email protected] | 2fa18c2 | 2011-06-14 23:40:43 | [diff] [blame^] | 388 | // TODO(isherman): Add form and field identities so we can use the cached form |
[email protected] | 3bb80e4 | 2010-11-29 22:27:16 | [diff] [blame] | 389 | // data in FormManager. |
[email protected] | e2aaa81 | 2011-03-08 18:46:04 | [diff] [blame] | 390 | field->label = FormManager::LabelForElement(element); |
[email protected] | 3bb80e4 | 2010-11-29 22:27:16 | [diff] [blame] | 391 | |
| 392 | return true; |
| 393 | } |
[email protected] | 7819208 | 2011-01-29 05:43:44 | [diff] [blame] | 394 | |
| 395 | } // namespace autofill |