autofill_agent.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/autofill/content/renderer/autofill_agent.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/message_loop/message_loop.h"
10#include "base/strings/string_split.h"
11#include "base/strings/string_util.h"
12#include "base/strings/utf_string_conversions.h"
13#include "base/time/time.h"
14#include "components/autofill/content/renderer/form_autofill_util.h"
15#include "components/autofill/content/renderer/page_click_tracker.h"
16#include "components/autofill/content/renderer/password_autofill_agent.h"
17#include "components/autofill/core/common/autocheckout_status.h"
18#include "components/autofill/core/common/autofill_constants.h"
19#include "components/autofill/core/common/autofill_messages.h"
20#include "components/autofill/core/common/autofill_switches.h"
21#include "components/autofill/core/common/form_data.h"
22#include "components/autofill/core/common/form_data_predictions.h"
23#include "components/autofill/core/common/form_field_data.h"
24#include "components/autofill/core/common/web_element_descriptor.h"
25#include "content/public/common/password_form.h"
26#include "content/public/common/ssl_status.h"
27#include "content/public/common/url_constants.h"
28#include "content/public/renderer/render_view.h"
29#include "grit/component_strings.h"
30#include "net/cert/cert_status_flags.h"
31#include "third_party/WebKit/public/platform/WebRect.h"
32#include "third_party/WebKit/public/platform/WebURLRequest.h"
33#include "third_party/WebKit/public/web/WebDataSource.h"
34#include "third_party/WebKit/public/web/WebDocument.h"
35#include "third_party/WebKit/public/web/WebFormControlElement.h"
36#include "third_party/WebKit/public/web/WebFormElement.h"
37#include "third_party/WebKit/public/web/WebFrame.h"
38#include "third_party/WebKit/public/web/WebInputEvent.h"
39#include "third_party/WebKit/public/web/WebNode.h"
40#include "third_party/WebKit/public/web/WebNodeCollection.h"
41#include "third_party/WebKit/public/web/WebOptionElement.h"
42#include "third_party/WebKit/public/web/WebView.h"
43#include "ui/base/keycodes/keyboard_codes.h"
44#include "ui/base/l10n/l10n_util.h"
45
46using WebKit::WebAutofillClient;
47using WebKit::WebFormControlElement;
48using WebKit::WebFormElement;
49using WebKit::WebFrame;
50using WebKit::WebInputElement;
51using WebKit::WebKeyboardEvent;
52using WebKit::WebNode;
53using WebKit::WebNodeCollection;
54using WebKit::WebOptionElement;
55using WebKit::WebString;
56
57namespace {
58
59// The size above which we stop triggering autofill for an input text field
60// (so to avoid sending long strings through IPC).
61const size_t kMaximumTextSizeForAutofill = 1000;
62
63// The maximum number of data list elements to send to the browser process
64// via IPC (to prevent long IPC messages).
65const size_t kMaximumDataListSizeForAutofill = 30;
66
67const int kAutocheckoutClickTimeout = 3;
68
69void AppendDataListSuggestions(const WebKit::WebInputElement& element,
70                               std::vector<base::string16>* values,
71                               std::vector<base::string16>* labels,
72                               std::vector<base::string16>* icons,
73                               std::vector<int>* item_ids) {
74  WebNodeCollection options = element.dataListOptions();
75  if (options.isNull())
76    return;
77
78  base::string16 prefix = element.editingValue();
79  if (element.isMultiple() &&
80      element.formControlType() == WebString::fromUTF8("email")) {
81    std::vector<base::string16> parts;
82    base::SplitStringDontTrim(prefix, ',', &parts);
83    if (parts.size() > 0)
84      TrimWhitespace(parts[parts.size() - 1], TRIM_LEADING, &prefix);
85  }
86  for (WebOptionElement option = options.firstItem().to<WebOptionElement>();
87       !option.isNull(); option = options.nextItem().to<WebOptionElement>()) {
88    if (!StartsWith(option.value(), prefix, false) ||
89        option.value() == prefix ||
90        !element.isValidValue(option.value()))
91      continue;
92
93    values->push_back(option.value());
94    if (option.value() != option.label())
95      labels->push_back(option.label());
96    else
97      labels->push_back(base::string16());
98    icons->push_back(base::string16());
99    item_ids->push_back(WebAutofillClient::MenuItemIDDataListEntry);
100  }
101}
102
103// Trim the vectors before sending them to the browser process to ensure we
104// don't send too much data through the IPC.
105void TrimDataListsForIPC(std::vector<base::string16>* values,
106                         std::vector<base::string16>* labels,
107                         std::vector<base::string16>* icons,
108                         std::vector<int>* unique_ids) {
109  // Limit the size of the vectors.
110  if (values->size() > kMaximumDataListSizeForAutofill) {
111    values->resize(kMaximumDataListSizeForAutofill);
112    labels->resize(kMaximumDataListSizeForAutofill);
113    icons->resize(kMaximumDataListSizeForAutofill);
114    unique_ids->resize(kMaximumDataListSizeForAutofill);
115  }
116
117  // Limit the size of the strings in the vectors
118  for (size_t i = 0; i < values->size(); ++i) {
119    if ((*values)[i].length() > kMaximumTextSizeForAutofill)
120      (*values)[i].resize(kMaximumTextSizeForAutofill);
121
122    if ((*labels)[i].length() > kMaximumTextSizeForAutofill)
123      (*labels)[i].resize(kMaximumTextSizeForAutofill);
124
125    if ((*icons)[i].length() > kMaximumTextSizeForAutofill)
126      (*icons)[i].resize(kMaximumTextSizeForAutofill);
127  }
128}
129
130gfx::RectF GetScaledBoundingBox(float scale, WebInputElement* element) {
131  gfx::Rect bounding_box(element->boundsInViewportSpace());
132  return gfx::RectF(bounding_box.x() * scale,
133                    bounding_box.y() * scale,
134                    bounding_box.width() * scale,
135                    bounding_box.height() * scale);
136}
137
138}  // namespace
139
140namespace autofill {
141
142AutofillAgent::AutofillAgent(content::RenderView* render_view,
143                             PasswordAutofillAgent* password_autofill_agent)
144    : content::RenderViewObserver(render_view),
145      password_autofill_agent_(password_autofill_agent),
146      autofill_query_id_(0),
147      autofill_action_(AUTOFILL_NONE),
148      topmost_frame_(NULL),
149      web_view_(render_view->GetWebView()),
150      display_warning_if_disabled_(false),
151      was_query_node_autofilled_(false),
152      has_shown_autofill_popup_for_current_edit_(false),
153      did_set_node_text_(false),
154      autocheckout_click_in_progress_(false),
155      is_autocheckout_supported_(false),
156      has_new_forms_for_browser_(false),
157      ignore_text_changes_(false),
158      weak_ptr_factory_(this) {
159  render_view->GetWebView()->setAutofillClient(this);
160
161  // The PageClickTracker is a RenderViewObserver, and hence will be freed when
162  // the RenderView is destroyed.
163  new PageClickTracker(render_view, this);
164}
165
166AutofillAgent::~AutofillAgent() {}
167
168bool AutofillAgent::OnMessageReceived(const IPC::Message& message) {
169  bool handled = true;
170  IPC_BEGIN_MESSAGE_MAP(AutofillAgent, message)
171    IPC_MESSAGE_HANDLER(AutofillMsg_GetAllForms, OnGetAllForms)
172    IPC_MESSAGE_HANDLER(AutofillMsg_FormDataFilled, OnFormDataFilled)
173    IPC_MESSAGE_HANDLER(AutofillMsg_FieldTypePredictionsAvailable,
174                        OnFieldTypePredictionsAvailable)
175    IPC_MESSAGE_HANDLER(AutofillMsg_SetAutofillActionFill,
176                        OnSetAutofillActionFill)
177    IPC_MESSAGE_HANDLER(AutofillMsg_ClearForm,
178                        OnClearForm)
179    IPC_MESSAGE_HANDLER(AutofillMsg_SetAutofillActionPreview,
180                        OnSetAutofillActionPreview)
181    IPC_MESSAGE_HANDLER(AutofillMsg_ClearPreviewedForm,
182                        OnClearPreviewedForm)
183    IPC_MESSAGE_HANDLER(AutofillMsg_SetNodeText,
184                        OnSetNodeText)
185    IPC_MESSAGE_HANDLER(AutofillMsg_AcceptDataListSuggestion,
186                        OnAcceptDataListSuggestion)
187    IPC_MESSAGE_HANDLER(AutofillMsg_AcceptPasswordAutofillSuggestion,
188                        OnAcceptPasswordAutofillSuggestion)
189    IPC_MESSAGE_HANDLER(AutofillMsg_RequestAutocompleteResult,
190                        OnRequestAutocompleteResult)
191    IPC_MESSAGE_HANDLER(AutofillMsg_FillFormsAndClick,
192                        OnFillFormsAndClick)
193    IPC_MESSAGE_HANDLER(AutofillMsg_AutocheckoutSupported,
194                        OnAutocheckoutSupported)
195    IPC_MESSAGE_UNHANDLED(handled = false)
196  IPC_END_MESSAGE_MAP()
197  return handled;
198}
199
200void AutofillAgent::DidFinishDocumentLoad(WebFrame* frame) {
201  // Record timestamp on document load. This is used to record overhead of
202  // Autofill feature.
203  forms_seen_timestamp_ = base::TimeTicks::Now();
204
205  // The document has now been fully loaded.  Scan for forms to be sent up to
206  // the browser.
207  std::vector<FormData> forms;
208  bool has_more_forms = false;
209  if (!frame->parent()) {
210    topmost_frame_ = frame;
211    form_elements_.clear();
212    has_more_forms = form_cache_.ExtractFormsAndFormElements(
213        *frame, kRequiredAutofillFields, &forms, &form_elements_);
214  } else {
215    form_cache_.ExtractForms(*frame, &forms);
216  }
217
218  autofill::FormsSeenState state = has_more_forms ?
219      autofill::PARTIAL_FORMS_SEEN : autofill::NO_SPECIAL_FORMS_SEEN;
220
221  // Always communicate to browser process for topmost frame.
222  if (!forms.empty() || !frame->parent()) {
223    Send(new AutofillHostMsg_FormsSeen(routing_id(), forms,
224                                       forms_seen_timestamp_,
225                                       state));
226  }
227}
228
229void AutofillAgent::DidStartProvisionalLoad(WebFrame* frame) {
230  if (!frame->parent()) {
231    is_autocheckout_supported_ = false;
232    topmost_frame_ = NULL;
233    if (click_timer_.IsRunning()) {
234      click_timer_.Stop();
235      autocheckout_click_in_progress_ = true;
236    }
237  }
238}
239
240void AutofillAgent::DidFailProvisionalLoad(WebFrame* frame,
241                                           const WebKit::WebURLError& error) {
242  if (!frame->parent() && autocheckout_click_in_progress_) {
243    autocheckout_click_in_progress_ = false;
244    ClickFailed();
245  }
246}
247
248void AutofillAgent::DidCommitProvisionalLoad(WebFrame* frame,
249                                             bool is_new_navigation) {
250  in_flight_request_form_.reset();
251  if (!frame->parent())
252    autocheckout_click_in_progress_ = false;
253}
254
255void AutofillAgent::FrameDetached(WebFrame* frame) {
256  form_cache_.ResetFrame(*frame);
257  if (!frame->parent()) {
258    // |frame| is about to be destroyed so we need to clear |top_most_frame_|.
259    topmost_frame_ = NULL;
260    click_timer_.Stop();
261  }
262}
263
264void AutofillAgent::WillSubmitForm(WebFrame* frame,
265                                   const WebFormElement& form) {
266  FormData form_data;
267  if (WebFormElementToFormData(form,
268                               WebFormControlElement(),
269                               REQUIRE_AUTOCOMPLETE,
270                               static_cast<ExtractMask>(
271                                   EXTRACT_VALUE | EXTRACT_OPTION_TEXT),
272                               &form_data,
273                               NULL)) {
274    Send(new AutofillHostMsg_FormSubmitted(routing_id(), form_data,
275                                           base::TimeTicks::Now()));
276  }
277}
278
279void AutofillAgent::ZoomLevelChanged() {
280  // Any time the zoom level changes, the page's content moves, so any Autofill
281  // popups should be hidden. This is only needed for the new Autofill UI
282  // because WebKit already knows to hide the old UI when this occurs.
283  HideHostAutofillUi();
284}
285
286void AutofillAgent::FocusedNodeChanged(const WebKit::WebNode& node) {
287  if (node.isNull() || !node.isElementNode())
288    return;
289
290  WebKit::WebElement web_element = node.toConst<WebKit::WebElement>();
291
292  if (!web_element.document().frame())
293      return;
294
295  const WebInputElement* element = toWebInputElement(&web_element);
296
297  if (!element || !element->isEnabled() || element->isReadOnly() ||
298      !element->isTextField() || element->isPasswordField())
299    return;
300
301  element_ = *element;
302
303  MaybeShowAutocheckoutBubble();
304}
305
306void AutofillAgent::MaybeShowAutocheckoutBubble() {
307  if (element_.isNull() || !element_.focused())
308    return;
309
310  FormData form;
311  FormFieldData field;
312  // This must be called to short circuit this method if it fails.
313  if (!FindFormAndFieldForInputElement(element_, &form, &field, REQUIRE_NONE))
314    return;
315
316  Send(new AutofillHostMsg_MaybeShowAutocheckoutBubble(
317      routing_id(),
318      form,
319      GetScaledBoundingBox(web_view_->pageScaleFactor(), &element_)));
320}
321
322void AutofillAgent::DidChangeScrollOffset(WebKit::WebFrame*) {
323  HideAutofillUi();
324}
325
326void AutofillAgent::didRequestAutocomplete(WebKit::WebFrame* frame,
327                                           const WebFormElement& form) {
328  GURL url(frame->document().url());
329  content::SSLStatus ssl_status = render_view()->GetSSLStatusOfFrame(frame);
330  FormData form_data;
331  if (!in_flight_request_form_.isNull() ||
332      (url.SchemeIs(chrome::kHttpsScheme) &&
333       (net::IsCertStatusError(ssl_status.cert_status) ||
334        net::IsCertStatusMinorError(ssl_status.cert_status))) ||
335      !WebFormElementToFormData(form,
336                                WebFormControlElement(),
337                                REQUIRE_AUTOCOMPLETE,
338                                EXTRACT_OPTIONS,
339                                &form_data,
340                                NULL)) {
341    WebFormElement(form).finishRequestAutocomplete(
342        WebFormElement::AutocompleteResultErrorDisabled);
343    return;
344  }
345
346  // Cancel any pending Autofill requests and hide any currently showing popups.
347  ++autofill_query_id_;
348  HideAutofillUi();
349
350  in_flight_request_form_ = form;
351  Send(new AutofillHostMsg_RequestAutocomplete(routing_id(), form_data, url));
352}
353
354void AutofillAgent::setIgnoreTextChanges(bool ignore) {
355  ignore_text_changes_ = ignore;
356}
357
358void AutofillAgent::InputElementClicked(const WebInputElement& element,
359                                        bool was_focused,
360                                        bool is_focused) {
361  if (was_focused)
362    ShowSuggestions(element, true, false, true);
363}
364
365void AutofillAgent::InputElementLostFocus() {
366  HideHostAutofillUi();
367}
368
369void AutofillAgent::didAcceptAutofillSuggestion(const WebNode& node,
370                                                const WebString& value,
371                                                const WebString& label,
372                                                int item_id,
373                                                unsigned index) {
374  if (password_autofill_agent_->DidAcceptAutofillSuggestion(node, value))
375    return;
376
377  DCHECK(node == element_);
378
379  switch (item_id) {
380    case WebAutofillClient::MenuItemIDWarningMessage:
381    case WebAutofillClient::MenuItemIDSeparator:
382      NOTREACHED();
383      break;
384    case WebAutofillClient::MenuItemIDAutofillOptions:
385      // User selected 'Autofill Options'.
386      Send(new AutofillHostMsg_ShowAutofillDialog(routing_id()));
387      break;
388    case WebAutofillClient::MenuItemIDClearForm:
389      // User selected 'Clear form'.
390      form_cache_.ClearFormWithElement(element_);
391      break;
392    case WebAutofillClient::MenuItemIDAutocompleteEntry:
393    case WebAutofillClient::MenuItemIDPasswordEntry:
394      // User selected an Autocomplete or password entry, so we fill directly.
395      SetNodeText(value, &element_);
396      break;
397    case WebAutofillClient::MenuItemIDDataListEntry:
398      AcceptDataListSuggestion(value);
399      break;
400    default:
401      // A positive item_id is a unique id for an autofill (vs. autocomplete)
402      // suggestion.
403      DCHECK_GT(item_id, 0);
404      // Fill the values for the whole form.
405      FillAutofillFormData(node, item_id, AUTOFILL_FILL);
406  }
407}
408
409void AutofillAgent::didSelectAutofillSuggestion(const WebNode& node,
410                                                const WebString& value,
411                                                const WebString& label,
412                                                int item_id) {
413  if (password_autofill_agent_->DidSelectAutofillSuggestion(node))
414    return;
415
416  didClearAutofillSelection(node);
417
418  if (item_id > 0)
419    FillAutofillFormData(node, item_id, AUTOFILL_PREVIEW);
420}
421
422void AutofillAgent::didClearAutofillSelection(const WebNode& node) {
423  if (password_autofill_agent_->DidClearAutofillSelection(node))
424    return;
425
426  if (!element_.isNull() && node == element_) {
427    ClearPreviewedFormWithElement(element_, was_query_node_autofilled_);
428  } else {
429    // TODO(isherman): There seem to be rare cases where this code *is*
430    // reachable: see [ http://crbug.com/96321#c6 ].  Ideally we would
431    // understand those cases and fix the code to avoid them.  However, so far I
432    // have been unable to reproduce such a case locally.  If you hit this
433    // NOTREACHED(), please file a bug against me.
434    NOTREACHED();
435  }
436}
437
438void AutofillAgent::removeAutocompleteSuggestion(const WebString& name,
439                                                 const WebString& value) {
440  Send(new AutofillHostMsg_RemoveAutocompleteEntry(routing_id(), name, value));
441}
442
443void AutofillAgent::textFieldDidEndEditing(const WebInputElement& element) {
444  password_autofill_agent_->TextFieldDidEndEditing(element);
445  has_shown_autofill_popup_for_current_edit_ = false;
446  Send(new AutofillHostMsg_DidEndTextFieldEditing(routing_id()));
447}
448
449void AutofillAgent::textFieldDidChange(const WebInputElement& element) {
450  if (ignore_text_changes_)
451    return;
452
453  if (did_set_node_text_) {
454    did_set_node_text_ = false;
455    return;
456  }
457
458  // We post a task for doing the Autofill as the caret position is not set
459  // properly at this point (http://bugs.webkit.org/show_bug.cgi?id=16976) and
460  // it is needed to trigger autofill.
461  weak_ptr_factory_.InvalidateWeakPtrs();
462  base::MessageLoop::current()->PostTask(
463      FROM_HERE,
464      base::Bind(&AutofillAgent::TextFieldDidChangeImpl,
465                 weak_ptr_factory_.GetWeakPtr(),
466                 element));
467}
468
469void AutofillAgent::TextFieldDidChangeImpl(const WebInputElement& element) {
470  // If the element isn't focused then the changes don't matter. This check is
471  // required to properly handle IME interactions.
472  if (!element.focused())
473    return;
474
475  if (password_autofill_agent_->TextDidChangeInTextField(element)) {
476    element_ = element;
477    return;
478  }
479
480  ShowSuggestions(element, false, true, false);
481
482  FormData form;
483  FormFieldData field;
484  if (FindFormAndFieldForInputElement(element, &form, &field, REQUIRE_NONE)) {
485    Send(new AutofillHostMsg_TextFieldDidChange(routing_id(), form, field,
486                                                base::TimeTicks::Now()));
487  }
488}
489
490void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element,
491                                               const WebKeyboardEvent& event) {
492  if (password_autofill_agent_->TextFieldHandlingKeyDown(element, event)) {
493    element_ = element;
494    return;
495  }
496
497  if (event.windowsKeyCode == ui::VKEY_DOWN ||
498      event.windowsKeyCode == ui::VKEY_UP)
499    ShowSuggestions(element, true, true, true);
500}
501
502void AutofillAgent::CombineDataListEntriesAndShow(
503    const WebKit::WebInputElement& element,
504    const std::vector<base::string16>& values,
505    const std::vector<base::string16>& labels,
506    const std::vector<base::string16>& icons,
507    const std::vector<int>& item_ids,
508    bool has_autofill_item) {
509  std::vector<base::string16> v;
510  std::vector<base::string16> l;
511  std::vector<base::string16> i;
512  std::vector<int> ids;
513
514  AppendDataListSuggestions(element, &v, &l, &i, &ids);
515
516  // If there are both <datalist> items and Autofill suggestions, add a
517  // separator between them.
518  if (!v.empty() && !values.empty()) {
519    v.push_back(base::string16());
520    l.push_back(base::string16());
521    i.push_back(base::string16());
522    ids.push_back(WebAutofillClient::MenuItemIDSeparator);
523  }
524
525  // Append the Autofill suggestions.
526  v.insert(v.end(), values.begin(), values.end());
527  l.insert(l.end(), labels.begin(), labels.end());
528  i.insert(i.end(), icons.begin(), icons.end());
529  ids.insert(ids.end(), item_ids.begin(), item_ids.end());
530
531  if (v.empty()) {
532    // No suggestions, any popup currently showing is obsolete.
533    HideAutofillUi();
534    return;
535  }
536
537  WebKit::WebView* web_view = render_view()->GetWebView();
538  if (!web_view)
539    return;
540
541  // Send to WebKit for display.
542  web_view->applyAutofillSuggestions(element, v, l, i, ids);
543
544  Send(new AutofillHostMsg_DidShowAutofillSuggestions(
545      routing_id(),
546      has_autofill_item && !has_shown_autofill_popup_for_current_edit_));
547  has_shown_autofill_popup_for_current_edit_ |= has_autofill_item;
548}
549
550void AutofillAgent::AcceptDataListSuggestion(
551    const base::string16& suggested_value) {
552  base::string16 new_value = suggested_value;
553  // If this element takes multiple values then replace the last part with
554  // the suggestion.
555  if (element_.isMultiple() &&
556      element_.formControlType() == WebString::fromUTF8("email")) {
557    std::vector<base::string16> parts;
558
559    base::SplitStringDontTrim(element_.editingValue(), ',', &parts);
560    if (parts.size() == 0)
561      parts.push_back(base::string16());
562
563    base::string16 last_part = parts.back();
564    // We want to keep just the leading whitespace.
565    for (size_t i = 0; i < last_part.size(); ++i) {
566      if (!IsWhitespace(last_part[i])) {
567        last_part = last_part.substr(0, i);
568        break;
569      }
570    }
571    last_part.append(suggested_value);
572    parts[parts.size() - 1] = last_part;
573
574    new_value = JoinString(parts, ',');
575  }
576  SetNodeText(new_value, &element_);
577}
578
579void AutofillAgent::OnFormDataFilled(int query_id,
580                                     const FormData& form) {
581  if (!render_view()->GetWebView() || query_id != autofill_query_id_)
582    return;
583
584  was_query_node_autofilled_ = element_.isAutofilled();
585
586  switch (autofill_action_) {
587    case AUTOFILL_FILL:
588      FillForm(form, element_);
589      Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id(),
590                                                       base::TimeTicks::Now()));
591      break;
592    case AUTOFILL_PREVIEW:
593      PreviewForm(form, element_);
594      Send(new AutofillHostMsg_DidPreviewAutofillFormData(routing_id()));
595      break;
596    default:
597      NOTREACHED();
598  }
599  autofill_action_ = AUTOFILL_NONE;
600}
601
602void AutofillAgent::OnFieldTypePredictionsAvailable(
603    const std::vector<FormDataPredictions>& forms) {
604  for (size_t i = 0; i < forms.size(); ++i) {
605    form_cache_.ShowPredictions(forms[i]);
606  }
607}
608
609void AutofillAgent::OnSetAutofillActionFill() {
610  autofill_action_ = AUTOFILL_FILL;
611}
612
613void AutofillAgent::OnClearForm() {
614  form_cache_.ClearFormWithElement(element_);
615}
616
617void AutofillAgent::OnSetAutofillActionPreview() {
618  autofill_action_ = AUTOFILL_PREVIEW;
619}
620
621void AutofillAgent::OnClearPreviewedForm() {
622  didClearAutofillSelection(element_);
623}
624
625void AutofillAgent::OnSetNodeText(const base::string16& value) {
626  SetNodeText(value, &element_);
627}
628
629void AutofillAgent::OnAcceptDataListSuggestion(const base::string16& value) {
630  AcceptDataListSuggestion(value);
631}
632
633void AutofillAgent::OnAcceptPasswordAutofillSuggestion(
634    const base::string16& value) {
635  // We need to make sure this is handled here because the browser process
636  // skipped it handling because it believed it would be handled here. If it
637  // isn't handled here then the browser logic needs to be updated.
638  bool handled = password_autofill_agent_->DidAcceptAutofillSuggestion(
639      element_,
640      value);
641  DCHECK(handled);
642}
643
644void AutofillAgent::OnGetAllForms() {
645  form_elements_.clear();
646
647  // Force fetch all non empty forms.
648  std::vector<FormData> forms;
649  form_cache_.ExtractFormsAndFormElements(
650      *topmost_frame_, 0, &forms, &form_elements_);
651
652  // OnGetAllForms should only be called if AutofillAgent reported to
653  // AutofillManager that there are more forms
654  DCHECK(!forms.empty());
655
656  // Report to AutofillManager that all forms are being sent.
657  Send(new AutofillHostMsg_FormsSeen(routing_id(), forms,
658                                     forms_seen_timestamp_,
659                                     NO_SPECIAL_FORMS_SEEN));
660}
661
662void AutofillAgent::OnRequestAutocompleteResult(
663    WebFormElement::AutocompleteResult result, const FormData& form_data) {
664  if (in_flight_request_form_.isNull())
665    return;
666
667  if (result == WebFormElement::AutocompleteResultSuccess) {
668    FillFormIncludingNonFocusableElements(form_data, in_flight_request_form_);
669    if (!in_flight_request_form_.checkValidityWithoutDispatchingEvents())
670      result = WebFormElement::AutocompleteResultErrorInvalid;
671  }
672
673  in_flight_request_form_.finishRequestAutocomplete(result);
674  in_flight_request_form_.reset();
675}
676
677void AutofillAgent::OnFillFormsAndClick(
678    const std::vector<FormData>& forms,
679    const std::vector<WebElementDescriptor>& click_elements_before_form_fill,
680    const std::vector<WebElementDescriptor>& click_elements_after_form_fill,
681    const WebElementDescriptor& click_element_descriptor) {
682  DCHECK_EQ(forms.size(), form_elements_.size());
683
684  // Click elements in click_elements_before_form_fill.
685  for (size_t i = 0; i < click_elements_before_form_fill.size(); ++i) {
686    if (!ClickElement(topmost_frame_->document(),
687                      click_elements_before_form_fill[i])) {
688      Send(new AutofillHostMsg_ClickFailed(routing_id(),
689           MISSING_CLICK_ELEMENT_BEFORE_FORM_FILLING));
690      return;
691    }
692  }
693
694  // Fill the form.
695  for (size_t i = 0; i < forms.size(); ++i)
696    FillFormIncludingNonFocusableElements(forms[i], form_elements_[i]);
697
698  // Click elements in click_elements_after_form_fill.
699  for (size_t i = 0; i < click_elements_after_form_fill.size(); ++i) {
700    if (!ClickElement(topmost_frame_->document(),
701                      click_elements_after_form_fill[i])) {
702      Send(new AutofillHostMsg_ClickFailed(routing_id(),
703           MISSING_CLICK_ELEMENT_AFTER_FORM_FILLING));
704      return;
705    }
706  }
707
708  // Exit early if there is nothing to click.
709  if (click_element_descriptor.retrieval_method == WebElementDescriptor::NONE)
710    return;
711
712  // It's possible that clicking the element to proceed in an Autocheckout
713  // flow will not actually proceed to the next step in the flow, e.g. there
714  // is a new required field that Autocheckout does not know how to fill.  In
715  // order to capture this case and present the user with an error a timer is
716  // set that informs the browser of the error. |click_timer_| has to be started
717  // before clicking so it can start before DidStartProvisionalLoad started.
718  click_timer_.Start(FROM_HERE,
719                     base::TimeDelta::FromSeconds(kAutocheckoutClickTimeout),
720                     this,
721                     &AutofillAgent::ClickFailed);
722  if (!ClickElement(topmost_frame_->document(),
723                    click_element_descriptor)) {
724    click_timer_.Stop();
725    Send(new AutofillHostMsg_ClickFailed(routing_id(),
726                                         MISSING_ADVANCE));
727  }
728}
729
730void AutofillAgent::OnAutocheckoutSupported() {
731  is_autocheckout_supported_ = true;
732  if (has_new_forms_for_browser_)
733    MaybeSendDynamicFormsSeen();
734  MaybeShowAutocheckoutBubble();
735}
736
737void AutofillAgent::ClickFailed() {
738  Send(new AutofillHostMsg_ClickFailed(routing_id(),
739                                       CANNOT_PROCEED));
740}
741
742void AutofillAgent::ShowSuggestions(const WebInputElement& element,
743                                    bool autofill_on_empty_values,
744                                    bool requires_caret_at_end,
745                                    bool display_warning_if_disabled) {
746  if (!element.isEnabled() || element.isReadOnly() || !element.isTextField() ||
747      element.isPasswordField() || !element.suggestedValue().isEmpty())
748    return;
749
750  // Don't attempt to autofill with values that are too large or if filling
751  // criteria are not met.
752  WebString value = element.editingValue();
753  if (value.length() > kMaximumTextSizeForAutofill ||
754      (!autofill_on_empty_values && value.isEmpty()) ||
755      (requires_caret_at_end &&
756       (element.selectionStart() != element.selectionEnd() ||
757        element.selectionEnd() != static_cast<int>(value.length())))) {
758    // Any popup currently showing is obsolete.
759    HideAutofillUi();
760    return;
761  }
762
763  element_ = element;
764  if (password_autofill_agent_->ShowSuggestions(element))
765    return;
766
767  // If autocomplete is disabled at the field level, ensure that the native
768  // UI won't try to show a warning, since that may conflict with a custom
769  // popup. Note that we cannot use the WebKit method element.autoComplete()
770  // as it does not allow us to distinguish the case where autocomplete is
771  // disabled for *both* the element and for the form.
772  const base::string16 autocomplete_attribute =
773      element.getAttribute("autocomplete");
774  if (LowerCaseEqualsASCII(autocomplete_attribute, "off"))
775    display_warning_if_disabled = false;
776
777  QueryAutofillSuggestions(element, display_warning_if_disabled);
778}
779
780void AutofillAgent::QueryAutofillSuggestions(const WebInputElement& element,
781                                             bool display_warning_if_disabled) {
782  if (!element.document().frame())
783    return;
784
785  static int query_counter = 0;
786  autofill_query_id_ = query_counter++;
787  display_warning_if_disabled_ = display_warning_if_disabled;
788
789  // If autocomplete is disabled at the form level, we want to see if there
790  // would have been any suggestions were it enabled, so that we can show a
791  // warning.  Otherwise, we want to ignore fields that disable autocomplete, so
792  // that the suggestions list does not include suggestions for these form
793  // fields -- see comment 1 on http://crbug.com/69914
794  const RequirementsMask requirements =
795      element.autoComplete() ? REQUIRE_AUTOCOMPLETE : REQUIRE_NONE;
796
797  FormData form;
798  FormFieldData field;
799  if (!FindFormAndFieldForInputElement(element, &form, &field, requirements)) {
800    // If we didn't find the cached form, at least let autocomplete have a shot
801    // at providing suggestions.
802    WebFormControlElementToFormField(element, EXTRACT_VALUE, &field);
803  }
804
805  gfx::RectF bounding_box_scaled =
806      GetScaledBoundingBox(web_view_->pageScaleFactor(), &element_);
807
808  // Find the datalist values and send them to the browser process.
809  std::vector<base::string16> data_list_values;
810  std::vector<base::string16> data_list_labels;
811  std::vector<base::string16> data_list_icons;
812  std::vector<int> data_list_unique_ids;
813  AppendDataListSuggestions(element_,
814                            &data_list_values,
815                            &data_list_labels,
816                            &data_list_icons,
817                            &data_list_unique_ids);
818
819  TrimDataListsForIPC(&data_list_values,
820                      &data_list_labels,
821                      &data_list_icons,
822                      &data_list_unique_ids);
823
824  Send(new AutofillHostMsg_SetDataList(routing_id(),
825                                       data_list_values,
826                                       data_list_labels,
827                                       data_list_icons,
828                                       data_list_unique_ids));
829
830  Send(new AutofillHostMsg_QueryFormFieldAutofill(routing_id(),
831                                                  autofill_query_id_,
832                                                  form,
833                                                  field,
834                                                  bounding_box_scaled,
835                                                  display_warning_if_disabled));
836}
837
838void AutofillAgent::FillAutofillFormData(const WebNode& node,
839                                         int unique_id,
840                                         AutofillAction action) {
841  DCHECK_GT(unique_id, 0);
842
843  static int query_counter = 0;
844  autofill_query_id_ = query_counter++;
845
846  FormData form;
847  FormFieldData field;
848  if (!FindFormAndFieldForInputElement(node.toConst<WebInputElement>(), &form,
849                                       &field, REQUIRE_AUTOCOMPLETE)) {
850    return;
851  }
852
853  autofill_action_ = action;
854  Send(new AutofillHostMsg_FillAutofillFormData(
855      routing_id(), autofill_query_id_, form, field, unique_id));
856}
857
858void AutofillAgent::SetNodeText(const base::string16& value,
859                                WebKit::WebInputElement* node) {
860  did_set_node_text_ = true;
861  base::string16 substring = value;
862  substring = substring.substr(0, node->maxLength());
863
864  node->setEditingValue(substring);
865}
866
867void AutofillAgent::HideAutofillUi() {
868  WebKit::WebView* web_view = render_view()->GetWebView();
869  if (web_view)
870    web_view->hidePopups();
871
872  HideHostAutofillUi();
873}
874
875void AutofillAgent::HideHostAutofillUi() {
876  Send(new AutofillHostMsg_HideAutofillUi(routing_id()));
877}
878
879void AutofillAgent::didAssociateFormControls(
880    const WebKit::WebVector<WebKit::WebNode>& nodes) {
881  for (size_t i = 0; i < nodes.size(); ++i) {
882    WebKit::WebNode node = nodes[i];
883    if (node.document().frame() == topmost_frame_) {
884      forms_seen_timestamp_ = base::TimeTicks::Now();
885      has_new_forms_for_browser_ = true;
886      break;
887    }
888  }
889
890  if (has_new_forms_for_browser_ && is_autocheckout_supported_)
891    MaybeSendDynamicFormsSeen();
892}
893
894void AutofillAgent::MaybeSendDynamicFormsSeen() {
895  has_new_forms_for_browser_ = false;
896  form_elements_.clear();
897  std::vector<FormData> forms;
898  // This will only be called for Autocheckout flows, so send all forms to
899  // save an IPC.
900  form_cache_.ExtractFormsAndFormElements(
901      *topmost_frame_, 0, &forms, &form_elements_);
902  autofill::FormsSeenState state = autofill::DYNAMIC_FORMS_SEEN;
903
904  if (!forms.empty()) {
905    if (click_timer_.IsRunning())
906      click_timer_.Stop();
907    Send(new AutofillHostMsg_FormsSeen(routing_id(), forms,
908                                       forms_seen_timestamp_,
909                                       state));
910  }
911}
912
913}  // namespace autofill
914