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