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