autofill_agent.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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() && element.isEmailField()) { 84 std::vector<base::string16> parts; 85 base::SplitStringDontTrim(prefix, ',', &parts); 86 if (parts.size() > 0) { 87 base::TrimWhitespace(parts[parts.size() - 1], base::TRIM_LEADING, 88 &prefix); 89 } 90 } 91 } 92 for (WebOptionElement option = options.firstItem().to<WebOptionElement>(); 93 !option.isNull(); option = options.nextItem().to<WebOptionElement>()) { 94 if (!StartsWith(option.value(), prefix, false) || 95 option.value() == prefix || 96 !element.isValidValue(option.value())) 97 continue; 98 99 values->push_back(option.value()); 100 if (option.value() != option.label()) 101 labels->push_back(option.label()); 102 else 103 labels->push_back(base::string16()); 104 } 105} 106 107// Trim the vector before sending it to the browser process to ensure we 108// don't send too much data through the IPC. 109void TrimStringVectorForIPC(std::vector<base::string16>* strings) { 110 // Limit the size of the vector. 111 if (strings->size() > kMaxListSize) 112 strings->resize(kMaxListSize); 113 114 // Limit the size of the strings in the vector. 115 for (size_t i = 0; i < strings->size(); ++i) { 116 if ((*strings)[i].length() > kMaxDataLength) 117 (*strings)[i].resize(kMaxDataLength); 118 } 119} 120 121} // namespace 122 123AutofillAgent::AutofillAgent(content::RenderView* render_view, 124 PasswordAutofillAgent* password_autofill_agent, 125 PasswordGenerationAgent* password_generation_agent) 126 : content::RenderViewObserver(render_view), 127 password_autofill_agent_(password_autofill_agent), 128 password_generation_agent_(password_generation_agent), 129 autofill_query_id_(0), 130 web_view_(render_view->GetWebView()), 131 display_warning_if_disabled_(false), 132 was_query_node_autofilled_(false), 133 has_shown_autofill_popup_for_current_edit_(false), 134 did_set_node_text_(false), 135 ignore_text_changes_(false), 136 is_popup_possibly_visible_(false), 137 main_frame_processed_(false), 138 weak_ptr_factory_(this) { 139 render_view->GetWebView()->setAutofillClient(this); 140 141 // The PageClickTracker is a RenderViewObserver, and hence will be freed when 142 // the RenderView is destroyed. 143 new PageClickTracker(render_view, this); 144} 145 146AutofillAgent::~AutofillAgent() {} 147 148bool AutofillAgent::OnMessageReceived(const IPC::Message& message) { 149 bool handled = true; 150 IPC_BEGIN_MESSAGE_MAP(AutofillAgent, message) 151 IPC_MESSAGE_HANDLER(AutofillMsg_Ping, OnPing) 152 IPC_MESSAGE_HANDLER(AutofillMsg_FillForm, OnFillForm) 153 IPC_MESSAGE_HANDLER(AutofillMsg_PreviewForm, OnPreviewForm) 154 IPC_MESSAGE_HANDLER(AutofillMsg_FieldTypePredictionsAvailable, 155 OnFieldTypePredictionsAvailable) 156 IPC_MESSAGE_HANDLER(AutofillMsg_ClearForm, OnClearForm) 157 IPC_MESSAGE_HANDLER(AutofillMsg_ClearPreviewedForm, OnClearPreviewedForm) 158 IPC_MESSAGE_HANDLER(AutofillMsg_FillFieldWithValue, OnFillFieldWithValue) 159 IPC_MESSAGE_HANDLER(AutofillMsg_PreviewFieldWithValue, 160 OnPreviewFieldWithValue) 161 IPC_MESSAGE_HANDLER(AutofillMsg_AcceptDataListSuggestion, 162 OnAcceptDataListSuggestion) 163 IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordSuggestion, 164 OnFillPasswordSuggestion) 165 IPC_MESSAGE_HANDLER(AutofillMsg_PreviewPasswordSuggestion, 166 OnPreviewPasswordSuggestion) 167 IPC_MESSAGE_HANDLER(AutofillMsg_RequestAutocompleteResult, 168 OnRequestAutocompleteResult) 169 IPC_MESSAGE_UNHANDLED(handled = false) 170 IPC_END_MESSAGE_MAP() 171 return handled; 172} 173 174void AutofillAgent::DidFinishDocumentLoad(WebLocalFrame* frame) { 175 // If the main frame just finished loading, we should process it. 176 if (!frame->parent()) 177 main_frame_processed_ = false; 178 179 ProcessForms(*frame); 180} 181 182void AutofillAgent::DidCommitProvisionalLoad(WebLocalFrame* frame, 183 bool is_new_navigation) { 184 form_cache_.ResetFrame(*frame); 185} 186 187void AutofillAgent::FrameDetached(WebFrame* frame) { 188 form_cache_.ResetFrame(*frame); 189} 190 191void AutofillAgent::FrameWillClose(WebFrame* frame) { 192 if (in_flight_request_form_.isNull()) 193 return; 194 195 for (WebFrame* temp = in_flight_request_form_.document().frame(); 196 temp; temp = temp->parent()) { 197 if (temp == frame) { 198 Send(new AutofillHostMsg_CancelRequestAutocomplete(routing_id())); 199 break; 200 } 201 } 202} 203 204void AutofillAgent::WillSubmitForm(WebLocalFrame* frame, 205 const WebFormElement& form) { 206 FormData form_data; 207 if (WebFormElementToFormData(form, 208 WebFormControlElement(), 209 REQUIRE_NONE, 210 static_cast<ExtractMask>( 211 EXTRACT_VALUE | EXTRACT_OPTION_TEXT), 212 &form_data, 213 NULL)) { 214 Send(new AutofillHostMsg_FormSubmitted(routing_id(), form_data, 215 base::TimeTicks::Now())); 216 } 217} 218 219void AutofillAgent::FocusedNodeChanged(const WebNode& node) { 220 HidePopup(); 221 222 if (password_generation_agent_ && 223 password_generation_agent_->FocusedNodeHasChanged(node)) { 224 is_popup_possibly_visible_ = true; 225 return; 226 } 227 228 if (node.isNull() || !node.isElementNode()) 229 return; 230 231 WebElement web_element = node.toConst<WebElement>(); 232 233 if (!web_element.document().frame()) 234 return; 235 236 const WebInputElement* element = toWebInputElement(&web_element); 237 238 if (!element || !element->isEnabled() || element->isReadOnly() || 239 !element->isTextField() || element->isPasswordField()) 240 return; 241 242 element_ = *element; 243} 244 245void AutofillAgent::OrientationChangeEvent() { 246 HidePopup(); 247} 248 249void AutofillAgent::DidChangeScrollOffset(WebLocalFrame*) { 250 HidePopup(); 251} 252 253void AutofillAgent::didRequestAutocomplete( 254 const WebFormElement& form) { 255 // Disallow the dialog over non-https or broken https, except when the 256 // ignore SSL flag is passed. See http://crbug.com/272512. 257 // TODO(palmer): this should be moved to the browser process after frames 258 // get their own processes. 259 GURL url(form.document().url()); 260 content::SSLStatus ssl_status = 261 render_view()->GetSSLStatusOfFrame(form.document().frame()); 262 bool is_safe = url.SchemeIs(url::kHttpsScheme) && 263 !net::IsCertStatusError(ssl_status.cert_status); 264 bool allow_unsafe = CommandLine::ForCurrentProcess()->HasSwitch( 265 ::switches::kReduceSecurityForTesting); 266 267 FormData form_data; 268 std::string error_message; 269 if (!in_flight_request_form_.isNull()) { 270 error_message = "already active."; 271 } else if (!is_safe && !allow_unsafe) { 272 error_message = 273 "must use a secure connection or --reduce-security-for-testing."; 274 } else if (!WebFormElementToFormData(form, 275 WebFormControlElement(), 276 REQUIRE_AUTOCOMPLETE, 277 static_cast<ExtractMask>( 278 EXTRACT_VALUE | 279 EXTRACT_OPTION_TEXT | 280 EXTRACT_OPTIONS), 281 &form_data, 282 NULL)) { 283 error_message = "failed to parse form."; 284 } 285 286 if (!error_message.empty()) { 287 WebConsoleMessage console_message = WebConsoleMessage( 288 WebConsoleMessage::LevelLog, 289 WebString(base::ASCIIToUTF16("requestAutocomplete: ") + 290 base::ASCIIToUTF16(error_message))); 291 form.document().frame()->addMessageToConsole(console_message); 292 WebFormElement(form).finishRequestAutocomplete( 293 WebFormElement::AutocompleteResultErrorDisabled); 294 return; 295 } 296 297 // Cancel any pending Autofill requests and hide any currently showing popups. 298 ++autofill_query_id_; 299 HidePopup(); 300 301 in_flight_request_form_ = form; 302 Send(new AutofillHostMsg_RequestAutocomplete(routing_id(), form_data, url)); 303} 304 305void AutofillAgent::setIgnoreTextChanges(bool ignore) { 306 ignore_text_changes_ = ignore; 307} 308 309void AutofillAgent::FormControlElementClicked( 310 const WebFormControlElement& element, 311 bool was_focused) { 312 const WebInputElement* input_element = toWebInputElement(&element); 313 if (!input_element && !IsTextAreaElement(element)) 314 return; 315 316 bool show_full_suggestion_list = element.isAutofilled() || was_focused; 317 bool show_password_suggestions_only = !was_focused; 318 ShowSuggestions(element, 319 true, 320 false, 321 true, 322 false, 323 show_full_suggestion_list, 324 show_password_suggestions_only); 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, 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, false, false); 399} 400 401void AutofillAgent::openTextDataListChooser(const WebInputElement& element) { 402 ShowSuggestions(element, true, false, false, true, false, false); 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() && input_element->isEmailField()) { 417 std::vector<base::string16> parts; 418 419 base::SplitStringDontTrim(input_element->editingValue(), ',', &parts); 420 if (parts.size() == 0) 421 parts.push_back(base::string16()); 422 423 base::string16 last_part = parts.back(); 424 // We want to keep just the leading whitespace. 425 for (size_t i = 0; i < last_part.size(); ++i) { 426 if (!IsWhitespace(last_part[i])) { 427 last_part = last_part.substr(0, i); 428 break; 429 } 430 } 431 last_part.append(suggested_value); 432 parts[parts.size() - 1] = last_part; 433 434 new_value = JoinString(parts, ','); 435 } 436 FillFieldWithValue(new_value, input_element); 437} 438 439void AutofillAgent::OnFieldTypePredictionsAvailable( 440 const std::vector<FormDataPredictions>& forms) { 441 for (size_t i = 0; i < forms.size(); ++i) { 442 form_cache_.ShowPredictions(forms[i]); 443 } 444} 445 446void AutofillAgent::OnFillForm(int query_id, const FormData& form) { 447 if (!render_view()->GetWebView() || query_id != autofill_query_id_) 448 return; 449 450 was_query_node_autofilled_ = element_.isAutofilled(); 451 FillForm(form, element_); 452 Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id(), 453 base::TimeTicks::Now())); 454} 455 456void AutofillAgent::OnPing() { 457 Send(new AutofillHostMsg_PingAck(routing_id())); 458} 459 460void AutofillAgent::OnPreviewForm(int query_id, const FormData& form) { 461 if (!render_view()->GetWebView() || query_id != autofill_query_id_) 462 return; 463 464 was_query_node_autofilled_ = element_.isAutofilled(); 465 PreviewForm(form, element_); 466 Send(new AutofillHostMsg_DidPreviewAutofillFormData(routing_id())); 467} 468 469void AutofillAgent::OnClearForm() { 470 form_cache_.ClearFormWithElement(element_); 471} 472 473void AutofillAgent::OnClearPreviewedForm() { 474 if (!element_.isNull()) { 475 if (password_autofill_agent_->DidClearAutofillSelection(element_)) 476 return; 477 478 ClearPreviewedFormWithElement(element_, was_query_node_autofilled_); 479 } else { 480 // TODO(isherman): There seem to be rare cases where this code *is* 481 // reachable: see [ http://crbug.com/96321#c6 ]. Ideally we would 482 // understand those cases and fix the code to avoid them. However, so far I 483 // have been unable to reproduce such a case locally. If you hit this 484 // NOTREACHED(), please file a bug against me. 485 NOTREACHED(); 486 } 487} 488 489void AutofillAgent::OnFillFieldWithValue(const base::string16& value) { 490 WebInputElement* input_element = toWebInputElement(&element_); 491 if (input_element) 492 FillFieldWithValue(value, input_element); 493} 494 495void AutofillAgent::OnPreviewFieldWithValue(const base::string16& value) { 496 WebInputElement* input_element = toWebInputElement(&element_); 497 if (input_element) 498 PreviewFieldWithValue(value, input_element); 499} 500 501void AutofillAgent::OnAcceptDataListSuggestion(const base::string16& value) { 502 AcceptDataListSuggestion(value); 503} 504 505void AutofillAgent::OnFillPasswordSuggestion(const base::string16& username, 506 const base::string16& password) { 507 bool handled = password_autofill_agent_->FillSuggestion( 508 element_, 509 username, 510 password); 511 DCHECK(handled); 512} 513 514void AutofillAgent::OnPreviewPasswordSuggestion( 515 const base::string16& username, 516 const base::string16& password) { 517 bool handled = password_autofill_agent_->PreviewSuggestion( 518 element_, 519 username, 520 password); 521 DCHECK(handled); 522} 523 524void AutofillAgent::OnRequestAutocompleteResult( 525 WebFormElement::AutocompleteResult result, 526 const base::string16& message, 527 const FormData& form_data) { 528 if (in_flight_request_form_.isNull()) 529 return; 530 531 if (result == WebFormElement::AutocompleteResultSuccess) { 532 FillFormIncludingNonFocusableElements(form_data, in_flight_request_form_); 533 if (!in_flight_request_form_.checkValidity()) 534 result = WebFormElement::AutocompleteResultErrorInvalid; 535 } 536 537 in_flight_request_form_.finishRequestAutocomplete(result); 538 539 if (!message.empty()) { 540 const base::string16 prefix(base::ASCIIToUTF16("requestAutocomplete: ")); 541 WebConsoleMessage console_message = WebConsoleMessage( 542 WebConsoleMessage::LevelLog, WebString(prefix + message)); 543 in_flight_request_form_.document().frame()->addMessageToConsole( 544 console_message); 545 } 546 547 in_flight_request_form_.reset(); 548} 549 550void AutofillAgent::ShowSuggestions(const WebFormControlElement& element, 551 bool autofill_on_empty_values, 552 bool requires_caret_at_end, 553 bool display_warning_if_disabled, 554 bool datalist_only, 555 bool show_full_suggestion_list, 556 bool show_password_suggestions_only) { 557 if (!element.isEnabled() || element.isReadOnly()) 558 return; 559 if (!datalist_only && !element.suggestedValue().isEmpty()) 560 return; 561 562 const WebInputElement* input_element = toWebInputElement(&element); 563 if (input_element) { 564 if (!input_element->isTextField() || input_element->isPasswordField()) 565 return; 566 if (!datalist_only && !input_element->suggestedValue().isEmpty()) 567 return; 568 } else { 569 DCHECK(IsTextAreaElement(element)); 570 if (!element.toConst<WebTextAreaElement>().suggestedValue().isEmpty()) 571 return; 572 } 573 574 // Don't attempt to autofill with values that are too large or if filling 575 // criteria are not met. 576 WebString value = element.editingValue(); 577 if (!datalist_only && 578 (value.length() > kMaxDataLength || 579 (!autofill_on_empty_values && value.isEmpty()) || 580 (requires_caret_at_end && 581 (element.selectionStart() != element.selectionEnd() || 582 element.selectionEnd() != static_cast<int>(value.length()))))) { 583 // Any popup currently showing is obsolete. 584 HidePopup(); 585 return; 586 } 587 588 element_ = element; 589 if (IsAutofillableInputElement(input_element) && 590 (password_autofill_agent_->ShowSuggestions(*input_element, 591 show_full_suggestion_list) || 592 show_password_suggestions_only)) { 593 is_popup_possibly_visible_ = true; 594 return; 595 } 596 597 // If autocomplete is disabled at the field level, ensure that the native 598 // UI won't try to show a warning, since that may conflict with a custom 599 // popup. Note that we cannot use the WebKit method element.autoComplete() 600 // as it does not allow us to distinguish the case where autocomplete is 601 // disabled for *both* the element and for the form. 602 const base::string16 autocomplete_attribute = 603 element.getAttribute("autocomplete"); 604 if (LowerCaseEqualsASCII(autocomplete_attribute, "off")) 605 display_warning_if_disabled = false; 606 607 QueryAutofillSuggestions(element, 608 display_warning_if_disabled, 609 datalist_only); 610} 611 612void AutofillAgent::QueryAutofillSuggestions( 613 const WebFormControlElement& element, 614 bool display_warning_if_disabled, 615 bool datalist_only) { 616 if (!element.document().frame()) 617 return; 618 619 DCHECK(toWebInputElement(&element) || IsTextAreaElement(element)); 620 621 static int query_counter = 0; 622 autofill_query_id_ = query_counter++; 623 display_warning_if_disabled_ = display_warning_if_disabled; 624 625 // If autocomplete is disabled at the form level, we want to see if there 626 // would have been any suggestions were it enabled, so that we can show a 627 // warning. Otherwise, we want to ignore fields that disable autocomplete, so 628 // that the suggestions list does not include suggestions for these form 629 // fields -- see comment 1 on http://crbug.com/69914 630 const RequirementsMask requirements = 631 element.autoComplete() ? REQUIRE_AUTOCOMPLETE : REQUIRE_NONE; 632 633 FormData form; 634 FormFieldData field; 635 if (!FindFormAndFieldForFormControlElement(element, &form, &field, 636 requirements)) { 637 // If we didn't find the cached form, at least let autocomplete have a shot 638 // at providing suggestions. 639 WebFormControlElementToFormField(element, EXTRACT_VALUE, &field); 640 } 641 if (datalist_only) 642 field.should_autocomplete = false; 643 644 gfx::RectF bounding_box_scaled = 645 GetScaledBoundingBox(web_view_->pageScaleFactor(), &element_); 646 647 std::vector<base::string16> data_list_values; 648 std::vector<base::string16> data_list_labels; 649 const WebInputElement* input_element = toWebInputElement(&element); 650 if (input_element) { 651 // Find the datalist values and send them to the browser process. 652 GetDataListSuggestions(*input_element, 653 datalist_only, 654 &data_list_values, 655 &data_list_labels); 656 TrimStringVectorForIPC(&data_list_values); 657 TrimStringVectorForIPC(&data_list_labels); 658 } 659 660 is_popup_possibly_visible_ = true; 661 Send(new AutofillHostMsg_SetDataList(routing_id(), 662 data_list_values, 663 data_list_labels)); 664 665 Send(new AutofillHostMsg_QueryFormFieldAutofill(routing_id(), 666 autofill_query_id_, 667 form, 668 field, 669 bounding_box_scaled, 670 display_warning_if_disabled)); 671} 672 673void AutofillAgent::FillFieldWithValue(const base::string16& value, 674 WebInputElement* node) { 675 did_set_node_text_ = true; 676 node->setEditingValue(value.substr(0, node->maxLength())); 677 node->setAutofilled(true); 678} 679 680void AutofillAgent::PreviewFieldWithValue(const base::string16& value, 681 WebInputElement* node) { 682 was_query_node_autofilled_ = element_.isAutofilled(); 683 node->setSuggestedValue(value.substr(0, node->maxLength())); 684 node->setAutofilled(true); 685 node->setSelectionRange(node->value().length(), 686 node->suggestedValue().length()); 687} 688 689void AutofillAgent::ProcessForms(const WebLocalFrame& frame) { 690 // Record timestamp of when the forms are first seen. This is used to 691 // measure the overhead of the Autofill feature. 692 base::TimeTicks forms_seen_timestamp = base::TimeTicks::Now(); 693 694 std::vector<FormData> forms; 695 form_cache_.ExtractNewForms(frame, &forms); 696 697 // Always communicate to browser process for topmost frame. 698 if (!forms.empty() || 699 (!frame.parent() && !main_frame_processed_)) { 700 Send(new AutofillHostMsg_FormsSeen(routing_id(), forms, 701 forms_seen_timestamp)); 702 } 703 704 if (!frame.parent()) 705 main_frame_processed_ = true; 706} 707 708void AutofillAgent::HidePopup() { 709 if (!is_popup_possibly_visible_) 710 return; 711 712 if (!element_.isNull()) 713 OnClearPreviewedForm(); 714 715 is_popup_possibly_visible_ = false; 716 Send(new AutofillHostMsg_HidePopup(routing_id())); 717} 718 719void AutofillAgent::didAssociateFormControls(const WebVector<WebNode>& nodes) { 720 for (size_t i = 0; i < nodes.size(); ++i) { 721 WebLocalFrame* frame = nodes[i].document().frame(); 722 // Only monitors dynamic forms created in the top frame. Dynamic forms 723 // inserted in iframes are not captured yet. Frame is only processed 724 // if it has finished loading, otherwise you can end up with a partially 725 // parsed form. 726 if (frame && !frame->parent() && !frame->isLoading()) { 727 ProcessForms(*frame); 728 password_autofill_agent_->OnDynamicFormsSeen(frame); 729 return; 730 } 731 } 732} 733 734} // namespace autofill 735