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