autofill_external_delegate.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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/core/browser/autofill_external_delegate.h"
6
7#include "base/strings/utf_string_conversions.h"
8#include "components/autofill/core/browser/autocomplete_history_manager.h"
9#include "components/autofill/core/browser/autofill_driver.h"
10#include "components/autofill/core/browser/autofill_manager.h"
11#include "components/autofill/core/common/autofill_messages.h"
12#include "content/public/browser/render_view_host.h"
13#include "content/public/browser/web_contents.h"
14#include "grit/component_strings.h"
15#include "third_party/WebKit/public/web/WebAutofillClient.h"
16#include "ui/base/l10n/l10n_util.h"
17
18using content::RenderViewHost;
19using WebKit::WebAutofillClient;
20
21namespace autofill {
22
23AutofillExternalDelegate::AutofillExternalDelegate(
24    content::WebContents* web_contents,
25    AutofillManager* autofill_manager,
26    AutofillDriver* autofill_driver)
27    : web_contents_(web_contents),
28      autofill_manager_(autofill_manager),
29      autofill_driver_(autofill_driver),
30      password_autofill_manager_(web_contents),
31      autofill_query_id_(0),
32      display_warning_if_disabled_(false),
33      has_autofill_suggestion_(false),
34      has_shown_autofill_popup_for_current_edit_(false),
35      registered_key_press_event_callback_with_(NULL),
36      weak_ptr_factory_(this) {
37  DCHECK(autofill_manager);
38}
39
40AutofillExternalDelegate::~AutofillExternalDelegate() {}
41
42void AutofillExternalDelegate::OnQuery(int query_id,
43                                       const FormData& form,
44                                       const FormFieldData& field,
45                                       const gfx::RectF& element_bounds,
46                                       bool display_warning_if_disabled) {
47  autofill_query_form_ = form;
48  autofill_query_field_ = field;
49  display_warning_if_disabled_ = display_warning_if_disabled;
50  autofill_query_id_ = query_id;
51  element_bounds_ = element_bounds;
52}
53
54void AutofillExternalDelegate::OnSuggestionsReturned(
55    int query_id,
56    const std::vector<base::string16>& autofill_values,
57    const std::vector<base::string16>& autofill_labels,
58    const std::vector<base::string16>& autofill_icons,
59    const std::vector<int>& autofill_unique_ids) {
60  if (query_id != autofill_query_id_)
61    return;
62
63  std::vector<base::string16> values(autofill_values);
64  std::vector<base::string16> labels(autofill_labels);
65  std::vector<base::string16> icons(autofill_icons);
66  std::vector<int> ids(autofill_unique_ids);
67
68  // Add or hide warnings as appropriate.
69  ApplyAutofillWarnings(&values, &labels, &icons, &ids);
70
71  // Add a separator to go between the values and menu items.
72  values.push_back(base::string16());
73  labels.push_back(base::string16());
74  icons.push_back(base::string16());
75  ids.push_back(WebAutofillClient::MenuItemIDSeparator);
76
77  // Only include "Autofill Options" special menu item if we have Autofill
78  // suggestions.
79  has_autofill_suggestion_ = false;
80  for (size_t i = 0; i < ids.size(); ++i) {
81    if (ids[i] > 0) {
82      has_autofill_suggestion_ = true;
83      break;
84    }
85  }
86
87  if (has_autofill_suggestion_)
88    ApplyAutofillOptions(&values, &labels, &icons, &ids);
89
90  // Remove the separator if it is the last element.
91  DCHECK_GT(ids.size(), 0U);
92  if (ids.back() == WebAutofillClient::MenuItemIDSeparator) {
93    values.pop_back();
94    labels.pop_back();
95    icons.pop_back();
96    ids.pop_back();
97  }
98
99  // If anything else is added to modify the values after inserting the data
100  // list, AutofillPopupControllerImpl::UpdateDataListValues will need to be
101  // updated to match.
102  InsertDataListValues(&values, &labels, &icons, &ids);
103
104  if (values.empty()) {
105    // No suggestions, any popup currently showing is obsolete.
106    autofill_manager_->delegate()->HideAutofillPopup();
107    return;
108  }
109
110  // Send to display.
111  if (autofill_query_field_.is_focusable) {
112    autofill_manager_->delegate()->ShowAutofillPopup(
113        element_bounds_,
114        autofill_query_field_.text_direction,
115        values,
116        labels,
117        icons,
118        ids,
119        GetWeakPtr());
120  }
121}
122
123void AutofillExternalDelegate::OnShowPasswordSuggestions(
124    const std::vector<base::string16>& suggestions,
125    const std::vector<base::string16>& realms,
126    const FormFieldData& field,
127    const gfx::RectF& element_bounds) {
128  autofill_query_field_ = field;
129  element_bounds_ = element_bounds;
130
131  if (suggestions.empty()) {
132    autofill_manager_->delegate()->HideAutofillPopup();
133    return;
134  }
135
136  std::vector<base::string16> empty(suggestions.size());
137  std::vector<int> password_ids(suggestions.size(),
138                                WebAutofillClient::MenuItemIDPasswordEntry);
139  autofill_manager_->delegate()->ShowAutofillPopup(
140      element_bounds_,
141      autofill_query_field_.text_direction,
142      suggestions,
143      realms,
144      empty,
145      password_ids,
146      GetWeakPtr());
147}
148
149void AutofillExternalDelegate::SetCurrentDataListValues(
150    const std::vector<base::string16>& data_list_values,
151    const std::vector<base::string16>& data_list_labels) {
152  data_list_values_ = data_list_values;
153  data_list_labels_ = data_list_labels;
154
155  autofill_manager_->delegate()->UpdateAutofillPopupDataListValues(
156      data_list_values,
157      data_list_labels);
158}
159
160void AutofillExternalDelegate::OnPopupShown(
161    content::RenderWidgetHost::KeyPressEventCallback* callback) {
162  if (callback && !registered_key_press_event_callback_with_) {
163    registered_key_press_event_callback_with_ =
164        web_contents_->GetRenderViewHost();
165    registered_key_press_event_callback_with_->AddKeyPressEventCallback(
166        *callback);
167  }
168
169  autofill_manager_->OnDidShowAutofillSuggestions(
170      has_autofill_suggestion_ && !has_shown_autofill_popup_for_current_edit_);
171  has_shown_autofill_popup_for_current_edit_ |= has_autofill_suggestion_;
172}
173
174void AutofillExternalDelegate::OnPopupHidden(
175    content::RenderWidgetHost::KeyPressEventCallback* callback) {
176  if (callback && (!web_contents_->IsBeingDestroyed()) &&
177      (registered_key_press_event_callback_with_ ==
178          web_contents_->GetRenderViewHost())) {
179    web_contents_->GetRenderViewHost()->RemoveKeyPressEventCallback(*callback);
180  }
181
182  registered_key_press_event_callback_with_ = NULL;
183}
184
185bool AutofillExternalDelegate::ShouldRepostEvent(const ui::MouseEvent& event) {
186  NOTREACHED();
187  return true;
188}
189
190void AutofillExternalDelegate::DidSelectSuggestion(int identifier) {
191  ClearPreviewedForm();
192
193  // Only preview the data if it is a profile.
194  if (identifier > 0)
195    FillAutofillFormData(identifier, true);
196}
197
198void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
199                                                   int identifier) {
200  RenderViewHost* host = web_contents_->GetRenderViewHost();
201
202  if (identifier == WebAutofillClient::MenuItemIDAutofillOptions) {
203    // User selected 'Autofill Options'.
204    autofill_manager_->OnShowAutofillDialog();
205  } else if (identifier == WebAutofillClient::MenuItemIDClearForm) {
206    // User selected 'Clear form'.
207    autofill_driver_->RendererShouldClearFilledForm();
208  } else if (identifier == WebAutofillClient::MenuItemIDPasswordEntry) {
209    bool success = password_autofill_manager_.DidAcceptAutofillSuggestion(
210        autofill_query_field_, value);
211    DCHECK(success);
212  } else if (identifier == WebAutofillClient::MenuItemIDDataListEntry) {
213    host->Send(new AutofillMsg_AcceptDataListSuggestion(host->GetRoutingID(),
214                                                        value));
215  } else if (identifier == WebAutofillClient::MenuItemIDAutocompleteEntry) {
216    // User selected an Autocomplete, so we fill directly.
217    host->Send(new AutofillMsg_SetNodeText(host->GetRoutingID(), value));
218  } else {
219    FillAutofillFormData(identifier, false);
220  }
221
222  autofill_manager_->delegate()->HideAutofillPopup();
223}
224
225void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value,
226                                                int identifier) {
227  if (identifier > 0) {
228    autofill_manager_->RemoveAutofillProfileOrCreditCard(identifier);
229  } else {
230    autofill_manager_->RemoveAutocompleteEntry(autofill_query_field_.name,
231                                               value);
232  }
233}
234
235void AutofillExternalDelegate::DidEndTextFieldEditing() {
236  autofill_manager_->delegate()->HideAutofillPopup();
237
238  has_shown_autofill_popup_for_current_edit_ = false;
239}
240
241void AutofillExternalDelegate::ClearPreviewedForm() {
242  autofill_driver_->RendererShouldClearPreviewedForm();
243}
244
245void AutofillExternalDelegate::Reset() {
246  autofill_manager_->delegate()->HideAutofillPopup();
247
248  password_autofill_manager_.Reset();
249}
250
251void AutofillExternalDelegate::AddPasswordFormMapping(
252      const FormFieldData& form,
253      const PasswordFormFillData& fill_data) {
254  password_autofill_manager_.AddPasswordFormMapping(form, fill_data);
255}
256
257base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() {
258  return weak_ptr_factory_.GetWeakPtr();
259}
260
261void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
262                                                    bool is_preview) {
263  // If the selected element is a warning we don't want to do anything.
264  if (unique_id == WebAutofillClient::MenuItemIDWarningMessage)
265    return;
266
267  AutofillDriver::RendererFormDataAction renderer_action = is_preview ?
268      AutofillDriver::FORM_DATA_ACTION_PREVIEW :
269      AutofillDriver::FORM_DATA_ACTION_FILL;
270
271  DCHECK(autofill_driver_->RendererIsAvailable());
272  autofill_driver_->SetRendererActionOnFormDataReception(renderer_action);
273  // Fill the values for the whole form.
274  autofill_manager_->OnFillAutofillFormData(autofill_query_id_,
275                                            autofill_query_form_,
276                                            autofill_query_field_,
277                                            unique_id);
278}
279
280void AutofillExternalDelegate::ApplyAutofillWarnings(
281    std::vector<base::string16>* autofill_values,
282    std::vector<base::string16>* autofill_labels,
283    std::vector<base::string16>* autofill_icons,
284    std::vector<int>* autofill_unique_ids) {
285  if (!autofill_query_field_.should_autocomplete) {
286    // Autofill is disabled.  If there were some profile or credit card
287    // suggestions to show, show a warning instead.  Otherwise, clear out the
288    // list of suggestions.
289    if (!autofill_unique_ids->empty() && (*autofill_unique_ids)[0] > 0) {
290      // If autofill is disabled and we had suggestions, show a warning instead.
291      autofill_values->assign(
292          1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED));
293      autofill_labels->assign(1, base::string16());
294      autofill_icons->assign(1, base::string16());
295      autofill_unique_ids->assign(1,
296                                  WebAutofillClient::MenuItemIDWarningMessage);
297    } else {
298      autofill_values->clear();
299      autofill_labels->clear();
300      autofill_icons->clear();
301      autofill_unique_ids->clear();
302    }
303  } else if (autofill_unique_ids->size() > 1 &&
304             (*autofill_unique_ids)[0] ==
305                 WebAutofillClient::MenuItemIDWarningMessage) {
306    // If we received a warning instead of suggestions from autofill but regular
307    // suggestions from autocomplete, don't show the autofill warning.
308    autofill_values->erase(autofill_values->begin());
309    autofill_labels->erase(autofill_labels->begin());
310    autofill_icons->erase(autofill_icons->begin());
311    autofill_unique_ids->erase(autofill_unique_ids->begin());
312  }
313
314  // If we were about to show a warning and we shouldn't, don't.
315  if (!autofill_unique_ids->empty() &&
316      (*autofill_unique_ids)[0] ==
317          WebAutofillClient::MenuItemIDWarningMessage &&
318      !display_warning_if_disabled_) {
319    autofill_values->clear();
320    autofill_labels->clear();
321    autofill_icons->clear();
322    autofill_unique_ids->clear();
323  }
324}
325
326void AutofillExternalDelegate::ApplyAutofillOptions(
327    std::vector<base::string16>* autofill_values,
328    std::vector<base::string16>* autofill_labels,
329    std::vector<base::string16>* autofill_icons,
330    std::vector<int>* autofill_unique_ids) {
331  // The form has been auto-filled, so give the user the chance to clear the
332  // form.  Append the 'Clear form' menu item.
333  if (autofill_query_field_.is_autofilled) {
334    autofill_values->push_back(
335        l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM));
336    autofill_labels->push_back(base::string16());
337    autofill_icons->push_back(base::string16());
338    autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDClearForm);
339  }
340
341  // Append the 'Chrome Autofill options' menu item;
342  autofill_values->push_back(
343      l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP));
344  autofill_labels->push_back(base::string16());
345  autofill_icons->push_back(base::string16());
346  autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDAutofillOptions);
347}
348
349void AutofillExternalDelegate::InsertDataListValues(
350    std::vector<base::string16>* autofill_values,
351    std::vector<base::string16>* autofill_labels,
352    std::vector<base::string16>* autofill_icons,
353    std::vector<int>* autofill_unique_ids) {
354  if (data_list_values_.empty())
355    return;
356
357  // Insert the separator between the datalist and Autofill values (if there
358  // are any).
359  if (!autofill_values->empty()) {
360    autofill_values->insert(autofill_values->begin(), base::string16());
361    autofill_labels->insert(autofill_labels->begin(), base::string16());
362    autofill_icons->insert(autofill_icons->begin(), base::string16());
363    autofill_unique_ids->insert(autofill_unique_ids->begin(),
364                                WebAutofillClient::MenuItemIDSeparator);
365  }
366
367  // Insert the datalist elements.
368  autofill_values->insert(autofill_values->begin(),
369                          data_list_values_.begin(),
370                          data_list_values_.end());
371  autofill_labels->insert(autofill_labels->begin(),
372                          data_list_labels_.begin(),
373                          data_list_labels_.end());
374
375  // Set the values that all datalist elements share.
376  autofill_icons->insert(autofill_icons->begin(),
377                         data_list_values_.size(),
378                         base::string16());
379  autofill_unique_ids->insert(autofill_unique_ids->begin(),
380                              data_list_values_.size(),
381                              WebAutofillClient::MenuItemIDDataListEntry);
382}
383
384}  // namespace autofill
385