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/common/autofill_messages.h" 15 #include "components/autofill/content/renderer/form_autofill_util.h" 16 #include "components/autofill/content/renderer/page_click_tracker.h" 17 #include "components/autofill/content/renderer/password_autofill_agent.h" 18 #include "components/autofill/content/renderer/password_generation_agent.h" 19 #include "components/autofill/core/common/autofill_constants.h" 20 #include "components/autofill/core/common/autofill_data_validation.h" 21 #include "components/autofill/core/common/autofill_switches.h" 22 #include "components/autofill/core/common/form_data.h" 23 #include "components/autofill/core/common/form_data_predictions.h" 24 #include "components/autofill/core/common/form_field_data.h" 25 #include "components/autofill/core/common/password_form.h" 26 #include "components/autofill/core/common/web_element_descriptor.h" 27 #include "content/public/common/content_switches.h" 28 #include "content/public/common/ssl_status.h" 29 #include "content/public/common/url_constants.h" 30 #include "content/public/renderer/render_view.h" 31 #include "grit/components_strings.h" 32 #include "net/cert/cert_status_flags.h" 33 #include "third_party/WebKit/public/platform/WebRect.h" 34 #include "third_party/WebKit/public/platform/WebURLRequest.h" 35 #include "third_party/WebKit/public/web/WebConsoleMessage.h" 36 #include "third_party/WebKit/public/web/WebDataSource.h" 37 #include "third_party/WebKit/public/web/WebDocument.h" 38 #include "third_party/WebKit/public/web/WebElementCollection.h" 39 #include "third_party/WebKit/public/web/WebFormControlElement.h" 40 #include "third_party/WebKit/public/web/WebFormElement.h" 41 #include "third_party/WebKit/public/web/WebInputEvent.h" 42 #include "third_party/WebKit/public/web/WebLocalFrame.h" 43 #include "third_party/WebKit/public/web/WebNode.h" 44 #include "third_party/WebKit/public/web/WebOptionElement.h" 45 #include "third_party/WebKit/public/web/WebTextAreaElement.h" 46 #include "third_party/WebKit/public/web/WebView.h" 47 #include "ui/base/l10n/l10n_util.h" 48 #include "ui/events/keycodes/keyboard_codes.h" 49 50 using blink::WebAutofillClient; 51 using blink::WebConsoleMessage; 52 using blink::WebElement; 53 using blink::WebElementCollection; 54 using blink::WebFormControlElement; 55 using blink::WebFormElement; 56 using blink::WebFrame; 57 using blink::WebInputElement; 58 using blink::WebKeyboardEvent; 59 using blink::WebLocalFrame; 60 using blink::WebNode; 61 using blink::WebOptionElement; 62 using blink::WebString; 63 using blink::WebTextAreaElement; 64 using blink::WebVector; 65 66 namespace autofill { 67 68 namespace { 69 70 // Gets all the data list values (with corresponding label) for the given 71 // element. 72 void GetDataListSuggestions(const WebInputElement& element, 73 bool ignore_current_value, 74 std::vector<base::string16>* values, 75 std::vector<base::string16>* labels) { 76 WebElementCollection options = element.dataListOptions(); 77 if (options.isNull()) 78 return; 79 80 base::string16 prefix; 81 if (!ignore_current_value) { 82 prefix = element.editingValue(); 83 if (element.isMultiple() && 84 element.formControlType() == WebString::fromUTF8("email")) { 85 std::vector<base::string16> parts; 86 base::SplitStringDontTrim(prefix, ',', &parts); 87 if (parts.size() > 0) { 88 base::TrimWhitespace(parts[parts.size() - 1], base::TRIM_LEADING, 89 &prefix); 90 } 91 } 92 } 93 for (WebOptionElement option = options.firstItem().to<WebOptionElement>(); 94 !option.isNull(); option = options.nextItem().to<WebOptionElement>()) { 95 if (!StartsWith(option.value(), prefix, false) || 96 option.value() == prefix || 97 !element.isValidValue(option.value())) 98 continue; 99 100 values->push_back(option.value()); 101 if (option.value() != option.label()) 102 labels->push_back(option.label()); 103 else 104 labels->push_back(base::string16()); 105 } 106 } 107 108 // Trim the vector before sending it to the browser process to ensure we 109 // don't send too much data through the IPC. 110 void TrimStringVectorForIPC(std::vector<base::string16>* strings) { 111 // Limit the size of the vector. 112 if (strings->size() > kMaxListSize) 113 strings->resize(kMaxListSize); 114 115 // Limit the size of the strings in the vector. 116 for (size_t i = 0; i < strings->size(); ++i) { 117 if ((*strings)[i].length() > kMaxDataLength) 118 (*strings)[i].resize(kMaxDataLength); 119 } 120 } 121 122 } // namespace 123 124 AutofillAgent::AutofillAgent(content::RenderView* render_view, 125 PasswordAutofillAgent* password_autofill_agent, 126 PasswordGenerationAgent* password_generation_agent) 127 : content::RenderViewObserver(render_view), 128 password_autofill_agent_(password_autofill_agent), 129 password_generation_agent_(password_generation_agent), 130 autofill_query_id_(0), 131 web_view_(render_view->GetWebView()), 132 display_warning_if_disabled_(false), 133 was_query_node_autofilled_(false), 134 has_shown_autofill_popup_for_current_edit_(false), 135 did_set_node_text_(false), 136 has_new_forms_for_browser_(false), 137 ignore_text_changes_(false), 138 is_popup_possibly_visible_(false), 139 main_frame_processed_(false), 140 weak_ptr_factory_(this) { 141 render_view->GetWebView()->setAutofillClient(this); 142 143 // The PageClickTracker is a RenderViewObserver, and hence will be freed when 144 // the RenderView is destroyed. 145 new PageClickTracker(render_view, this); 146 } 147 148 AutofillAgent::~AutofillAgent() {} 149 150 bool AutofillAgent::OnMessageReceived(const IPC::Message& message) { 151 bool handled = true; 152 IPC_BEGIN_MESSAGE_MAP(AutofillAgent, message) 153 IPC_MESSAGE_HANDLER(AutofillMsg_Ping, OnPing) 154 IPC_MESSAGE_HANDLER(AutofillMsg_FillForm, OnFillForm) 155 IPC_MESSAGE_HANDLER(AutofillMsg_PreviewForm, OnPreviewForm) 156 IPC_MESSAGE_HANDLER(AutofillMsg_FieldTypePredictionsAvailable, 157 OnFieldTypePredictionsAvailable) 158 IPC_MESSAGE_HANDLER(AutofillMsg_ClearForm, OnClearForm) 159 IPC_MESSAGE_HANDLER(AutofillMsg_ClearPreviewedForm, OnClearPreviewedForm) 160 IPC_MESSAGE_HANDLER(AutofillMsg_FillFieldWithValue, OnFillFieldWithValue) 161 IPC_MESSAGE_HANDLER(AutofillMsg_PreviewFieldWithValue, 162 OnPreviewFieldWithValue) 163 IPC_MESSAGE_HANDLER(AutofillMsg_AcceptDataListSuggestion, 164 OnAcceptDataListSuggestion) 165 IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordSuggestion, 166 OnFillPasswordSuggestion) 167 IPC_MESSAGE_HANDLER(AutofillMsg_PreviewPasswordSuggestion, 168 OnPreviewPasswordSuggestion) 169 IPC_MESSAGE_HANDLER(AutofillMsg_RequestAutocompleteResult, 170 OnRequestAutocompleteResult) 171 IPC_MESSAGE_UNHANDLED(handled = false) 172 IPC_END_MESSAGE_MAP() 173 return handled; 174 } 175 176 void AutofillAgent::DidFinishDocumentLoad(WebLocalFrame* frame) { 177 // If the main frame just finished loading, we should process it. 178 if (!frame->parent()) 179 main_frame_processed_ = false; 180 181 ProcessForms(*frame); 182 } 183 184 void AutofillAgent::DidCommitProvisionalLoad(WebLocalFrame* frame, 185 bool is_new_navigation) { 186 form_cache_.ResetFrame(*frame); 187 } 188 189 void AutofillAgent::FrameDetached(WebFrame* frame) { 190 form_cache_.ResetFrame(*frame); 191 } 192 193 void AutofillAgent::FrameWillClose(WebFrame* frame) { 194 if (in_flight_request_form_.isNull()) 195 return; 196 197 for (WebFrame* temp = in_flight_request_form_.document().frame(); 198 temp; temp = temp->parent()) { 199 if (temp == frame) { 200 Send(new AutofillHostMsg_CancelRequestAutocomplete(routing_id())); 201 break; 202 } 203 } 204 } 205 206 void AutofillAgent::WillSubmitForm(WebLocalFrame* frame, 207 const WebFormElement& form) { 208 FormData form_data; 209 if (WebFormElementToFormData(form, 210 WebFormControlElement(), 211 REQUIRE_AUTOCOMPLETE, 212 static_cast<ExtractMask>( 213 EXTRACT_VALUE | EXTRACT_OPTION_TEXT), 214 &form_data, 215 NULL)) { 216 Send(new AutofillHostMsg_FormSubmitted(routing_id(), form_data, 217 base::TimeTicks::Now())); 218 } 219 } 220 221 void AutofillAgent::ZoomLevelChanged() { 222 // Any time the zoom level changes, the page's content moves, so any Autofill 223 // popups should be hidden. This is only needed for the new Autofill UI 224 // because WebKit already knows to hide the old UI when this occurs. 225 HidePopup(); 226 } 227 228 void AutofillAgent::FocusedNodeChanged(const WebNode& node) { 229 if (password_generation_agent_ && 230 password_generation_agent_->FocusedNodeHasChanged(node)) { 231 is_popup_possibly_visible_ = true; 232 return; 233 } 234 235 if (node.isNull() || !node.isElementNode()) 236 return; 237 238 WebElement web_element = node.toConst<WebElement>(); 239 240 if (!web_element.document().frame()) 241 return; 242 243 const WebInputElement* element = toWebInputElement(&web_element); 244 245 if (!element || !element->isEnabled() || element->isReadOnly() || 246 !element->isTextField() || element->isPasswordField()) 247 return; 248 249 element_ = *element; 250 } 251 252 void AutofillAgent::OrientationChangeEvent() { 253 HidePopup(); 254 } 255 256 void AutofillAgent::DidChangeScrollOffset(WebLocalFrame*) { 257 HidePopup(); 258 } 259 260 void AutofillAgent::didRequestAutocomplete( 261 const WebFormElement& form, 262 const blink::WebAutocompleteParams& details) { 263 didRequestAutocomplete(form); 264 } 265 266 void AutofillAgent::didRequestAutocomplete( 267 const WebFormElement& form) { 268 // Disallow the dialog over non-https or broken https, except when the 269 // ignore SSL flag is passed. See http://crbug.com/272512. 270 // TODO(palmer): this should be moved to the browser process after frames 271 // get their own processes. 272 GURL url(form.document().url()); 273 content::SSLStatus ssl_status = 274 render_view()->GetSSLStatusOfFrame(form.document().frame()); 275 bool is_safe = url.SchemeIs(url::kHttpsScheme) && 276 !net::IsCertStatusError(ssl_status.cert_status); 277 bool allow_unsafe = CommandLine::ForCurrentProcess()->HasSwitch( 278 ::switches::kReduceSecurityForTesting); 279 280 FormData form_data; 281 std::string error_message; 282 if (!in_flight_request_form_.isNull()) { 283 error_message = "already active."; 284 } else if (!is_safe && !allow_unsafe) { 285 error_message = 286 "must use a secure connection or --reduce-security-for-testing."; 287 } else if (!WebFormElementToFormData(form, 288 WebFormControlElement(), 289 REQUIRE_AUTOCOMPLETE, 290 EXTRACT_OPTIONS, 291 &form_data, 292 NULL)) { 293 error_message = "failed to parse form."; 294 } 295 296 if (!error_message.empty()) { 297 WebConsoleMessage console_message = WebConsoleMessage( 298 WebConsoleMessage::LevelLog, 299 WebString(base::ASCIIToUTF16("requestAutocomplete: ") + 300 base::ASCIIToUTF16(error_message))); 301 form.document().frame()->addMessageToConsole(console_message); 302 WebFormElement(form).finishRequestAutocomplete( 303 WebFormElement::AutocompleteResultErrorDisabled); 304 return; 305 } 306 307 // Cancel any pending Autofill requests and hide any currently showing popups. 308 ++autofill_query_id_; 309 HidePopup(); 310 311 in_flight_request_form_ = form; 312 Send(new AutofillHostMsg_RequestAutocomplete(routing_id(), form_data, url)); 313 } 314 315 void AutofillAgent::setIgnoreTextChanges(bool ignore) { 316 ignore_text_changes_ = ignore; 317 } 318 319 void AutofillAgent::FormControlElementClicked( 320 const WebFormControlElement& element, 321 bool was_focused) { 322 const WebInputElement* input_element = toWebInputElement(&element); 323 if (!input_element && !IsTextAreaElement(element)) 324 return; 325 326 if (was_focused) 327 ShowSuggestions(element, true, false, true, false); 328 } 329 330 void AutofillAgent::FormControlElementLostFocus() { 331 HidePopup(); 332 } 333 334 void AutofillAgent::textFieldDidEndEditing(const WebInputElement& element) { 335 password_autofill_agent_->TextFieldDidEndEditing(element); 336 has_shown_autofill_popup_for_current_edit_ = false; 337 Send(new AutofillHostMsg_DidEndTextFieldEditing(routing_id())); 338 } 339 340 void AutofillAgent::textFieldDidChange(const WebFormControlElement& element) { 341 if (ignore_text_changes_) 342 return; 343 344 DCHECK(toWebInputElement(&element) || IsTextAreaElement(element)); 345 346 if (did_set_node_text_) { 347 did_set_node_text_ = false; 348 return; 349 } 350 351 // We post a task for doing the Autofill as the caret position is not set 352 // properly at this point (http://bugs.webkit.org/show_bug.cgi?id=16976) and 353 // it is needed to trigger autofill. 354 weak_ptr_factory_.InvalidateWeakPtrs(); 355 base::MessageLoop::current()->PostTask( 356 FROM_HERE, 357 base::Bind(&AutofillAgent::TextFieldDidChangeImpl, 358 weak_ptr_factory_.GetWeakPtr(), 359 element)); 360 } 361 362 void AutofillAgent::TextFieldDidChangeImpl( 363 const WebFormControlElement& element) { 364 // If the element isn't focused then the changes don't matter. This check is 365 // required to properly handle IME interactions. 366 if (!element.focused()) 367 return; 368 369 const WebInputElement* input_element = toWebInputElement(&element); 370 if (input_element) { 371 if (password_generation_agent_ && 372 password_generation_agent_->TextDidChangeInTextField(*input_element)) { 373 is_popup_possibly_visible_ = true; 374 return; 375 } 376 377 if (password_autofill_agent_->TextDidChangeInTextField(*input_element)) { 378 element_ = element; 379 return; 380 } 381 } 382 383 ShowSuggestions(element, false, true, false, false); 384 385 FormData form; 386 FormFieldData field; 387 if (FindFormAndFieldForFormControlElement(element, 388 &form, 389 &field, 390 REQUIRE_NONE)) { 391 Send(new AutofillHostMsg_TextFieldDidChange(routing_id(), form, field, 392 base::TimeTicks::Now())); 393 } 394 } 395 396 void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element, 397 const WebKeyboardEvent& event) { 398 if (password_autofill_agent_->TextFieldHandlingKeyDown(element, event)) { 399 element_ = element; 400 return; 401 } 402 403 if (event.windowsKeyCode == ui::VKEY_DOWN || 404 event.windowsKeyCode == ui::VKEY_UP) 405 ShowSuggestions(element, true, true, true, false); 406 } 407 408 void AutofillAgent::openTextDataListChooser(const WebInputElement& element) { 409 ShowSuggestions(element, true, false, false, true); 410 } 411 412 void AutofillAgent::firstUserGestureObserved() { 413 password_autofill_agent_->FirstUserGestureObserved(); 414 } 415 416 void AutofillAgent::AcceptDataListSuggestion( 417 const base::string16& suggested_value) { 418 WebInputElement* input_element = toWebInputElement(&element_); 419 DCHECK(input_element); 420 base::string16 new_value = suggested_value; 421 // If this element takes multiple values then replace the last part with 422 // the suggestion. 423 if (input_element->isMultiple() && 424 input_element->formControlType() == WebString::fromUTF8("email")) { 425 std::vector<base::string16> parts; 426 427 base::SplitStringDontTrim(input_element->editingValue(), ',', &parts); 428 if (parts.size() == 0) 429 parts.push_back(base::string16()); 430 431 base::string16 last_part = parts.back(); 432 // We want to keep just the leading whitespace. 433 for (size_t i = 0; i < last_part.size(); ++i) { 434 if (!IsWhitespace(last_part[i])) { 435 last_part = last_part.substr(0, i); 436 break; 437 } 438 } 439 last_part.append(suggested_value); 440 parts[parts.size() - 1] = last_part; 441 442 new_value = JoinString(parts, ','); 443 } 444 FillFieldWithValue(new_value, input_element); 445 } 446 447 void AutofillAgent::OnFieldTypePredictionsAvailable( 448 const std::vector<FormDataPredictions>& forms) { 449 for (size_t i = 0; i < forms.size(); ++i) { 450 form_cache_.ShowPredictions(forms[i]); 451 } 452 } 453 454 void AutofillAgent::OnFillForm(int query_id, const FormData& form) { 455 if (!render_view()->GetWebView() || query_id != autofill_query_id_) 456 return; 457 458 was_query_node_autofilled_ = element_.isAutofilled(); 459 FillForm(form, element_); 460 Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id(), 461 base::TimeTicks::Now())); 462 } 463 464 void AutofillAgent::OnPing() { 465 Send(new AutofillHostMsg_PingAck(routing_id())); 466 } 467 468 void AutofillAgent::OnPreviewForm(int query_id, const FormData& form) { 469 if (!render_view()->GetWebView() || query_id != autofill_query_id_) 470 return; 471 472 was_query_node_autofilled_ = element_.isAutofilled(); 473 PreviewForm(form, element_); 474 Send(new AutofillHostMsg_DidPreviewAutofillFormData(routing_id())); 475 } 476 477 void AutofillAgent::OnClearForm() { 478 form_cache_.ClearFormWithElement(element_); 479 } 480 481 void AutofillAgent::OnClearPreviewedForm() { 482 if (!element_.isNull()) { 483 if (password_autofill_agent_->DidClearAutofillSelection(element_)) 484 return; 485 486 ClearPreviewedFormWithElement(element_, was_query_node_autofilled_); 487 } else { 488 // TODO(isherman): There seem to be rare cases where this code *is* 489 // reachable: see [ http://crbug.com/96321#c6 ]. Ideally we would 490 // understand those cases and fix the code to avoid them. However, so far I 491 // have been unable to reproduce such a case locally. If you hit this 492 // NOTREACHED(), please file a bug against me. 493 NOTREACHED(); 494 } 495 } 496 497 void AutofillAgent::OnFillFieldWithValue(const base::string16& value) { 498 WebInputElement* input_element = toWebInputElement(&element_); 499 if (input_element) 500 FillFieldWithValue(value, input_element); 501 } 502 503 void AutofillAgent::OnPreviewFieldWithValue(const base::string16& value) { 504 WebInputElement* input_element = toWebInputElement(&element_); 505 if (input_element) 506 PreviewFieldWithValue(value, input_element); 507 } 508 509 void AutofillAgent::OnAcceptDataListSuggestion(const base::string16& value) { 510 AcceptDataListSuggestion(value); 511 } 512 513 void AutofillAgent::OnFillPasswordSuggestion(const base::string16& username, 514 const base::string16& password) { 515 bool handled = password_autofill_agent_->FillSuggestion( 516 element_, 517 username, 518 password); 519 DCHECK(handled); 520 } 521 522 void AutofillAgent::OnPreviewPasswordSuggestion( 523 const base::string16& username, 524 const base::string16& password) { 525 bool handled = password_autofill_agent_->PreviewSuggestion( 526 element_, 527 username, 528 password); 529 DCHECK(handled); 530 } 531 532 void AutofillAgent::OnRequestAutocompleteResult( 533 WebFormElement::AutocompleteResult result, 534 const base::string16& message, 535 const FormData& form_data) { 536 if (in_flight_request_form_.isNull()) 537 return; 538 539 if (result == WebFormElement::AutocompleteResultSuccess) { 540 FillFormIncludingNonFocusableElements(form_data, in_flight_request_form_); 541 if (!in_flight_request_form_.checkValidity()) 542 result = WebFormElement::AutocompleteResultErrorInvalid; 543 } 544 545 in_flight_request_form_.finishRequestAutocomplete(result); 546 547 if (!message.empty()) { 548 const base::string16 prefix(base::ASCIIToUTF16("requestAutocomplete: ")); 549 WebConsoleMessage console_message = WebConsoleMessage( 550 WebConsoleMessage::LevelLog, WebString(prefix + message)); 551 in_flight_request_form_.document().frame()->addMessageToConsole( 552 console_message); 553 } 554 555 in_flight_request_form_.reset(); 556 } 557 558 void AutofillAgent::ShowSuggestions(const WebFormControlElement& element, 559 bool autofill_on_empty_values, 560 bool requires_caret_at_end, 561 bool display_warning_if_disabled, 562 bool datalist_only) { 563 if (!element.isEnabled() || element.isReadOnly()) 564 return; 565 566 const WebInputElement* input_element = toWebInputElement(&element); 567 if (input_element) { 568 if (!input_element->isTextField() || input_element->isPasswordField()) 569 return; 570 if (!datalist_only && !input_element->suggestedValue().isEmpty()) 571 return; 572 } else { 573 DCHECK(IsTextAreaElement(element)); 574 if (!element.toConst<WebTextAreaElement>().suggestedValue().isEmpty()) 575 return; 576 } 577 578 // Don't attempt to autofill with values that are too large or if filling 579 // criteria are not met. 580 WebString value = element.editingValue(); 581 if (!datalist_only && 582 (value.length() > kMaxDataLength || 583 (!autofill_on_empty_values && value.isEmpty()) || 584 (requires_caret_at_end && 585 (element.selectionStart() != element.selectionEnd() || 586 element.selectionEnd() != static_cast<int>(value.length()))))) { 587 // Any popup currently showing is obsolete. 588 HidePopup(); 589 return; 590 } 591 592 element_ = element; 593 if (input_element && 594 password_autofill_agent_->ShowSuggestions(*input_element)) { 595 is_popup_possibly_visible_ = true; 596 return; 597 } 598 599 // If autocomplete is disabled at the field level, ensure that the native 600 // UI won't try to show a warning, since that may conflict with a custom 601 // popup. Note that we cannot use the WebKit method element.autoComplete() 602 // as it does not allow us to distinguish the case where autocomplete is 603 // disabled for *both* the element and for the form. 604 const base::string16 autocomplete_attribute = 605 element.getAttribute("autocomplete"); 606 if (LowerCaseEqualsASCII(autocomplete_attribute, "off")) 607 display_warning_if_disabled = false; 608 609 QueryAutofillSuggestions(element, 610 display_warning_if_disabled, 611 datalist_only); 612 } 613 614 void AutofillAgent::QueryAutofillSuggestions( 615 const WebFormControlElement& element, 616 bool display_warning_if_disabled, 617 bool datalist_only) { 618 if (!element.document().frame()) 619 return; 620 621 DCHECK(toWebInputElement(&element) || IsTextAreaElement(element)); 622 623 static int query_counter = 0; 624 autofill_query_id_ = query_counter++; 625 display_warning_if_disabled_ = display_warning_if_disabled; 626 627 // If autocomplete is disabled at the form level, we want to see if there 628 // would have been any suggestions were it enabled, so that we can show a 629 // warning. Otherwise, we want to ignore fields that disable autocomplete, so 630 // that the suggestions list does not include suggestions for these form 631 // fields -- see comment 1 on http://crbug.com/69914 632 const RequirementsMask requirements = 633 element.autoComplete() ? REQUIRE_AUTOCOMPLETE : REQUIRE_NONE; 634 635 FormData form; 636 FormFieldData field; 637 if (!FindFormAndFieldForFormControlElement(element, &form, &field, 638 requirements)) { 639 // If we didn't find the cached form, at least let autocomplete have a shot 640 // at providing suggestions. 641 WebFormControlElementToFormField(element, EXTRACT_VALUE, &field); 642 } 643 if (datalist_only) 644 field.should_autocomplete = false; 645 646 gfx::RectF bounding_box_scaled = 647 GetScaledBoundingBox(web_view_->pageScaleFactor(), &element_); 648 649 std::vector<base::string16> data_list_values; 650 std::vector<base::string16> data_list_labels; 651 const WebInputElement* input_element = toWebInputElement(&element); 652 if (input_element) { 653 // Find the datalist values and send them to the browser process. 654 GetDataListSuggestions(*input_element, 655 datalist_only, 656 &data_list_values, 657 &data_list_labels); 658 TrimStringVectorForIPC(&data_list_values); 659 TrimStringVectorForIPC(&data_list_labels); 660 } 661 662 is_popup_possibly_visible_ = true; 663 Send(new AutofillHostMsg_SetDataList(routing_id(), 664 data_list_values, 665 data_list_labels)); 666 667 Send(new AutofillHostMsg_QueryFormFieldAutofill(routing_id(), 668 autofill_query_id_, 669 form, 670 field, 671 bounding_box_scaled, 672 display_warning_if_disabled)); 673 } 674 675 void AutofillAgent::FillFieldWithValue(const base::string16& value, 676 WebInputElement* node) { 677 did_set_node_text_ = true; 678 node->setEditingValue(value.substr(0, node->maxLength())); 679 node->setAutofilled(true); 680 } 681 682 void AutofillAgent::PreviewFieldWithValue(const base::string16& value, 683 WebInputElement* node) { 684 was_query_node_autofilled_ = element_.isAutofilled(); 685 node->setSuggestedValue(value.substr(0, node->maxLength())); 686 node->setAutofilled(true); 687 node->setSelectionRange(node->value().length(), 688 node->suggestedValue().length()); 689 } 690 691 void AutofillAgent::ProcessForms(const WebLocalFrame& frame) { 692 // Record timestamp of when the forms are first seen. This is used to 693 // measure the overhead of the Autofill feature. 694 base::TimeTicks forms_seen_timestamp = base::TimeTicks::Now(); 695 696 std::vector<FormData> forms; 697 form_cache_.ExtractNewForms(frame, &forms); 698 699 // Always communicate to browser process for topmost frame. 700 if (!forms.empty() || 701 (!frame.parent() && !main_frame_processed_)) { 702 Send(new AutofillHostMsg_FormsSeen(routing_id(), forms, 703 forms_seen_timestamp)); 704 } 705 706 if (!frame.parent()) 707 main_frame_processed_ = true; 708 } 709 710 void AutofillAgent::HidePopup() { 711 if (!is_popup_possibly_visible_) 712 return; 713 714 if (!element_.isNull()) 715 OnClearPreviewedForm(); 716 717 is_popup_possibly_visible_ = false; 718 Send(new AutofillHostMsg_HidePopup(routing_id())); 719 } 720 721 void AutofillAgent::didAssociateFormControls(const WebVector<WebNode>& nodes) { 722 for (size_t i = 0; i < nodes.size(); ++i) { 723 WebLocalFrame* frame = nodes[i].document().frame(); 724 // Only monitors dynamic forms created in the top frame. Dynamic forms 725 // inserted in iframes are not captured yet. Frame is only processed 726 // if it has finished loading, otherwise you can end up with a partially 727 // parsed form. 728 if (frame && !frame->parent() && !frame->isLoading()) { 729 ProcessForms(*frame); 730 password_autofill_agent_->OnDynamicFormsSeen(frame); 731 return; 732 } 733 } 734 } 735 736 } // namespace autofill 737