 Chromium Code Reviews
 Chromium Code Reviews Issue 11270018:
  [autofill] Adding new API to request an interactive autocomplete UI flow.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 11270018:
  [autofill] Adding new API to request an interactive autocomplete UI flow.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "chrome/renderer/autofill/autofill_agent.h" | 5 #include "chrome/renderer/autofill/autofill_agent.h" | 
| 6 | 6 | 
| 7 #include "base/bind.h" | 7 #include "base/bind.h" | 
| 8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" | 
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" | 
| 10 #include "base/string_split.h" | 10 #include "base/string_split.h" | 
| 11 #include "base/time.h" | 11 #include "base/time.h" | 
| 12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" | 
| 13 #include "chrome/common/autofill_messages.h" | 13 #include "chrome/common/autofill_messages.h" | 
| 14 #include "chrome/common/chrome_constants.h" | 14 #include "chrome/common/chrome_constants.h" | 
| 15 #include "chrome/common/form_data.h" | 15 #include "chrome/common/form_data.h" | 
| 16 #include "chrome/common/form_data_predictions.h" | 16 #include "chrome/common/form_data_predictions.h" | 
| 17 #include "chrome/common/form_field_data.h" | 17 #include "chrome/common/form_field_data.h" | 
| 18 #include "chrome/renderer/autofill/form_autofill_util.h" | 18 #include "chrome/renderer/autofill/form_autofill_util.h" | 
| 19 #include "chrome/renderer/autofill/password_autofill_manager.h" | 19 #include "chrome/renderer/autofill/password_autofill_manager.h" | 
| 20 #include "content/public/common/password_form.h" | 20 #include "content/public/common/password_form.h" | 
| 21 #include "content/public/renderer/render_view.h" | 21 #include "content/public/renderer/render_view.h" | 
| 22 #include "grit/chromium_strings.h" | 22 #include "grit/chromium_strings.h" | 
| 23 #include "grit/generated_resources.h" | 23 #include "grit/generated_resources.h" | 
| 24 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" | 24 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" | 
| 25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | 25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | 
| 26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFormControlElement .h" | 26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFormControlElement .h" | 
| 27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFormElement.h" | |
| 27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 28 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 
| 28 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" | 29 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" | 
| 29 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h" | 30 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h" | 
| 30 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNodeCollection.h" | 31 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNodeCollection.h" | 
| 31 #include "third_party/WebKit/Source/WebKit/chromium/public/WebOptionElement.h" | 32 #include "third_party/WebKit/Source/WebKit/chromium/public/WebOptionElement.h" | 
| 32 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | 33 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | 
| 33 #include "ui/base/keycodes/keyboard_codes.h" | 34 #include "ui/base/keycodes/keyboard_codes.h" | 
| 34 #include "ui/base/l10n/l10n_util.h" | 35 #include "ui/base/l10n/l10n_util.h" | 
| 35 | 36 | 
| 36 using WebKit::WebAutofillClient; | 37 using WebKit::WebAutofillClient; | 
| (...skipping 10 matching lines...) Expand all Loading... | |
| 47 namespace { | 48 namespace { | 
| 48 | 49 | 
| 49 // The size above which we stop triggering autofill for an input text field | 50 // The size above which we stop triggering autofill for an input text field | 
| 50 // (so to avoid sending long strings through IPC). | 51 // (so to avoid sending long strings through IPC). | 
| 51 const size_t kMaximumTextSizeForAutofill = 1000; | 52 const size_t kMaximumTextSizeForAutofill = 1000; | 
| 52 | 53 | 
| 53 // The maximum number of data list elements to send to the browser process | 54 // The maximum number of data list elements to send to the browser process | 
| 54 // via IPC (to prevent long IPC messages). | 55 // via IPC (to prevent long IPC messages). | 
| 55 const size_t kMaximumDataListSizeForAutofill = 30; | 56 const size_t kMaximumDataListSizeForAutofill = 30; | 
| 56 | 57 | 
| 58 // A query counter for requests to show an interactive autocomplete UI. | |
| 59 int request_autocomplete_query_id_ = 0; | |
| 
Ilya Sherman
2012/10/27 07:44:11
This should be a private member of the class.  Als
 
Dan Beam
2012/10/29 19:17:05
I don't think this is relevant any more.
 | |
| 60 | |
| 57 void AppendDataListSuggestions(const WebKit::WebInputElement& element, | 61 void AppendDataListSuggestions(const WebKit::WebInputElement& element, | 
| 58 std::vector<string16>* values, | 62 std::vector<string16>* values, | 
| 59 std::vector<string16>* labels, | 63 std::vector<string16>* labels, | 
| 60 std::vector<string16>* icons, | 64 std::vector<string16>* icons, | 
| 61 std::vector<int>* item_ids) { | 65 std::vector<int>* item_ids) { | 
| 62 WebNodeCollection options = element.dataListOptions(); | 66 WebNodeCollection options = element.dataListOptions(); | 
| 63 if (options.isNull()) | 67 if (options.isNull()) | 
| 64 return; | 68 return; | 
| 65 | 69 | 
| 66 string16 prefix = element.editingValue(); | 70 string16 prefix = element.editingValue(); | 
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 152 IPC_MESSAGE_HANDLER(AutofillMsg_SetAutofillActionPreview, | 156 IPC_MESSAGE_HANDLER(AutofillMsg_SetAutofillActionPreview, | 
| 153 OnSetAutofillActionPreview) | 157 OnSetAutofillActionPreview) | 
| 154 IPC_MESSAGE_HANDLER(AutofillMsg_ClearPreviewedForm, | 158 IPC_MESSAGE_HANDLER(AutofillMsg_ClearPreviewedForm, | 
| 155 OnClearPreviewedForm) | 159 OnClearPreviewedForm) | 
| 156 IPC_MESSAGE_HANDLER(AutofillMsg_SetNodeText, | 160 IPC_MESSAGE_HANDLER(AutofillMsg_SetNodeText, | 
| 157 OnSetNodeText) | 161 OnSetNodeText) | 
| 158 IPC_MESSAGE_HANDLER(AutofillMsg_AcceptDataListSuggestion, | 162 IPC_MESSAGE_HANDLER(AutofillMsg_AcceptDataListSuggestion, | 
| 159 OnAcceptDataListSuggestion) | 163 OnAcceptDataListSuggestion) | 
| 160 IPC_MESSAGE_HANDLER(AutofillMsg_AcceptPasswordAutofillSuggestion, | 164 IPC_MESSAGE_HANDLER(AutofillMsg_AcceptPasswordAutofillSuggestion, | 
| 161 OnAcceptPasswordAutofillSuggestion) | 165 OnAcceptPasswordAutofillSuggestion) | 
| 166 IPC_MESSAGE_HANDLER(AutofillMsg_RequestAutocompleteFinished, | |
| 167 OnRequestAutocompleteFinished) | |
| 162 IPC_MESSAGE_UNHANDLED(handled = false) | 168 IPC_MESSAGE_UNHANDLED(handled = false) | 
| 163 IPC_END_MESSAGE_MAP() | 169 IPC_END_MESSAGE_MAP() | 
| 164 return handled; | 170 return handled; | 
| 165 } | 171 } | 
| 166 | 172 | 
| 167 void AutofillAgent::DidFinishDocumentLoad(WebFrame* frame) { | 173 void AutofillAgent::DidFinishDocumentLoad(WebFrame* frame) { | 
| 168 // The document has now been fully loaded. Scan for forms to be sent up to | 174 // The document has now been fully loaded. Scan for forms to be sent up to | 
| 169 // the browser. | 175 // the browser. | 
| 170 std::vector<FormData> forms; | 176 std::vector<FormData> forms; | 
| 171 form_cache_.ExtractForms(*frame, &forms); | 177 form_cache_.ExtractForms(*frame, &forms); | 
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 206 Send(new AutofillHostMsg_HideAutofillPopup(routing_id())); | 212 Send(new AutofillHostMsg_HideAutofillPopup(routing_id())); | 
| 207 } | 213 } | 
| 208 | 214 | 
| 209 void AutofillAgent::DidChangeScrollOffset(WebKit::WebFrame*) { | 215 void AutofillAgent::DidChangeScrollOffset(WebKit::WebFrame*) { | 
| 210 // Any time the scroll offset changes, the page's content moves, so Autofill | 216 // Any time the scroll offset changes, the page's content moves, so Autofill | 
| 211 // popups should be hidden. This is only needed for the new Autofill UI | 217 // popups should be hidden. This is only needed for the new Autofill UI | 
| 212 // because WebKit already knows to hide the old UI when this occurs. | 218 // because WebKit already knows to hide the old UI when this occurs. | 
| 213 Send(new AutofillHostMsg_HideAutofillPopup(routing_id())); | 219 Send(new AutofillHostMsg_HideAutofillPopup(routing_id())); | 
| 214 } | 220 } | 
| 215 | 221 | 
| 222 void AutofillAgent::didRequestAutocomplete(WebKit::WebFrame* frame, | |
| 223 const WebFormElement& form) { | |
| 224 request_autocomplete_query_id_ += 1; | |
| 
Evan Stade
2012/10/29 17:54:28
++
 
Dan Beam
2012/10/29 19:17:05
Done.
 | |
| 225 | |
| 226 // Cancel any pending autofill requests. | |
| 227 autofill_query_id_ += 1; | |
| 228 | |
| 229 // Any popup currently showing is obsolete. | |
| 230 HidePopups(); | |
| 231 | |
| 232 FormData form_data; | |
| 233 if (WebFormElementToFormData(form, | |
| 234 WebFormControlElement(), | |
| 235 REQUIRE_AUTOCOMPLETE, | |
| 236 EXTRACT_NONE, | |
| 237 &form_data, | |
| 238 NULL)) { | |
| 239 form_ = form; | |
| 240 Send(new AutofillHostMsg_RequestAutocomplete( | |
| 241 routing_id(), request_autocomplete_query_id_, form_data)); | |
| 242 } | |
| 243 } | |
| 244 | |
| 216 bool AutofillAgent::InputElementClicked(const WebInputElement& element, | 245 bool AutofillAgent::InputElementClicked(const WebInputElement& element, | 
| 217 bool was_focused, | 246 bool was_focused, | 
| 218 bool is_focused) { | 247 bool is_focused) { | 
| 219 if (was_focused) | 248 if (was_focused) | 
| 220 ShowSuggestions(element, true, false, true); | 249 ShowSuggestions(element, true, false, true); | 
| 221 | 250 | 
| 222 return false; | 251 return false; | 
| 223 } | 252 } | 
| 224 | 253 | 
| 225 bool AutofillAgent::InputElementLostFocus() { | 254 bool AutofillAgent::InputElementLostFocus() { | 
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 575 void AutofillAgent::OnAcceptPasswordAutofillSuggestion(const string16& value) { | 604 void AutofillAgent::OnAcceptPasswordAutofillSuggestion(const string16& value) { | 
| 576 // We need to make sure this is handled here because the browser process | 605 // We need to make sure this is handled here because the browser process | 
| 577 // skipped it handling because it believed it would be handled here. If it | 606 // skipped it handling because it believed it would be handled here. If it | 
| 578 // isn't handled here then the browser logic needs to be updated. | 607 // isn't handled here then the browser logic needs to be updated. | 
| 579 bool handled = password_autofill_manager_->DidAcceptAutofillSuggestion( | 608 bool handled = password_autofill_manager_->DidAcceptAutofillSuggestion( | 
| 580 element_, | 609 element_, | 
| 581 value); | 610 value); | 
| 582 DCHECK(handled); | 611 DCHECK(handled); | 
| 583 } | 612 } | 
| 584 | 613 | 
| 614 void AutofillAgent::OnRequestAutocompleteFinished(int query_id, int result) { | |
| 615 DCHECK_GT(query_id, 0); | |
| 616 if (query_id != request_autocomplete_query_id_) | |
| 617 return; | |
| 618 | |
| 619 if (result == WebFormElement::AutocompleteSuccess || | |
| 620 result == WebFormElement::AutocompleteError) { | |
| 621 form_.finishRequestAutocomplete( | |
| 622 static_cast<WebFormElement::AutocompleteResult>(result)); | |
| 623 } else { | |
| 624 NOTREACHED() << "Unknown autocomplete result."; | |
| 
Ilya Sherman
2012/10/27 07:44:11
nit: Please remove the logged text; you can add it
 
Dan Beam
2012/10/29 19:17:05
Done.
 | |
| 625 } | |
| 626 } | |
| 627 | |
| 585 void AutofillAgent::ShowSuggestions(const WebInputElement& element, | 628 void AutofillAgent::ShowSuggestions(const WebInputElement& element, | 
| 586 bool autofill_on_empty_values, | 629 bool autofill_on_empty_values, | 
| 587 bool requires_caret_at_end, | 630 bool requires_caret_at_end, | 
| 588 bool display_warning_if_disabled) { | 631 bool display_warning_if_disabled) { | 
| 589 if (!element.isEnabled() || element.isReadOnly() || !element.isTextField() || | 632 if (!element.isEnabled() || element.isReadOnly() || !element.isTextField() || | 
| 590 element.isPasswordField() || !element.suggestedValue().isEmpty()) | 633 element.isPasswordField() || !element.suggestedValue().isEmpty()) | 
| 591 return; | 634 return; | 
| 592 | 635 | 
| 593 // Don't attempt to autofill with values that are too large or if filling | 636 // Don't attempt to autofill with values that are too large or if filling | 
| 594 // criteria are not met. | 637 // criteria are not met. | 
| 595 WebString value = element.editingValue(); | 638 WebString value = element.editingValue(); | 
| 596 if (value.length() > kMaximumTextSizeForAutofill || | 639 if (value.length() > kMaximumTextSizeForAutofill || | 
| 597 (!autofill_on_empty_values && value.isEmpty()) || | 640 (!autofill_on_empty_values && value.isEmpty()) || | 
| 598 (requires_caret_at_end && | 641 (requires_caret_at_end && | 
| 599 (element.selectionStart() != element.selectionEnd() || | 642 (element.selectionStart() != element.selectionEnd() || | 
| 600 element.selectionEnd() != static_cast<int>(value.length())))) { | 643 element.selectionEnd() != static_cast<int>(value.length())))) { | 
| 601 // Any popup currently showing is obsolete. | 644 // Any popup currently showing is obsolete. | 
| 602 WebKit::WebView* web_view = render_view()->GetWebView(); | 645 HidePopups(); | 
| 603 if (web_view) | |
| 604 web_view->hidePopups(); | |
| 605 | |
| 606 return; | 646 return; | 
| 607 } | 647 } | 
| 608 | 648 | 
| 609 element_ = element; | 649 element_ = element; | 
| 610 | 650 | 
| 611 // If autocomplete is disabled at the form level, then we might want to show | 651 // If autocomplete is disabled at the form level, then we might want to show | 
| 612 // a warning in place of suggestions. However, if autocomplete is disabled | 652 // a warning in place of suggestions. However, if autocomplete is disabled | 
| 613 // specifically for this field, we never want to show a warning. Otherwise, | 653 // specifically for this field, we never want to show a warning. Otherwise, | 
| 614 // we might interfere with custom popups (e.g. search suggestions) used by | 654 // we might interfere with custom popups (e.g. search suggestions) used by | 
| 615 // the website. Also, if the field has no name, then we won't have values. | 655 // the website. Also, if the field has no name, then we won't have values. | 
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 695 | 735 | 
| 696 void AutofillAgent::SetNodeText(const string16& value, | 736 void AutofillAgent::SetNodeText(const string16& value, | 
| 697 WebKit::WebInputElement* node) { | 737 WebKit::WebInputElement* node) { | 
| 698 did_set_node_text_ = true; | 738 did_set_node_text_ = true; | 
| 699 string16 substring = value; | 739 string16 substring = value; | 
| 700 substring = substring.substr(0, node->maxLength()); | 740 substring = substring.substr(0, node->maxLength()); | 
| 701 | 741 | 
| 702 node->setEditingValue(substring); | 742 node->setEditingValue(substring); | 
| 703 } | 743 } | 
| 704 | 744 | 
| 745 void AutofillAgent::HidePopups() { | |
| 746 WebKit::WebView* web_view = render_view()->GetWebView(); | |
| 747 if (web_view) | |
| 748 web_view->hidePopups(); | |
| 
Ilya Sherman
2012/10/27 07:44:11
You should also hide any popups that might be show
 
Dan Beam
2012/10/29 19:17:05
The code wasn't doing this before and I'm simply p
 
Ilya Sherman
2012/10/29 21:27:47
Feel free to file a bug against csharp@ and annota
 
Dan Beam
2012/10/29 23:08:23
https://chromiumcodereview.appspot.com/11273096/
 | |
| 749 } | |
| 750 | |
| 
Evan Stade
2012/10/29 17:54:28
extra newline
 
Dan Beam
2012/10/29 19:17:05
Done.
 | |
| 751 | |
| 705 } // namespace autofill | 752 } // namespace autofill | 
| OLD | NEW |