summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcsharp@chromium.org <csharp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-05 02:56:26 +0000
committercsharp@chromium.org <csharp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-05 02:56:26 +0000
commite7e834702fcd0237014e1808f72097e367ef8a63 (patch)
tree39f6a6f7a8d67ead2b3d2ad2f4c73b94b4167e49
parent634bc5d15ae1b294dcd29a17111a11e4228bd0ac (diff)
downloadchromium_src-e7e834702fcd0237014e1808f72097e367ef8a63.zip
chromium_src-e7e834702fcd0237014e1808f72097e367ef8a63.tar.gz
chromium_src-e7e834702fcd0237014e1808f72097e367ef8a63.tar.bz2
Add Password Autofill Manager to New Autofill
Copied over the password Autofill Manager functions from the renderer to the browser to allow the new Autofill UI to have access to them. BUG=51644 TEST= Review URL: http://codereview.chromium.org/9600038 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@130824 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/autofill/autofill_external_delegate.cc66
-rw-r--r--chrome/browser/autofill/autofill_external_delegate.h22
-rw-r--r--chrome/browser/autofill/autofill_external_delegate_gtk.cc5
-rw-r--r--chrome/browser/autofill/autofill_external_delegate_gtk.h1
-rw-r--r--chrome/browser/autofill/autofill_manager.cc27
-rw-r--r--chrome/browser/autofill/autofill_manager.h10
-rw-r--r--chrome/browser/autofill/password_autofill_manager.cc97
-rw-r--r--chrome/browser/autofill/password_autofill_manager.h81
-rw-r--r--chrome/browser/autofill/password_autofill_manager_unittest.cc94
-rw-r--r--chrome/browser/autofill/test_autofill_external_delegate.cc2
-rw-r--r--chrome/browser/autofill/test_autofill_external_delegate.h2
-rw-r--r--chrome/browser/password_manager_delegate_impl.cc6
-rw-r--r--chrome/chrome_browser.gypi6
-rw-r--r--chrome/chrome_tests.gypi3
-rw-r--r--chrome/common/autofill_messages.h24
-rw-r--r--chrome/renderer/autofill/autofill_agent.cc20
-rw-r--r--chrome/renderer/autofill/autofill_agent.h1
-rw-r--r--chrome/renderer/autofill/password_autofill_manager.cc37
-rw-r--r--chrome/renderer/autofill/password_autofill_manager.h8
-rw-r--r--chrome/renderer/autofill/password_autofill_manager_browsertest.cc2
-rw-r--r--webkit/forms/form_field.cc9
-rw-r--r--webkit/forms/form_field.h4
22 files changed, 504 insertions, 23 deletions
diff --git a/chrome/browser/autofill/autofill_external_delegate.cc b/chrome/browser/autofill/autofill_external_delegate.cc
index 13f0b7d..ff94bd4 100644
--- a/chrome/browser/autofill/autofill_external_delegate.cc
+++ b/chrome/browser/autofill/autofill_external_delegate.cc
@@ -16,6 +16,16 @@
using content::RenderViewHost;
+namespace {
+
+// The value to give as the unique id for all warnings.
+const int kWarningId = -1;
+
+// The value to give as the unique id for all password entries.
+const int kPasswordEntryId = -2;
+
+} // namespace
+
AutofillExternalDelegate::~AutofillExternalDelegate() {
}
@@ -24,6 +34,8 @@ AutofillExternalDelegate::AutofillExternalDelegate(
AutofillManager* autofill_manager)
: tab_contents_wrapper_(tab_contents_wrapper),
autofill_manager_(autofill_manager),
+ password_autofill_manager_(
+ tab_contents_wrapper ? tab_contents_wrapper->web_contents() : NULL),
autofill_query_id_(0),
display_warning_if_disabled_(false),
has_shown_autofill_popup_for_current_edit_(false),
@@ -33,9 +45,13 @@ AutofillExternalDelegate::AutofillExternalDelegate(
void AutofillExternalDelegate::SelectAutofillSuggestionAtIndex(int unique_id,
int list_index) {
+ if (password_autofill_manager_.DidSelectAutofillSuggestion(
+ autofill_query_field_))
+ return;
+
if (list_index == suggestions_options_index_ ||
list_index == suggestions_clear_index_ ||
- unique_id == -1)
+ unique_id == kWarningId)
return;
FillAutofillFormData(unique_id, true);
@@ -81,7 +97,7 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
v.assign(1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED));
l.assign(1, string16());
i.assign(1, string16());
- ids.assign(1, -1);
+ ids.assign(1, kWarningId);
} else if (ids[0] < 0 && ids.size() > 1) {
// If we received a warning instead of suggestions from autofill but regular
// suggestions from autocomplete, don't show the autofill warning.
@@ -136,6 +152,24 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
has_shown_autofill_popup_for_current_edit_ |= has_autofill_item;
}
+void AutofillExternalDelegate::OnShowPasswordSuggestions(
+ const std::vector<string16>& suggestions,
+ const webkit::forms::FormField& field,
+ const gfx::Rect& bounds) {
+ autofill_query_field_ = field;
+
+ if (suggestions.empty()) {
+ HideAutofillPopup();
+ return;
+ }
+
+ SetBounds(bounds);
+
+ std::vector<string16> empty(suggestions.size());
+ std::vector<int> password_ids(suggestions.size(), kPasswordEntryId);
+ ApplyAutofillSuggestions(suggestions, empty, empty, password_ids, -1);
+}
+
void AutofillExternalDelegate::DidEndTextFieldEditing() {
has_shown_autofill_popup_for_current_edit_ = false;
}
@@ -145,13 +179,9 @@ bool AutofillExternalDelegate::DidAcceptAutofillSuggestions(
int unique_id,
unsigned index) {
// If the selected element is a warning we don't want to do anything.
- if (unique_id < 0)
+ if (unique_id == kWarningId)
return false;
- // 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'.
@@ -162,8 +192,12 @@ bool AutofillExternalDelegate::DidAcceptAutofillSuggestions(
RenderViewHost* host =
tab_contents_wrapper_->web_contents()->GetRenderViewHost();
host->Send(new AutofillMsg_ClearForm(host->GetRoutingID()));
+ } else if (password_autofill_manager_.DidAcceptAutofillSuggestion(
+ autofill_query_field_, value)) {
+ // DidAcceptAutofillSuggestion has already handled the work to fill in
+ // the page as required.
} else if (!unique_id) {
- // User selected an Autocomplete entry, so we fill directly.
+ // User selected an Autocomplete, so we fill directly.
RenderViewHost* host =
tab_contents_wrapper_->web_contents()->GetRenderViewHost();
host->Send(new AutofillMsg_SetNodeText(
@@ -179,6 +213,10 @@ bool AutofillExternalDelegate::DidAcceptAutofillSuggestions(
}
void AutofillExternalDelegate::ClearPreviewedForm() {
+ if (password_autofill_manager_.DidClearAutofillSelection(
+ autofill_query_field_))
+ return;
+
RenderViewHost* host =
tab_contents_wrapper_->web_contents()->GetRenderViewHost();
host->Send(new AutofillMsg_ClearPreviewedForm(host->GetRoutingID()));
@@ -191,6 +229,18 @@ void AutofillExternalDelegate::HideAutofillPopup() {
HideAutofillPopupInternal();
}
+void AutofillExternalDelegate::Reset() {
+ HideAutofillPopup();
+
+ password_autofill_manager_.Reset();
+}
+
+void AutofillExternalDelegate::AddPasswordFormMapping(
+ const webkit::forms::FormField& form,
+ const webkit::forms::PasswordFormFillData& fill_data) {
+ password_autofill_manager_.AddPasswordFormMapping(form, fill_data);
+}
+
void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
bool is_preview) {
RenderViewHost* host =
diff --git a/chrome/browser/autofill/autofill_external_delegate.h b/chrome/browser/autofill/autofill_external_delegate.h
index 11a5341..18aa57c 100644
--- a/chrome/browser/autofill/autofill_external_delegate.h
+++ b/chrome/browser/autofill/autofill_external_delegate.h
@@ -10,8 +10,10 @@
#include "base/compiler_specific.h"
#include "base/string16.h"
+#include "chrome/browser/autofill/password_autofill_manager.h"
#include "webkit/forms/form_data.h"
#include "webkit/forms/form_field.h"
+#include "webkit/forms/password_form_dom_manager.h"
class AutofillManager;
class TabContentsWrapper;
@@ -57,6 +59,11 @@ class AutofillExternalDelegate {
const std::vector<string16>& autofill_icons,
const std::vector<int>& autofill_unique_ids);
+ // Show password suggestions in the popup.
+ void OnShowPasswordSuggestions(const std::vector<string16>& suggestions,
+ const webkit::forms::FormField& field,
+ const gfx::Rect& bounds);
+
// 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();
@@ -73,6 +80,15 @@ class AutofillExternalDelegate {
// Hide the Autofill poup.
virtual void HideAutofillPopup();
+ // Returns the delegate to its starting state by removing any page specific
+ // values or settings.
+ void Reset();
+
+ // Inform the Password Manager of a filled form.
+ void AddPasswordFormMapping(
+ const webkit::forms::FormField& form,
+ const webkit::forms::PasswordFormFillData& fill_data);
+
// Platforms that wish to implement an external Autofill delegate
// MUST implement this. The 1st arg is the tab contents that owns
// this delegate; the second is the Autofill manager owned by the
@@ -102,6 +118,9 @@ class AutofillExternalDelegate {
// Handle platform-dependent hiding.
virtual void HideAutofillPopupInternal() = 0;
+ // Set the bounds of the Autofill element being worked with.
+ virtual void SetBounds(const gfx::Rect& bounds) = 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
@@ -112,6 +131,9 @@ class AutofillExternalDelegate {
TabContentsWrapper* tab_contents_wrapper_; // weak; owns me.
AutofillManager* autofill_manager_; // weak.
+ // Password Autofill manager, handles all password-related Autofilling.
+ PasswordAutofillManager password_autofill_manager_;
+
// The ID of the last request sent for form field Autofill. Used to ignore
// out of date responses.
int autofill_query_id_;
diff --git a/chrome/browser/autofill/autofill_external_delegate_gtk.cc b/chrome/browser/autofill/autofill_external_delegate_gtk.cc
index 4c7bbfa..e140d3b 100644
--- a/chrome/browser/autofill/autofill_external_delegate_gtk.cc
+++ b/chrome/browser/autofill/autofill_external_delegate_gtk.cc
@@ -61,6 +61,11 @@ void AutofillExternalDelegateGtk::ApplyAutofillSuggestions(
separator_index);
}
+void AutofillExternalDelegateGtk::SetBounds(const gfx::Rect& bounds) {
+ CreateViewIfNeeded();
+ view_->set_element_bounds(bounds);
+}
+
void AutofillExternalDelegateGtk::CreateViewIfNeeded() {
if (view_.get())
return;
diff --git a/chrome/browser/autofill/autofill_external_delegate_gtk.h b/chrome/browser/autofill/autofill_external_delegate_gtk.h
index c2f9185..aada4f0 100644
--- a/chrome/browser/autofill/autofill_external_delegate_gtk.h
+++ b/chrome/browser/autofill/autofill_external_delegate_gtk.h
@@ -40,6 +40,7 @@ class AutofillExternalDelegateGtk : public AutofillExternalDelegate {
const std::vector<string16>& autofill_icons,
const std::vector<int>& autofill_unique_ids,
int separator_index) OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
private:
// Create a valid view to display the autofill results if one doesn't
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc
index a85cd88..902cb5f 100644
--- a/chrome/browser/autofill/autofill_manager.cc
+++ b/chrome/browser/autofill/autofill_manager.cc
@@ -60,6 +60,7 @@
#include "webkit/forms/form_data.h"
#include "webkit/forms/form_data_predictions.h"
#include "webkit/forms/form_field.h"
+#include "webkit/forms/password_form_dom_manager.h"
using base::TimeTicks;
using content::BrowserThread;
@@ -267,6 +268,10 @@ void AutofillManager::DidNavigateMainFrame(
Reset();
}
+bool AutofillManager::HasExternalDelegate() {
+ return external_delegate_ != NULL;
+}
+
bool AutofillManager::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(AutofillManager, message)
@@ -292,6 +297,10 @@ bool AutofillManager::OnMessageReceived(const IPC::Message& message) {
OnHideAutofillPopup)
IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup,
OnShowPasswordGenerationPopup)
+ IPC_MESSAGE_HANDLER(AutofillHostMsg_AddPasswordFormMapping,
+ OnAddPasswordFormMapping)
+ IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordSuggestions,
+ OnShowPasswordSuggestions)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -679,6 +688,21 @@ void AutofillManager::OnShowPasswordGenerationPopup(const gfx::Rect& bounds) {
#endif // #if defined(OS_ANDROID)
}
+void AutofillManager::OnAddPasswordFormMapping(
+ const webkit::forms::FormField& form,
+ const webkit::forms::PasswordFormFillData& fill_data) {
+ if (external_delegate_)
+ external_delegate_->AddPasswordFormMapping(form, fill_data);
+}
+
+void AutofillManager::OnShowPasswordSuggestions(
+ const webkit::forms::FormField& field,
+ const gfx::Rect& bounds,
+ const std::vector<string16>& suggestions) {
+ if (external_delegate_)
+ external_delegate_->OnShowPasswordSuggestions(suggestions, field, bounds);
+}
+
void AutofillManager::OnLoadedServerPredictions(
const std::string& response_xml) {
// Parse and store the server predictions.
@@ -787,6 +811,9 @@ void AutofillManager::Reset() {
user_did_edit_autofilled_field_ = false;
forms_loaded_timestamp_ = TimeTicks();
initial_interaction_timestamp_ = TimeTicks();
+
+ if (external_delegate_)
+ external_delegate_->Reset();
}
AutofillManager::AutofillManager(TabContentsWrapper* tab_contents,
diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h
index 86203c5..11bfbc0 100644
--- a/chrome/browser/autofill/autofill_manager.h
+++ b/chrome/browser/autofill/autofill_manager.h
@@ -54,6 +54,7 @@ namespace webkit {
namespace forms {
struct FormData;
struct FormField;
+struct PasswordFormFillData;
}
}
@@ -77,6 +78,9 @@ class AutofillManager : public content::WebContentsObserver,
external_delegate_ = delegate;
}
+ // Used to say if this class has an external delegate that it is using.
+ bool HasExternalDelegate();
+
// Called from our external delegate so they cannot be private.
virtual void OnFillAutofillFormData(int query_id,
const webkit::forms::FormData& form,
@@ -187,6 +191,12 @@ class AutofillManager : public content::WebContentsObserver,
bool display_warning);
void OnDidEndTextFieldEditing();
void OnHideAutofillPopup();
+ void OnAddPasswordFormMapping(
+ const webkit::forms::FormField& form,
+ const webkit::forms::PasswordFormFillData& fill_data);
+ void OnShowPasswordSuggestions(const webkit::forms::FormField& field,
+ const gfx::Rect& bounds,
+ const std::vector<string16>& suggestions);
// Fills |host| with the RenderViewHost for this tab.
// Returns false if Autofill is disabled or if the host is unavailable.
diff --git a/chrome/browser/autofill/password_autofill_manager.cc b/chrome/browser/autofill/password_autofill_manager.cc
new file mode 100644
index 0000000..6d22a7f
--- /dev/null
+++ b/chrome/browser/autofill/password_autofill_manager.cc
@@ -0,0 +1,97 @@
+// 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/password_autofill_manager.h"
+#include "chrome/common/autofill_messages.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// PasswordAutofillManager, public:
+
+PasswordAutofillManager::PasswordAutofillManager(
+ content::WebContents* web_contents) : web_contents_(web_contents) {
+}
+
+PasswordAutofillManager::~PasswordAutofillManager() {
+}
+
+bool PasswordAutofillManager::DidAcceptAutofillSuggestion(
+ const webkit::forms::FormField& field,
+ const string16& value) {
+ webkit::forms::PasswordFormFillData password;
+ if (!FindLoginInfo(field, &password))
+ return false;
+
+ if (WillFillUserNameAndPassword(value, password)) {
+ if (web_contents_) {
+ content::RenderViewHost* render_view_host =
+ web_contents_->GetRenderViewHost();
+ render_view_host->Send(new AutofillMsg_AcceptPasswordAutofillSuggestion(
+ render_view_host->GetRoutingID(),
+ value));
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool PasswordAutofillManager::DidSelectAutofillSuggestion(
+ const webkit::forms::FormField& field) {
+ webkit::forms::FormField input;
+ webkit::forms::PasswordFormFillData password;
+ return FindLoginInfo(field, &password);
+}
+
+bool PasswordAutofillManager::DidClearAutofillSelection(
+ const webkit::forms::FormField& field) {
+ webkit::forms::FormField input;
+ webkit::forms::PasswordFormFillData password;
+ return FindLoginInfo(field, &password);
+}
+
+void PasswordAutofillManager::AddPasswordFormMapping(
+ const webkit::forms::FormField& username_element,
+ const webkit::forms::PasswordFormFillData& password) {
+ login_to_password_info_[username_element] = password;
+}
+
+void PasswordAutofillManager::Reset() {
+ login_to_password_info_.clear();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PasswordAutofillManager, private:
+
+bool PasswordAutofillManager::WillFillUserNameAndPassword(
+ const string16& current_username,
+ const webkit::forms::PasswordFormFillData& fill_data) {
+ // Look for any suitable matches to current field text.
+ if (fill_data.basic_data.fields[0].value == current_username) {
+ return true;
+ } else {
+ // Scan additional logins for a match.
+ webkit::forms::PasswordFormFillData::LoginCollection::const_iterator iter;
+ for (iter = fill_data.additional_logins.begin();
+ iter != fill_data.additional_logins.end(); ++iter) {
+ if (iter->first == current_username)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool PasswordAutofillManager::FindLoginInfo(
+ const webkit::forms::FormField& field,
+ webkit::forms::PasswordFormFillData* found_password) {
+ LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(field);
+ if (iter == login_to_password_info_.end())
+ return false;
+
+ *found_password = iter->second;
+ return true;
+}
diff --git a/chrome/browser/autofill/password_autofill_manager.h b/chrome/browser/autofill/password_autofill_manager.h
new file mode 100644
index 0000000..46d4b8e
--- /dev/null
+++ b/chrome/browser/autofill/password_autofill_manager.h
@@ -0,0 +1,81 @@
+// 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_PASSWORD_AUTOFILL_MANAGER_H_
+#define CHROME_BROWSER_AUTOFILL_PASSWORD_AUTOFILL_MANAGER_H_
+#pragma once
+
+// This file was contains some repeated code from
+// chrome/renderer/autofill/password_autofill_manager because as we move to the
+// new Autofill UI we needs these functions in both the browser and renderer.
+// Once the move is completed the repeated code in the renderer half should be
+// removed.
+// http://crbug.com/51644
+
+#include <map>
+
+#include "webkit/forms/password_form_dom_manager.h"
+
+namespace content {
+class WebContents;
+} // namespace content
+
+// This class is responsible for filling password forms.
+class PasswordAutofillManager {
+ public:
+ explicit PasswordAutofillManager(content::WebContents* web_contents);
+ virtual ~PasswordAutofillManager();
+
+ // Fills the password associated with user name |value|. Returns true if the
+ // username and password fields were filled, false otherwise.
+ bool DidAcceptAutofillSuggestion(const webkit::forms::FormField& field,
+ const string16& value);
+
+ // A no-op. No filling happens for selection. But this method returns
+ // true when |node| is fillable by password Autofill.
+ bool DidSelectAutofillSuggestion(const webkit::forms::FormField& field);
+
+ // A no-op. Password forms are not previewed, so they do not need to be
+ // cleared when the selection changes. However, this method returns
+ // true when |node| is fillable by password Autofill.
+ bool DidClearAutofillSelection(const webkit::forms::FormField& field);
+
+ // Invoked when a password mapping is added.
+ void AddPasswordFormMapping(
+ const webkit::forms::FormField& username_element,
+ const webkit::forms::PasswordFormFillData& password);
+
+ // Invoked to clear any page specific cached values.
+ void Reset();
+
+ private:
+ // TODO(csharp): Modify the AutofillExternalDeletegate code so that it can
+ // figure out if a entry is a password one without using this mapping.
+ // crbug.com/118601
+ typedef std::map<webkit::forms::FormField,
+ webkit::forms::PasswordFormFillData>
+ LoginToPasswordInfoMap;
+
+ // Returns true if |current_username| matches a username for one of the
+ // login mappings in |password|.
+ bool WillFillUserNameAndPassword(
+ const string16& current_username,
+ const webkit::forms::PasswordFormFillData& password);
+
+ // Finds login information for a |node| that was previously filled.
+ bool FindLoginInfo(const webkit::forms::FormField& field,
+ webkit::forms::PasswordFormFillData* found_password);
+
+ // The logins we have filled so far with their associated info.
+ LoginToPasswordInfoMap login_to_password_info_;
+
+ // We only need the RenderViewHost pointer in WebContents, but if we attempt
+ // to just store RenderViewHost on creation, it becomes invalid once we start
+ // using it. By having the WebContents we can always get a valid pointer.
+ content::WebContents* web_contents_; // Weak reference.
+
+ DISALLOW_COPY_AND_ASSIGN(PasswordAutofillManager);
+};
+
+#endif // CHROME_BROWSER_AUTOFILL_PASSWORD_AUTOFILL_MANAGER_H_
diff --git a/chrome/browser/autofill/password_autofill_manager_unittest.cc b/chrome/browser/autofill/password_autofill_manager_unittest.cc
new file mode 100644
index 0000000..325f31e
--- /dev/null
+++ b/chrome/browser/autofill/password_autofill_manager_unittest.cc
@@ -0,0 +1,94 @@
+// 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 "base/compiler_specific.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autofill/password_autofill_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// The name of the username/password element in the form.
+const char* const kUsernameName = "username";
+const char* const kInvalidUsername = "no-username";
+const char* const kPasswordName = "password";
+
+const char* const kAliceUsername = "alice";
+const char* const kAlicePassword = "password";
+
+const char* const kValue = "password";
+
+} // namespace
+
+class PasswordAutofillManagerTest : public testing::Test {
+ protected:
+ PasswordAutofillManagerTest() : password_autofill_manager_(NULL) {}
+
+ virtual void SetUp() OVERRIDE {
+ // Add a preferred login and an additional login to the FillData.
+ string16 username1 = ASCIIToUTF16(kAliceUsername);
+ string16 password1 = ASCIIToUTF16(kAlicePassword);
+
+ username_field_.name = ASCIIToUTF16(kUsernameName);
+ username_field_.value = username1;
+ fill_data_.basic_data.fields.push_back(username_field_);
+
+ webkit::forms::FormField password_field;
+ password_field.name = ASCIIToUTF16(kPasswordName);
+ password_field.value = password1;
+ fill_data_.basic_data.fields.push_back(password_field);
+
+ password_autofill_manager_.AddPasswordFormMapping(username_field_,
+ fill_data_);
+ }
+
+ PasswordAutofillManager* password_autofill_manager() {
+ return &password_autofill_manager_;
+ }
+
+ const webkit::forms::FormField& username_field() { return username_field_; }
+
+ private:
+ webkit::forms::PasswordFormFillData fill_data_;
+ webkit::forms::FormField username_field_;
+
+ PasswordAutofillManager password_autofill_manager_;
+};
+
+TEST_F(PasswordAutofillManagerTest, DidAcceptAutofillSuggestion) {
+ EXPECT_TRUE(password_autofill_manager()->DidAcceptAutofillSuggestion(
+ username_field(), ASCIIToUTF16(kAliceUsername)));
+ EXPECT_FALSE(password_autofill_manager()->DidAcceptAutofillSuggestion(
+ username_field(), ASCIIToUTF16(kInvalidUsername)));
+
+ webkit::forms::FormField invalid_username_field;
+ invalid_username_field.name = ASCIIToUTF16(kInvalidUsername);
+
+ EXPECT_FALSE(password_autofill_manager()->DidAcceptAutofillSuggestion(
+ invalid_username_field, ASCIIToUTF16(kAliceUsername)));
+
+ password_autofill_manager()->Reset();
+ EXPECT_FALSE(password_autofill_manager()->DidAcceptAutofillSuggestion(
+ username_field(), ASCIIToUTF16(kAliceUsername)));
+}
+
+TEST_F(PasswordAutofillManagerTest, DidSelectAutofillSuggestion) {
+ EXPECT_TRUE(password_autofill_manager()->DidSelectAutofillSuggestion(
+ username_field()));
+
+ password_autofill_manager()->Reset();
+
+ EXPECT_FALSE(password_autofill_manager()->DidSelectAutofillSuggestion(
+ username_field()));
+}
+
+TEST_F(PasswordAutofillManagerTest, DidClearAutofillSelection) {
+ EXPECT_TRUE(password_autofill_manager()->DidClearAutofillSelection(
+ username_field()));
+
+ password_autofill_manager()->Reset();
+
+ EXPECT_FALSE(password_autofill_manager()->DidClearAutofillSelection(
+ username_field()));
+}
diff --git a/chrome/browser/autofill/test_autofill_external_delegate.cc b/chrome/browser/autofill/test_autofill_external_delegate.cc
index 9f076f1..c461bb4 100644
--- a/chrome/browser/autofill/test_autofill_external_delegate.cc
+++ b/chrome/browser/autofill/test_autofill_external_delegate.cc
@@ -24,3 +24,5 @@ void TestAutofillExternalDelegate::OnQueryPlatformSpecific(
const gfx::Rect& bounds) {}
void TestAutofillExternalDelegate::HideAutofillPopupInternal() {}
+
+void TestAutofillExternalDelegate::SetBounds(const gfx::Rect& bounds) {}
diff --git a/chrome/browser/autofill/test_autofill_external_delegate.h b/chrome/browser/autofill/test_autofill_external_delegate.h
index 771fcf8..6b95d85 100644
--- a/chrome/browser/autofill/test_autofill_external_delegate.h
+++ b/chrome/browser/autofill/test_autofill_external_delegate.h
@@ -35,6 +35,8 @@ class TestAutofillExternalDelegate : public AutofillExternalDelegate {
virtual void HideAutofillPopupInternal() OVERRIDE;
+ virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
+
private:
DISALLOW_COPY_AND_ASSIGN(TestAutofillExternalDelegate);
};
diff --git a/chrome/browser/password_manager_delegate_impl.cc b/chrome/browser/password_manager_delegate_impl.cc
index 5a3b572..f0caecb 100644
--- a/chrome/browser/password_manager_delegate_impl.cc
+++ b/chrome/browser/password_manager_delegate_impl.cc
@@ -6,6 +6,7 @@
#include "base/memory/singleton.h"
#include "base/metrics/histogram.h"
+#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/infobars/infobar_tab_helper.h"
#include "chrome/browser/password_manager/password_form_manager.h"
#include "chrome/browser/password_manager/password_manager.h"
@@ -123,10 +124,13 @@ SavePasswordInfoBarDelegate::AsSavePasswordInfoBarDelegate() {
void PasswordManagerDelegateImpl::FillPasswordForm(
const webkit::forms::PasswordFormFillData& form_data) {
+ bool disable_popup = tab_contents_->autofill_manager()->HasExternalDelegate();
+
tab_contents_->web_contents()->GetRenderViewHost()->Send(
new AutofillMsg_FillPasswordForm(
tab_contents_->web_contents()->GetRenderViewHost()->GetRoutingID(),
- form_data));
+ form_data,
+ disable_popup));
}
void PasswordManagerDelegateImpl::AddSavePasswordInfoBarIfPermitted(
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 9e1eeee..8821250 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -199,8 +199,10 @@
'browser/autofill/form_structure.h',
'browser/autofill/name_field.cc',
'browser/autofill/name_field.h',
- 'browser/autofill/password_generator.cc',
- 'browser/autofill/password_generator.h',
+ 'browser/autofill/password_autofill_manager.cc',
+ 'browser/autofill/password_autofill_manager.h',
+ 'browser/autofill/password_generator.cc',
+ 'browser/autofill/password_generator.h',
'browser/autofill/personal_data_manager.cc',
'browser/autofill/personal_data_manager.h',
'browser/autofill/personal_data_manager_factory.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index b89dfb5..80b5f3dd 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1270,7 +1270,8 @@
'browser/autofill/form_field_unittest.cc',
'browser/autofill/form_structure_unittest.cc',
'browser/autofill/name_field_unittest.cc',
- 'browser/autofill/password_generator_unittest.cc',
+ 'browser/autofill/password_autofill_manager_unittest.cc',
+ 'browser/autofill/password_generator_unittest.cc',
'browser/autofill/personal_data_manager_unittest.cc',
'browser/autofill/phone_field_unittest.cc',
'browser/autofill/phone_number_unittest.cc',
diff --git a/chrome/common/autofill_messages.h b/chrome/common/autofill_messages.h
index 473271a..0297c07 100644
--- a/chrome/common/autofill_messages.h
+++ b/chrome/common/autofill_messages.h
@@ -82,9 +82,11 @@ IPC_MESSAGE_ROUTED2(AutofillMsg_FormDataFilled,
webkit::forms::FormData /* form data */)
// Fill a password form and prepare field autocomplete for multiple
-// matching logins.
-IPC_MESSAGE_ROUTED1(AutofillMsg_FillPasswordForm,
- webkit::forms::PasswordFormFillData)
+// matching logins. Lets the renderer know if it should disable the popup
+// because the browser process will own the popup UI.
+IPC_MESSAGE_ROUTED2(AutofillMsg_FillPasswordForm,
+ webkit::forms::PasswordFormFillData, /* the fill form data*/
+ bool /* disable popup */ )
// Send the heuristic and server field type predictions to the renderer.
IPC_MESSAGE_ROUTED1(
@@ -121,6 +123,10 @@ IPC_MESSAGE_ROUTED1(AutofillMsg_GeneratedPasswordAccepted,
IPC_MESSAGE_ROUTED1(AutofillMsg_PasswordSyncEnabled,
bool /* is_enabled */)
+// Tells the renderer that the password field has accept the suggestion.
+IPC_MESSAGE_ROUTED1(AutofillMsg_AcceptPasswordAutofillSuggestion,
+ string16 /* username value*/)
+
// Autofill messages sent from the renderer to the browser.
// Notification that forms have been seen that are candidates for
@@ -197,3 +203,15 @@ IPC_MESSAGE_ROUTED0(AutofillHostMsg_HideAutofillPopup)
// coordinate system.
IPC_MESSAGE_ROUTED1(AutofillHostMsg_ShowPasswordGenerationPopup,
gfx::Rect /* source location */)
+
+// Instruct the browser that a password mapping has been found for a field.
+IPC_MESSAGE_ROUTED2(AutofillHostMsg_AddPasswordFormMapping,
+ webkit::forms::FormField, /* the user name field */
+ webkit::forms::PasswordFormFillData /* password pairings */)
+
+// Instruct the browser to show a popup with the following suggestions from the
+// password manager.
+IPC_MESSAGE_ROUTED3(AutofillHostMsg_ShowPasswordSuggestions,
+ webkit::forms::FormField /* the form field */,
+ gfx::Rect /* input field bounds, window-relative */,
+ std::vector<string16> /* suggestions */)
diff --git a/chrome/renderer/autofill/autofill_agent.cc b/chrome/renderer/autofill/autofill_agent.cc
index d51cc48..294ba19 100644
--- a/chrome/renderer/autofill/autofill_agent.cc
+++ b/chrome/renderer/autofill/autofill_agent.cc
@@ -86,6 +86,8 @@ bool AutofillAgent::OnMessageReceived(const IPC::Message& message) {
OnClearPreviewedForm)
IPC_MESSAGE_HANDLER(AutofillMsg_SetNodeText,
OnSetNodeText)
+ IPC_MESSAGE_HANDLER(AutofillMsg_AcceptPasswordAutofillSuggestion,
+ OnAcceptPasswordAutofillSuggestion)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -230,8 +232,10 @@ void AutofillAgent::textFieldDidChange(const WebInputElement& element) {
}
void AutofillAgent::TextFieldDidChangeImpl(const WebInputElement& element) {
- if (password_autofill_manager_->TextDidChangeInTextField(element))
+ if (password_autofill_manager_->TextDidChangeInTextField(element)) {
+ autofill_query_element_ = element;
return;
+ }
ShowSuggestions(element, false, true, false);
@@ -245,8 +249,10 @@ void AutofillAgent::TextFieldDidChangeImpl(const WebInputElement& element) {
void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element,
const WebKeyboardEvent& event) {
- if (password_autofill_manager_->TextFieldHandlingKeyDown(element, event))
+ if (password_autofill_manager_->TextFieldHandlingKeyDown(element, event)) {
+ autofill_query_element_ = element;
return;
+ }
if (event.windowsKeyCode == ui::VKEY_DOWN ||
event.windowsKeyCode == ui::VKEY_UP)
@@ -398,6 +404,16 @@ void AutofillAgent::OnSetNodeText(const string16& value) {
SetNodeText(value, &autofill_query_element_);
}
+void AutofillAgent::OnAcceptPasswordAutofillSuggestion(const string16& value) {
+ // We need to make sure this is handled here because the browser process
+ // skipped it handling because it believed it would be handled here. If it
+ // isn't handled here then the browser logic needs to be updated.
+ bool handled = password_autofill_manager_->DidAcceptAutofillSuggestion(
+ autofill_query_element_,
+ value);
+ DCHECK(handled);
+}
+
void AutofillAgent::ShowSuggestions(const WebInputElement& element,
bool autofill_on_empty_values,
bool requires_caret_at_end,
diff --git a/chrome/renderer/autofill/autofill_agent.h b/chrome/renderer/autofill/autofill_agent.h
index d02a903..843ee6c 100644
--- a/chrome/renderer/autofill/autofill_agent.h
+++ b/chrome/renderer/autofill/autofill_agent.h
@@ -110,6 +110,7 @@ class AutofillAgent : public content::RenderViewObserver,
void OnSetAutofillActionPreview();
void OnClearPreviewedForm();
void OnSetNodeText(const string16& value);
+ void OnAcceptPasswordAutofillSuggestion(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
diff --git a/chrome/renderer/autofill/password_autofill_manager.cc b/chrome/renderer/autofill/password_autofill_manager.cc
index 26e6fd6f..2bbee31 100644
--- a/chrome/renderer/autofill/password_autofill_manager.cc
+++ b/chrome/renderer/autofill/password_autofill_manager.cc
@@ -8,6 +8,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "chrome/common/autofill_messages.h"
+#include "chrome/renderer/autofill/form_autofill_util.h"
#include "content/public/renderer/render_view.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
@@ -204,6 +205,7 @@ namespace autofill {
PasswordAutofillManager::PasswordAutofillManager(
content::RenderView* render_view)
: content::RenderViewObserver(render_view),
+ disable_popup_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
}
@@ -293,6 +295,10 @@ bool PasswordAutofillManager::TextDidChangeInTextField(
bool PasswordAutofillManager::TextFieldHandlingKeyDown(
const WebKit::WebInputElement& element,
const WebKit::WebKeyboardEvent& event) {
+ // If using the new Autofill UI that lives in the browser, it will handle
+ // keypresses before this function. This is not currently an issue but if
+ // the keys handled there or here change, this issue may appear.
+
LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(element);
if (iter == login_to_password_info_.end())
return false;
@@ -425,7 +431,10 @@ bool PasswordAutofillManager::InputElementLostFocus() {
}
void PasswordAutofillManager::OnFillPasswordForm(
- const webkit::forms::PasswordFormFillData& form_data) {
+ const webkit::forms::PasswordFormFillData& form_data,
+ bool disable_popup) {
+ disable_popup_ = disable_popup;
+
FormElementsList forms;
// We own the FormElements* in forms.
FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms);
@@ -458,6 +467,15 @@ void PasswordAutofillManager::OnFillPasswordForm(
password_info.fill_data = form_data;
password_info.password_field = password_element;
login_to_password_info_[username_element] = password_info;
+
+ webkit::forms::FormData form;
+ webkit::forms::FormField field;
+ FindFormAndFieldForInputElement(
+ username_element, &form, &field, REQUIRE_NONE);
+ Send(new AutofillHostMsg_AddPasswordFormMapping(
+ routing_id(),
+ field,
+ form_data));
}
}
@@ -492,6 +510,23 @@ bool PasswordAutofillManager::ShowSuggestionPopup(
std::vector<string16> suggestions;
GetSuggestions(fill_data, user_input.value(), &suggestions);
+
+ if (disable_popup_) {
+ webkit::forms::FormData form;
+ webkit::forms::FormField field;
+ FindFormAndFieldForInputElement(
+ user_input, &form, &field, REQUIRE_NONE);
+
+ WebKit::WebInputElement selected_element = user_input;
+ gfx::Rect bounding_box(selected_element.boundsInViewportSpace());
+ Send(new AutofillHostMsg_ShowPasswordSuggestions(routing_id(),
+ field,
+ bounding_box,
+ suggestions));
+ return !suggestions.empty();
+ }
+
+
if (suggestions.empty()) {
webview->hidePopups();
return false;
diff --git a/chrome/renderer/autofill/password_autofill_manager.h b/chrome/renderer/autofill/password_autofill_manager.h
index 254571a89..0fd1906 100644
--- a/chrome/renderer/autofill/password_autofill_manager.h
+++ b/chrome/renderer/autofill/password_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.
@@ -75,7 +75,8 @@ class PasswordAutofillManager : public content::RenderViewObserver,
virtual bool InputElementLostFocus() OVERRIDE;
// RenderView IPC handlers:
- void OnFillPasswordForm(const webkit::forms::PasswordFormFillData& form_data);
+ void OnFillPasswordForm(const webkit::forms::PasswordFormFillData& form_data,
+ bool disable_popup);
// Scans the given frame for password forms and sends them up to the browser.
// If |only_visible| is true, only forms visible in the layout are sent.
@@ -114,6 +115,9 @@ class PasswordAutofillManager : public content::RenderViewObserver,
// The logins we have filled so far with their associated info.
LoginToPasswordInfoMap login_to_password_info_;
+ // Used to disable and hide the popup.
+ bool disable_popup_;
+
base::WeakPtrFactory<PasswordAutofillManager> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(PasswordAutofillManager);
diff --git a/chrome/renderer/autofill/password_autofill_manager_browsertest.cc b/chrome/renderer/autofill/password_autofill_manager_browsertest.cc
index 7d1dea0..d242e6d 100644
--- a/chrome/renderer/autofill/password_autofill_manager_browsertest.cc
+++ b/chrome/renderer/autofill/password_autofill_manager_browsertest.cc
@@ -65,7 +65,7 @@ class PasswordAutofillManagerTest : public ChromeRenderViewTest {
// protected.
void SimulateOnFillPasswordForm(
const PasswordFormFillData& fill_data) {
- AutofillMsg_FillPasswordForm msg(0, fill_data);
+ AutofillMsg_FillPasswordForm msg(0, fill_data, false);
password_autofill_->OnMessageReceived(msg);
}
diff --git a/webkit/forms/form_field.cc b/webkit/forms/form_field.cc
index 1c9a0a7..f32b830 100644
--- a/webkit/forms/form_field.cc
+++ b/webkit/forms/form_field.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.
@@ -44,6 +44,13 @@ bool FormField::operator!=(const FormField& field) const {
return !operator==(field);
}
+bool FormField::operator<(const FormField& field) const {
+ if (label == field.label)
+ return name < field.name;
+
+ return label < field.label;
+}
+
std::ostream& operator<<(std::ostream& os, const FormField& field) {
return os
<< UTF16ToUTF8(field.label)
diff --git a/webkit/forms/form_field.h b/webkit/forms/form_field.h
index d1b17c0..2f5f0b2 100644
--- a/webkit/forms/form_field.h
+++ b/webkit/forms/form_field.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.
@@ -25,6 +25,8 @@ struct WEBKIT_FORMS_EXPORT FormField {
// ids.
bool operator==(const FormField& field) const;
bool operator!=(const FormField& field) const;
+ // Comparsion operator exposed for STL map. Uses label, then name to sort.
+ bool operator<(const FormField& field) const;
string16 label;
string16 name;