summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcsharp@chromium.org <csharp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-09 15:21:53 +0000
committercsharp@chromium.org <csharp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-09 15:21:53 +0000
commit6f001a6cf0c8e74345ebab5c2ddb65babe892cc2 (patch)
treefcb5d37e8c9a834a1ebd87eb7fde8c2b2750caa9
parent6f7f89a4d8651e9916640100106b8dfe95d03c71 (diff)
downloadchromium_src-6f001a6cf0c8e74345ebab5c2ddb65babe892cc2.zip
chromium_src-6f001a6cf0c8e74345ebab5c2ddb65babe892cc2.tar.gz
chromium_src-6f001a6cf0c8e74345ebab5c2ddb65babe892cc2.tar.bz2
Adding Mouse Support for new GTK Autofill
Adds the ability use the mouse to select an Autofill option and see the preview of an option. BUG=51644 TEST= Review URL: http://codereview.chromium.org/9235072 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@121234 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/autocomplete_history_manager_unittest.cc33
-rw-r--r--chrome/browser/autofill/autofill_external_delegate.cc96
-rw-r--r--chrome/browser/autofill/autofill_external_delegate.h47
-rw-r--r--chrome/browser/autofill/autofill_external_delegate_gtk.cc23
-rw-r--r--chrome/browser/autofill/autofill_external_delegate_gtk.h4
-rw-r--r--chrome/browser/autofill/autofill_external_delegate_unittest.cc88
-rw-r--r--chrome/browser/autofill/autofill_manager.h14
-rw-r--r--chrome/browser/autofill/autofill_manager_unittest.cc15
-rw-r--r--chrome/browser/autofill/autofill_popup_view.cc33
-rw-r--r--chrome/browser/autofill/autofill_popup_view.h32
-rw-r--r--chrome/browser/autofill/autofill_popup_view_browsertest.cc85
-rw-r--r--chrome/browser/autofill/test_autofill_external_delegate.cc26
-rw-r--r--chrome/browser/autofill/test_autofill_external_delegate.h42
-rw-r--r--chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc93
-rw-r--r--chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h20
-rw-r--r--chrome/chrome_tests.gypi2
-rw-r--r--chrome/common/autofill_messages.h18
-rw-r--r--chrome/renderer/autofill/autofill_agent.cc51
-rw-r--r--chrome/renderer/autofill/autofill_agent.h10
-rw-r--r--chrome/renderer/autofill/autofill_browsertest.cc8
20 files changed, 583 insertions, 157 deletions
diff --git a/chrome/browser/autocomplete_history_manager_unittest.cc b/chrome/browser/autocomplete_history_manager_unittest.cc
index add04f0..d49f03d 100644
--- a/chrome/browser/autocomplete_history_manager_unittest.cc
+++ b/chrome/browser/autocomplete_history_manager_unittest.cc
@@ -8,7 +8,7 @@
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete_history_manager.h"
-#include "chrome/browser/autofill/autofill_external_delegate.h"
+#include "chrome/browser/autofill/test_autofill_external_delegate.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -139,17 +139,18 @@ TEST_F(AutocompleteHistoryManagerTest, SearchField) {
namespace {
-class MockAutofillExternalDelegate : public AutofillExternalDelegate {
+class MockAutofillExternalDelegate : public TestAutofillExternalDelegate {
public:
explicit MockAutofillExternalDelegate(TabContentsWrapper* wrapper)
- : AutofillExternalDelegate(wrapper, NULL) {}
+ : TestAutofillExternalDelegate(wrapper, NULL) {}
virtual ~MockAutofillExternalDelegate() {}
- virtual void OnQuery(int query_id,
- const webkit::forms::FormData& form,
- const webkit::forms::FormField& field,
- const gfx::Rect& bounds,
- bool display_warning) OVERRIDE {}
+ virtual void ApplyAutofillSuggestions(
+ const std::vector<string16>& autofill_values,
+ const std::vector<string16>& autofill_labels,
+ const std::vector<string16>& autofill_icons,
+ const std::vector<int>& autofill_unique_ids,
+ int separator_index) OVERRIDE {};
MOCK_METHOD5(OnSuggestionsReturned,
void(int query_id,
@@ -158,22 +159,6 @@ class MockAutofillExternalDelegate : public AutofillExternalDelegate {
const std::vector<string16>& autofill_icons,
const std::vector<int>& autofill_unique_ids));
- virtual void HideAutofillPopup() OVERRIDE {}
-
-
- virtual void ApplyAutofillSuggestions(
- const std::vector<string16>& autofill_values,
- const std::vector<string16>& autofill_labels,
- const std::vector<string16>& autofill_icons,
- const std::vector<int>& autofill_unique_ids,
- int separator_index) OVERRIDE {}
-
- virtual void OnQueryPlatformSpecific(
- int query_id,
- const webkit::forms::FormData& form,
- const webkit::forms::FormField& field,
- const gfx::Rect& bounds) OVERRIDE {}
-
private:
DISALLOW_COPY_AND_ASSIGN(MockAutofillExternalDelegate);
};
diff --git a/chrome/browser/autofill/autofill_external_delegate.cc b/chrome/browser/autofill/autofill_external_delegate.cc
index f3a7e94..491ffee 100644
--- a/chrome/browser/autofill/autofill_external_delegate.cc
+++ b/chrome/browser/autofill/autofill_external_delegate.cc
@@ -24,15 +24,19 @@ AutofillExternalDelegate::AutofillExternalDelegate(
autofill_manager_(autofill_manager),
autofill_query_id_(0),
display_warning_if_disabled_(false),
- has_shown_autofill_popup_for_current_edit_(false) {
+ has_shown_autofill_popup_for_current_edit_(false),
+ suggestions_clear_index_(-1),
+ suggestions_options_index_(-1) {
}
-void AutofillExternalDelegate::SelectAutofillSuggestionAtIndex(int listIndex) {
- RenderViewHost* host =
- tab_contents_wrapper_->web_contents()->GetRenderViewHost();
- host->Send(new AutofillMsg_SelectAutofillSuggestionAtIndex(
- host->routing_id(),
- listIndex));
+void AutofillExternalDelegate::SelectAutofillSuggestionAtIndex(int unique_id,
+ int list_index) {
+ if (list_index == suggestions_options_index_ ||
+ list_index == suggestions_clear_index_ ||
+ unique_id == -1)
+ return;
+
+ FillAutofillFormData(unique_id, true);
}
void AutofillExternalDelegate::OnQuery(int query_id,
@@ -40,6 +44,7 @@ void AutofillExternalDelegate::OnQuery(int query_id,
const webkit::forms::FormField& field,
const gfx::Rect& bounds,
bool display_warning_if_disabled) {
+ autofill_query_form_ = form;
autofill_query_field_ = field;
display_warning_if_disabled_ = display_warning_if_disabled;
autofill_query_id_ = query_id;
@@ -47,10 +52,6 @@ void AutofillExternalDelegate::OnQuery(int query_id,
OnQueryPlatformSpecific(query_id, form, field, bounds);
}
-void AutofillExternalDelegate::DidEndTextFieldEditing() {
- has_shown_autofill_popup_for_current_edit_ = false;
-}
-
void AutofillExternalDelegate::OnSuggestionsReturned(
int query_id,
const std::vector<string16>& values,
@@ -110,6 +111,7 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
l.push_back(string16());
i.push_back(string16());
ids.push_back(0);
+ suggestions_clear_index_ = v.size() - 1;
separator_index = v.size() - 1;
}
@@ -119,6 +121,7 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
l.push_back(string16());
i.push_back(string16());
ids.push_back(0);
+ suggestions_options_index_ = v.size() - 1;
separator_index = values.size();
}
@@ -131,6 +134,77 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
has_shown_autofill_popup_for_current_edit_ |= has_autofill_item;
}
+void AutofillExternalDelegate::DidEndTextFieldEditing() {
+ has_shown_autofill_popup_for_current_edit_ = false;
+}
+
+void AutofillExternalDelegate::DidAcceptAutofillSuggestions(string16 value,
+ int unique_id,
+ unsigned index) {
+ // If the selected element is a warning we don't want to do anything.
+ if (unique_id < 0)
+ return;
+
+ // TODO(csharp): Add the password autofill manager.
+ // if (password_autofill_manager_->DidAcceptAutofillSuggestion(node, value))
+ // return;
+
+ if (suggestions_options_index_ != -1 &&
+ index == static_cast<unsigned>(suggestions_options_index_)) {
+ // User selected 'Autofill Options'.
+ autofill_manager_->OnShowAutofillDialog();
+ } else if (suggestions_clear_index_ != -1 &&
+ index == static_cast<unsigned>(suggestions_clear_index_)) {
+ // User selected 'Clear form'.
+ RenderViewHost* host =
+ tab_contents_wrapper_->web_contents()->GetRenderViewHost();
+ host->Send(new AutofillMsg_ClearForm(host->routing_id()));
+ } else if (!unique_id) {
+ // User selected an Autocomplete entry, so we fill directly.
+ RenderViewHost* host =
+ tab_contents_wrapper_->web_contents()->GetRenderViewHost();
+ host->Send(new AutofillMsg_SetNodeText(
+ host->routing_id(),
+ value));
+ } else {
+ FillAutofillFormData(unique_id, false);
+ }
+
+ HideAutofillPopup();
+}
+
+void AutofillExternalDelegate::ClearPreviewedForm() {
+ RenderViewHost* host =
+ tab_contents_wrapper_->web_contents()->GetRenderViewHost();
+ host->Send(new AutofillMsg_ClearPreviewedForm(host->routing_id()));
+}
+
+void AutofillExternalDelegate::HideAutofillPopup() {
+ suggestions_clear_index_ = -1;
+ suggestions_options_index_ = -1;
+
+ HideAutofillPopupInternal();
+}
+
+void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
+ bool is_preview) {
+ RenderViewHost* host =
+ tab_contents_wrapper_->web_contents()->GetRenderViewHost();
+
+ if (is_preview) {
+ host->Send(new AutofillMsg_SetAutofillActionPreview(
+ host->routing_id()));
+ } else {
+ host->Send(new AutofillMsg_SetAutofillActionFill(
+ host->routing_id()));
+ }
+
+ // Fill the values for the whole form.
+ autofill_manager_->OnFillAutofillFormData(autofill_query_id_,
+ autofill_query_form_,
+ autofill_query_field_,
+ unique_id);
+}
// Add a "!defined(OS_YOUROS) for each platform that implements this
// in an autofill_external_delegate_YOUROS.cc. Currently there are
diff --git a/chrome/browser/autofill/autofill_external_delegate.h b/chrome/browser/autofill/autofill_external_delegate.h
index 20d15bb..6953594 100644
--- a/chrome/browser/autofill/autofill_external_delegate.h
+++ b/chrome/browser/autofill/autofill_external_delegate.h
@@ -8,7 +8,9 @@
#include <vector>
+#include "base/compiler_specific.h"
#include "base/string16.h"
+#include "webkit/forms/form_data.h"
#include "webkit/forms/form_field.h"
class AutofillManager;
@@ -18,12 +20,6 @@ namespace gfx {
class Rect;
}
-namespace webkit {
-namespace forms {
-struct FormData;
-}
-}
-
// TODO(csharp): A lot of the logic in this class is copied from autofillagent.
// Once Autofill is moved out of WebKit this class should be the only home for
// this logic. See http://crbug.com/51644
@@ -37,7 +33,7 @@ class AutofillExternalDelegate {
// When using an external Autofill delegate. Allows Chrome to tell
// WebKit which Autofill selection has been chosen.
// TODO(jrg): add feedback mechanism for hover on relevant platforms.
- void SelectAutofillSuggestionAtIndex(int listIndex);
+ virtual void SelectAutofillSuggestionAtIndex(int unique_id, int list_index);
// Records and associates a query_id with web form data. Called
// when the renderer posts an Autofill query to the browser. |bounds|
@@ -61,8 +57,20 @@ class AutofillExternalDelegate {
const std::vector<string16>& autofill_icons,
const std::vector<int>& autofill_unique_ids);
+ // Inform the delegate that the text field editing has ended, this is
+ // used to help record the metrics of when a new popup is shown.
+ void DidEndTextFieldEditing();
+
+ // Inform the delegate that an autofill suggestion have been chosen.
+ void DidAcceptAutofillSuggestions(string16 value,
+ int unique_id,
+ unsigned index);
+
+ // Informs the delegate that the Autofill previewed form should be cleared.
+ virtual void ClearPreviewedForm();
+
// Hide the Autofill poup.
- virtual void HideAutofillPopup() = 0;
+ virtual void HideAutofillPopup();
// Platforms that wish to implement an external Autofill delegate
// MUST implement this. The 1st arg is the tab contents that owns
@@ -70,11 +78,6 @@ class AutofillExternalDelegate {
// tab contents.
static AutofillExternalDelegate* Create(TabContentsWrapper*,
AutofillManager*);
-
- // Inform the delegate that the text field editing has ended, this is
- // used to help record the metrics of when a new popup is shown.
- void DidEndTextFieldEditing();
-
protected:
explicit AutofillExternalDelegate(TabContentsWrapper* tab_contents_wrapper,
AutofillManager* autofill_manager);
@@ -95,7 +98,16 @@ class AutofillExternalDelegate {
const webkit::forms::FormField& field,
const gfx::Rect& bounds) = 0;
+ // Handle platform-dependent hiding.
+ virtual void HideAutofillPopupInternal() = 0;
+
private:
+ // Fills the form with the Autofill data corresponding to |unique_id|.
+ // If |is_preview| is true then this is just a preview to show the user what
+ // would be selected and if |is_preview| is false then the user has selected
+ // this data.
+ void FillAutofillFormData(int unique_id, bool is_preview);
+
TabContentsWrapper* tab_contents_wrapper_; // weak; owns me.
AutofillManager* autofill_manager_; // weak.
@@ -103,7 +115,8 @@ class AutofillExternalDelegate {
// out of date responses.
int autofill_query_id_;
- // The current field selected by Autofill.
+ // The current form and field selected by Autofill.
+ webkit::forms::FormData autofill_query_form_;
webkit::forms::FormField autofill_query_field_;
// Should we display a warning if Autofill is disabled?
@@ -113,6 +126,12 @@ class AutofillExternalDelegate {
// currently editing? Used to keep track of state for metrics logging.
bool has_shown_autofill_popup_for_current_edit_;
+ // 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_;
+
DISALLOW_COPY_AND_ASSIGN(AutofillExternalDelegate);
};
diff --git a/chrome/browser/autofill/autofill_external_delegate_gtk.cc b/chrome/browser/autofill/autofill_external_delegate_gtk.cc
index 992dbd33..4c7bbfa 100644
--- a/chrome/browser/autofill/autofill_external_delegate_gtk.cc
+++ b/chrome/browser/autofill/autofill_external_delegate_gtk.cc
@@ -28,6 +28,17 @@ AutofillExternalDelegateGtk::AutofillExternalDelegateGtk(
AutofillExternalDelegateGtk::~AutofillExternalDelegateGtk() {
}
+void AutofillExternalDelegateGtk::HideAutofillPopupInternal() {
+ if (!view_.get())
+ return;
+
+ view_->Hide();
+ view_.reset();
+
+ GtkWidget* toplevel = gtk_widget_get_toplevel(tab_native_view_);
+ g_signal_handler_disconnect(toplevel, event_handler_id_);
+}
+
void AutofillExternalDelegateGtk::OnQueryPlatformSpecific(
int query_id,
const webkit::forms::FormData& form,
@@ -50,22 +61,12 @@ void AutofillExternalDelegateGtk::ApplyAutofillSuggestions(
separator_index);
}
-void AutofillExternalDelegateGtk::HideAutofillPopup() {
- if (!view_.get())
- return;
-
- view_->Hide();
- view_.reset();
-
- GtkWidget* toplevel = gtk_widget_get_toplevel(tab_native_view_);
- g_signal_handler_disconnect(toplevel, event_handler_id_);
-}
-
void AutofillExternalDelegateGtk::CreateViewIfNeeded() {
if (view_.get())
return;
view_.reset(new AutofillPopupViewGtk(web_contents_,
+ this,
tab_native_view_));
GtkWidget* toplevel = gtk_widget_get_toplevel(tab_native_view_);
diff --git a/chrome/browser/autofill/autofill_external_delegate_gtk.h b/chrome/browser/autofill/autofill_external_delegate_gtk.h
index 31e2fd0..c2f9185 100644
--- a/chrome/browser/autofill/autofill_external_delegate_gtk.h
+++ b/chrome/browser/autofill/autofill_external_delegate_gtk.h
@@ -26,11 +26,9 @@ class AutofillExternalDelegateGtk : public AutofillExternalDelegate {
virtual ~AutofillExternalDelegateGtk();
- // AutofillExternalDelegate implementation.
- virtual void HideAutofillPopup() OVERRIDE;
-
protected:
// AutofillExternalDelegate implementations.
+ virtual void HideAutofillPopupInternal() OVERRIDE;
virtual void OnQueryPlatformSpecific(
int query_id,
const webkit::forms::FormData& form,
diff --git a/chrome/browser/autofill/autofill_external_delegate_unittest.cc b/chrome/browser/autofill/autofill_external_delegate_unittest.cc
index f9e6f6c..e0ba283 100644
--- a/chrome/browser/autofill/autofill_external_delegate_unittest.cc
+++ b/chrome/browser/autofill/autofill_external_delegate_unittest.cc
@@ -7,8 +7,8 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/string16.h"
-#include "chrome/browser/autofill/autofill_external_delegate.h"
#include "chrome/browser/autofill/autofill_manager.h"
+#include "chrome/browser/autofill/test_autofill_external_delegate.h"
#include "chrome/browser/ui/tab_contents/test_tab_contents_wrapper.h"
#include "chrome/test/base/testing_profile.h"
#include "content/test/test_browser_thread.h"
@@ -25,14 +25,12 @@ using webkit::forms::FormField;
namespace {
-class MockAutofillExternalDelegate : public AutofillExternalDelegate {
+class MockAutofillExternalDelegate : public TestAutofillExternalDelegate {
public:
- explicit MockAutofillExternalDelegate(TabContentsWrapper* wrapper,
- AutofillManager* autofill_manager)
- : AutofillExternalDelegate(wrapper, autofill_manager) {}
- virtual ~MockAutofillExternalDelegate() {}
-
- virtual void HideAutofillPopup() OVERRIDE {}
+ MockAutofillExternalDelegate(TabContentsWrapper* wrapper,
+ AutofillManager* autofill_manger)
+ : TestAutofillExternalDelegate(wrapper, autofill_manger) {}
+ ~MockAutofillExternalDelegate() {}
MOCK_METHOD5(ApplyAutofillSuggestions, void(
const std::vector<string16>& autofill_values,
@@ -47,36 +45,53 @@ class MockAutofillExternalDelegate : public AutofillExternalDelegate {
const webkit::forms::FormField& field,
const gfx::Rect& bounds));
+ MOCK_METHOD0(HideAutofillPopup, void());
+
private:
- DISALLOW_COPY_AND_ASSIGN(MockAutofillExternalDelegate);
+ virtual void HideAutofillPopupInternal() {};
+};
+
+class MockAutofillManager : public AutofillManager {
+ public:
+ explicit MockAutofillManager(TabContentsWrapper* tab_contents)
+ : AutofillManager(tab_contents) {}
+ ~MockAutofillManager() {}
+
+ MOCK_METHOD4(OnFillAutofillFormData,
+ void(int query_id,
+ const webkit::forms::FormData& form,
+ const webkit::forms::FormField& field,
+ int unique_id));
};
} // namespace
-class AutofillExternalDelegateTest : public TabContentsWrapperTestHarness {
+class AutofillExternalDelegateUnitTest : public TabContentsWrapperTestHarness {
public:
- AutofillExternalDelegateTest()
+ AutofillExternalDelegateUnitTest()
: ui_thread_(BrowserThread::UI, &message_loop_) {}
- virtual ~AutofillExternalDelegateTest() {}
+ virtual ~AutofillExternalDelegateUnitTest() {}
virtual void SetUp() OVERRIDE {
TabContentsWrapperTestHarness::SetUp();
- autofill_manager_ = new AutofillManager(contents_wrapper());
+ autofill_manager_ = new MockAutofillManager(contents_wrapper());
+ external_delegate_.reset(new MockAutofillExternalDelegate(
+ contents_wrapper(),
+ autofill_manager_));
}
protected:
- scoped_refptr<AutofillManager> autofill_manager_;
+ scoped_refptr<MockAutofillManager> autofill_manager_;
+ scoped_ptr<MockAutofillExternalDelegate> external_delegate_;
private:
content::TestBrowserThread ui_thread_;
- DISALLOW_COPY_AND_ASSIGN(AutofillExternalDelegateTest);
+ DISALLOW_COPY_AND_ASSIGN(AutofillExternalDelegateUnitTest);
};
// Test that our external delegate called the virtual methods at the right time.
-TEST_F(AutofillExternalDelegateTest, TestExternalDelegateVirtualCalls) {
- MockAutofillExternalDelegate external_delegate(contents_wrapper(),
- autofill_manager_);
+TEST_F(AutofillExternalDelegateUnitTest, TestExternalDelegateVirtualCalls) {
const int kQueryId = 5;
const FormData form;
FormField field;
@@ -84,23 +99,42 @@ TEST_F(AutofillExternalDelegateTest, TestExternalDelegateVirtualCalls) {
field.should_autocomplete = true;
const gfx::Rect bounds;
- EXPECT_CALL(external_delegate,
+ EXPECT_CALL(*external_delegate_,
OnQueryPlatformSpecific(kQueryId, form, field, bounds));
// This should call OnQueryPlatform specific.
- external_delegate.OnQuery(kQueryId, form, field, bounds, false);
-
+ external_delegate_->OnQuery(kQueryId, form, field, bounds, false);
- EXPECT_CALL(external_delegate, ApplyAutofillSuggestions(_, _, _, _, _));
+ EXPECT_CALL(*external_delegate_, ApplyAutofillSuggestions(_, _, _, _, _));
// This should call ApplyAutofillSuggestions.
std::vector<string16> autofill_item;
autofill_item.push_back(string16());
std::vector<int> autofill_ids;
autofill_ids.push_back(1);
- external_delegate.OnSuggestionsReturned(kQueryId,
- autofill_item,
- autofill_item,
- autofill_item,
- autofill_ids);
+ external_delegate_->OnSuggestionsReturned(kQueryId,
+ autofill_item,
+ autofill_item,
+ autofill_item,
+ autofill_ids);
+
+
+ EXPECT_CALL(*external_delegate_, HideAutofillPopup());
+
+ // This should trigger a call to hide the popup since
+ // we've selected an option.
+ external_delegate_->DidAcceptAutofillSuggestions(autofill_item[0],
+ autofill_ids[0], 0);
+}
+
+// Test that the Autofill delegate doesn't try and fill a form with a
+// negative unique id.
+TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateInvalidUniqueId) {
+ // Ensure it doesn't try to preview the negative id.
+ EXPECT_CALL(*autofill_manager_, OnFillAutofillFormData(_, _, _, _)).Times(0);
+ external_delegate_->SelectAutofillSuggestionAtIndex(-1, 0);
+
+ // Ensure it doesn't try to fill the form in with the negative id.
+ EXPECT_CALL(*autofill_manager_, OnFillAutofillFormData(_, _, _, _)).Times(0);
+ external_delegate_->DidAcceptAutofillSuggestions(string16(), -1, 0);
}
diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h
index 9079d09..058ee25 100644
--- a/chrome/browser/autofill/autofill_manager.h
+++ b/chrome/browser/autofill/autofill_manager.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -71,12 +71,14 @@ class AutofillManager : public content::WebContentsObserver,
}
// Called from our external delegate so they cannot be private.
- void OnFillAutofillFormData(int query_id,
- const webkit::forms::FormData& form,
- const webkit::forms::FormField& field,
- int unique_id);
+ virtual void OnFillAutofillFormData(int query_id,
+ const webkit::forms::FormData& form,
+ const webkit::forms::FormField& field,
+ int unique_id);
void OnDidShowAutofillSuggestions(bool is_new_popup);
void OnDidFillAutofillFormData(const base::TimeTicks& timestamp);
+ void OnShowAutofillDialog();
+ void OnDidPreviewAutofillFormData();
protected:
// Only test code should subclass AutofillManager.
@@ -158,8 +160,6 @@ class AutofillManager : public content::WebContentsObserver,
const webkit::forms::FormField& field,
const gfx::Rect& bounding_box,
bool display_warning);
- void OnShowAutofillDialog();
- void OnDidPreviewAutofillFormData();
void OnDidEndTextFieldEditing();
void OnHideAutofillPopup();
diff --git a/chrome/browser/autofill/autofill_manager_unittest.cc b/chrome/browser/autofill/autofill_manager_unittest.cc
index ee42ca3..3d1e400 100644
--- a/chrome/browser/autofill/autofill_manager_unittest.cc
+++ b/chrome/browser/autofill/autofill_manager_unittest.cc
@@ -15,12 +15,12 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete_history_manager.h"
#include "chrome/browser/autofill/autofill_common_test.h"
-#include "chrome/browser/autofill/autofill_external_delegate.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h"
+#include "chrome/browser/autofill/test_autofill_external_delegate.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
@@ -2862,11 +2862,11 @@ TEST_F(AutofillManagerTest, DeterminePossibleFieldTypesForUpload) {
namespace {
-class MockAutofillExternalDelegate : public AutofillExternalDelegate {
+class MockAutofillExternalDelegate : public TestAutofillExternalDelegate {
public:
explicit MockAutofillExternalDelegate(TabContentsWrapper* wrapper,
AutofillManager* autofill_manager)
- : AutofillExternalDelegate(wrapper, autofill_manager) {}
+ : TestAutofillExternalDelegate(wrapper, autofill_manager) {}
virtual ~MockAutofillExternalDelegate() {}
MOCK_METHOD5(OnQuery, void(int query_id,
@@ -2875,15 +2875,6 @@ class MockAutofillExternalDelegate : public AutofillExternalDelegate {
const gfx::Rect& bounds,
bool display_warning));
- virtual void HideAutofillPopup() OVERRIDE {}
-
- virtual void ApplyAutofillSuggestions(
- const std::vector<string16>& autofill_values,
- const std::vector<string16>& autofill_labels,
- const std::vector<string16>& autofill_icons,
- const std::vector<int>& autofill_unique_ids,
- int separator_index) OVERRIDE {}
-
virtual void OnQueryPlatformSpecific(int query_id,
const webkit::forms::FormData& form,
const webkit::forms::FormField& field,
diff --git a/chrome/browser/autofill/autofill_popup_view.cc b/chrome/browser/autofill/autofill_popup_view.cc
index bd28553..7e3ba5a 100644
--- a/chrome/browser/autofill/autofill_popup_view.cc
+++ b/chrome/browser/autofill/autofill_popup_view.cc
@@ -4,13 +4,19 @@
#include "chrome/browser/autofill/autofill_popup_view.h"
+#include "base/logging.h"
+#include "chrome/browser/autofill/autofill_external_delegate.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
-AutofillPopupView::AutofillPopupView(content::WebContents* web_contents) {
+AutofillPopupView::AutofillPopupView(
+ content::WebContents* web_contents,
+ AutofillExternalDelegate* external_delegate)
+ : external_delegate_(external_delegate),
+ selected_line_(-1) {
registrar_.Add(this,
content::NOTIFICATION_WEB_CONTENTS_HIDDEN,
content::Source<content::WebContents>(web_contents));
@@ -23,6 +29,12 @@ AutofillPopupView::AutofillPopupView(content::WebContents* web_contents) {
AutofillPopupView::~AutofillPopupView() {}
+void AutofillPopupView::Hide() {
+ HideInternal();
+
+ external_delegate_->ClearPreviewedForm();
+}
+
void AutofillPopupView::Show(const std::vector<string16>& autofill_values,
const std::vector<string16>& autofill_labels,
const std::vector<string16>& autofill_icons,
@@ -38,6 +50,25 @@ void AutofillPopupView::Show(const std::vector<string16>& autofill_values,
ShowInternal();
}
+void AutofillPopupView::SetSelectedLine(int selected_line) {
+ if (selected_line_ == selected_line)
+ return;
+
+ if (selected_line_ != -1)
+ InvalidateRow(selected_line_);
+
+ if (selected_line != -1)
+ InvalidateRow(selected_line);
+
+ selected_line_ = selected_line;
+
+ if (selected_line_ != -1) {
+ external_delegate_->SelectAutofillSuggestionAtIndex(
+ autofill_unique_ids_[selected_line_],
+ selected_line);
+ }
+}
+
void AutofillPopupView::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
diff --git a/chrome/browser/autofill/autofill_popup_view.h b/chrome/browser/autofill/autofill_popup_view.h
index 9344ee0..1ca8908 100644
--- a/chrome/browser/autofill/autofill_popup_view.h
+++ b/chrome/browser/autofill/autofill_popup_view.h
@@ -18,13 +18,16 @@ namespace content {
class WebContents;
}
+class AutofillExternalDelegate;
+
class AutofillPopupView : public content::NotificationObserver {
public:
- explicit AutofillPopupView(content::WebContents* web_contents);
+ explicit AutofillPopupView(content::WebContents* web_contents,
+ AutofillExternalDelegate* external_delegate_);
virtual ~AutofillPopupView();
- // Hide the popup from view.
- virtual void Hide() = 0;
+ // Hide the popup from view. Platform-indepent work.
+ virtual void Hide();
// Display the autofill popup and fill it in with the values passed in.
// Platform-independent work.
@@ -34,7 +37,6 @@ class AutofillPopupView : public content::NotificationObserver {
const std::vector<int>& autofill_unique_ids,
int separator_index);
-
void set_element_bounds(const gfx::Rect& bounds) {
element_bounds_ = bounds;
}
@@ -46,6 +48,14 @@ class AutofillPopupView : public content::NotificationObserver {
// Platform-dependent work.
virtual void ShowInternal() = 0;
+ // Hide the popup from view. Platform-dependent work.
+ virtual void HideInternal() = 0;
+
+ // Invalide the given row and redraw it.
+ virtual void InvalidateRow(size_t row) = 0;
+
+ AutofillExternalDelegate* external_delegate() { return external_delegate_; }
+
const std::vector<string16>& autofill_values() const {
return autofill_values_;
}
@@ -55,8 +65,16 @@ class AutofillPopupView : public content::NotificationObserver {
const std::vector<string16>& autofill_icons() const {
return autofill_icons_;
}
+ const std::vector<int>& autofill_unique_ids() const {
+ return autofill_unique_ids_;
+ }
int separator_index() const { return separator_index_; }
+ int selected_line() const { return selected_line_; }
+
+ // Change which line is currently selected by the user.
+ void SetSelectedLine(int selected_line);
+
private:
// content::NotificationObserver method override.
virtual void Observe(int type,
@@ -66,6 +84,8 @@ class AutofillPopupView : public content::NotificationObserver {
// A scoped container for notification registries.
content::NotificationRegistrar registrar_;
+ AutofillExternalDelegate* external_delegate_;
+
// The bounds of the text element that is the focus of the Autofill.
gfx::Rect element_bounds_;
@@ -78,6 +98,10 @@ class AutofillPopupView : public content::NotificationObserver {
// The location of the separator index (which separates the returned values
// from the Autofill options).
int separator_index_;
+
+ // The line that is currently selected by the user.
+ // -1 indicates that no line is currently selected.
+ int selected_line_;
};
#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_POPUP_VIEW_H_
diff --git a/chrome/browser/autofill/autofill_popup_view_browsertest.cc b/chrome/browser/autofill/autofill_popup_view_browsertest.cc
index 06b80ad..1990a97 100644
--- a/chrome/browser/autofill/autofill_popup_view_browsertest.cc
+++ b/chrome/browser/autofill/autofill_popup_view_browsertest.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/autofill/autofill_popup_view.h"
#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/autofill/test_autofill_external_delegate.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/navigation_controller.h"
@@ -18,38 +19,70 @@
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::AtLeast;
+using testing::_;
+
+namespace {
+
+class MockAutofillExternalDelegate : public TestAutofillExternalDelegate {
+ public:
+ MockAutofillExternalDelegate() : TestAutofillExternalDelegate(NULL, NULL) {}
+ ~MockAutofillExternalDelegate() {}
+
+ virtual void SelectAutofillSuggestionAtIndex(int unique_id, int list_index)
+ OVERRIDE {}
+};
class TestAutofillPopupView : public AutofillPopupView {
public:
- explicit TestAutofillPopupView(content::WebContents* web_contents)
- : AutofillPopupView(web_contents) {}
+ explicit TestAutofillPopupView(
+ content::WebContents* web_contents,
+ AutofillExternalDelegate* autofill_external_delegate)
+ : AutofillPopupView(web_contents, autofill_external_delegate) {}
virtual ~TestAutofillPopupView() {}
MOCK_METHOD0(Hide, void());
+ MOCK_METHOD1(InvalidateRow, void(size_t));
+
+ void SetSelectedLine(size_t selected_line) {
+ AutofillPopupView::SetSelectedLine(selected_line);
+ }
+
+ protected:
virtual void ShowInternal() OVERRIDE {}
+
+ virtual void HideInternal() OVERRIDE {}
};
+} // namespace
+
class AutofillPopupViewBrowserTest : public InProcessBrowserTest {
public:
AutofillPopupViewBrowserTest() {}
virtual ~AutofillPopupViewBrowserTest() {}
+ virtual void SetUpOnMainThread() OVERRIDE {
+ web_contents_ = browser()->GetSelectedWebContents();
+ ASSERT_TRUE(web_contents_ != NULL);
+
+ autofill_popup_view_.reset(new TestAutofillPopupView(
+ web_contents_,
+ &autofill_external_delegate_));
+ }
+
protected:
+ content::WebContents* web_contents_;
scoped_ptr<TestAutofillPopupView> autofill_popup_view_;
+ MockAutofillExternalDelegate autofill_external_delegate_;
};
-IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, SwitchTabAndHideAutofillPopup) {
- content::WebContents* web_contents = browser()->GetSelectedWebContents();
- TestAutofillPopupView autofill_popup_view(web_contents);
-
- // Using AtLeast here because current Hide is called once on Linux and Mac,
- // and three times on Windows and ChromeOS. http://crbug.com/109269
- EXPECT_CALL(autofill_popup_view, Hide()).Times(AtLeast(1));
+IN_PROC_BROWSER_TEST_F(AutofillPopupViewBrowserTest,
+ SwitchTabAndHideAutofillPopup) {
+ EXPECT_CALL(*autofill_popup_view_, Hide()).Times(AtLeast(1));
ui_test_utils::WindowedNotificationObserver observer(
content::NOTIFICATION_WEB_CONTENTS_HIDDEN,
- content::Source<content::WebContents>(web_contents));
+ content::Source<content::WebContents>(web_contents_));
browser()->AddSelectedTabWithURL(GURL(chrome::kAboutBlankURL),
content::PAGE_TRANSITION_START_PAGE);
observer.Wait();
@@ -57,16 +90,14 @@ IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, SwitchTabAndHideAutofillPopup) {
// The mock verifies that the call was made.
}
-IN_PROC_BROWSER_TEST_F(InProcessBrowserTest,
+IN_PROC_BROWSER_TEST_F(AutofillPopupViewBrowserTest,
TestPageNavigationHidingAutofillPopup) {
- content::WebContents* web_contents = browser()->GetSelectedWebContents();
- TestAutofillPopupView autofill_popup_view(web_contents);
- EXPECT_CALL(autofill_popup_view, Hide());
+ EXPECT_CALL(*autofill_popup_view_, Hide()).Times(AtLeast(1));
ui_test_utils::WindowedNotificationObserver observer(
content::NOTIFICATION_NAV_ENTRY_COMMITTED,
content::Source<content::NavigationController>(
- &(web_contents->GetController())));
+ &(web_contents_->GetController())));
browser()->OpenURL(content::OpenURLParams(
GURL(chrome::kAboutBlankURL), content::Referrer(),
CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false));
@@ -77,3 +108,27 @@ IN_PROC_BROWSER_TEST_F(InProcessBrowserTest,
// The mock verifies that the call was made.
}
+
+IN_PROC_BROWSER_TEST_F(AutofillPopupViewBrowserTest,
+ SetSelectedAutofillLineAndCallInvalidate) {
+ std::vector<string16> autofill_values;
+ autofill_values.push_back(string16());
+ std::vector<int> autofill_ids;
+ autofill_ids.push_back(0);
+ autofill_popup_view_->Show(
+ autofill_values, autofill_values, autofill_values, autofill_ids, 0);
+
+ // Make sure that when a new line is selected, it is invalidated so it can
+ // be updated to show it is selected.
+ int selected_line = 0;
+ EXPECT_CALL(*autofill_popup_view_, InvalidateRow(selected_line));
+ autofill_popup_view_->SetSelectedLine(selected_line);
+
+ // Ensure that the row isn't invalidated if it didn't change.
+ EXPECT_CALL(*autofill_popup_view_, InvalidateRow(selected_line)).Times(0);
+ autofill_popup_view_->SetSelectedLine(selected_line);
+
+ // Change back to no selection.
+ EXPECT_CALL(*autofill_popup_view_, InvalidateRow(selected_line));
+ autofill_popup_view_->SetSelectedLine(-1);
+}
diff --git a/chrome/browser/autofill/test_autofill_external_delegate.cc b/chrome/browser/autofill/test_autofill_external_delegate.cc
new file mode 100644
index 0000000..9f076f1
--- /dev/null
+++ b/chrome/browser/autofill/test_autofill_external_delegate.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/autofill/test_autofill_external_delegate.h"
+
+TestAutofillExternalDelegate::TestAutofillExternalDelegate(
+ TabContentsWrapper* wrapper, AutofillManager* autofill_manager) :
+ AutofillExternalDelegate(wrapper, autofill_manager) {}
+
+TestAutofillExternalDelegate::~TestAutofillExternalDelegate() {}
+
+void TestAutofillExternalDelegate::ApplyAutofillSuggestions(
+ const std::vector<string16>& autofill_values,
+ const std::vector<string16>& autofill_labels,
+ const std::vector<string16>& autofill_icons,
+ const std::vector<int>& autofill_unique_ids,
+ int separator_index) {}
+
+void TestAutofillExternalDelegate::OnQueryPlatformSpecific(
+ int query_id,
+ const webkit::forms::FormData& form,
+ const webkit::forms::FormField& field,
+ const gfx::Rect& bounds) {}
+
+void TestAutofillExternalDelegate::HideAutofillPopupInternal() {}
diff --git a/chrome/browser/autofill/test_autofill_external_delegate.h b/chrome/browser/autofill/test_autofill_external_delegate.h
new file mode 100644
index 0000000..771fcf8
--- /dev/null
+++ b/chrome/browser/autofill/test_autofill_external_delegate.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_AUTOFILL_TEST_AUTOFILL_EXTERNAL_DELEGATE_H_
+#define CHROME_BROWSER_AUTOFILL_TEST_AUTOFILL_EXTERNAL_DELEGATE_H_
+#pragma once
+
+#include "chrome/browser/autofill/autofill_external_delegate.h"
+
+class AutofillManager;
+class TabContentsWrapper;
+
+// This test class is meant to give tests a base AutofillExternalDelegate
+// class that requires no additional work to compile with (i.e. all the
+// pure virtual functions have been giving empty methods).
+class TestAutofillExternalDelegate : public AutofillExternalDelegate {
+ public:
+ TestAutofillExternalDelegate(TabContentsWrapper* wrapper,
+ AutofillManager* autofill_manager);
+ virtual ~TestAutofillExternalDelegate();
+
+ virtual void ApplyAutofillSuggestions(
+ const std::vector<string16>& autofill_values,
+ const std::vector<string16>& autofill_labels,
+ const std::vector<string16>& autofill_icons,
+ const std::vector<int>& autofill_unique_ids,
+ int separator_index) OVERRIDE;
+
+ virtual void OnQueryPlatformSpecific(int query_id,
+ const webkit::forms::FormData& form,
+ const webkit::forms::FormField& field,
+ const gfx::Rect& bounds) OVERRIDE;
+
+
+ virtual void HideAutofillPopupInternal() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestAutofillExternalDelegate);
+};
+
+#endif // CHROME_BROWSER_AUTOFILL_TEST_AUTOFILL_EXTERNAL_DELEGATE_H_
diff --git a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc
index 93a347e..c65d110 100644
--- a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc
+++ b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/autofill/autofill_external_delegate.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "ui/base/gtk/gtk_compat.h"
#include "ui/base/gtk/gtk_hig_constants.h"
@@ -15,6 +16,7 @@
namespace {
const GdkColor kBorderColor = GDK_COLOR_RGB(0xc7, 0xca, 0xce);
+const GdkColor kHoveredBackgroundColor = GDK_COLOR_RGB(0x0CD, 0xCD, 0xCD);
const GdkColor kTextColor = GDK_COLOR_RGB(0x00, 0x00, 0x00);
// The amount of minimum padding between the Autofill value and label in pixels.
@@ -35,9 +37,11 @@ gfx::Rect GetRectForRow(size_t index, int width, int height) {
} // namespace
-AutofillPopupViewGtk::AutofillPopupViewGtk(content::WebContents* web_contents,
- GtkWidget* parent)
- : AutofillPopupView(web_contents),
+AutofillPopupViewGtk::AutofillPopupViewGtk(
+ content::WebContents* web_contents,
+ AutofillExternalDelegate* external_delegate,
+ GtkWidget* parent)
+ : AutofillPopupView(web_contents, external_delegate),
parent_(parent),
window_(gtk_window_new(GTK_WINDOW_POPUP)) {
CHECK(parent != NULL);
@@ -45,11 +49,19 @@ AutofillPopupViewGtk::AutofillPopupViewGtk(content::WebContents* web_contents,
gtk_widget_set_app_paintable(window_, TRUE);
gtk_widget_set_double_buffered(window_, TRUE);
- // Setup the window to ensure it recieves the expose event.
- gtk_widget_add_events(window_, GDK_EXPOSURE_MASK);
+ // Setup the window to ensure it receives the expose event.
+ gtk_widget_add_events(window_, GDK_BUTTON_MOTION_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_EXPOSURE_MASK |
+ GDK_POINTER_MOTION_MASK);
g_signal_connect(window_, "expose-event",
G_CALLBACK(HandleExposeThunk), this);
+ g_signal_connect(window_, "motion-notify-event",
+ G_CALLBACK(HandleMotionThunk), this);
+ g_signal_connect(window_, "button-release-event",
+ G_CALLBACK(HandleButtonReleaseThunk), this);
+
// Cache the layout so we don't have to create it for every expose.
layout_ = gtk_widget_create_pango_layout(window_, NULL);
@@ -61,19 +73,7 @@ AutofillPopupViewGtk::~AutofillPopupViewGtk() {
gtk_widget_destroy(window_);
}
-void AutofillPopupViewGtk::Hide() {
- gtk_widget_hide(window_);
-}
-
void AutofillPopupViewGtk::ShowInternal() {
- gint origin_x, origin_y;
- gdk_window_get_origin(gtk_widget_get_window(parent_), &origin_x, &origin_y);
-
- // Move the popup to appear right below the text field it is using.
- gtk_window_move(GTK_WINDOW(window_),
- origin_x + element_bounds().x(),
- origin_y + element_bounds().y() + element_bounds().height());
-
// Find out the maximum bounds required by the popup.
// TODO(csharp): Once the icon is also displayed it will affect the required
// size so it will need to be included in the calculation.
@@ -86,6 +86,18 @@ void AutofillPopupViewGtk::ShowInternal() {
font_.GetStringWidth(autofill_labels()[i]));
}
+ gint origin_x, origin_y;
+ gdk_window_get_origin(gtk_widget_get_window(parent_), &origin_x, &origin_y);
+
+ // Move the popup to appear right below the text field it is using.
+ bounds_.SetRect(
+ origin_x + element_bounds().x(),
+ origin_y + element_bounds().y() + element_bounds().height(),
+ popup_width,
+ row_height_ * autofill_values().size());
+
+ gtk_window_move(GTK_WINDOW(window_), bounds_.x(), bounds_.y());
+
gtk_widget_set_size_request(
window_,
popup_width,
@@ -98,6 +110,33 @@ void AutofillPopupViewGtk::ShowInternal() {
ui::StackPopupWindow(window_, toplevel);
}
+void AutofillPopupViewGtk::HideInternal() {
+ gtk_widget_hide(window_);
+}
+
+void AutofillPopupViewGtk::InvalidateRow(size_t row) {
+ GdkRectangle row_rect = GetRectForRow(
+ row, bounds_.width(), row_height_).ToGdkRectangle();
+ gdk_window_invalidate_rect(window_->window, &row_rect, FALSE);
+}
+
+gboolean AutofillPopupViewGtk::HandleButtonRelease(GtkWidget* widget,
+ GdkEventButton* event) {
+ // We only care about the left click.
+ if (event->button != 1)
+ return FALSE;
+
+ size_t line = LineFromY(event->y);
+ DCHECK_LT(line, autofill_values().size());
+
+ external_delegate()->DidAcceptAutofillSuggestions(
+ autofill_values()[line],
+ autofill_unique_ids()[line],
+ line);
+
+ return TRUE;
+}
+
gboolean AutofillPopupViewGtk::HandleExpose(GtkWidget* widget,
GdkEventExpose* event) {
gfx::Rect window_rect = GetWindowRect(event->window);
@@ -139,6 +178,13 @@ gboolean AutofillPopupViewGtk::HandleExpose(GtkWidget* widget,
cairo_restore(cr);
}
+ if (selected_line() == static_cast<int>(i)) {
+ gdk_cairo_set_source_color(cr, &kHoveredBackgroundColor);
+ cairo_rectangle(cr, line_rect.x(), line_rect.y(),
+ line_rect.width(), line_rect.height());
+ cairo_fill(cr);
+ }
+
// Center the text within the line.
int content_y = std::max(
line_rect.y(),
@@ -168,6 +214,15 @@ gboolean AutofillPopupViewGtk::HandleExpose(GtkWidget* widget,
return TRUE;
}
+gboolean AutofillPopupViewGtk::HandleMotion(GtkWidget* widget,
+ GdkEventMotion* event) {
+ int line = LineFromY(event->y);
+
+ SetSelectedLine(line);
+
+ return TRUE;
+}
+
void AutofillPopupViewGtk::SetupLayout(const gfx::Rect& window_rect,
const GdkColor& text_color) {
int allocated_content_width = window_rect.width();
@@ -185,3 +240,7 @@ void AutofillPopupViewGtk::SetupLayout(const gfx::Rect& window_rect,
pango_layout_set_attributes(layout_, attrs); // Ref taken.
pango_attr_list_unref(attrs);
}
+
+int AutofillPopupViewGtk::LineFromY(int y) {
+ return y / row_height_;
+}
diff --git a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h
index 8e86987..999dd46 100644
--- a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h
+++ b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h
@@ -17,26 +17,39 @@ namespace gfx {
class Rect;
}
+typedef struct _GdkEventButton GdkEventButton;
typedef struct _GdkEventExpose GdkEventExpose;
+typedef struct _GdkEventMotion GdkEventMotion;
typedef struct _GdkColor GdkColor;
typedef struct _GtkWidget GtkWidget;
class AutofillPopupViewGtk : public AutofillPopupView {
public:
- AutofillPopupViewGtk(content::WebContents* web_contents, GtkWidget* parent);
+ AutofillPopupViewGtk(content::WebContents* web_contents,
+ AutofillExternalDelegate* external_delegate,
+ GtkWidget* parent);
virtual ~AutofillPopupViewGtk();
+ protected:
// AutofillPopupView implementations.
- virtual void Hide() OVERRIDE;
virtual void ShowInternal() OVERRIDE;
+ virtual void HideInternal() OVERRIDE;
+ virtual void InvalidateRow(size_t row) OVERRIDE;
private:
+ CHROMEGTK_CALLBACK_1(AutofillPopupViewGtk, gboolean, HandleButtonRelease,
+ GdkEventButton*);
CHROMEGTK_CALLBACK_1(AutofillPopupViewGtk, gboolean, HandleExpose,
GdkEventExpose*);
+ CHROMEGTK_CALLBACK_1(AutofillPopupViewGtk, gboolean, HandleMotion,
+ GdkEventMotion*);
// Setup the pango layout to display the autofill results.
void SetupLayout(const gfx::Rect& window_rect, const GdkColor& text_color);
+ // Convert a y-coordinate to the closest line.
+ int LineFromY(int y);
+
GtkWidget* parent_; // Weak reference.
GtkWidget* window_; // Strong reference.
PangoLayout* layout_; // Strong reference
@@ -44,6 +57,9 @@ class AutofillPopupViewGtk : public AutofillPopupView {
// The height of each individual Autofill popup row.
int row_height_;
+
+ // The size of the popup.
+ gfx::Rect bounds_;
};
#endif // CHROME_BROWSER_UI_GTK_AUTOFILL_AUTOFILL_POPUP_VIEW_GTK_H_
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 7cddca8..2129fb2 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -83,6 +83,8 @@
'browser/autofill/autofill_common_test.h',
'browser/autofill/data_driven_test.cc',
'browser/autofill/data_driven_test.h',
+ 'browser/autofill/test_autofill_external_delegate.cc',
+ 'browser/autofill/test_autofill_external_delegate.h',
'browser/automation/mock_tab_event_observer.cc',
'browser/automation/mock_tab_event_observer.h',
'browser/chromeos/cros/mock_cryptohome_library.cc',
diff --git a/chrome/common/autofill_messages.h b/chrome/common/autofill_messages.h
index 95adf65..d7a4b05 100644
--- a/chrome/common/autofill_messages.h
+++ b/chrome/common/autofill_messages.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -95,6 +95,22 @@ IPC_MESSAGE_ROUTED1(
IPC_MESSAGE_ROUTED1(AutofillMsg_SelectAutofillSuggestionAtIndex,
int /* listIndex */)
+// Tells the renderer that the next form will be filled for real.
+IPC_MESSAGE_ROUTED0(AutofillMsg_SetAutofillActionFill)
+
+// Clears the currently displayed Autofill results.
+IPC_MESSAGE_ROUTED0(AutofillMsg_ClearForm)
+
+// Tells the renderer that the next form will be filled as a preview.
+IPC_MESSAGE_ROUTED0(AutofillMsg_SetAutofillActionPreview)
+
+// Tells the renderer that the Autofill previewed form should be cleared.
+IPC_MESSAGE_ROUTED0(AutofillMsg_ClearPreviewedForm)
+
+// Sets the currently selected nodes value.
+IPC_MESSAGE_ROUTED1(AutofillMsg_SetNodeText,
+ string16)
+
// Autofill messages sent from the renderer to the browser.
// Notification that forms have been seen that are candidates for
diff --git a/chrome/renderer/autofill/autofill_agent.cc b/chrome/renderer/autofill/autofill_agent.cc
index 9130b10..54731fe9 100644
--- a/chrome/renderer/autofill/autofill_agent.cc
+++ b/chrome/renderer/autofill/autofill_agent.cc
@@ -76,6 +76,16 @@ bool AutofillAgent::OnMessageReceived(const IPC::Message& message) {
OnFieldTypePredictionsAvailable)
IPC_MESSAGE_HANDLER(AutofillMsg_SelectAutofillSuggestionAtIndex,
OnSelectAutofillSuggestionAtIndex)
+ IPC_MESSAGE_HANDLER(AutofillMsg_SetAutofillActionFill,
+ OnSetAutofillActionFill)
+ IPC_MESSAGE_HANDLER(AutofillMsg_ClearForm,
+ OnClearForm)
+ IPC_MESSAGE_HANDLER(AutofillMsg_SetAutofillActionPreview,
+ OnSetAutofillActionPreview)
+ IPC_MESSAGE_HANDLER(AutofillMsg_ClearPreviewedForm,
+ OnClearPreviewedForm)
+ IPC_MESSAGE_HANDLER(AutofillMsg_SetNodeText,
+ OnSetNodeText)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -139,6 +149,8 @@ void AutofillAgent::didAcceptAutofillSuggestion(const WebNode& node,
if (password_autofill_manager_->DidAcceptAutofillSuggestion(node, value))
return;
+ DCHECK(node == autofill_query_element_);
+
if (suggestions_options_index_ != -1 &&
index == static_cast<unsigned>(suggestions_options_index_)) {
// User selected 'Autofill Options'.
@@ -146,15 +158,11 @@ void AutofillAgent::didAcceptAutofillSuggestion(const WebNode& node,
} else if (suggestions_clear_index_ != -1 &&
index == static_cast<unsigned>(suggestions_clear_index_)) {
// User selected 'Clear form'.
- DCHECK(node == autofill_query_element_);
form_cache_.ClearFormWithElement(autofill_query_element_);
} else if (!unique_id) {
// User selected an Autocomplete entry, so we fill directly.
WebInputElement element = node.toConst<WebInputElement>();
-
- string16 substring = value;
- substring = substring.substr(0, element.maxLength());
- element.setValue(substring, true);
+ SetNodeText(value, &element);
} else {
// Fill the values for the whole form.
FillAutofillFormData(node, unique_id, AUTOFILL_FILL);
@@ -337,6 +345,8 @@ void AutofillAgent::OnFormDataFilled(int query_id,
if (!render_view()->GetWebView() || query_id != autofill_query_id_)
return;
+ was_query_node_autofilled_ = autofill_query_element_.isAutofilled();
+
switch (autofill_action_) {
case AUTOFILL_FILL:
FillForm(form, autofill_query_element_);
@@ -344,6 +354,8 @@ void AutofillAgent::OnFormDataFilled(int query_id,
base::TimeTicks::Now()));
break;
case AUTOFILL_PREVIEW:
+ didClearAutofillSelection(autofill_query_element_);
+
PreviewForm(form, autofill_query_element_);
Send(new AutofillHostMsg_DidPreviewAutofillFormData(routing_id()));
break;
@@ -366,6 +378,26 @@ void AutofillAgent::OnSelectAutofillSuggestionAtIndex(int listIndex) {
// render_view()->webview()->selectAutofillSuggestionAtIndex(listIndex);
}
+void AutofillAgent::OnSetAutofillActionFill() {
+ autofill_action_ = AUTOFILL_FILL;
+}
+
+void AutofillAgent::OnClearForm() {
+ form_cache_.ClearFormWithElement(autofill_query_element_);
+}
+
+void AutofillAgent::OnSetAutofillActionPreview() {
+ autofill_action_ = AUTOFILL_PREVIEW;
+}
+
+void AutofillAgent::OnClearPreviewedForm() {
+ didClearAutofillSelection(autofill_query_element_);
+}
+
+void AutofillAgent::OnSetNodeText(const string16& value) {
+ SetNodeText(value, &autofill_query_element_);
+}
+
void AutofillAgent::ShowSuggestions(const WebInputElement& element,
bool autofill_on_empty_values,
bool requires_caret_at_end,
@@ -442,9 +474,16 @@ void AutofillAgent::FillAutofillFormData(const WebNode& node,
}
autofill_action_ = action;
- was_query_node_autofilled_ = field.is_autofilled;
Send(new AutofillHostMsg_FillAutofillFormData(
routing_id(), autofill_query_id_, form, field, unique_id));
}
+void AutofillAgent::SetNodeText(const string16& value,
+ WebKit::WebInputElement* node) {
+ string16 substring = value;
+ substring = substring.substr(0, node->maxLength());
+
+ node->setValue(substring, true);
+}
+
} // namespace autofill
diff --git a/chrome/renderer/autofill/autofill_agent.h b/chrome/renderer/autofill/autofill_agent.h
index 85ea7e6..d02a903 100644
--- a/chrome/renderer/autofill/autofill_agent.h
+++ b/chrome/renderer/autofill/autofill_agent.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -105,6 +105,11 @@ class AutofillAgent : public content::RenderViewObserver,
// For external Autofill selection.
void OnSelectAutofillSuggestionAtIndex(int listIndex);
+ void OnSetAutofillActionFill();
+ void OnClearForm();
+ void OnSetAutofillActionPreview();
+ void OnClearPreviewedForm();
+ void OnSetNodeText(const string16& value);
// Called in a posted task by textFieldDidChange() to work-around a WebKit bug
// http://bugs.webkit.org/show_bug.cgi?id=16976
@@ -146,6 +151,9 @@ class AutofillAgent : public content::RenderViewObserver,
webkit::forms::FormData* form,
webkit::forms::FormField* field) WARN_UNUSED_RESULT;
+ // Set |node| to display the given |value|.
+ void SetNodeText(const string16& value, WebKit::WebInputElement* node);
+
FormCache form_cache_;
PasswordAutofillManager* password_autofill_manager_; // WEAK reference.
diff --git a/chrome/renderer/autofill/autofill_browsertest.cc b/chrome/renderer/autofill/autofill_browsertest.cc
index 50694dd..34dbb69 100644
--- a/chrome/renderer/autofill/autofill_browsertest.cc
+++ b/chrome/renderer/autofill/autofill_browsertest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -83,6 +83,9 @@ TEST_F(ChromeRenderViewTest, SendForms) {
WebInputElement firstname =
document.getElementById("firstname").to<WebInputElement>();
+ // Make sure to query for Autofill suggestions before selecting one.
+ autofill_agent_->QueryAutofillSuggestions(firstname, false);
+
// Accept suggestion that contains a label. Labeled items indicate Autofill
// as opposed to Autocomplete. We're testing this distinction below with
// the |AutofillHostMsg_FillAutofillFormData::ID| message.
@@ -149,6 +152,9 @@ TEST_F(ChromeRenderViewTest, FillFormElement) {
document.getElementById("middlename").to<WebInputElement>();
middlename.setAutofilled(true);
+ // Make sure to query for Autofill suggestions before selecting one.
+ autofill_agent_->QueryAutofillSuggestions(firstname, false);
+
// Accept a suggestion in a form that has been auto-filled. This triggers
// the direct filling of the firstname element with value parameter.
autofill_agent_->didAcceptAutofillSuggestion(firstname,