diff options
-rw-r--r-- | chrome/browser/autocomplete_history_manager.cc | 4 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_manager_unittest.cc | 75 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host.cc | 46 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host.h | 9 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 7 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 74 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 7 | ||||
-rw-r--r-- | chrome/renderer/render_view_unittest.cc | 12 | ||||
-rw-r--r-- | webkit/glue/webpasswordautocompletelistener_impl.cc | 19 | ||||
-rw-r--r-- | webkit/glue/webpasswordautocompletelistener_impl.h | 3 |
10 files changed, 180 insertions, 76 deletions
diff --git a/chrome/browser/autocomplete_history_manager.cc b/chrome/browser/autocomplete_history_manager.cc index 12c661e..f30ec2b 100644 --- a/chrome/browser/autocomplete_history_manager.cc +++ b/chrome/browser/autocomplete_history_manager.cc @@ -179,9 +179,9 @@ void AutocompleteHistoryManager::SendSuggestions(const WDTypedResult* result) { const WDResult<std::vector<string16> >* autofill_result = static_cast<const WDResult<std::vector<string16> >*>(result); host->AutocompleteSuggestionsReturned( - query_id_, autofill_result->GetValue(), -1); + query_id_, autofill_result->GetValue()); } else { host->AutocompleteSuggestionsReturned( - query_id_, std::vector<string16>(), -1); + query_id_, std::vector<string16>()); } } diff --git a/chrome/browser/autofill/autofill_manager_unittest.cc b/chrome/browser/autofill/autofill_manager_unittest.cc index e989269..1549079 100644 --- a/chrome/browser/autofill/autofill_manager_unittest.cc +++ b/chrome/browser/autofill/autofill_manager_unittest.cc @@ -285,6 +285,10 @@ TEST_F(AutoFillManagerTest, GetProfileSuggestionsEmptyValue) { "First Name", "firstname", "", "text", &field); EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, false, field)); + // No suggestions provided, so send an empty vector as the results. + // This triggers the combined message send. + rvh()->AutocompleteSuggestionsReturned(kPageID, std::vector<string16>()); + // Test that we sent the right message to the renderer. int page_id = 0; std::vector<string16> values; @@ -317,6 +321,10 @@ TEST_F(AutoFillManagerTest, GetProfileSuggestionsMatchCharacter) { "First Name", "firstname", "E", "text", &field); EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, false, field)); + // No suggestions provided, so send an empty vector as the results. + // This triggers the combined message send. + rvh()->AutocompleteSuggestionsReturned(kPageID, std::vector<string16>()); + // Test that we sent the right message to the renderer. int page_id = 0; std::vector<string16> values; @@ -347,6 +355,10 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsEmptyValue) { "Card Number", "cardnumber", "", "text", &field); EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, false, field)); + // No suggestions provided, so send an empty vector as the results. + // This triggers the combined message send. + rvh()->AutocompleteSuggestionsReturned(kPageID, std::vector<string16>()); + // Test that we sent the right message to the renderer. int page_id = 0; std::vector<string16> values; @@ -387,6 +399,10 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsMatchCharacter) { "Card Number", "cardnumber", "1", "text", &field); EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, false, field)); + // No suggestions provided, so send an empty vector as the results. + // This triggers the combined message send. + rvh()->AutocompleteSuggestionsReturned(kPageID, std::vector<string16>()); + // Test that we sent the right message to the renderer. int page_id = 0; std::vector<string16> values; @@ -421,6 +437,10 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsNonCCNumber) { "Name on Card", "nameoncard", "", "text", &field); EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, false, field)); + // No suggestions provided, so send an empty vector as the results. + // This triggers the combined message send. + rvh()->AutocompleteSuggestionsReturned(kPageID, std::vector<string16>()); + // Test that we sent the right message to the renderer. int page_id = 0; std::vector<string16> values; @@ -470,6 +490,10 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsSemicolon) { "Name on Card", "nameoncard", "", "text", &field); EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, false, field)); + // No suggestions provided, so send an empty vector as the results. + // This triggers the combined message send. + rvh()->AutocompleteSuggestionsReturned(kPageID, std::vector<string16>()); + // Test that we sent the right message to the renderer. int page_id = 0; std::vector<string16> values; @@ -496,6 +520,49 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsSemicolon) { EXPECT_EQ(ASCIIToUTF16("Home; 8765; 8765"), labels[7]); } +TEST_F(AutoFillManagerTest, GetCombinedAutoFillAndAutocompleteSuggestions) { + FormData form; + CreateTestFormData(&form); + + // Set up our FormStructures. + std::vector<FormData> forms; + forms.push_back(form); + autofill_manager_->FormsSeen(forms); + + // The page ID sent to the AutoFillManager from the RenderView, used to send + // an IPC message back to the renderer. + const int kPageID = 1; + + webkit_glue::FormField field; + autofill_unittest::CreateTestFormField( + "First Name", "firstname", "", "text", &field); + EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, false, field)); + + // Add some Autocomplete suggestions. + // This triggers the combined message send. + std::vector<string16> suggestions; + suggestions.push_back(ASCIIToUTF16("Jay")); + suggestions.push_back(ASCIIToUTF16("Jason")); + rvh()->AutocompleteSuggestionsReturned(kPageID, suggestions); + + // Test that we sent the right message to the renderer. + int page_id = 0; + std::vector<string16> values; + std::vector<string16> labels; + EXPECT_TRUE(GetAutoFillSuggestionsMessage(&page_id, &values, &labels)); + EXPECT_EQ(kPageID, page_id); + ASSERT_EQ(4U, values.size()); + EXPECT_EQ(ASCIIToUTF16("Elvis"), values[0]); + EXPECT_EQ(ASCIIToUTF16("Charles"), values[1]); + EXPECT_EQ(ASCIIToUTF16("Jay"), values[2]); + EXPECT_EQ(ASCIIToUTF16("Jason"), values[3]); + ASSERT_EQ(4U, labels.size()); + EXPECT_EQ(ASCIIToUTF16("Home"), labels[0]); + EXPECT_EQ(ASCIIToUTF16("Work"), labels[1]); + EXPECT_EQ(string16(), labels[2]); + EXPECT_EQ(string16(), labels[3]); +} + TEST_F(AutoFillManagerTest, GetFieldSuggestionsFormIsAutoFilled) { FormData form; CreateTestFormData(&form); @@ -514,6 +581,10 @@ TEST_F(AutoFillManagerTest, GetFieldSuggestionsFormIsAutoFilled) { "First Name", "firstname", "", "text", &field); EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, true, field)); + // No suggestions provided, so send an empty vector as the results. + // This triggers the combined message send. + rvh()->AutocompleteSuggestionsReturned(kPageID, std::vector<string16>()); + // Test that we sent the right message to the renderer. int page_id = 0; std::vector<string16> values; @@ -552,6 +623,10 @@ TEST_F(AutoFillManagerTest, GetFieldSuggestionsWithDuplicateValues) { "First Name", "firstname", "", "text", &field); EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, true, field)); + // No suggestions provided, so send an empty vector as the results. + // This triggers the combined message send. + rvh()->AutocompleteSuggestionsReturned(kPageID, std::vector<string16>()); + // Test that we sent the right message to the renderer. int page_id = 0; std::vector<string16> values; diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index ba6cfac..28b44a3 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -1591,12 +1591,18 @@ void RenderViewHost::OnQueryFormFieldAutoFill( int query_id, bool form_autofilled, const webkit_glue::FormField& field) { RenderViewHostDelegate::AutoFill* autofill_delegate = delegate_->GetAutoFillDelegate(); - // If the AutoFill delegate has results to return, we don't need any results - // from the Autocomplete delegate. + // We first save the AutoFill delegate's suggestions. Then we fetch the + // Autocomplete delegate's suggestions and send the combined results back to + // the render view. if (autofill_delegate && - autofill_delegate->GetAutoFillSuggestions( - query_id, form_autofilled, field)) { - return; + autofill_delegate->GetAutoFillSuggestions(query_id, + form_autofilled, + field)) { + } else { + // No suggestions provided, so supply an empty vector as the results. + AutoFillSuggestionsReturned(query_id, + std::vector<string16>(), + std::vector<string16>()); } RenderViewHostDelegate::Autocomplete* autocomplete_delegate = @@ -1604,11 +1610,10 @@ void RenderViewHost::OnQueryFormFieldAutoFill( if (autocomplete_delegate && autocomplete_delegate->GetAutocompleteSuggestions( query_id, field.name(), field.value())) { - return; + } else { + // No suggestions provided, so send an empty vector as the results. + AutocompleteSuggestionsReturned(query_id, std::vector<string16>()); } - - // No suggestions provided, so send an empty vector as the results. - AutocompleteSuggestionsReturned(query_id, std::vector<string16>(), -1); } void RenderViewHost::OnRemoveAutocompleteEntry(const string16& field_name, @@ -1644,16 +1649,25 @@ void RenderViewHost::AutoFillSuggestionsReturned( int query_id, const std::vector<string16>& names, const std::vector<string16>& labels) { - Send(new ViewMsg_AutoFillSuggestionsReturned( - routing_id(), query_id, names, labels)); + autofill_query_id_ = query_id; + autofill_values_.clear(); + autofill_values_.insert(autofill_values_.begin(), names.begin(), names.end()); + autofill_labels_.clear(); + autofill_labels_.insert( + autofill_labels_.begin(), labels.begin(), labels.end()); } void RenderViewHost::AutocompleteSuggestionsReturned( - int query_id, const std::vector<string16>& suggestions, - int default_suggestion_index) { - Send(new ViewMsg_AutocompleteSuggestionsReturned( - routing_id(), query_id, suggestions, -1)); - // Default index -1 means no default suggestion. + int query_id, const std::vector<string16>& suggestions) { + DCHECK_EQ(autofill_query_id_, query_id); + + // Combine AutoFill and Autocomplete values into values and labels. + for (size_t i = 0; i < suggestions.size(); ++i) { + autofill_values_.push_back(suggestions[i]); + autofill_labels_.push_back(string16()); + } + Send(new ViewMsg_AutoFillSuggestionsReturned( + routing_id(), query_id, autofill_values_, autofill_labels_)); } void RenderViewHost::AutoFillFormDataFilled(int query_id, diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index 90f600d..25d3c15 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -393,8 +393,7 @@ class RenderViewHost : public RenderWidgetHost { // ready. void AutocompleteSuggestionsReturned( int query_id, - const std::vector<string16>& suggestions, - int default_suggestion_index); + const std::vector<string16>& suggestions); // Called by the AutoFillManager when the FormData has been filled out. void AutoFillFormDataFilled(int query_id, const webkit_glue::FormData& form); @@ -718,6 +717,12 @@ class RenderViewHost : public RenderWidgetHost { // what process type we use. bool is_extension_process_; + // AutoFill and Autocomplete suggestions. We accumulate these separately and + // send them back to the renderer together. + int autofill_query_id_; + std::vector<string16> autofill_values_; + std::vector<string16> autofill_labels_; + DISALLOW_COPY_AND_ASSIGN(RenderViewHost); }; diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 421e4fb..042b7c6 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -637,13 +637,6 @@ IPC_BEGIN_MESSAGES(View) std::vector<string16> /* names */, std::vector<string16> /* labels */) - // Reply to the ViewHostMsg_QueryFormFieldAutofill message with the - // Autocomplete suggestions. - IPC_MESSAGE_ROUTED3(ViewMsg_AutocompleteSuggestionsReturned, - int /* id of the request message */, - std::vector<string16> /* suggestions */, - int /* index of default suggestion */) - // Reply to the ViewHostMsg_FillAutoFillFormData message with the // AutoFill form data. IPC_MESSAGE_ROUTED2(ViewMsg_AutoFillFormDataFilled, diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index f05e975..004c31c 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -433,7 +433,8 @@ RenderView::RenderView(RenderThreadBase* render_thread, browser_window_id_(-1), autofill_query_id_(0), autofill_action_(AUTOFILL_NONE), - suggestions_count_(0), + suggestions_clear_index_(-1), + suggestions_options_index_(-1), ALLOW_THIS_IN_INITIALIZER_LIST(pepper_delegate_(this)), ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), ALLOW_THIS_IN_INITIALIZER_LIST(translate_helper_(this)), @@ -692,8 +693,6 @@ void RenderView::OnMessageReceived(const IPC::Message& message) { OnDisassociateFromPopupCount) IPC_MESSAGE_HANDLER(ViewMsg_AutoFillSuggestionsReturned, OnAutoFillSuggestionsReturned) - IPC_MESSAGE_HANDLER(ViewMsg_AutocompleteSuggestionsReturned, - OnAutocompleteSuggestionsReturned) IPC_MESSAGE_HANDLER(ViewMsg_AutoFillFormDataFilled, OnAutoFillFormDataFilled) IPC_MESSAGE_HANDLER(ViewMsg_AllowScriptToClose, @@ -1522,32 +1521,37 @@ void RenderView::OnAutoFillSuggestionsReturned( if (webview() && query_id == autofill_query_id_) { std::vector<string16> v(values); std::vector<string16> l(labels); - int separator_index = v.size(); + int separator_index = -1; // The form has been auto-filled, so give the user the chance to clear the - // form. + // form. Append the 'Clear form' menu item. if (form_manager_.FormWithNodeIsAutoFilled(autofill_query_node_)) { - v.push_back(l10n_util::GetStringUTF16( - IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM)); + v.push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM)); l.push_back(string16()); + suggestions_clear_index_ = v.size() - 1; + separator_index = values.size(); } - // Append the 'AutoFill Options...' menu item. - v.push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS)); - l.push_back(string16()); - suggestions_count_ = v.size(); - webview()->applyAutoFillSuggestions( - autofill_query_node_, v, l, separator_index); - } -} + size_t labeled_item_count = 0; + for (size_t i = 0; i < l.size(); ++i) { + if (!l[i].empty()) + labeled_item_count++; + } -void RenderView::OnAutocompleteSuggestionsReturned( - int query_id, - const std::vector<string16>& suggestions, - int default_suggestion_index) { - if (webview() && query_id == autofill_query_id_) { - webview()->applyAutocompleteSuggestions( - autofill_query_node_, suggestions, default_suggestion_index); + // Only include "AutoFill Options" special menu item if we have labeled + // items. + if (labeled_item_count > 0) { + // Append the 'AutoFill Options...' menu item. + v.push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS)); + l.push_back(string16()); + suggestions_options_index_ = v.size() - 1; + separator_index = values.size(); + } + + // Send to WebKit for display. + if (!v.empty()) + webview()->applyAutoFillSuggestions( + autofill_query_node_, v, l, separator_index); } } @@ -2108,28 +2112,32 @@ void RenderView::didAcceptAutoFillSuggestion(const WebKit::WebNode& node, const WebKit::WebString& value, const WebKit::WebString& label, unsigned index) { - DCHECK_NE(0U, suggestions_count_); - - if (index == suggestions_count_ - 1) { - // User selected 'AutoFill Options...'. + if (suggestions_options_index_ != -1 && + index == static_cast<unsigned>(suggestions_options_index_)) { + // User selected 'AutoFill Options'. Send(new ViewHostMsg_ShowAutoFillDialog(routing_id_)); - } else if (form_manager_.FormWithNodeIsAutoFilled(node) && - index == suggestions_count_ - 2) { + } else if (suggestions_clear_index_ != -1 && + index == static_cast<unsigned>(suggestions_clear_index_)) { + // User selected 'Clear form'. // The form has been auto-filled, so give the user the chance to clear the // form. form_manager_.ClearFormWithNode(node); - } else if (form_manager_.FormWithNodeIsAutoFilled(node)) { - // Fill a specific field value. - // Cast away const'ness in this case where we're filling the element - // directly. + } else if (form_manager_.FormWithNodeIsAutoFilled(node) || label.isEmpty()) { + // User selected an unlabeled menu item, so we fill directly. WebInputElement element = node.toConst<WebInputElement>(); element.setValue(value); + + WebFrame* webframe = node.document().frame(); + if (webframe) { + webframe->notifiyPasswordListenerOfAutocomplete(element); + } } else { // Fill the values for the whole form. QueryAutoFillFormData(node, value, label, AUTOFILL_FILL); } - suggestions_count_ = 0; + suggestions_clear_index_ = -1; + suggestions_options_index_ = -1; } void RenderView::didSelectAutoFillSuggestion(const WebKit::WebNode& node, diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index c52fe51..30af943 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -1157,8 +1157,11 @@ class RenderView : public RenderWidget, // The action to take when receiving AutoFill data from the AutoFillManager. AutoFillAction autofill_action_; - // The number of suggestions sent to the AutoFill popup in WebKit. - size_t suggestions_count_; + // The menu index of the "Clear" menu item. + int suggestions_clear_index_; + + // The menu index of the "AutoFill options..." menu item. + int suggestions_options_index_; // Plugins ------------------------------------------------------------------- diff --git a/chrome/renderer/render_view_unittest.cc b/chrome/renderer/render_view_unittest.cc index b914553..9b9640e 100644 --- a/chrome/renderer/render_view_unittest.cc +++ b/chrome/renderer/render_view_unittest.cc @@ -987,11 +987,13 @@ TEST_F(RenderViewTest, SendForms) { WebDocument document = web_frame->document(); WebInputElement firstname = document.getElementById("firstname").to<WebInputElement>(); - // didAcceptAutoFillSuggestions expects a non-zero number of suggestions. - view_->suggestions_count_ = 1; + + // Accept suggestion that contains a label. Labeled items indicate AutoFill + // as opposed to Autocomplete. We're testing this distinction below with + // the |ViewHostMsg_FillAutoFillFormData::ID| message. view_->didAcceptAutoFillSuggestion(firstname, - WebKit::WebString(), - WebKit::WebString(), + WebKit::WebString::fromUTF8("Johnny"), + WebKit::WebString::fromUTF8("Home"), -1); ProcessPendingMessages(); @@ -1065,8 +1067,6 @@ TEST_F(RenderViewTest, FillFormElement) { WebInputElement middlename = document.getElementById("middlename").to<WebInputElement>(); middlename.setAutofilled(true); - // didAcceptAutoFillSuggestions expects a non-zero number of suggestions. - view_->suggestions_count_ = 4; // Accept a suggestion in a form that has been auto-filled. This triggers // the direct filling of the firstname element with value parameter. diff --git a/webkit/glue/webpasswordautocompletelistener_impl.cc b/webkit/glue/webpasswordautocompletelistener_impl.cc index 8791c80..a1ea755 100644 --- a/webkit/glue/webpasswordautocompletelistener_impl.cc +++ b/webkit/glue/webpasswordautocompletelistener_impl.cc @@ -54,12 +54,19 @@ void WebInputElementDelegate::SetSelectionRange(size_t start, size_t end) { } void WebInputElementDelegate::RefreshAutofillPopup( - const std::vector<string16>& suggestions, - int default_suggestion_index) { + const std::vector<string16>& suggestions) { WebView* webview = element_.document().frame()->view(); - if (webview) - webview->applyAutocompleteSuggestions(element_, suggestions, - default_suggestion_index); + if (webview) { + std::vector<string16> names; + std::vector<string16> labels; + + for (size_t i = 0; i < suggestions.size(); ++i) { + names.push_back(suggestions[i]); + labels.push_back(string16()); + } + + webview->applyAutoFillSuggestions(element_, names, labels, -1); + } } WebPasswordAutocompleteListenerImpl::WebPasswordAutocompleteListenerImpl( @@ -151,7 +158,7 @@ bool WebPasswordAutocompleteListenerImpl::showSuggestionPopup( if (suggestions.empty()) return false; - username_delegate_->RefreshAutofillPopup(suggestions, -1); + username_delegate_->RefreshAutofillPopup(suggestions); return true; } diff --git a/webkit/glue/webpasswordautocompletelistener_impl.h b/webkit/glue/webpasswordautocompletelistener_impl.h index 0c37b89e..ca4604b 100644 --- a/webkit/glue/webpasswordautocompletelistener_impl.h +++ b/webkit/glue/webpasswordautocompletelistener_impl.h @@ -34,8 +34,7 @@ class WebInputElementDelegate { virtual bool IsAutofilled() const; virtual void SetAutofilled(bool autofilled); virtual void SetSelectionRange(size_t start, size_t end); - virtual void RefreshAutofillPopup(const std::vector<string16>& suggestions, - int default_suggestion_index); + virtual void RefreshAutofillPopup(const std::vector<string16>& suggestions); private: // The underlying DOM element we're wrapping. |