Commit 375564a1 authored by zysxqn@google.com's avatar zysxqn@google.com

Generate passwords only for the forms that autofill server classifies one of...

Generate passwords only for the forms that autofill server classifies one of its fields as ACCOUNT_CREATION_PASSWORD.

BUG=

Review URL: https://chromiumcodereview.appspot.com/23432002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221773 0039d316-1c4b-4281-b951-d872f2087c98
parent a15f140a
...@@ -151,6 +151,9 @@ bool AwAutofillManagerDelegate::IsAutocompleteEnabled() { ...@@ -151,6 +151,9 @@ bool AwAutofillManagerDelegate::IsAutocompleteEnabled() {
return GetSaveFormData(); return GetSaveFormData();
} }
void AwAutofillManagerDelegate::DetectAccountCreationForms(
const std::vector<autofill::FormStructure*>& forms) {}
void AwAutofillManagerDelegate::SuggestionSelected(JNIEnv* env, void AwAutofillManagerDelegate::SuggestionSelected(JNIEnv* env,
jobject object, jobject object,
jint position) { jint position) {
......
...@@ -83,6 +83,8 @@ class AwAutofillManagerDelegate ...@@ -83,6 +83,8 @@ class AwAutofillManagerDelegate
const std::vector<base::string16>& labels) OVERRIDE; const std::vector<base::string16>& labels) OVERRIDE;
virtual void HideAutofillPopup() OVERRIDE; virtual void HideAutofillPopup() OVERRIDE;
virtual bool IsAutocompleteEnabled() OVERRIDE; virtual bool IsAutocompleteEnabled() OVERRIDE;
virtual void DetectAccountCreationForms(
const std::vector<autofill::FormStructure*>& forms) OVERRIDE;
void SuggestionSelected(JNIEnv* env, void SuggestionSelected(JNIEnv* env,
jobject obj, jobject obj,
......
...@@ -13,8 +13,12 @@ ...@@ -13,8 +13,12 @@
#include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/password_generator.h" #include "components/autofill/core/browser/password_generator.h"
#include "components/autofill/core/common/autofill_messages.h" #include "components/autofill/core/common/autofill_messages.h"
#include "components/autofill/core/common/form_data.h"
#include "components/user_prefs/pref_registry_syncable.h" #include "components/user_prefs/pref_registry_syncable.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
...@@ -55,6 +59,25 @@ void PasswordGenerationManager::RegisterProfilePrefs( ...@@ -55,6 +59,25 @@ void PasswordGenerationManager::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
} }
void PasswordGenerationManager::DetectAccountCreationForms(
const std::vector<autofill::FormStructure*>& forms) {
std::vector<autofill::FormData> account_creation_forms;
for (std::vector<autofill::FormStructure*>::const_iterator form_it =
forms.begin(); form_it != forms.end(); ++form_it) {
autofill::FormStructure* form = *form_it;
for (std::vector<autofill::AutofillField*>::const_iterator field_it =
form->begin(); field_it != form->end(); ++field_it) {
autofill::AutofillField* field = *field_it;
if (field->server_type() == autofill::ACCOUNT_CREATION_PASSWORD) {
account_creation_forms.push_back(form->ToFormData());
break;
}
}
}
SendAccountCreationFormsToRenderer(web_contents()->GetRenderViewHost(),
account_creation_forms);
}
void PasswordGenerationManager::RegisterWithSyncService() { void PasswordGenerationManager::RegisterWithSyncService() {
Profile* profile = Profile::FromBrowserContext( Profile* profile = Profile::FromBrowserContext(
web_contents()->GetBrowserContext()); web_contents()->GetBrowserContext());
...@@ -151,6 +174,13 @@ void PasswordGenerationManager::SendStateToRenderer( ...@@ -151,6 +174,13 @@ void PasswordGenerationManager::SendStateToRenderer(
enabled)); enabled));
} }
void PasswordGenerationManager::SendAccountCreationFormsToRenderer(
content::RenderViewHost* host,
const std::vector<autofill::FormData>& forms) {
host->Send(new AutofillMsg_AccountCreationFormsDetected(
host->GetRoutingID(), forms));
}
void PasswordGenerationManager::OnShowPasswordGenerationPopup( void PasswordGenerationManager::OnShowPasswordGenerationPopup(
const gfx::Rect& bounds, const gfx::Rect& bounds,
int max_length, int max_length,
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "content/public/browser/web_contents_user_data.h" #include "content/public/browser/web_contents_user_data.h"
namespace autofill { namespace autofill {
struct FormData;
class FormStructure;
class PasswordGenerator; class PasswordGenerator;
} }
...@@ -49,6 +51,10 @@ class PasswordGenerationManager ...@@ -49,6 +51,10 @@ class PasswordGenerationManager
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
virtual ~PasswordGenerationManager(); virtual ~PasswordGenerationManager();
// Detect account creation forms from forms with autofill type annotated.
void DetectAccountCreationForms(
const std::vector<autofill::FormStructure*>& forms);
protected: protected:
explicit PasswordGenerationManager(content::WebContents* contents); explicit PasswordGenerationManager(content::WebContents* contents);
...@@ -81,6 +87,10 @@ class PasswordGenerationManager ...@@ -81,6 +87,10 @@ class PasswordGenerationManager
// is a separate function to aid in testing. // is a separate function to aid in testing.
virtual void SendStateToRenderer(content::RenderViewHost* host, bool enabled); virtual void SendStateToRenderer(content::RenderViewHost* host, bool enabled);
virtual void SendAccountCreationFormsToRenderer(
content::RenderViewHost* host,
const std::vector<autofill::FormData>& forms);
// Causes the password generation bubble UI to be shown for the specified // Causes the password generation bubble UI to be shown for the specified
// form. The popup will be anchored at |icon_bounds|. The generated // form. The popup will be anchored at |icon_bounds|. The generated
// password will be no longer than |max_length|. // password will be no longer than |max_length|.
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <vector> #include <vector>
#include "base/prefs/pref_service.h" #include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/password_manager/password_generation_manager.h" #include "chrome/browser/password_manager/password_generation_manager.h"
#include "chrome/browser/password_manager/password_manager.h" #include "chrome/browser/password_manager/password_manager.h"
#include "chrome/browser/password_manager/password_manager_delegate_impl.h" #include "chrome/browser/password_manager/password_manager_delegate_impl.h"
...@@ -13,8 +14,27 @@ ...@@ -13,8 +14,27 @@
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "content/public/test/test_browser_thread.h" #include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace {
// Unlike the base AutofillMetrics, exposes copy and assignment constructors,
// which are handy for briefer test code. The AutofillMetrics class is
// stateless, so this is safe.
class TestAutofillMetrics : public autofill::AutofillMetrics {
public:
TestAutofillMetrics() {}
virtual ~TestAutofillMetrics() {}
};
} // anonymous namespace
class TestPasswordGenerationManager : public PasswordGenerationManager { class TestPasswordGenerationManager : public PasswordGenerationManager {
public: public:
...@@ -27,16 +47,32 @@ class TestPasswordGenerationManager : public PasswordGenerationManager { ...@@ -27,16 +47,32 @@ class TestPasswordGenerationManager : public PasswordGenerationManager {
sent_states_.push_back(enabled); sent_states_.push_back(enabled);
} }
virtual void SendAccountCreationFormsToRenderer(
content::RenderViewHost* host,
const std::vector<autofill::FormData>& forms) OVERRIDE {
sent_account_creation_forms_.insert(
sent_account_creation_forms_.begin(), forms.begin(), forms.end());
}
const std::vector<bool>& GetSentStates() { const std::vector<bool>& GetSentStates() {
return sent_states_; return sent_states_;
} }
const std::vector<autofill::FormData>& GetSentAccountCreationForms() {
return sent_account_creation_forms_;
}
void ClearSentStates() { void ClearSentStates() {
sent_states_.clear(); sent_states_.clear();
} }
void ClearSentAccountCreationForms() {
sent_account_creation_forms_.clear();
}
private: private:
std::vector<bool> sent_states_; std::vector<bool> sent_states_;
std::vector<autofill::FormData> sent_account_creation_forms_;
DISALLOW_COPY_AND_ASSIGN(TestPasswordGenerationManager); DISALLOW_COPY_AND_ASSIGN(TestPasswordGenerationManager);
}; };
...@@ -59,6 +95,11 @@ class PasswordGenerationManagerTest : public ChromeRenderViewHostTestHarness { ...@@ -59,6 +95,11 @@ class PasswordGenerationManagerTest : public ChromeRenderViewHostTestHarness {
password_generation_manager_->UpdateState(NULL, new_renderer); password_generation_manager_->UpdateState(NULL, new_renderer);
} }
void DetectAccountCreationForms(
const std::vector<autofill::FormStructure*>& forms) {
password_generation_manager_->DetectAccountCreationForms(forms);
}
scoped_ptr<TestPasswordGenerationManager> password_generation_manager_; scoped_ptr<TestPasswordGenerationManager> password_generation_manager_;
}; };
...@@ -180,6 +221,56 @@ TEST_F(PasswordGenerationManagerTest, UpdatePasswordSyncState) { ...@@ -180,6 +221,56 @@ TEST_F(PasswordGenerationManagerTest, UpdatePasswordSyncState) {
password_generation_manager_->ClearSentStates(); password_generation_manager_->ClearSentStates();
} }
TEST_F(PasswordGenerationManagerTest, DetectAccountCreationForms) {
autofill::FormData login_form;
login_form.origin = GURL("http://www.yahoo.com/login/");
autofill::FormFieldData username;
username.label = ASCIIToUTF16("username");
username.name = ASCIIToUTF16("login");
username.form_control_type = "text";
login_form.fields.push_back(username);
autofill::FormFieldData password;
password.label = ASCIIToUTF16("password");
password.name = ASCIIToUTF16("password");
password.form_control_type = "password";
login_form.fields.push_back(password);
autofill::FormStructure form1(login_form);
std::vector<autofill::FormStructure*> forms;
forms.push_back(&form1);
autofill::FormData account_creation_form;
account_creation_form.origin = GURL("http://accounts.yahoo.com/");
account_creation_form.fields.push_back(username);
account_creation_form.fields.push_back(password);
autofill::FormFieldData confirm_password;
confirm_password.label = ASCIIToUTF16("confirm_password");
confirm_password.name = ASCIIToUTF16("password");
confirm_password.form_control_type = "password";
account_creation_form.fields.push_back(confirm_password);
autofill::FormStructure form2(account_creation_form);
forms.push_back(&form2);
// Simulate the server response to set the field types.
const char* const kServerResponse =
"<autofillqueryresponse>"
"<field autofilltype=\"9\" />"
"<field autofilltype=\"75\" />"
"<field autofilltype=\"9\" />"
"<field autofilltype=\"76\" />"
"<field autofilltype=\"75\" />"
"</autofillqueryresponse>";
autofill::FormStructure::ParseQueryResponse(
kServerResponse,
forms,
TestAutofillMetrics());
DetectAccountCreationForms(forms);
EXPECT_EQ(1u,
password_generation_manager_->GetSentAccountCreationForms().size());
EXPECT_EQ(
GURL("http://accounts.yahoo.com/"),
password_generation_manager_->GetSentAccountCreationForms()[0].origin);
}
TEST_F(IncognitoPasswordGenerationManagerTest, TEST_F(IncognitoPasswordGenerationManagerTest,
UpdatePasswordSyncStateIncognito) { UpdatePasswordSyncStateIncognito) {
// Disable password manager by going incognito, and enable syncing. The // Disable password manager by going incognito, and enable syncing. The
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "chrome/browser/autofill/autofill_cc_infobar_delegate.h" #include "chrome/browser/autofill/autofill_cc_infobar_delegate.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/password_manager/password_generation_manager.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/autofill/autofill_dialog_controller.h" #include "chrome/browser/ui/autofill/autofill_dialog_controller.h"
#include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h"
...@@ -171,4 +172,12 @@ void TabAutofillManagerDelegate::WebContentsDestroyed( ...@@ -171,4 +172,12 @@ void TabAutofillManagerDelegate::WebContentsDestroyed(
HideAutofillPopup(); HideAutofillPopup();
} }
void TabAutofillManagerDelegate::DetectAccountCreationForms(
const std::vector<autofill::FormStructure*>& forms) {
PasswordGenerationManager* manager =
PasswordGenerationManager::FromWebContents(web_contents_);
if (manager)
manager->DetectAccountCreationForms(forms);
}
} // namespace autofill } // namespace autofill
...@@ -64,6 +64,9 @@ class TabAutofillManagerDelegate ...@@ -64,6 +64,9 @@ class TabAutofillManagerDelegate
virtual void HideAutofillPopup() OVERRIDE; virtual void HideAutofillPopup() OVERRIDE;
virtual bool IsAutocompleteEnabled() OVERRIDE; virtual bool IsAutocompleteEnabled() OVERRIDE;
virtual void DetectAccountCreationForms(
const std::vector<autofill::FormStructure*>& forms) OVERRIDE;
// content::WebContentsObserver implementation. // content::WebContentsObserver implementation.
virtual void DidNavigateMainFrame( virtual void DidNavigateMainFrame(
const content::LoadCommittedDetails& details, const content::LoadCommittedDetails& details,
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "chrome/test/base/chrome_render_view_test.h" #include "chrome/test/base/chrome_render_view_test.h"
#include "components/autofill/content/renderer/password_generation_manager.h" #include "components/autofill/content/renderer/password_generation_manager.h"
#include "components/autofill/core/common/autofill_messages.h" #include "components/autofill/core/common/autofill_messages.h"
#include "components/autofill/core/common/form_data.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebDocument.h"
...@@ -38,6 +39,10 @@ class TestPasswordGenerationManager : public PasswordGenerationManager { ...@@ -38,6 +39,10 @@ class TestPasswordGenerationManager : public PasswordGenerationManager {
return messages_.get(); return messages_.get();
} }
void ClearMessages() {
messages_.clear();
}
protected: protected:
virtual bool ShouldAnalyzeDocument(const WebKit::WebDocument& document) const virtual bool ShouldAnalyzeDocument(const WebKit::WebDocument& document) const
OVERRIDE { OVERRIDE {
...@@ -74,6 +79,7 @@ class PasswordGenerationManagerTest : public ChromeRenderViewTest { ...@@ -74,6 +79,7 @@ class PasswordGenerationManagerTest : public ChromeRenderViewTest {
} }
void SimulateClickOnDecoration(WebKit::WebInputElement* input_element) { void SimulateClickOnDecoration(WebKit::WebInputElement* input_element) {
generation_manager_->ClearMessages();
WebKit::WebElement decoration = WebKit::WebElement decoration =
input_element->decorationElementFor(generation_manager_.get()); input_element->decorationElementFor(generation_manager_.get());
decoration.simulateClick(); decoration.simulateClick();
...@@ -85,6 +91,11 @@ class PasswordGenerationManagerTest : public ChromeRenderViewTest { ...@@ -85,6 +91,11 @@ class PasswordGenerationManagerTest : public ChromeRenderViewTest {
return decoration.hasNonEmptyBoundingBox(); return decoration.hasNonEmptyBoundingBox();
} }
void SetPasswordGenerationEnabledMessage(void) {
AutofillMsg_PasswordGenerationEnabled msg(0, true);
generation_manager_->OnMessageReceived(msg);
}
void SetNotBlacklistedMessage(const char* form_str) { void SetNotBlacklistedMessage(const char* form_str) {
content::PasswordForm form; content::PasswordForm form;
form.origin = form.origin =
...@@ -93,6 +104,33 @@ class PasswordGenerationManagerTest : public ChromeRenderViewTest { ...@@ -93,6 +104,33 @@ class PasswordGenerationManagerTest : public ChromeRenderViewTest {
generation_manager_->OnMessageReceived(msg); generation_manager_->OnMessageReceived(msg);
} }
void SetAccountCreationFormsDetectedMessage(const char* form_str) {
autofill::FormData form;
form.origin =
GURL(base::StringPrintf("data:text/html;charset=utf-8,%s", form_str));
std::vector<autofill::FormData> forms;
forms.push_back(form);
AutofillMsg_AccountCreationFormsDetected msg(0, forms);
generation_manager_->OnMessageReceived(msg);
}
void ExpectPasswordGenerationIconShown(const char* element_id, bool shown) {
WebDocument document = GetMainFrame()->document();
WebElement element =
document.getElementById(WebString::fromUTF8(element_id));
ASSERT_FALSE(element.isNull());
WebInputElement target_element = element.to<WebInputElement>();
if (shown) {
EXPECT_TRUE(DecorationIsVisible(&target_element));
SimulateClickOnDecoration(&target_element);
EXPECT_EQ(1u, generation_manager_->messages().size());
EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
generation_manager_->messages()[0]->type());
} else {
EXPECT_FALSE(DecorationIsVisible(&target_element));
}
}
protected: protected:
scoped_ptr<TestPasswordGenerationManager> generation_manager_; scoped_ptr<TestPasswordGenerationManager> generation_manager_;
...@@ -134,66 +172,42 @@ const char kInvalidActionAccountCreationFormHTML[] = ...@@ -134,66 +172,42 @@ const char kInvalidActionAccountCreationFormHTML[] =
"</FORM>"; "</FORM>";
TEST_F(PasswordGenerationManagerTest, DetectionTest) { TEST_F(PasswordGenerationManagerTest, DetectionTest) {
// Don't shown the icon for non account creation forms.
LoadHTML(kSigninFormHTML); LoadHTML(kSigninFormHTML);
ExpectPasswordGenerationIconShown("password", false);
WebDocument document = GetMainFrame()->document();
WebElement element =
document.getElementById(WebString::fromUTF8("password"));
ASSERT_FALSE(element.isNull());
WebInputElement password_element = element.to<WebInputElement>();
EXPECT_FALSE(DecorationIsVisible(&password_element));
LoadHTML(kAccountCreationFormHTML);
// We don't show the decoration yet because the feature isn't enabled. // We don't show the decoration yet because the feature isn't enabled.
document = GetMainFrame()->document(); LoadHTML(kAccountCreationFormHTML);
element = document.getElementById(WebString::fromUTF8("first_password")); ExpectPasswordGenerationIconShown("first_password", false);
ASSERT_FALSE(element.isNull());
WebInputElement first_password_element = element.to<WebInputElement>();
EXPECT_FALSE(DecorationIsVisible(&first_password_element));
// Pretend like password generation was enabled. // Pretend like password generation was enabled.
AutofillMsg_PasswordGenerationEnabled msg(0, true); SetPasswordGenerationEnabledMessage();
generation_manager_->OnMessageReceived(msg);
// Pretend like We have received message indicating site is not blacklisted,
// and we have received message indicating the form is classified as
// ACCOUNT_CREATION_FORM form Autofill server. We should show the icon.
LoadHTML(kAccountCreationFormHTML); LoadHTML(kAccountCreationFormHTML);
// Pretend like we have received message indicating site is not blacklisted.
SetNotBlacklistedMessage(kAccountCreationFormHTML); SetNotBlacklistedMessage(kAccountCreationFormHTML);
SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
document = GetMainFrame()->document(); ExpectPasswordGenerationIconShown("first_password", true);
element = document.getElementById(WebString::fromUTF8("first_password"));
ASSERT_FALSE(element.isNull());
first_password_element = element.to<WebInputElement>();
EXPECT_TRUE(DecorationIsVisible(&first_password_element));
SimulateClickOnDecoration(&first_password_element);
EXPECT_EQ(1u, generation_manager_->messages().size());
EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
generation_manager_->messages()[0]->type());
// This doesn't trigger because hidden password fields are ignored. // This doesn't trigger because hidden password fields are ignored.
LoadHTML(kHiddenPasswordAccountCreationFormHTML); LoadHTML(kHiddenPasswordAccountCreationFormHTML);
SetNotBlacklistedMessage(kAccountCreationFormHTML); SetNotBlacklistedMessage(kHiddenPasswordAccountCreationFormHTML);
document = GetMainFrame()->document(); SetAccountCreationFormsDetectedMessage(
element = document.getElementById(WebString::fromUTF8("first_password")); kHiddenPasswordAccountCreationFormHTML);
ASSERT_FALSE(element.isNull()); ExpectPasswordGenerationIconShown("first_password", false);
first_password_element = element.to<WebInputElement>();
EXPECT_FALSE(DecorationIsVisible(&first_password_element));
// This doesn't trigger because the form action is invalid. // This doesn't trigger because the form action is invalid.
LoadHTML(kInvalidActionAccountCreationFormHTML); LoadHTML(kInvalidActionAccountCreationFormHTML);
SetNotBlacklistedMessage(kAccountCreationFormHTML); SetNotBlacklistedMessage(kInvalidActionAccountCreationFormHTML);
document = GetMainFrame()->document(); SetAccountCreationFormsDetectedMessage(kInvalidActionAccountCreationFormHTML);
element = document.getElementById(WebString::fromUTF8("first_password")); ExpectPasswordGenerationIconShown("first_password", false);
ASSERT_FALSE(element.isNull());
first_password_element = element.to<WebInputElement>();
EXPECT_FALSE(DecorationIsVisible(&first_password_element));
} }
TEST_F(PasswordGenerationManagerTest, FillTest) { TEST_F(PasswordGenerationManagerTest, FillTest) {
// Make sure that we are enabled before loading HTML. // Make sure that we are enabled before loading HTML.
AutofillMsg_PasswordGenerationEnabled enabled_msg(0, true); SetPasswordGenerationEnabledMessage();
generation_manager_->OnMessageReceived(enabled_msg);
LoadHTML(kAccountCreationFormHTML); LoadHTML(kAccountCreationFormHTML);
WebDocument document = GetMainFrame()->document(); WebDocument document = GetMainFrame()->document();
...@@ -229,57 +243,53 @@ TEST_F(PasswordGenerationManagerTest, FillTest) { ...@@ -229,57 +243,53 @@ TEST_F(PasswordGenerationManagerTest, FillTest) {
TEST_F(PasswordGenerationManagerTest, BlacklistedTest) { TEST_F(PasswordGenerationManagerTest, BlacklistedTest) {
// Make sure password generation is enabled. // Make sure password generation is enabled.
AutofillMsg_PasswordGenerationEnabled enabled_msg(0, true); SetPasswordGenerationEnabledMessage();
generation_manager_->OnMessageReceived(enabled_msg);
// Did not receive not blacklisted message. Don't show password generation // Did not receive not blacklisted message. Don't show password generation
// icon. // icon.
LoadHTML(kAccountCreationFormHTML); LoadHTML(kAccountCreationFormHTML);
WebDocument document = GetMainFrame()->document(); SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
WebElement element = ExpectPasswordGenerationIconShown("first_password", false);
document.getElementById(WebString::fromUTF8("first_password"));
ASSERT_FALSE(element.isNull());
WebInputElement first_password_element = element.to<WebInputElement>();
EXPECT_FALSE(DecorationIsVisible(&first_password_element));
// Receive one not blacklisted message for non account creation form. Don't // Receive one not blacklisted message for non account creation form. Don't
// show password generation icon. // show password generation icon.
LoadHTML(kAccountCreationFormHTML); LoadHTML(kAccountCreationFormHTML);
SetNotBlacklistedMessage(kSigninFormHTML); SetNotBlacklistedMessage(kSigninFormHTML);
document = GetMainFrame()->document(); SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
element = document.getElementById(WebString::fromUTF8("first_password")); ExpectPasswordGenerationIconShown("first_password", false);
ASSERT_FALSE(element.isNull());
first_password_element = element.to<WebInputElement>();
EXPECT_FALSE(DecorationIsVisible(&first_password_element));
// Receive one not blackliste message for account creation form. Show password // Receive one not blackliste message for account creation form. Show password
// generation icon. // generation icon.
LoadHTML(kAccountCreationFormHTML); LoadHTML(kAccountCreationFormHTML);
SetNotBlacklistedMessage(kAccountCreationFormHTML); SetNotBlacklistedMessage(kAccountCreationFormHTML);
document = GetMainFrame()->document(); SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
element = document.getElementById(WebString::fromUTF8("first_password")); ExpectPasswordGenerationIconShown("first_password", true);
ASSERT_FALSE(element.isNull());
first_password_element = element.to<WebInputElement>();
EXPECT_TRUE(DecorationIsVisible(&first_password_element));
SimulateClickOnDecoration(&first_password_element);
EXPECT_EQ(1u, generation_manager_->messages().size());
EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
generation_manager_->messages()[0]->type());
// Receive two not blacklisted messages, one is for account creation form and // Receive two not blacklisted messages, one is for account creation form and
// the other is not. Show password generation icon. // the other is not. Show password generation icon.
LoadHTML(kAccountCreationFormHTML); LoadHTML(kAccountCreationFormHTML);
SetNotBlacklistedMessage(kAccountCreationFormHTML); SetNotBlacklistedMessage(kAccountCreationFormHTML);
SetNotBlacklistedMessage(kSigninFormHTML); SetNotBlacklistedMessage(kSigninFormHTML);
document = GetMainFrame()->document(); SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
element = document.getElementById(WebString::fromUTF8("first_password")); ExpectPasswordGenerationIconShown("first_password", true);
ASSERT_FALSE(element.isNull()); }
first_password_element = element.to<WebInputElement>();
EXPECT_TRUE(DecorationIsVisible(&first_password_element)); TEST_F(PasswordGenerationManagerTest, AccountCreationFormsDetectedTest) {
SimulateClickOnDecoration(&first_password_element); // Make sure password generation is enabled.
EXPECT_EQ(2u, generation_manager_->messages().size()); SetPasswordGenerationEnabledMessage();
EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
generation_manager_->messages()[1]->type()); // Did not receive account creation forms detected messege. Don't show
// password generation icon.
LoadHTML(kAccountCreationFormHTML);
SetNotBlacklistedMessage(kAccountCreationFormHTML);
ExpectPasswordGenerationIconShown("first_password", false);
// Receive the account creation forms detected message. Show password
// generation icon.
LoadHTML(kAccountCreationFormHTML);
SetNotBlacklistedMessage(kAccountCreationFormHTML);
SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML);
ExpectPasswordGenerationIconShown("first_password", true);
} }
} // namespace autofill } // namespace autofill
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
#include "components/autofill/content/renderer/password_generation_manager.h" #include "components/autofill/content/renderer/password_generation_manager.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "components/autofill/content/renderer/password_form_conversion_utils.h" #include "components/autofill/content/renderer/password_form_conversion_utils.h"
#include "components/autofill/core/common/autofill_messages.h" #include "components/autofill/core/common/autofill_messages.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/password_generation_util.h" #include "components/autofill/core/common/password_generation_util.h"
#include "content/public/renderer/render_view.h" #include "content/public/renderer/render_view.h"
#include "google_apis/gaia/gaia_urls.h" #include "google_apis/gaia/gaia_urls.h"
...@@ -64,6 +66,27 @@ bool GetAccountCreationPasswordFields( ...@@ -64,6 +66,27 @@ bool GetAccountCreationPasswordFields(
return false; return false;
} }
bool ContainsURL(const std::vector<GURL>& urls, const GURL& url) {
return std::find(urls.begin(), urls.end(), url) != urls.end();
}
// Returns true if the |form1| is essentially equal to |form2|.
bool FormEquals(const autofill::FormData& form1,
const content::PasswordForm& form2) {
// TODO(zysxqn): use more signals than just origin to compare.
return form1.origin == form2.origin;
}
bool ContainsForm(const std::vector<autofill::FormData>& forms,
const content::PasswordForm& form) {
for (std::vector<autofill::FormData>::const_iterator it =
forms.begin(); it != forms.end(); ++it) {
if (FormEquals(*it, form))
return true;
}
return false;
}
} // namespace } // namespace
PasswordGenerationManager::PasswordGenerationManager( PasswordGenerationManager::PasswordGenerationManager(
...@@ -83,10 +106,13 @@ void PasswordGenerationManager::DidFinishDocumentLoad(WebKit::WebFrame* frame) { ...@@ -83,10 +106,13 @@ void PasswordGenerationManager::DidFinishDocumentLoad(WebKit::WebFrame* frame) {
// as we don't want subframe loads to clear state that we have recieved from // as we don't want subframe loads to clear state that we have recieved from
// the main frame. Note that we assume there is only one account creation // the main frame. Note that we assume there is only one account creation
// form, but there could be multiple password forms in each frame. // form, but there could be multiple password forms in each frame.
//
// TODO(zysxqn): Add stat when local heuristic fires but we don't show the
// password generation icon.
if (!frame->parent()) { if (!frame->parent()) {
not_blacklisted_password_form_origins_.clear(); not_blacklisted_password_form_origins_.clear();
// Initialize to an empty and invalid GURL. account_creation_forms_.clear();
account_creation_form_origin_ = GURL(); possible_account_creation_form_.reset(new content::PasswordForm());
passwords_.clear(); passwords_.clear();
} }
} }
...@@ -127,7 +153,7 @@ void PasswordGenerationManager::DidFinishLoad(WebKit::WebFrame* frame) { ...@@ -127,7 +153,7 @@ void PasswordGenerationManager::DidFinishLoad(WebKit::WebFrame* frame) {
password_generation::LogPasswordGenerationEvent( password_generation::LogPasswordGenerationEvent(
password_generation::SIGN_UP_DETECTED); password_generation::SIGN_UP_DETECTED);
passwords_ = passwords; passwords_ = passwords;
account_creation_form_origin_ = password_form->origin; possible_account_creation_form_.swap(password_form);
MaybeShowIcon(); MaybeShowIcon();
// We assume that there is only one account creation field per URL. // We assume that there is only one account creation field per URL.
return; return;
...@@ -176,6 +202,8 @@ bool PasswordGenerationManager::OnMessageReceived(const IPC::Message& message) { ...@@ -176,6 +202,8 @@ bool PasswordGenerationManager::OnMessageReceived(const IPC::Message& message) {
OnPasswordAccepted) OnPasswordAccepted)
IPC_MESSAGE_HANDLER(AutofillMsg_PasswordGenerationEnabled, IPC_MESSAGE_HANDLER(AutofillMsg_PasswordGenerationEnabled,
OnPasswordGenerationEnabled) OnPasswordGenerationEnabled)
IPC_MESSAGE_HANDLER(AutofillMsg_AccountCreationFormsDetected,
OnAccountCreationFormsDetected)
IPC_MESSAGE_UNHANDLED(handled = false) IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP() IPC_END_MESSAGE_MAP()
return handled; return handled;
...@@ -203,27 +231,39 @@ void PasswordGenerationManager::OnPasswordGenerationEnabled(bool enabled) { ...@@ -203,27 +231,39 @@ void PasswordGenerationManager::OnPasswordGenerationEnabled(bool enabled) {
enabled_ = enabled; enabled_ = enabled;
} }
void PasswordGenerationManager::OnAccountCreationFormsDetected(
const std::vector<autofill::FormData>& forms) {
account_creation_forms_.insert(
account_creation_forms_.end(), forms.begin(), forms.end());
MaybeShowIcon();
}
void PasswordGenerationManager::MaybeShowIcon() { void PasswordGenerationManager::MaybeShowIcon() {
// We should show the password generation icon only when we have detected // We should show the password generation icon only when we have detected
// account creation form and we have confirmed from browser that this form // account creation form, we have confirmed from browser that this form
// is not blacklisted by the users. // is not blacklisted by the users, and the Autofill server has marked one
if (!account_creation_form_origin_.is_valid() || // of its field as ACCOUNT_CREATION_PASSWORD.
if (!possible_account_creation_form_.get() ||
passwords_.empty() || passwords_.empty() ||
not_blacklisted_password_form_origins_.empty()) { not_blacklisted_password_form_origins_.empty() ||
account_creation_forms_.empty()) {
return; return;
} }
for (std::vector<GURL>::iterator it = if (!ContainsURL(not_blacklisted_password_form_origins_,
not_blacklisted_password_form_origins_.begin(); possible_account_creation_form_->origin)) {
it != not_blacklisted_password_form_origins_.end(); ++it) { return;
if (*it == account_creation_form_origin_) {
passwords_[0].passwordGeneratorButtonElement().setAttribute("style",
"display:block");
password_generation::LogPasswordGenerationEvent(
password_generation::ICON_SHOWN);
return;
}
} }
if (!ContainsForm(account_creation_forms_,
*possible_account_creation_form_)) {
return;
}
passwords_[0].passwordGeneratorButtonElement().setAttribute("style",
"display:block");
password_generation::LogPasswordGenerationEvent(
password_generation::ICON_SHOWN);
} }
} // namespace autofill } // namespace autofill
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "base/memory/scoped_ptr.h"
#include "content/public/renderer/render_view_observer.h" #include "content/public/renderer/render_view_observer.h"
#include "third_party/WebKit/public/web/WebInputElement.h" #include "third_party/WebKit/public/web/WebInputElement.h"
#include "third_party/WebKit/public/web/WebPasswordGeneratorClient.h" #include "third_party/WebKit/public/web/WebPasswordGeneratorClient.h"
...@@ -19,6 +20,10 @@ class WebCString; ...@@ -19,6 +20,10 @@ class WebCString;
class WebDocument; class WebDocument;
} }
namespace autofill {
struct FormData;
}
namespace content { namespace content {
struct PasswordForm; struct PasswordForm;
} }
...@@ -54,6 +59,8 @@ class PasswordGenerationManager : public content::RenderViewObserver, ...@@ -54,6 +59,8 @@ class PasswordGenerationManager : public content::RenderViewObserver,
void OnFormNotBlacklisted(const content::PasswordForm& form); void OnFormNotBlacklisted(const content::PasswordForm& form);
void OnPasswordAccepted(const base::string16& password); void OnPasswordAccepted(const base::string16& password);
void OnPasswordGenerationEnabled(bool enabled); void OnPasswordGenerationEnabled(bool enabled);
void OnAccountCreationFormsDetected(
const std::vector<autofill::FormData>& forms);
// Helper function to decide whether we should show password generation icon. // Helper function to decide whether we should show password generation icon.
void MaybeShowIcon(); void MaybeShowIcon();
...@@ -65,13 +72,17 @@ class PasswordGenerationManager : public content::RenderViewObserver, ...@@ -65,13 +72,17 @@ class PasswordGenerationManager : public content::RenderViewObserver,
bool enabled_; bool enabled_;
// Stores the origin of the account creation form we detected. // Stores the origin of the account creation form we detected.
GURL account_creation_form_origin_; scoped_ptr<content::PasswordForm> possible_account_creation_form_;
// Stores the origins of the password forms confirmed not to be blacklisted // Stores the origins of the password forms confirmed not to be blacklisted
// by the browser. A form can be blacklisted if a user chooses "never save // by the browser. A form can be blacklisted if a user chooses "never save
// passwords for this site". // passwords for this site".
std::vector<GURL> not_blacklisted_password_form_origins_; std::vector<GURL> not_blacklisted_password_form_origins_;
// Stores each password form for which the Autofill server classifies one of
// the form's fields as an ACCOUNT_CREATION_PASSWORD.
std::vector<autofill::FormData> account_creation_forms_;
std::vector<WebKit::WebInputElement> passwords_; std::vector<WebKit::WebInputElement> passwords_;
DISALLOW_COPY_AND_ASSIGN(PasswordGenerationManager); DISALLOW_COPY_AND_ASSIGN(PasswordGenerationManager);
......
...@@ -707,6 +707,10 @@ void AutofillManager::OnLoadedServerPredictions( ...@@ -707,6 +707,10 @@ void AutofillManager::OnLoadedServerPredictions(
form_structures_.get(), form_structures_.get(),
*metric_logger_); *metric_logger_);
// Forward form structures to the password generation manager to detect
// account creation forms.
manager_delegate_->DetectAccountCreationForms(form_structures_.get());
// If the corresponding flag is set, annotate forms with the predicted types. // If the corresponding flag is set, annotate forms with the predicted types.
driver_->SendAutofillTypePredictionsToRenderer(form_structures_.get()); driver_->SendAutofillTypePredictionsToRenderer(form_structures_.get());
} }
......
...@@ -95,6 +95,11 @@ class AutofillManagerDelegate { ...@@ -95,6 +95,11 @@ class AutofillManagerDelegate {
// Whether the Autocomplete feature of Autofill should be enabled. // Whether the Autocomplete feature of Autofill should be enabled.
virtual bool IsAutocompleteEnabled() = 0; virtual bool IsAutocompleteEnabled() = 0;
// Pass the form structures to the password generation manager to detect
// account creation forms.
virtual void DetectAccountCreationForms(
const std::vector<autofill::FormStructure*>& forms) = 0;
}; };
} // namespace autofill } // namespace autofill
......
...@@ -862,6 +862,7 @@ FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) { ...@@ -862,6 +862,7 @@ FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) {
case NO_GROUP: case NO_GROUP:
case CREDIT_CARD: case CREDIT_CARD:
case PASSWORD_FIELD:
return NULL; return NULL;
} }
......
...@@ -108,6 +108,10 @@ FieldTypeGroup AutofillType::group() const { ...@@ -108,6 +108,10 @@ FieldTypeGroup AutofillType::group() const {
case COMPANY_NAME: case COMPANY_NAME:
return COMPANY; return COMPANY;
case PASSWORD:
case ACCOUNT_CREATION_PASSWORD:
return PASSWORD_FIELD;
case NO_SERVER_DATA: case NO_SERVER_DATA:
case EMPTY_TYPE: case EMPTY_TYPE:
case PHONE_FAX_NUMBER: case PHONE_FAX_NUMBER:
...@@ -116,6 +120,8 @@ FieldTypeGroup AutofillType::group() const { ...@@ -116,6 +120,8 @@ FieldTypeGroup AutofillType::group() const {
case PHONE_FAX_CITY_AND_NUMBER: case PHONE_FAX_CITY_AND_NUMBER:
case PHONE_FAX_WHOLE_NUMBER: case PHONE_FAX_WHOLE_NUMBER:
case FIELD_WITH_DEFAULT_VALUE: case FIELD_WITH_DEFAULT_VALUE:
case MERCHANT_EMAIL_SIGNUP:
case MERCHANT_PROMO_CODE:
return NO_GROUP; return NO_GROUP;
case MAX_VALID_FIELD_TYPE: case MAX_VALID_FIELD_TYPE:
...@@ -529,6 +535,14 @@ std::string AutofillType::ToString() const { ...@@ -529,6 +535,14 @@ std::string AutofillType::ToString() const {
return "PHONE_BILLING_CITY_AND_NUMBER"; return "PHONE_BILLING_CITY_AND_NUMBER";
case PHONE_BILLING_WHOLE_NUMBER: case PHONE_BILLING_WHOLE_NUMBER:
return "PHONE_BILLING_WHOLE_NUMBER"; return "PHONE_BILLING_WHOLE_NUMBER";
case MERCHANT_EMAIL_SIGNUP:
return "MERCHANT_EMAIL_SIGNUP";
case MERCHANT_PROMO_CODE:
return "MERCHANT_PROMO_CODE";
case PASSWORD:
return "PASSWORD";
case ACCOUNT_CREATION_PASSWORD:
return "ACCOUNT_CREATION_PASSWORD";
case MAX_VALID_FIELD_TYPE: case MAX_VALID_FIELD_TYPE:
return std::string(); return std::string();
} }
......
...@@ -99,10 +99,22 @@ enum ServerFieldType { ...@@ -99,10 +99,22 @@ enum ServerFieldType {
NAME_BILLING_FULL = 71, NAME_BILLING_FULL = 71,
NAME_BILLING_SUFFIX = 72, NAME_BILLING_SUFFIX = 72,
// Field types for options generally found in merchant buyflows. Given that
// these are likely to be filled out differently on a case by case basis,
// they are here primarly for use by Autocheckout.
MERCHANT_EMAIL_SIGNUP = 73,
MERCHANT_PROMO_CODE = 74,
// Field types for the password fields. PASSWORD is the default type for all
// password fields. ACCOUNT_CREATION_PASSWORD is the first password field in
// an account creation form and will trigger password generation.
PASSWORD = 75,
ACCOUNT_CREATION_PASSWORD = 76,
// No new types can be added without a corresponding change to the Autofill // No new types can be added without a corresponding change to the Autofill
// server. // server.
MAX_VALID_FIELD_TYPE = 73, MAX_VALID_FIELD_TYPE = 77,
}; };
// The list of all HTML autocomplete field type hints supported by Chrome. // The list of all HTML autocomplete field type hints supported by Chrome.
...@@ -181,6 +193,7 @@ enum FieldTypeGroup { ...@@ -181,6 +193,7 @@ enum FieldTypeGroup {
PHONE_HOME, PHONE_HOME,
PHONE_BILLING, PHONE_BILLING,
CREDIT_CARD, CREDIT_CARD,
PASSWORD_FIELD,
}; };
typedef std::set<ServerFieldType> ServerFieldTypeSet; typedef std::set<ServerFieldType> ServerFieldTypeSet;
......
...@@ -660,7 +660,7 @@ std::string FormStructure::FormSignature() const { ...@@ -660,7 +660,7 @@ std::string FormStructure::FormSignature() const {
} }
bool FormStructure::ShouldSkipField(const FormFieldData& field) const { bool FormStructure::ShouldSkipField(const FormFieldData& field) const {
return (field.is_checkable || field.form_control_type == "password"); return field.is_checkable;
} }
bool FormStructure::IsAutofillable(bool require_method_post) const { bool FormStructure::IsAutofillable(bool require_method_post) const {
......
...@@ -2261,10 +2261,11 @@ TEST(FormStructureTest, CheckFormSignature) { ...@@ -2261,10 +2261,11 @@ TEST(FormStructureTest, CheckFormSignature) {
field.name = ASCIIToUTF16("first"); field.name = ASCIIToUTF16("first");
form.fields.push_back(field); form.fields.push_back(field);
// Password fields shouldn't affect the signature. // Checkable fields shouldn't affect the signature.
field.label = ASCIIToUTF16("Password"); field.label = ASCIIToUTF16("Select");
field.name = ASCIIToUTF16("password"); field.name = ASCIIToUTF16("Select");
field.form_control_type = "password"; field.form_control_type = "checkbox";
field.is_checkable = true;
form.fields.push_back(field); form.fields.push_back(field);
form_structure.reset(new FormStructure(form)); form_structure.reset(new FormStructure(form));
...@@ -2291,6 +2292,7 @@ TEST(FormStructureTest, CheckFormSignature) { ...@@ -2291,6 +2292,7 @@ TEST(FormStructureTest, CheckFormSignature) {
std::string("https://login.facebook.com&login_form&email&first")), std::string("https://login.facebook.com&login_form&email&first")),
form_structure->FormSignature()); form_structure->FormSignature());
field.is_checkable = false;
field.label = ASCIIToUTF16("Random Field label"); field.label = ASCIIToUTF16("Random Field label");
field.name = ASCIIToUTF16("random1234"); field.name = ASCIIToUTF16("random1234");
field.form_control_type = "text"; field.form_control_type = "text";
...@@ -2356,14 +2358,16 @@ TEST(FormStructureTest, SkipFieldTest) { ...@@ -2356,14 +2358,16 @@ TEST(FormStructureTest, SkipFieldTest) {
field.form_control_type = "text"; field.form_control_type = "text";
form.fields.push_back(field); form.fields.push_back(field);
field.label = ASCIIToUTF16("password"); field.label = ASCIIToUTF16("select");
field.name = ASCIIToUTF16("password"); field.name = ASCIIToUTF16("select");
field.form_control_type = "password"; field.form_control_type = "checkbox";
field.is_checkable = true;
form.fields.push_back(field); form.fields.push_back(field);
field.label = base::string16(); field.label = base::string16();
field.name = ASCIIToUTF16("email"); field.name = ASCIIToUTF16("email");
field.form_control_type = "text"; field.form_control_type = "text";
field.is_checkable = false;
form.fields.push_back(field); form.fields.push_back(field);
ScopedVector<FormStructure> forms; ScopedVector<FormStructure> forms;
......
...@@ -51,4 +51,7 @@ bool TestAutofillManagerDelegate::IsAutocompleteEnabled() { ...@@ -51,4 +51,7 @@ bool TestAutofillManagerDelegate::IsAutocompleteEnabled() {
return true; return true;
} }
void TestAutofillManagerDelegate::DetectAccountCreationForms(
const std::vector<autofill::FormStructure*>& forms) {}
} // namespace autofill } // namespace autofill
...@@ -46,6 +46,9 @@ class TestAutofillManagerDelegate : public AutofillManagerDelegate { ...@@ -46,6 +46,9 @@ class TestAutofillManagerDelegate : public AutofillManagerDelegate {
virtual void HideAutofillPopup() OVERRIDE; virtual void HideAutofillPopup() OVERRIDE;
virtual bool IsAutocompleteEnabled() OVERRIDE; virtual bool IsAutocompleteEnabled() OVERRIDE;
virtual void DetectAccountCreationForms(
const std::vector<autofill::FormStructure*>& forms) OVERRIDE;
private: private:
DISALLOW_COPY_AND_ASSIGN(TestAutofillManagerDelegate); DISALLOW_COPY_AND_ASSIGN(TestAutofillManagerDelegate);
}; };
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include "ipc/ipc_message_utils.h" #include "ipc/ipc_message_utils.h"
#include "third_party/WebKit/public/web/WebFormElement.h" #include "third_party/WebKit/public/web/WebFormElement.h"
#include "ui/gfx/rect.h" #include "ui/gfx/rect.h"
#include "url/gurl.h"
#define IPC_MESSAGE_START AutofillMsgStart #define IPC_MESSAGE_START AutofillMsgStart
...@@ -169,6 +168,11 @@ IPC_MESSAGE_ROUTED2(AutofillMsg_RequestAutocompleteResult, ...@@ -169,6 +168,11 @@ IPC_MESSAGE_ROUTED2(AutofillMsg_RequestAutocompleteResult,
// after being preloaded. // after being preloaded.
IPC_MESSAGE_ROUTED0(AutofillMsg_PageShown) IPC_MESSAGE_ROUTED0(AutofillMsg_PageShown)
// Sent when Autofill manager gets the query response from the Autofill server
// and there are fields classified as ACCOUNT_CREATION_PASSWORD in the response.
IPC_MESSAGE_ROUTED1(AutofillMsg_AccountCreationFormsDetected,
std::vector<autofill::FormData> /* forms */)
// Autofill messages sent from the renderer to the browser. // Autofill messages sent from the renderer to the browser.
// TODO(creis): check in the browser that the renderer actually has permission // TODO(creis): check in the browser that the renderer actually has permission
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment