blob: 16099c0ccf87a3fde366742d6713521311f3c175 [file] [log] [blame]
[email protected]f07e4442013-06-06 23:03:481// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]679f128f2010-07-22 22:57:442// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]f07e4442013-06-06 23:03:485#include "components/autofill/content/renderer/autofill_agent.h"
[email protected]679f128f2010-07-22 22:57:446
rouslan6a3f8d92015-04-28 01:00:017#include "base/auto_reset.h"
[email protected]a1cb57f2011-09-28 22:41:298#include "base/bind.h"
[email protected]f920d6e2013-03-12 20:20:509#include "base/command_line.h"
[email protected]c50a6932013-07-17 22:16:1310#include "base/message_loop/message_loop.h"
[email protected]1988e1c2013-02-28 20:27:4211#include "base/strings/string_split.h"
[email protected]c72674b2013-06-11 04:16:4312#include "base/strings/string_util.h"
[email protected]d2d79d52013-06-07 22:23:4813#include "base/strings/utf_string_conversions.h"
[email protected]bbd8da92013-06-28 02:12:2014#include "base/time/time.h"
[email protected]45b53fb2013-12-12 19:28:0615#include "components/autofill/content/common/autofill_messages.h"
[email protected]f07e4442013-06-06 23:03:4816#include "components/autofill/content/renderer/form_autofill_util.h"
17#include "components/autofill/content/renderer/page_click_tracker.h"
18#include "components/autofill/content/renderer/password_autofill_agent.h"
[email protected]3cbdf9362014-01-31 23:12:2319#include "components/autofill/content/renderer/password_generation_agent.h"
[email protected]d04f81912013-06-18 14:52:1320#include "components/autofill/core/common/autofill_constants.h"
[email protected]d86263dcd2014-01-09 10:35:2121#include "components/autofill/core/common/autofill_data_validation.h"
[email protected]d04f81912013-06-18 14:52:1322#include "components/autofill/core/common/autofill_switches.h"
23#include "components/autofill/core/common/form_data.h"
24#include "components/autofill/core/common/form_data_predictions.h"
25#include "components/autofill/core/common/form_field_data.h"
[email protected]e620d362013-09-09 08:01:5326#include "components/autofill/core/common/password_form.h"
[email protected]d04f81912013-06-18 14:52:1327#include "components/autofill/core/common/web_element_descriptor.h"
[email protected]fed9d4f2013-12-17 21:32:4728#include "content/public/common/content_switches.h"
[email protected]e4495212012-12-06 03:09:1229#include "content/public/common/ssl_status.h"
[email protected]ca5190f2013-07-08 11:10:3130#include "content/public/common/url_constants.h"
estadeb1bc9bd2014-12-02 22:44:1131#include "content/public/renderer/render_frame.h"
[email protected]a2ef54c2011-10-10 16:20:3132#include "content/public/renderer/render_view.h"
[email protected]ca5190f2013-07-08 11:10:3133#include "net/cert/cert_status_flags.h"
[email protected]f07e4442013-06-06 23:03:4834#include "third_party/WebKit/public/platform/WebRect.h"
35#include "third_party/WebKit/public/platform/WebURLRequest.h"
[email protected]dbdd60272014-04-14 22:48:4036#include "third_party/WebKit/public/web/WebConsoleMessage.h"
[email protected]a0962a92013-06-20 18:27:3437#include "third_party/WebKit/public/web/WebDataSource.h"
38#include "third_party/WebKit/public/web/WebDocument.h"
[email protected]961783a2014-02-07 18:38:0539#include "third_party/WebKit/public/web/WebElementCollection.h"
[email protected]a0962a92013-06-20 18:27:3440#include "third_party/WebKit/public/web/WebFormControlElement.h"
41#include "third_party/WebKit/public/web/WebFormElement.h"
[email protected]a0962a92013-06-20 18:27:3442#include "third_party/WebKit/public/web/WebInputEvent.h"
[email protected]80504652014-04-18 04:41:5043#include "third_party/WebKit/public/web/WebLocalFrame.h"
[email protected]a0962a92013-06-20 18:27:3444#include "third_party/WebKit/public/web/WebNode.h"
[email protected]a0962a92013-06-20 18:27:3445#include "third_party/WebKit/public/web/WebOptionElement.h"
[email protected]e9d29d392014-03-25 01:15:1546#include "third_party/WebKit/public/web/WebTextAreaElement.h"
rouslan6a3f8d92015-04-28 01:00:0147#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
[email protected]a0962a92013-06-20 18:27:3448#include "third_party/WebKit/public/web/WebView.h"
[email protected]c051a1b2011-01-21 23:30:1749#include "ui/base/l10n/l10n_util.h"
[email protected]7e9acd082013-09-17 23:31:1650#include "ui/events/keycodes/keyboard_codes.h"
[email protected]679f128f2010-07-22 22:57:4451
[email protected]a1221aea2013-11-07 01:31:3052using blink::WebAutofillClient;
[email protected]dbdd60272014-04-14 22:48:4053using blink::WebConsoleMessage;
rouslanf7ebd8832015-01-22 01:54:1454using blink::WebDocument;
[email protected]5e7e8612014-03-20 14:43:1955using blink::WebElement;
56using blink::WebElementCollection;
[email protected]a1221aea2013-11-07 01:31:3057using blink::WebFormControlElement;
58using blink::WebFormElement;
59using blink::WebFrame;
60using blink::WebInputElement;
61using blink::WebKeyboardEvent;
[email protected]c5041c322014-04-08 05:06:4762using blink::WebLocalFrame;
[email protected]a1221aea2013-11-07 01:31:3063using blink::WebNode;
[email protected]a1221aea2013-11-07 01:31:3064using blink::WebOptionElement;
65using blink::WebString;
[email protected]e9d29d392014-03-25 01:15:1566using blink::WebTextAreaElement;
rouslan6a3f8d92015-04-28 01:00:0167using blink::WebUserGestureIndicator;
[email protected]5e7e8612014-03-20 14:43:1968using blink::WebVector;
[email protected]679f128f2010-07-22 22:57:4469
[email protected]d86263dcd2014-01-09 10:35:2170namespace autofill {
71
[email protected]e47aec52010-08-12 00:50:3072namespace {
73
[email protected]45a07942013-07-26 08:28:2174// Gets all the data list values (with corresponding label) for the given
75// element.
[email protected]5e7e8612014-03-20 14:43:1976void GetDataListSuggestions(const WebInputElement& element,
[email protected]efeb565f2013-12-12 17:16:4177 bool ignore_current_value,
[email protected]45a07942013-07-26 08:28:2178 std::vector<base::string16>* values,
79 std::vector<base::string16>* labels) {
[email protected]961783a2014-02-07 18:38:0580 WebElementCollection options = element.dataListOptions();
[email protected]bef7f9272012-04-17 10:47:4981 if (options.isNull())
82 return;
83
[email protected]efeb565f2013-12-12 17:16:4184 base::string16 prefix;
85 if (!ignore_current_value) {
86 prefix = element.editingValue();
[email protected]7bc44532014-07-10 16:02:1587 if (element.isMultiple() && element.isEmailField()) {
[email protected]efeb565f2013-12-12 17:16:4188 std::vector<base::string16> parts;
89 base::SplitStringDontTrim(prefix, ',', &parts);
[email protected]8af69c6c2014-03-03 19:05:3190 if (parts.size() > 0) {
91 base::TrimWhitespace(parts[parts.size() - 1], base::TRIM_LEADING,
92 &prefix);
93 }
[email protected]efeb565f2013-12-12 17:16:4194 }
[email protected]71a90b32012-05-18 09:16:5395 }
[email protected]bef7f9272012-04-17 10:47:4996 for (WebOptionElement option = options.firstItem().to<WebOptionElement>();
[email protected]71a90b32012-05-18 09:16:5397 !option.isNull(); option = options.nextItem().to<WebOptionElement>()) {
98 if (!StartsWith(option.value(), prefix, false) ||
99 option.value() == prefix ||
[email protected]3f812632012-05-16 04:13:36100 !element.isValidValue(option.value()))
[email protected]bef7f9272012-04-17 10:47:49101 continue;
102
103 values->push_back(option.value());
104 if (option.value() != option.label())
105 labels->push_back(option.label());
106 else
[email protected]d5ca8fb2013-04-11 17:54:31107 labels->push_back(base::string16());
[email protected]bef7f9272012-04-17 10:47:49108 }
109}
110
[email protected]ead7fb02013-07-18 18:50:12111// Trim the vector before sending it to the browser process to ensure we
[email protected]5c8de6b92012-06-08 21:24:08112// don't send too much data through the IPC.
[email protected]ead7fb02013-07-18 18:50:12113void TrimStringVectorForIPC(std::vector<base::string16>* strings) {
114 // Limit the size of the vector.
[email protected]d86263dcd2014-01-09 10:35:21115 if (strings->size() > kMaxListSize)
116 strings->resize(kMaxListSize);
[email protected]5c8de6b92012-06-08 21:24:08117
[email protected]ead7fb02013-07-18 18:50:12118 // Limit the size of the strings in the vector.
119 for (size_t i = 0; i < strings->size(); ++i) {
[email protected]d86263dcd2014-01-09 10:35:21120 if ((*strings)[i].length() > kMaxDataLength)
121 (*strings)[i].resize(kMaxDataLength);
[email protected]5c8de6b92012-06-08 21:24:08122 }
123}
124
mathp692aba82015-03-06 20:55:02125// Extract FormData from the form element and return whether the operation was
126// successful.
127bool ExtractFormDataOnSave(const WebFormElement& form_element, FormData* data) {
128 return WebFormElementToFormData(
estadea15be7b2015-04-07 00:55:58129 form_element, WebFormControlElement(),
mathp692aba82015-03-06 20:55:02130 static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTION_TEXT), data,
131 NULL);
132}
133
[email protected]e47aec52010-08-12 00:50:30134} // namespace
135
brettwb505b7a2014-11-26 22:05:32136AutofillAgent::ShowSuggestionsOptions::ShowSuggestionsOptions()
137 : autofill_on_empty_values(false),
138 requires_caret_at_end(false),
brettwb505b7a2014-11-26 22:05:32139 datalist_only(false),
140 show_full_suggestion_list(false),
141 show_password_suggestions_only(false) {
142}
143
estadeb1bc9bd2014-12-02 22:44:11144AutofillAgent::AutofillAgent(content::RenderFrame* render_frame,
[email protected]3cbdf9362014-01-31 23:12:23145 PasswordAutofillAgent* password_autofill_agent,
146 PasswordGenerationAgent* password_generation_agent)
estadeb1bc9bd2014-12-02 22:44:11147 : content::RenderFrameObserver(render_frame),
estadeff02e6d2014-12-15 21:18:31148 form_cache_(*render_frame->GetWebFrame()),
[email protected]ad19b302013-04-03 07:42:19149 password_autofill_agent_(password_autofill_agent),
[email protected]3cbdf9362014-01-31 23:12:23150 password_generation_agent_(password_generation_agent),
estadeb1bc9bd2014-12-02 22:44:11151 legacy_(render_frame->GetRenderView(), this),
[email protected]679f128f2010-07-22 22:57:44152 autofill_query_id_(0),
[email protected]d77ddc8062010-11-24 01:14:06153 was_query_node_autofilled_(false),
[email protected]e4dce0af2011-09-19 22:22:28154 has_shown_autofill_popup_for_current_edit_(false),
[email protected]90f26252013-02-15 19:48:32155 ignore_text_changes_(false),
[email protected]b648f242014-02-25 13:49:06156 is_popup_possibly_visible_(false),
[email protected]2c305252013-04-26 19:57:05157 weak_ptr_factory_(this) {
estadeb1bc9bd2014-12-02 22:44:11158 render_frame->GetWebFrame()->setAutofillClient(this);
estade78d655f82015-01-30 01:55:08159
160 // This owns itself, and will delete itself when |render_frame| is destructed
161 // (same as AutofillAgent).
162 new PageClickTracker(render_frame, this);
[email protected]679f128f2010-07-22 22:57:44163}
164
[email protected]a64fdc32013-07-31 09:21:13165AutofillAgent::~AutofillAgent() {}
[email protected]d2f05d02011-01-27 18:51:01166
mathp692aba82015-03-06 20:55:02167bool AutofillAgent::FormDataCompare::operator()(const FormData& lhs,
168 const FormData& rhs) const {
169 if (lhs.name != rhs.name)
170 return lhs.name < rhs.name;
171 if (lhs.origin != rhs.origin)
172 return lhs.origin < rhs.origin;
173 if (lhs.action != rhs.action)
174 return lhs.action < rhs.action;
175 if (lhs.is_form_tag != rhs.is_form_tag)
176 return lhs.is_form_tag < rhs.is_form_tag;
177 return lhs.fields < rhs.fields;
178}
179
[email protected]663bd9e2011-03-21 01:07:01180bool AutofillAgent::OnMessageReceived(const IPC::Message& message) {
[email protected]676126f72011-01-15 00:03:51181 bool handled = true;
[email protected]663bd9e2011-03-21 01:07:01182 IPC_BEGIN_MESSAGE_MAP(AutofillAgent, message)
estadeb1bc9bd2014-12-02 22:44:11183 IPC_MESSAGE_HANDLER(AutofillMsg_FirstUserGestureObservedInTab,
184 OnFirstUserGestureObservedInTab)
[email protected]8527a78f2014-06-12 12:49:15185 IPC_MESSAGE_HANDLER(AutofillMsg_Ping, OnPing)
[email protected]63560b32014-03-04 07:06:26186 IPC_MESSAGE_HANDLER(AutofillMsg_FillForm, OnFillForm)
187 IPC_MESSAGE_HANDLER(AutofillMsg_PreviewForm, OnPreviewForm)
[email protected]3eb5728c2011-06-20 22:32:24188 IPC_MESSAGE_HANDLER(AutofillMsg_FieldTypePredictionsAvailable,
189 OnFieldTypePredictionsAvailable)
[email protected]93f2e502013-12-20 09:47:25190 IPC_MESSAGE_HANDLER(AutofillMsg_ClearForm, OnClearForm)
[email protected]93f2e502013-12-20 09:47:25191 IPC_MESSAGE_HANDLER(AutofillMsg_ClearPreviewedForm, OnClearPreviewedForm)
[email protected]ac9b92f2014-03-15 00:48:32192 IPC_MESSAGE_HANDLER(AutofillMsg_FillFieldWithValue, OnFillFieldWithValue)
193 IPC_MESSAGE_HANDLER(AutofillMsg_PreviewFieldWithValue,
194 OnPreviewFieldWithValue)
[email protected]5c8de6b92012-06-08 21:24:08195 IPC_MESSAGE_HANDLER(AutofillMsg_AcceptDataListSuggestion,
196 OnAcceptDataListSuggestion)
[email protected]126b1ad2014-05-21 22:37:33197 IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordSuggestion,
198 OnFillPasswordSuggestion)
199 IPC_MESSAGE_HANDLER(AutofillMsg_PreviewPasswordSuggestion,
200 OnPreviewPasswordSuggestion)
[email protected]82fc1b12013-01-12 00:53:56201 IPC_MESSAGE_HANDLER(AutofillMsg_RequestAutocompleteResult,
202 OnRequestAutocompleteResult)
[email protected]676126f72011-01-15 00:03:51203 IPC_MESSAGE_UNHANDLED(handled = false)
204 IPC_END_MESSAGE_MAP()
205 return handled;
206}
207
mlamouri9ef14c22015-02-27 13:30:54208void AutofillAgent::DidCommitProvisionalLoad(bool is_new_navigation,
209 bool is_same_page_navigation) {
estadeff02e6d2014-12-15 21:18:31210 form_cache_.Reset();
mathp692aba82015-03-06 20:55:02211 submitted_forms_.clear();
[email protected]676126f72011-01-15 00:03:51212}
213
estadeb1bc9bd2014-12-02 22:44:11214void AutofillAgent::DidFinishDocumentLoad() {
215 ProcessForms();
[email protected]3609c962014-07-11 03:18:25216}
217
mathp692aba82015-03-06 20:55:02218void AutofillAgent::WillSendSubmitEvent(const WebFormElement& form) {
219 FormData form_data;
220 if (!ExtractFormDataOnSave(form, &form_data))
221 return;
222
223 // The WillSendSubmitEvent function is called when there is a submit handler
224 // on the form, such as in the case of (but not restricted to)
225 // JavaScript-submitted forms. Sends a WillSubmitForm message to the browser
226 // and remembers for which form it did that in the current frame load, so that
227 // no additional message is sent if AutofillAgent::WillSubmitForm() is called
228 // (which is itself not guaranteed if the submit event is prevented by
229 // JavaScript).
230 Send(new AutofillHostMsg_WillSubmitForm(routing_id(), form_data,
231 base::TimeTicks::Now()));
232 submitted_forms_.insert(form_data);
233}
234
estade13da3e42014-12-18 02:10:24235void AutofillAgent::WillSubmitForm(const WebFormElement& form) {
[email protected]2a5b1732011-04-01 23:55:55236 FormData form_data;
mathp692aba82015-03-06 20:55:02237 if (!ExtractFormDataOnSave(form, &form_data))
238 return;
239
240 // If WillSubmitForm message had not been sent for this form, send it.
241 if (!submitted_forms_.count(form_data)) {
242 Send(new AutofillHostMsg_WillSubmitForm(routing_id(), form_data,
243 base::TimeTicks::Now()));
[email protected]2a5b1732011-04-01 23:55:55244 }
mathp692aba82015-03-06 20:55:02245
246 Send(new AutofillHostMsg_FormSubmitted(routing_id(), form_data));
[email protected]2a5b1732011-04-01 23:55:55247}
248
estade2792527072014-12-17 00:41:47249void AutofillAgent::DidChangeScrollOffset() {
estadeb1bc9bd2014-12-02 22:44:11250 HidePopup();
251}
252
[email protected]5e7e8612014-03-20 14:43:19253void AutofillAgent::FocusedNodeChanged(const WebNode& node) {
[email protected]91dcc6d32014-07-30 00:01:33254 HidePopup();
255
estadeb1bc9bd2014-12-02 22:44:11256 if (node.isNull() || !node.isElementNode())
257 return;
258
[email protected]5e7e8612014-03-20 14:43:19259 WebElement web_element = node.toConst<WebElement>();
[email protected]f920d6e2013-03-12 20:20:50260 const WebInputElement* element = toWebInputElement(&web_element);
261
262 if (!element || !element->isEnabled() || element->isReadOnly() ||
rouslanf7ebd8832015-01-22 01:54:14263 !element->isTextField())
[email protected]f920d6e2013-03-12 20:20:50264 return;
265
[email protected]e5057a22013-04-22 12:41:39266 element_ = *element;
[email protected]e5057a22013-04-22 12:41:39267}
268
rouslanf7ebd8832015-01-22 01:54:14269void AutofillAgent::FocusChangeComplete() {
270 WebDocument doc = render_frame()->GetWebFrame()->document();
271 WebElement focused_element;
272 if (!doc.isNull())
273 focused_element = doc.focusedElement();
274
275 if (!focused_element.isNull() && password_generation_agent_ &&
276 password_generation_agent_->FocusedNodeHasChanged(focused_element)) {
277 is_popup_possibly_visible_ = true;
278 }
279}
280
[email protected]1c6269a62014-04-12 03:17:14281void AutofillAgent::didRequestAutocomplete(
[email protected]304130f2014-05-23 22:58:55282 const WebFormElement& form) {
estadeb1bc9bd2014-12-02 22:44:11283 DCHECK_EQ(form.document().frame(), render_frame()->GetWebFrame());
284
[email protected]fed9d4f2013-12-17 21:32:47285 // Disallow the dialog over non-https or broken https, except when the
286 // ignore SSL flag is passed. See http://crbug.com/272512.
287 // TODO(palmer): this should be moved to the browser process after frames
288 // get their own processes.
[email protected]1c6269a62014-04-12 03:17:14289 GURL url(form.document().url());
290 content::SSLStatus ssl_status =
estadeb1bc9bd2014-12-02 22:44:11291 render_frame()->GetRenderView()->GetSSLStatusOfFrame(
292 form.document().frame());
[email protected]e8ca69c2014-05-07 15:31:19293 bool is_safe = url.SchemeIs(url::kHttpsScheme) &&
[email protected]fed9d4f2013-12-17 21:32:47294 !net::IsCertStatusError(ssl_status.cert_status);
brettwb505b7a2014-11-26 22:05:32295 bool allow_unsafe = base::CommandLine::ForCurrentProcess()->HasSwitch(
[email protected]fed9d4f2013-12-17 21:32:47296 ::switches::kReduceSecurityForTesting);
[email protected]81cd52332012-11-05 20:36:07297 FormData form_data;
[email protected]a3d81cf2014-04-15 23:26:16298 std::string error_message;
299 if (!in_flight_request_form_.isNull()) {
300 error_message = "already active.";
301 } else if (!is_safe && !allow_unsafe) {
302 error_message =
303 "must use a secure connection or --reduce-security-for-testing.";
304 } else if (!WebFormElementToFormData(form,
305 WebFormControlElement(),
[email protected]191279cb2014-06-26 08:02:11306 static_cast<ExtractMask>(
307 EXTRACT_VALUE |
308 EXTRACT_OPTION_TEXT |
309 EXTRACT_OPTIONS),
[email protected]a3d81cf2014-04-15 23:26:16310 &form_data,
311 NULL)) {
312 error_message = "failed to parse form.";
313 }
314
315 if (!error_message.empty()) {
316 WebConsoleMessage console_message = WebConsoleMessage(
317 WebConsoleMessage::LevelLog,
318 WebString(base::ASCIIToUTF16("requestAutocomplete: ") +
319 base::ASCIIToUTF16(error_message)));
[email protected]b221bd62014-06-06 10:16:37320 form.document().frame()->addMessageToConsole(console_message);
[email protected]81cd52332012-11-05 20:36:07321 WebFormElement(form).finishRequestAutocomplete(
[email protected]82fc1b12013-01-12 00:53:56322 WebFormElement::AutocompleteResultErrorDisabled);
[email protected]81cd52332012-11-05 20:36:07323 return;
324 }
325
326 // Cancel any pending Autofill requests and hide any currently showing popups.
327 ++autofill_query_id_;
[email protected]b648f242014-02-25 13:49:06328 HidePopup();
[email protected]81cd52332012-11-05 20:36:07329
330 in_flight_request_form_ = form;
estade1dbe1232015-01-06 22:45:04331 Send(new AutofillHostMsg_RequestAutocomplete(routing_id(), form_data));
[email protected]81cd52332012-11-05 20:36:07332}
333
[email protected]90f26252013-02-15 19:48:32334void AutofillAgent::setIgnoreTextChanges(bool ignore) {
335 ignore_text_changes_ = ignore;
336}
337
[email protected]e9d29d392014-03-25 01:15:15338void AutofillAgent::FormControlElementClicked(
339 const WebFormControlElement& element,
340 bool was_focused) {
estadeb1bc9bd2014-12-02 22:44:11341 // TODO(estade): Remove this check when PageClickTracker is per-frame.
342 if (element.document().frame() != render_frame()->GetWebFrame())
343 return;
344
[email protected]e9d29d392014-03-25 01:15:15345 const WebInputElement* input_element = toWebInputElement(&element);
346 if (!input_element && !IsTextAreaElement(element))
347 return;
348
brettwb505b7a2014-11-26 22:05:32349 ShowSuggestionsOptions options;
350 options.autofill_on_empty_values = true;
brettwb505b7a2014-11-26 22:05:32351 options.show_full_suggestion_list = element.isAutofilled();
gcasto2c6462272014-11-04 01:14:11352
Evan Stade8ce41c82015-01-23 22:18:26353 // On Android, default to showing the dropdown on field focus.
354 // On desktop, require an extra click after field focus.
355 // See http://crbug.com/427660
estade354304b2015-01-23 01:20:23356#if defined(OS_ANDROID)
357 bool single_click_autofill =
358 !base::CommandLine::ForCurrentProcess()->HasSwitch(
359 switches::kDisableSingleClickAutofill);
360#else
361 bool single_click_autofill =
362 base::CommandLine::ForCurrentProcess()->HasSwitch(
363 switches::kEnableSingleClickAutofill);
364#endif
365
366 if (!single_click_autofill) {
brettwb505b7a2014-11-26 22:05:32367 // Show full suggestions when clicking on an already-focused form field. On
368 // the initial click (not focused yet), only show password suggestions.
brettwb505b7a2014-11-26 22:05:32369 options.show_full_suggestion_list =
370 options.show_full_suggestion_list || was_focused;
371 options.show_password_suggestions_only = !was_focused;
gcasto2c6462272014-11-04 01:14:11372 }
brettwb505b7a2014-11-26 22:05:32373 ShowSuggestions(element, options);
[email protected]676126f72011-01-15 00:03:51374}
375
[email protected]2fa18c22011-06-14 23:40:43376void AutofillAgent::textFieldDidEndEditing(const WebInputElement& element) {
[email protected]ad19b302013-04-03 07:42:19377 password_autofill_agent_->TextFieldDidEndEditing(element);
[email protected]7d24db72011-08-26 06:02:31378 has_shown_autofill_popup_for_current_edit_ = false;
[email protected]2739e0e2011-11-22 22:49:11379 Send(new AutofillHostMsg_DidEndTextFieldEditing(routing_id()));
[email protected]676126f72011-01-15 00:03:51380}
381
[email protected]e9d29d392014-03-25 01:15:15382void AutofillAgent::textFieldDidChange(const WebFormControlElement& element) {
rouslan6a3f8d92015-04-28 01:00:01383 DCHECK(toWebInputElement(&element) || IsTextAreaElement(element));
[email protected]90f26252013-02-15 19:48:32384 if (ignore_text_changes_)
385 return;
386
rouslan6a3f8d92015-04-28 01:00:01387 if (!WebUserGestureIndicator::isProcessingUserGesture())
[email protected]b96a1d12012-11-30 22:44:32388 return;
[email protected]b37043c2012-05-31 17:08:12389
[email protected]663bd9e2011-03-21 01:07:01390 // We post a task for doing the Autofill as the caret position is not set
[email protected]676126f72011-01-15 00:03:51391 // properly at this point (http://bugs.webkit.org/show_bug.cgi?id=16976) and
392 // it is needed to trigger autofill.
[email protected]5219146e2013-02-28 11:42:30393 weak_ptr_factory_.InvalidateWeakPtrs();
[email protected]d14c5b32013-05-06 05:25:11394 base::MessageLoop::current()->PostTask(
395 FROM_HERE,
396 base::Bind(&AutofillAgent::TextFieldDidChangeImpl,
397 weak_ptr_factory_.GetWeakPtr(),
398 element));
[email protected]676126f72011-01-15 00:03:51399}
400
[email protected]e9d29d392014-03-25 01:15:15401void AutofillAgent::TextFieldDidChangeImpl(
402 const WebFormControlElement& element) {
[email protected]f9af2832012-12-14 04:20:43403 // If the element isn't focused then the changes don't matter. This check is
404 // required to properly handle IME interactions.
405 if (!element.focused())
406 return;
407
[email protected]e9d29d392014-03-25 01:15:15408 const WebInputElement* input_element = toWebInputElement(&element);
409 if (input_element) {
410 if (password_generation_agent_ &&
411 password_generation_agent_->TextDidChangeInTextField(*input_element)) {
[email protected]7e048272014-04-17 03:38:52412 is_popup_possibly_visible_ = true;
[email protected]e9d29d392014-03-25 01:15:15413 return;
414 }
[email protected]3cbdf9362014-01-31 23:12:23415
[email protected]e9d29d392014-03-25 01:15:15416 if (password_autofill_agent_->TextDidChangeInTextField(*input_element)) {
rouslan2f5993f2015-01-29 00:18:31417 is_popup_possibly_visible_ = true;
[email protected]e9d29d392014-03-25 01:15:15418 element_ = element;
419 return;
420 }
[email protected]e7e83472012-04-05 02:56:26421 }
[email protected]676126f72011-01-15 00:03:51422
brettwb505b7a2014-11-26 22:05:32423 ShowSuggestionsOptions options;
424 options.requires_caret_at_end = true;
425 ShowSuggestions(element, options);
[email protected]7d24db72011-08-26 06:02:31426
[email protected]1ecbe862012-10-05 01:29:14427 FormData form;
428 FormFieldData field;
estadea15be7b2015-04-07 00:55:58429 if (FindFormAndFieldForFormControlElement(element, &form, &field)) {
[email protected]1d14f582011-09-02 20:42:04430 Send(new AutofillHostMsg_TextFieldDidChange(routing_id(), form, field,
431 base::TimeTicks::Now()));
432 }
[email protected]676126f72011-01-15 00:03:51433}
434
[email protected]2fa18c22011-06-14 23:40:43435void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element,
436 const WebKeyboardEvent& event) {
[email protected]ad19b302013-04-03 07:42:19437 if (password_autofill_agent_->TextFieldHandlingKeyDown(element, event)) {
[email protected]bef7f9272012-04-17 10:47:49438 element_ = element;
[email protected]fc1964a2011-01-20 19:33:07439 return;
[email protected]e7e83472012-04-05 02:56:26440 }
[email protected]676126f72011-01-15 00:03:51441
442 if (event.windowsKeyCode == ui::VKEY_DOWN ||
brettwb505b7a2014-11-26 22:05:32443 event.windowsKeyCode == ui::VKEY_UP) {
444 ShowSuggestionsOptions options;
445 options.autofill_on_empty_values = true;
446 options.requires_caret_at_end = true;
brettwb505b7a2014-11-26 22:05:32447 ShowSuggestions(element, options);
448 }
[email protected]efeb565f2013-12-12 17:16:41449}
450
451void AutofillAgent::openTextDataListChooser(const WebInputElement& element) {
brettwb505b7a2014-11-26 22:05:32452 ShowSuggestionsOptions options;
453 options.autofill_on_empty_values = true;
454 options.datalist_only = true;
455 ShowSuggestions(element, options);
[email protected]676126f72011-01-15 00:03:51456}
457
estadedf5088a2014-12-15 02:04:07458void AutofillAgent::dataListOptionsChanged(const WebInputElement& element) {
459 if (!is_popup_possibly_visible_ || !element.focused())
460 return;
461
462 TextFieldDidChangeImpl(element);
463}
464
[email protected]fc22ae52014-04-23 13:48:04465void AutofillAgent::firstUserGestureObserved() {
466 password_autofill_agent_->FirstUserGestureObserved();
estadeb1bc9bd2014-12-02 22:44:11467 Send(new AutofillHostMsg_FirstUserGestureObserved(routing_id()));
[email protected]fc22ae52014-04-23 13:48:04468}
469
[email protected]d5ca8fb2013-04-11 17:54:31470void AutofillAgent::AcceptDataListSuggestion(
471 const base::string16& suggested_value) {
[email protected]e9d29d392014-03-25 01:15:15472 WebInputElement* input_element = toWebInputElement(&element_);
473 DCHECK(input_element);
[email protected]d5ca8fb2013-04-11 17:54:31474 base::string16 new_value = suggested_value;
[email protected]71a90b32012-05-18 09:16:53475 // If this element takes multiple values then replace the last part with
476 // the suggestion.
[email protected]7bc44532014-07-10 16:02:15477 if (input_element->isMultiple() && input_element->isEmailField()) {
[email protected]d5ca8fb2013-04-11 17:54:31478 std::vector<base::string16> parts;
[email protected]71a90b32012-05-18 09:16:53479
[email protected]e9d29d392014-03-25 01:15:15480 base::SplitStringDontTrim(input_element->editingValue(), ',', &parts);
[email protected]71a90b32012-05-18 09:16:53481 if (parts.size() == 0)
[email protected]d5ca8fb2013-04-11 17:54:31482 parts.push_back(base::string16());
[email protected]71a90b32012-05-18 09:16:53483
[email protected]d5ca8fb2013-04-11 17:54:31484 base::string16 last_part = parts.back();
[email protected]71a90b32012-05-18 09:16:53485 // We want to keep just the leading whitespace.
486 for (size_t i = 0; i < last_part.size(); ++i) {
487 if (!IsWhitespace(last_part[i])) {
488 last_part = last_part.substr(0, i);
489 break;
490 }
491 }
492 last_part.append(suggested_value);
493 parts[parts.size() - 1] = last_part;
494
495 new_value = JoinString(parts, ',');
496 }
[email protected]e9d29d392014-03-25 01:15:15497 FillFieldWithValue(new_value, input_element);
[email protected]71a90b32012-05-18 09:16:53498}
499
[email protected]3eb5728c2011-06-20 22:32:24500void AutofillAgent::OnFieldTypePredictionsAvailable(
501 const std::vector<FormDataPredictions>& forms) {
502 for (size_t i = 0; i < forms.size(); ++i) {
[email protected]aaa80c92011-09-16 00:23:54503 form_cache_.ShowPredictions(forms[i]);
[email protected]3eb5728c2011-06-20 22:32:24504 }
505}
506
[email protected]63560b32014-03-04 07:06:26507void AutofillAgent::OnFillForm(int query_id, const FormData& form) {
estadeb1bc9bd2014-12-02 22:44:11508 if (query_id != autofill_query_id_)
[email protected]63560b32014-03-04 07:06:26509 return;
510
511 was_query_node_autofilled_ = element_.isAutofilled();
512 FillForm(form, element_);
513 Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id(),
514 base::TimeTicks::Now()));
515}
516
estadeb1bc9bd2014-12-02 22:44:11517void AutofillAgent::OnFirstUserGestureObservedInTab() {
518 password_autofill_agent_->FirstUserGestureObserved();
519}
520
[email protected]8527a78f2014-06-12 12:49:15521void AutofillAgent::OnPing() {
522 Send(new AutofillHostMsg_PingAck(routing_id()));
523}
524
[email protected]63560b32014-03-04 07:06:26525void AutofillAgent::OnPreviewForm(int query_id, const FormData& form) {
estadeb1bc9bd2014-12-02 22:44:11526 if (query_id != autofill_query_id_)
[email protected]63560b32014-03-04 07:06:26527 return;
528
529 was_query_node_autofilled_ = element_.isAutofilled();
530 PreviewForm(form, element_);
531 Send(new AutofillHostMsg_DidPreviewAutofillFormData(routing_id()));
[email protected]6f001a6cf2012-02-09 15:21:53532}
533
534void AutofillAgent::OnClearForm() {
[email protected]bef7f9272012-04-17 10:47:49535 form_cache_.ClearFormWithElement(element_);
[email protected]6f001a6cf2012-02-09 15:21:53536}
537
[email protected]6f001a6cf2012-02-09 15:21:53538void AutofillAgent::OnClearPreviewedForm() {
[email protected]93f2e502013-12-20 09:47:25539 if (!element_.isNull()) {
[email protected]b5b1d69f2014-01-23 23:49:32540 if (password_autofill_agent_->DidClearAutofillSelection(element_))
541 return;
542
[email protected]93f2e502013-12-20 09:47:25543 ClearPreviewedFormWithElement(element_, was_query_node_autofilled_);
544 } else {
545 // TODO(isherman): There seem to be rare cases where this code *is*
546 // reachable: see [ http://crbug.com/96321#c6 ]. Ideally we would
547 // understand those cases and fix the code to avoid them. However, so far I
548 // have been unable to reproduce such a case locally. If you hit this
549 // NOTREACHED(), please file a bug against me.
550 NOTREACHED();
551 }
[email protected]6f001a6cf2012-02-09 15:21:53552}
553
[email protected]ac9b92f2014-03-15 00:48:32554void AutofillAgent::OnFillFieldWithValue(const base::string16& value) {
[email protected]e9d29d392014-03-25 01:15:15555 WebInputElement* input_element = toWebInputElement(&element_);
ziran.sunee0fd4432014-08-27 10:10:49556 if (input_element) {
[email protected]e9d29d392014-03-25 01:15:15557 FillFieldWithValue(value, input_element);
ziran.sunee0fd4432014-08-27 10:10:49558 input_element->setAutofilled(true);
559 }
[email protected]ac9b92f2014-03-15 00:48:32560}
561
562void AutofillAgent::OnPreviewFieldWithValue(const base::string16& value) {
[email protected]e9d29d392014-03-25 01:15:15563 WebInputElement* input_element = toWebInputElement(&element_);
564 if (input_element)
565 PreviewFieldWithValue(value, input_element);
[email protected]6f001a6cf2012-02-09 15:21:53566}
567
[email protected]d5ca8fb2013-04-11 17:54:31568void AutofillAgent::OnAcceptDataListSuggestion(const base::string16& value) {
[email protected]5c8de6b92012-06-08 21:24:08569 AcceptDataListSuggestion(value);
570}
571
[email protected]126b1ad2014-05-21 22:37:33572void AutofillAgent::OnFillPasswordSuggestion(const base::string16& username,
573 const base::string16& password) {
574 bool handled = password_autofill_agent_->FillSuggestion(
575 element_,
576 username,
577 password);
578 DCHECK(handled);
579}
580
581void AutofillAgent::OnPreviewPasswordSuggestion(
[email protected]c281d502014-04-24 21:07:36582 const base::string16& username,
583 const base::string16& password) {
[email protected]126b1ad2014-05-21 22:37:33584 bool handled = password_autofill_agent_->PreviewSuggestion(
[email protected]bef7f9272012-04-17 10:47:49585 element_,
[email protected]c281d502014-04-24 21:07:36586 username,
587 password);
[email protected]e7e83472012-04-05 02:56:26588 DCHECK(handled);
589}
590
[email protected]82fc1b12013-01-12 00:53:56591void AutofillAgent::OnRequestAutocompleteResult(
[email protected]5e7e8612014-03-20 14:43:19592 WebFormElement::AutocompleteResult result,
[email protected]dbdd60272014-04-14 22:48:40593 const base::string16& message,
[email protected]5e7e8612014-03-20 14:43:19594 const FormData& form_data) {
[email protected]364481b2013-01-29 01:52:28595 if (in_flight_request_form_.isNull())
596 return;
597
[email protected]9793fb232013-06-21 10:25:35598 if (result == WebFormElement::AutocompleteResultSuccess) {
[email protected]82fc1b12013-01-12 00:53:56599 FillFormIncludingNonFocusableElements(form_data, in_flight_request_form_);
[email protected]3bf260a2014-04-16 19:37:12600 if (!in_flight_request_form_.checkValidity())
[email protected]9793fb232013-06-21 10:25:35601 result = WebFormElement::AutocompleteResultErrorInvalid;
602 }
[email protected]364481b2013-01-29 01:52:28603
[email protected]81cd52332012-11-05 20:36:07604 in_flight_request_form_.finishRequestAutocomplete(result);
[email protected]dbdd60272014-04-14 22:48:40605
606 if (!message.empty()) {
607 const base::string16 prefix(base::ASCIIToUTF16("requestAutocomplete: "));
608 WebConsoleMessage console_message = WebConsoleMessage(
609 WebConsoleMessage::LevelLog, WebString(prefix + message));
610 in_flight_request_form_.document().frame()->addMessageToConsole(
611 console_message);
612 }
613
[email protected]81cd52332012-11-05 20:36:07614 in_flight_request_form_.reset();
615}
616
[email protected]e9d29d392014-03-25 01:15:15617void AutofillAgent::ShowSuggestions(const WebFormControlElement& element,
brettwb505b7a2014-11-26 22:05:32618 const ShowSuggestionsOptions& options) {
[email protected]e9d29d392014-03-25 01:15:15619 if (!element.isEnabled() || element.isReadOnly())
[email protected]efeb565f2013-12-12 17:16:41620 return;
brettwb505b7a2014-11-26 22:05:32621 if (!options.datalist_only && !element.suggestedValue().isEmpty())
[email protected]580c38052014-07-16 07:28:09622 return;
[email protected]e9d29d392014-03-25 01:15:15623
624 const WebInputElement* input_element = toWebInputElement(&element);
625 if (input_element) {
jww20355072014-12-12 21:00:55626 if (!input_element->isTextField())
[email protected]e9d29d392014-03-25 01:15:15627 return;
brettwb505b7a2014-11-26 22:05:32628 if (!options.datalist_only && !input_element->suggestedValue().isEmpty())
[email protected]e9d29d392014-03-25 01:15:15629 return;
630 } else {
631 DCHECK(IsTextAreaElement(element));
632 if (!element.toConst<WebTextAreaElement>().suggestedValue().isEmpty())
633 return;
634 }
[email protected]e47aec52010-08-12 00:50:30635
[email protected]1c69f8b72012-03-14 03:18:50636 // Don't attempt to autofill with values that are too large or if filling
637 // criteria are not met.
[email protected]71a90b32012-05-18 09:16:53638 WebString value = element.editingValue();
brettwb505b7a2014-11-26 22:05:32639 if (!options.datalist_only &&
[email protected]d86263dcd2014-01-09 10:35:21640 (value.length() > kMaxDataLength ||
brettwb505b7a2014-11-26 22:05:32641 (!options.autofill_on_empty_values && value.isEmpty()) ||
642 (options.requires_caret_at_end &&
[email protected]efeb565f2013-12-12 17:16:41643 (element.selectionStart() != element.selectionEnd() ||
644 element.selectionEnd() != static_cast<int>(value.length()))))) {
[email protected]1c69f8b72012-03-14 03:18:50645 // Any popup currently showing is obsolete.
[email protected]b648f242014-02-25 13:49:06646 HidePopup();
[email protected]e47aec52010-08-12 00:50:30647 return;
[email protected]1c69f8b72012-03-14 03:18:50648 }
[email protected]e47aec52010-08-12 00:50:30649
[email protected]bef7f9272012-04-17 10:47:49650 element_ = element;
[email protected]580c38052014-07-16 07:28:09651 if (IsAutofillableInputElement(input_element) &&
brettwb505b7a2014-11-26 22:05:32652 (password_autofill_agent_->ShowSuggestions(
653 *input_element, options.show_full_suggestion_list) ||
654 options.show_password_suggestions_only)) {
[email protected]b648f242014-02-25 13:49:06655 is_popup_possibly_visible_ = true;
[email protected]c66ba982013-04-05 09:56:17656 return;
[email protected]b648f242014-02-25 13:49:06657 }
[email protected]bef7f9272012-04-17 10:47:49658
jww20355072014-12-12 21:00:55659 // Password field elements should only have suggestions shown by the password
660 // autofill agent.
661 if (input_element && input_element->isPasswordField())
662 return;
663
estadea15be7b2015-04-07 00:55:58664 QueryAutofillSuggestions(element, options.datalist_only);
[email protected]77bb0da2010-11-20 01:55:30665}
666
[email protected]e9d29d392014-03-25 01:15:15667void AutofillAgent::QueryAutofillSuggestions(
668 const WebFormControlElement& element,
[email protected]e9d29d392014-03-25 01:15:15669 bool datalist_only) {
[email protected]e69b5f72013-01-24 00:59:13670 if (!element.document().frame())
671 return;
672
[email protected]e9d29d392014-03-25 01:15:15673 DCHECK(toWebInputElement(&element) || IsTextAreaElement(element));
674
[email protected]77bb0da2010-11-20 01:55:30675 static int query_counter = 0;
676 autofill_query_id_ = query_counter++;
estade0ee91262014-10-23 19:29:19677
[email protected]1ecbe862012-10-05 01:29:14678 FormData form;
679 FormFieldData field;
estadea15be7b2015-04-07 00:55:58680 if (!FindFormAndFieldForFormControlElement(element, &form, &field)) {
[email protected]7837be62011-01-18 23:45:08681 // If we didn't find the cached form, at least let autocomplete have a shot
682 // at providing suggestions.
[email protected]aaa80c92011-09-16 00:23:54683 WebFormControlElementToFormField(element, EXTRACT_VALUE, &field);
[email protected]7837be62011-01-18 23:45:08684 }
[email protected]efeb565f2013-12-12 17:16:41685 if (datalist_only)
686 field.should_autocomplete = false;
[email protected]77bb0da2010-11-20 01:55:30687
estadeb1bc9bd2014-12-02 22:44:11688 gfx::RectF bounding_box_scaled = GetScaledBoundingBox(
689 render_frame()->GetRenderView()->GetWebView()->pageScaleFactor(),
690 &element_);
[email protected]73a087f2013-02-06 07:02:06691
[email protected]7d0ea5362014-05-01 23:39:43692 std::vector<base::string16> data_list_values;
693 std::vector<base::string16> data_list_labels;
[email protected]e9d29d392014-03-25 01:15:15694 const WebInputElement* input_element = toWebInputElement(&element);
695 if (input_element) {
696 // Find the datalist values and send them to the browser process.
[email protected]e9d29d392014-03-25 01:15:15697 GetDataListSuggestions(*input_element,
698 datalist_only,
699 &data_list_values,
700 &data_list_labels);
701 TrimStringVectorForIPC(&data_list_values);
702 TrimStringVectorForIPC(&data_list_labels);
[email protected]e9d29d392014-03-25 01:15:15703 }
[email protected]5c8de6b92012-06-08 21:24:08704
[email protected]b648f242014-02-25 13:49:06705 is_popup_possibly_visible_ = true;
[email protected]7d0ea5362014-05-01 23:39:43706 Send(new AutofillHostMsg_SetDataList(routing_id(),
707 data_list_values,
708 data_list_labels));
709
estadea15be7b2015-04-07 00:55:58710 Send(new AutofillHostMsg_QueryFormFieldAutofill(
711 routing_id(), autofill_query_id_, form, field, bounding_box_scaled));
[email protected]e47aec52010-08-12 00:50:30712}
713
[email protected]ac9b92f2014-03-15 00:48:32714void AutofillAgent::FillFieldWithValue(const base::string16& value,
[email protected]5e7e8612014-03-20 14:43:19715 WebInputElement* node) {
rouslan6a3f8d92015-04-28 01:00:01716 base::AutoReset<bool> auto_reset(&ignore_text_changes_, true);
[email protected]2ee19ec2014-02-25 12:44:31717 node->setEditingValue(value.substr(0, node->maxLength()));
[email protected]ac9b92f2014-03-15 00:48:32718}
719
720void AutofillAgent::PreviewFieldWithValue(const base::string16& value,
[email protected]5e7e8612014-03-20 14:43:19721 WebInputElement* node) {
[email protected]ac9b92f2014-03-15 00:48:32722 was_query_node_autofilled_ = element_.isAutofilled();
723 node->setSuggestedValue(value.substr(0, node->maxLength()));
724 node->setAutofilled(true);
[email protected]f47d3022014-03-24 21:24:18725 node->setSelectionRange(node->value().length(),
726 node->suggestedValue().length());
[email protected]6f001a6cf2012-02-09 15:21:53727}
728
estadeb1bc9bd2014-12-02 22:44:11729void AutofillAgent::ProcessForms() {
[email protected]5193ea52014-05-14 01:10:02730 // Record timestamp of when the forms are first seen. This is used to
731 // measure the overhead of the Autofill feature.
732 base::TimeTicks forms_seen_timestamp = base::TimeTicks::Now();
733
estadeb1bc9bd2014-12-02 22:44:11734 WebLocalFrame* frame = render_frame()->GetWebFrame();
estadeff02e6d2014-12-15 21:18:31735 std::vector<FormData> forms = form_cache_.ExtractNewForms();
[email protected]5193ea52014-05-14 01:10:02736
737 // Always communicate to browser process for topmost frame.
estadeb1bc9bd2014-12-02 22:44:11738 if (!forms.empty() || !frame->parent()) {
[email protected]5193ea52014-05-14 01:10:02739 Send(new AutofillHostMsg_FormsSeen(routing_id(), forms,
740 forms_seen_timestamp));
741 }
[email protected]5193ea52014-05-14 01:10:02742}
743
[email protected]b648f242014-02-25 13:49:06744void AutofillAgent::HidePopup() {
745 if (!is_popup_possibly_visible_)
746 return;
[email protected]b648f242014-02-25 13:49:06747 is_popup_possibly_visible_ = false;
748 Send(new AutofillHostMsg_HidePopup(routing_id()));
[email protected]81cd52332012-11-05 20:36:07749}
750
[email protected]5e7e8612014-03-20 14:43:19751void AutofillAgent::didAssociateFormControls(const WebVector<WebNode>& nodes) {
[email protected]704b6232013-09-16 21:19:12752 for (size_t i = 0; i < nodes.size(); ++i) {
[email protected]5193ea52014-05-14 01:10:02753 WebLocalFrame* frame = nodes[i].document().frame();
[email protected]704b6232013-09-16 21:19:12754 // Only monitors dynamic forms created in the top frame. Dynamic forms
[email protected]5193ea52014-05-14 01:10:02755 // inserted in iframes are not captured yet. Frame is only processed
756 // if it has finished loading, otherwise you can end up with a partially
757 // parsed form.
estadeb1bc9bd2014-12-02 22:44:11758 if (frame && !frame->isLoading()) {
759 ProcessForms();
760 password_autofill_agent_->OnDynamicFormsSeen();
gcasto93a96502014-10-21 04:15:30761 if (password_generation_agent_)
estadeb1bc9bd2014-12-02 22:44:11762 password_generation_agent_->OnDynamicFormsSeen();
[email protected]704b6232013-09-16 21:19:12763 return;
764 }
765 }
[email protected]17b6be72013-04-30 21:33:08766}
767
gcastoc21f1c4c2015-03-19 21:57:03768void AutofillAgent::xhrSucceeded() {
769 password_autofill_agent_->XHRSucceeded();
770}
771
estadeb1bc9bd2014-12-02 22:44:11772// LegacyAutofillAgent ---------------------------------------------------------
773
774AutofillAgent::LegacyAutofillAgent::LegacyAutofillAgent(
775 content::RenderView* render_view,
776 AutofillAgent* agent)
777 : content::RenderViewObserver(render_view), agent_(agent) {
778}
779
780AutofillAgent::LegacyAutofillAgent::~LegacyAutofillAgent() {
781}
782
783void AutofillAgent::LegacyAutofillAgent::OnDestruct() {
784 // No-op. Don't delete |this|.
785}
786
rouslanf7ebd8832015-01-22 01:54:14787void AutofillAgent::LegacyAutofillAgent::FocusChangeComplete() {
788 agent_->FocusChangeComplete();
789}
790
[email protected]78192082011-01-29 05:43:44791} // namespace autofill