summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;