summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordgwallinga@chromium.org <dgwallinga@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-30 21:33:08 +0000
committerdgwallinga@chromium.org <dgwallinga@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-30 21:33:08 +0000
commit17b6be77f10220c35d5eda624a8d4570ea4bdfbc (patch)
tree3507ab64be5f535faa677529f80aab9195a7256b
parente7bd97ddcf62efc9f737c537cd0e92f1712d400f (diff)
downloadchromium_src-17b6be77f10220c35d5eda624a8d4570ea4bdfbc.zip
chromium_src-17b6be77f10220c35d5eda624a8d4570ea4bdfbc.tar.gz
chromium_src-17b6be77f10220c35d5eda624a8d4570ea4bdfbc.tar.bz2
Requery the autofill server when forms and input fields are dynamically added.
BUG=224802 Review URL: https://chromiumcodereview.appspot.com/13264002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@197479 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/renderer/autofill/autofill_renderer_browsertest.cc55
-rw-r--r--components/autofill/browser/autofill_manager.cc17
-rw-r--r--components/autofill/browser/autofill_manager.h3
-rw-r--r--components/autofill/browser/autofill_manager_unittest.cc48
-rw-r--r--components/autofill/browser/autofill_metrics_unittest.cc37
-rw-r--r--components/autofill/common/autofill_messages.h4
-rw-r--r--components/autofill/common/forms_seen_state.h22
-rw-r--r--components/autofill/renderer/autofill_agent.cc47
-rw-r--r--components/autofill/renderer/autofill_agent.h13
9 files changed, 225 insertions, 21 deletions
diff --git a/chrome/renderer/autofill/autofill_renderer_browsertest.cc b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
index c09c4c2..c2b57b2 100644
--- a/chrome/renderer/autofill/autofill_renderer_browsertest.cc
+++ b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
@@ -125,6 +125,61 @@ TEST_F(ChromeRenderViewTest, SendForms) {
EXPECT_FORM_FIELD_DATA_EQUALS(expected, form2.fields[2]);
}
+TEST_F(ChromeRenderViewTest, SendDynamicForms) {
+ // Don't want any delay for form state sync changes. This will still post a
+ // message so updates will get coalesced, but as soon as we spin the message
+ // loop, it will generate an update.
+ SendContentStateImmediately();
+
+ LoadHTML("<form method=\"POST\" id=\"testform\">"
+ " <input type=\"text\" id=\"firstname\"/>"
+ " <input type=\"text\" id=\"middlename\"/>"
+ " <input type=\"text\" id=\"lastname\" autoComplete=\"off\"/>"
+ " <input type=\"hidden\" id=\"email\"/>"
+ " <select id=\"state\"/>"
+ " <option>?</option>"
+ " <option>California</option>"
+ " <option>Texas</option>"
+ " </select>"
+ "</form>");
+
+ // Verify that "FormsSeen" sends the expected number of fields.
+ const IPC::Message* message = render_thread_->sink().GetFirstMessageMatching(
+ AutofillHostMsg_FormsSeen::ID);
+ ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
+ AutofillHostMsg_FormsSeen::Param params;
+ AutofillHostMsg_FormsSeen::Read(message, &params);
+ const std::vector<FormData>& forms = params.a;
+ ASSERT_EQ(1UL, forms.size());
+ ASSERT_EQ(4UL, forms[0].fields.size());
+
+ autofill_agent_->OnAutocheckoutSupported();
+ render_thread_->sink().ClearMessages();
+ ExecuteJavaScript("var newInput=document.createElement(\"input\");"
+ "newInput.setAttribute(\"type\",\"text\");"
+ "newInput.setAttribute(\"id\", \"telephone\");"
+ "document.getElementById(\"testform\")"
+ ".appendChild(newInput);");
+ msg_loop_.RunUntilIdle();
+
+ // Verify that FormsSeen is present with the new field.
+ const IPC::Message* message2 = render_thread_->sink().GetFirstMessageMatching(
+ AutofillHostMsg_FormsSeen::ID);
+ ASSERT_NE(static_cast<IPC::Message*>(NULL), message2);
+ AutofillHostMsg_FormsSeen::Read(message2, &params);
+ const std::vector<FormData>& new_forms = params.a;
+ ASSERT_EQ(1UL, new_forms.size());
+ ASSERT_EQ(5UL, new_forms[0].fields.size());
+
+ FormFieldData expected;
+
+ expected.name = ASCIIToUTF16("telephone");
+ expected.value = string16();
+ expected.form_control_type = "text";
+ expected.max_length = WebInputElement::defaultMaxLength();
+ EXPECT_FORM_FIELD_DATA_EQUALS(expected, forms[0].fields[4]);
+}
+
TEST_F(ChromeRenderViewTest, FillFormElement) {
// Don't want any delay for form state sync changes. This will still post a
// message so updates will get coalesced, but as soon as we spin the message
diff --git a/components/autofill/browser/autofill_manager.cc b/components/autofill/browser/autofill_manager.cc
index 20c16e8..f2e2907 100644
--- a/components/autofill/browser/autofill_manager.cc
+++ b/components/autofill/browser/autofill_manager.cc
@@ -381,17 +381,28 @@ bool AutofillManager::OnFormSubmitted(const FormData& form,
void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms,
const TimeTicks& timestamp,
- bool has_more_forms) {
+ autofill::FormsSeenState state) {
+ bool is_post_document_load = state == autofill::DYNAMIC_FORMS_SEEN;
+ bool has_more_forms = state == autofill::PARTIAL_FORMS_SEEN;
+ // If new forms were added via AJAX or DHML, treat as new page.
+ if (is_post_document_load)
+ Reset();
+
RenderViewHost* host = web_contents()->GetRenderViewHost();
if (!host)
return;
if (!GetAutocheckoutURLPrefix().empty()) {
// If whitelisted URL, fetch all the forms.
- if (has_more_forms) {
+ if (has_more_forms)
host->Send(new AutofillMsg_GetAllForms(host->GetRoutingID()));
- return;
+ if (!is_post_document_load) {
+ host->Send(
+ new AutofillMsg_AutocheckoutSupported(host->GetRoutingID()));
}
+ // Now return early, as OnFormsSeen will get called again with all forms.
+ if (has_more_forms)
+ return;
}
autocheckout_manager_.OnFormsSeen();
diff --git a/components/autofill/browser/autofill_manager.h b/components/autofill/browser/autofill_manager.h
index 9912c23..9fd261b 100644
--- a/components/autofill/browser/autofill_manager.h
+++ b/components/autofill/browser/autofill_manager.h
@@ -29,6 +29,7 @@
#include "components/autofill/browser/personal_data_manager.h"
#include "components/autofill/common/autocheckout_status.h"
#include "components/autofill/common/form_data.h"
+#include "components/autofill/common/forms_seen_state.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/ssl_status.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFormElement.h"
@@ -214,7 +215,7 @@ class AutofillManager : public content::WebContentsObserver,
void OnFormsSeen(const std::vector<FormData>& forms,
const base::TimeTicks& timestamp,
- bool has_more_forms);
+ autofill::FormsSeenState state);
void OnTextFieldDidChange(const FormData& form,
const FormFieldData& field,
const base::TimeTicks& timestamp);
diff --git a/components/autofill/browser/autofill_manager_unittest.cc b/components/autofill/browser/autofill_manager_unittest.cc
index 0c9b9ce0..1c9bd68 100644
--- a/components/autofill/browser/autofill_manager_unittest.cc
+++ b/components/autofill/browser/autofill_manager_unittest.cc
@@ -38,6 +38,7 @@
#include "components/autofill/common/autofill_messages.h"
#include "components/autofill/common/form_data.h"
#include "components/autofill/common/form_field_data.h"
+#include "components/autofill/common/forms_seen_state.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/mock_render_process_host.h"
@@ -697,11 +698,18 @@ class AutofillManagerTest : public ChromeRenderViewHostTestHarness {
}
void FormsSeen(const std::vector<FormData>& forms) {
- autofill_manager_->OnFormsSeen(forms, base::TimeTicks(), false);
+ autofill_manager_->OnFormsSeen(forms, base::TimeTicks(),
+ autofill::NO_SPECIAL_FORMS_SEEN);
}
void PartialFormsSeen(const std::vector<FormData>& forms) {
- autofill_manager_->OnFormsSeen(forms, base::TimeTicks(), true);
+ autofill_manager_->OnFormsSeen(forms, base::TimeTicks(),
+ autofill::PARTIAL_FORMS_SEEN);
+ }
+
+ void DynamicFormsSeen(const std::vector<FormData>& forms) {
+ autofill_manager_->OnFormsSeen(forms, base::TimeTicks(),
+ autofill::DYNAMIC_FORMS_SEEN);
}
void FormSubmitted(const FormData& form) {
@@ -907,6 +915,42 @@ TEST_F(AutofillManagerTest, AutocheckoutFormsSeen) {
EXPECT_EQ("/form.html", form_structures[2]->source_url().path());
}
+// Test that in the case of Autocheckout, forms seen are in order supplied.
+TEST_F(AutofillManagerTest, DynamicFormsSeen) {
+ FormData shipping_options;
+ CreateTestShippingOptionsFormData(&shipping_options);
+ FormData user_supplied;
+ CreateTestFormWithAutocompleteAttribute(&user_supplied);
+ FormData address;
+ CreateTestAddressFormData(&address);
+
+ autofill_manager_->set_autocheckout_url_prefix("test-prefix");
+ // Push user_supplied only
+ std::vector<FormData> forms;
+ forms.push_back(user_supplied);
+
+ // Make sure normal form is handled correctly.
+ FormsSeen(forms);
+ std::vector<FormStructure*> form_structures;
+ form_structures = autofill_manager_->GetFormStructures();
+ ASSERT_EQ(1U, form_structures.size());
+ EXPECT_EQ("/userspecified.html", form_structures[0]->source_url().path());
+
+ // Push other forms
+ forms.push_back(shipping_options);
+ forms.push_back(address);
+
+ // FormStructure should contain three and only three forms. Otherwise, it
+ // would indicate that the manager didn't reset upon being notified of
+ // the new forms;
+ DynamicFormsSeen(forms);
+ form_structures = autofill_manager_->GetFormStructures();
+ ASSERT_EQ(3U, form_structures.size());
+ EXPECT_EQ("/userspecified.html", form_structures[0]->source_url().path());
+ EXPECT_EQ("/shipping.html", form_structures[1]->source_url().path());
+ EXPECT_EQ("/form.html", form_structures[2]->source_url().path());
+}
+
// Test that we return only matching address profile suggestions when the
// selected form field has been partially filled out.
TEST_F(AutofillManagerTest, GetProfileSuggestionsMatchCharacter) {
diff --git a/components/autofill/browser/autofill_metrics_unittest.cc b/components/autofill/browser/autofill_metrics_unittest.cc
index b6df550..14c5c19 100644
--- a/components/autofill/browser/autofill_metrics_unittest.cc
+++ b/components/autofill/browser/autofill_metrics_unittest.cc
@@ -22,6 +22,7 @@
#include "components/autofill/browser/personal_data_manager.h"
#include "components/autofill/common/form_data.h"
#include "components/autofill/common/form_field_data.h"
+#include "components/autofill/common/forms_seen_state.h"
#include "components/webdata/common/web_data_results.h"
#include "content/public/test/test_browser_thread.h"
#include "content/public/test/test_utils.h"
@@ -777,7 +778,8 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
{
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogDeveloperEngagementMetric(_)).Times(0);
- autofill_manager_->OnFormsSeen(forms, TimeTicks(), false);
+ autofill_manager_->OnFormsSeen(forms, TimeTicks(),
+ autofill::NO_SPECIAL_FORMS_SEEN);
autofill_manager_->Reset();
Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger());
}
@@ -797,7 +799,8 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
*autofill_manager_->metric_logger(),
LogDeveloperEngagementMetric(
AutofillMetrics::FILLABLE_FORM_CONTAINS_TYPE_HINTS)).Times(0);
- autofill_manager_->OnFormsSeen(forms, TimeTicks(), false);
+ autofill_manager_->OnFormsSeen(forms, TimeTicks(),
+ autofill::NO_SPECIAL_FORMS_SEEN);
autofill_manager_->Reset();
Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger());
}
@@ -828,7 +831,8 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
*autofill_manager_->metric_logger(),
LogDeveloperEngagementMetric(
AutofillMetrics::FILLABLE_FORM_CONTAINS_TYPE_HINTS)).Times(1);
- autofill_manager_->OnFormsSeen(forms, TimeTicks(), false);
+ autofill_manager_->OnFormsSeen(forms, TimeTicks(),
+ autofill::NO_SPECIAL_FORMS_SEEN);
autofill_manager_->Reset();
Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger());
}
@@ -1103,7 +1107,8 @@ TEST_F(AutofillMetricsTest, AutofillIsEnabledAtPageLoad) {
LogIsAutofillEnabledAtPageLoad(true)).Times(1);
autofill_manager_->set_autofill_enabled(true);
- autofill_manager_->OnFormsSeen(std::vector<FormData>(), TimeTicks(), false);
+ autofill_manager_->OnFormsSeen(std::vector<FormData>(), TimeTicks(),
+ autofill::NO_SPECIAL_FORMS_SEEN);
// Reset the autofill manager state.
autofill_manager_->Reset();
@@ -1113,7 +1118,8 @@ TEST_F(AutofillMetricsTest, AutofillIsEnabledAtPageLoad) {
LogIsAutofillEnabledAtPageLoad(false)).Times(1);
autofill_manager_->set_autofill_enabled(false);
- autofill_manager_->OnFormsSeen(std::vector<FormData>(), TimeTicks(), false);
+ autofill_manager_->OnFormsSeen(std::vector<FormData>(), TimeTicks(),
+ autofill::NO_SPECIAL_FORMS_SEEN);
}
// Test that credit card infobar metrics are logged correctly.
@@ -1226,7 +1232,8 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) {
{
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED)).Times(0);
- autofill_manager_->OnFormsSeen(forms, TimeTicks(), false);
+ autofill_manager_->OnFormsSeen(forms, TimeTicks(),
+ autofill::NO_SPECIAL_FORMS_SEEN);
}
@@ -1262,7 +1269,8 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) {
{
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED));
- autofill_manager_->OnFormsSeen(forms, TimeTicks(), false);
+ autofill_manager_->OnFormsSeen(forms, TimeTicks(),
+ autofill::NO_SPECIAL_FORMS_SEEN);
}
// Expect a notification when the form is submitted.
@@ -1362,7 +1370,8 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) {
{
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED));
- autofill_manager_->OnFormsSeen(forms, TimeTicks(), false);
+ autofill_manager_->OnFormsSeen(forms, TimeTicks(),
+ autofill::NO_SPECIAL_FORMS_SEEN);
}
// Simulate typing.
@@ -1482,7 +1491,8 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogFormFillDurationFromInteractionWithoutAutofill(_)).Times(0);
autofill_manager_->OnFormsSeen(
- forms, TimeTicks::FromInternalValue(1), false);
+ forms, TimeTicks::FromInternalValue(1),
+ autofill::NO_SPECIAL_FORMS_SEEN);
autofill_manager_->FormSubmitted(form, TimeTicks::FromInternalValue(17));
autofill_manager_->Reset();
Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger());
@@ -1501,7 +1511,8 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
LogFormFillDurationFromInteractionWithoutAutofill(
TimeDelta::FromInternalValue(14)));
autofill_manager_->OnFormsSeen(
- forms, TimeTicks::FromInternalValue(1), false);
+ forms, TimeTicks::FromInternalValue(1),
+ autofill::NO_SPECIAL_FORMS_SEEN);
autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
TimeTicks::FromInternalValue(3));
autofill_manager_->FormSubmitted(form, TimeTicks::FromInternalValue(17));
@@ -1523,7 +1534,8 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogFormFillDurationFromInteractionWithoutAutofill(_)).Times(0);
autofill_manager_->OnFormsSeen(
- forms, TimeTicks::FromInternalValue(1), false);
+ forms, TimeTicks::FromInternalValue(1),
+ autofill::NO_SPECIAL_FORMS_SEEN);
autofill_manager_->OnDidFillAutofillFormData(
TimeTicks::FromInternalValue(5));
autofill_manager_->FormSubmitted(form, TimeTicks::FromInternalValue(17));
@@ -1546,7 +1558,8 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogFormFillDurationFromInteractionWithoutAutofill(_)).Times(0);
autofill_manager_->OnFormsSeen(
- forms, TimeTicks::FromInternalValue(1), false);
+ forms, TimeTicks::FromInternalValue(1),
+ autofill::NO_SPECIAL_FORMS_SEEN);
autofill_manager_->OnDidFillAutofillFormData(
TimeTicks::FromInternalValue(5));
autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
diff --git a/components/autofill/common/autofill_messages.h b/components/autofill/common/autofill_messages.h
index abcb0be..f8efa89 100644
--- a/components/autofill/common/autofill_messages.h
+++ b/components/autofill/common/autofill_messages.h
@@ -12,6 +12,7 @@
#include "components/autofill/common/form_data_predictions.h"
#include "components/autofill/common/form_field_data.h"
#include "components/autofill/common/form_field_data_predictions.h"
+#include "components/autofill/common/forms_seen_state.h"
#include "components/autofill/common/password_form_fill_data.h"
#include "components/autofill/common/web_element_descriptor.h"
#include "content/public/common/common_param_traits.h"
@@ -27,6 +28,7 @@
#define IPC_MESSAGE_START AutofillMsgStart
IPC_ENUM_TRAITS(autofill::AutocheckoutStatus)
+IPC_ENUM_TRAITS(autofill::FormsSeenState)
IPC_STRUCT_TRAITS_BEGIN(autofill::WebElementDescriptor)
IPC_STRUCT_TRAITS_MEMBER(descriptor)
@@ -181,7 +183,7 @@ IPC_MESSAGE_ROUTED0(AutofillMsg_AutocheckoutSupported)
IPC_MESSAGE_ROUTED3(AutofillHostMsg_FormsSeen,
std::vector<autofill::FormData> /* forms */,
base::TimeTicks /* timestamp */,
- bool /* has_more_forms */)
+ autofill::FormsSeenState /* state */)
// Notification that password forms have been seen that are candidates for
// filling/submitting by the password manager.
diff --git a/components/autofill/common/forms_seen_state.h b/components/autofill/common/forms_seen_state.h
new file mode 100644
index 0000000..5f6f582
--- /dev/null
+++ b/components/autofill/common/forms_seen_state.h
@@ -0,0 +1,22 @@
+// Copyright 2013 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 COMPONENTS_AUTOFILL_COMMON_FORMS_SEEN_PARAM_H_
+#define COMPONENTS_AUTOFILL_COMMON_FORMS_SEEN_PARAM_H_
+
+namespace autofill {
+
+// Specifies the nature of the forms triggering the call.
+enum FormsSeenState {
+ // Forms present on page load with no additional unsent forms.
+ NO_SPECIAL_FORMS_SEEN = 0,
+ // If this an Autocheckout page, there are more that should be checked.
+ PARTIAL_FORMS_SEEN = 1,
+ // Forms were added dynamically post-page load.
+ DYNAMIC_FORMS_SEEN = 2,
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_COMMON_FORMS_SEEN_PARAM_H_
diff --git a/components/autofill/renderer/autofill_agent.cc b/components/autofill/renderer/autofill_agent.cc
index beefed0..fa2b8a8 100644
--- a/components/autofill/renderer/autofill_agent.cc
+++ b/components/autofill/renderer/autofill_agent.cc
@@ -151,6 +151,8 @@ AutofillAgent::AutofillAgent(content::RenderView* render_view,
has_shown_autofill_popup_for_current_edit_(false),
did_set_node_text_(false),
autocheckout_click_in_progress_(false),
+ is_autocheckout_supported_(false),
+ has_new_forms_for_browser_(false),
try_to_show_autocheckout_bubble_(false),
ignore_text_changes_(false),
weak_ptr_factory_(this) {
@@ -214,11 +216,14 @@ void AutofillAgent::DidFinishDocumentLoad(WebFrame* frame) {
form_cache_.ExtractForms(*frame, &forms);
}
+ autofill::FormsSeenState state = has_more_forms ?
+ autofill::PARTIAL_FORMS_SEEN : autofill::NO_SPECIAL_FORMS_SEEN;
+
// Always communicate to browser process for topmost frame.
if (!forms.empty() || !frame->parent()) {
Send(new AutofillHostMsg_FormsSeen(routing_id(), forms,
forms_seen_timestamp_,
- has_more_forms));
+ state));
}
}
@@ -736,7 +741,8 @@ void AutofillAgent::OnGetAllForms() {
// Report to AutofillManager that all forms are being sent.
Send(new AutofillHostMsg_FormsSeen(routing_id(), forms,
- forms_seen_timestamp_, false));
+ forms_seen_timestamp_,
+ NO_SPECIAL_FORMS_SEEN));
}
void AutofillAgent::OnRequestAutocompleteResult(
@@ -783,7 +789,10 @@ void AutofillAgent::OnFillFormsAndClick(
}
void AutofillAgent::OnAutocheckoutSupported() {
+ is_autocheckout_supported_ = true;
try_to_show_autocheckout_bubble_ = true;
+ if (has_new_forms_for_browser_)
+ MaybeSendDynamicFormsSeen();
MaybeShowAutocheckoutBubble();
}
@@ -945,4 +954,38 @@ void AutofillAgent::HideHostAutofillUi() {
Send(new AutofillHostMsg_HideAutofillUi(routing_id()));
}
+void AutofillAgent::didAssociateFormControls(
+ const WebKit::WebVector<WebKit::WebNode>& nodes) {
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ WebKit::WebNode node = nodes[i];
+ if (node.document().frame() == topmost_frame_) {
+ forms_seen_timestamp_ = base::TimeTicks::Now();
+ has_new_forms_for_browser_ = true;
+ break;
+ }
+ }
+
+ if (has_new_forms_for_browser_ && is_autocheckout_supported_)
+ MaybeSendDynamicFormsSeen();
+}
+
+void AutofillAgent::MaybeSendDynamicFormsSeen() {
+ has_new_forms_for_browser_ = false;
+ form_elements_.clear();
+ std::vector<FormData> forms;
+ // This will only be called for Autocheckout flows, so send all forms to
+ // save an IPC.
+ form_cache_.ExtractFormsAndFormElements(
+ *topmost_frame_, 0, &forms, &form_elements_);
+ autofill::FormsSeenState state = autofill::DYNAMIC_FORMS_SEEN;
+
+ if (!forms.empty()) {
+ if (click_timer_.IsRunning())
+ click_timer_.Stop();
+ Send(new AutofillHostMsg_FormsSeen(routing_id(), forms,
+ forms_seen_timestamp_,
+ state));
+ }
+}
+
} // namespace autofill
diff --git a/components/autofill/renderer/autofill_agent.h b/components/autofill/renderer/autofill_agent.h
index d47ab77..7d882b1 100644
--- a/components/autofill/renderer/autofill_agent.h
+++ b/components/autofill/renderer/autofill_agent.h
@@ -13,6 +13,7 @@
#include "base/memory/weak_ptr.h"
#include "base/time.h"
#include "base/timer.h"
+#include "components/autofill/common/forms_seen_state.h"
#include "components/autofill/renderer/form_cache.h"
#include "components/autofill/renderer/page_click_listener.h"
#include "content/public/renderer/render_view_observer.h"
@@ -103,6 +104,8 @@ class AutofillAgent : public content::RenderViewObserver,
WebKit::WebFrame* frame,
const WebKit::WebFormElement& form) OVERRIDE;
virtual void setIgnoreTextChanges(bool ignore) OVERRIDE;
+ virtual void didAssociateFormControls(
+ const WebKit::WebVector<WebKit::WebNode>& nodes) OVERRIDE;
void OnSuggestionsReturned(int query_id,
const std::vector<base::string16>& values,
@@ -206,6 +209,8 @@ class AutofillAgent : public content::RenderViewObserver,
// Hides any currently showing Autofill UI in the browser only.
void HideHostAutofillUi();
+ void MaybeSendDynamicFormsSeen();
+
// Send |AutofillHostMsg_MaybeShowAutocheckoutBubble| to browser if needed.
void MaybeShowAutocheckoutBubble();
@@ -256,6 +261,13 @@ class AutofillAgent : public content::RenderViewObserver,
// Autocheckout flow.
bool autocheckout_click_in_progress_;
+ // Whether or not |topmost_frame_| is whitelisted for Autocheckout.
+ bool is_autocheckout_supported_;
+
+ // Whether or not new forms/fields have been dynamically added
+ // since the last loaded forms were sent to the browser process.
+ bool has_new_forms_for_browser_;
+
// Whether or not we should try to offer the user Autocheckout functionality
// by sending |AutofillHostMsg_MaybeShowAutocheckoutBubble| to the browser.
bool try_to_show_autocheckout_bubble_;
@@ -273,6 +285,7 @@ class AutofillAgent : public content::RenderViewObserver,
friend class PasswordAutofillAgentTest;
FRIEND_TEST_ALL_PREFIXES(ChromeRenderViewTest, FillFormElement);
FRIEND_TEST_ALL_PREFIXES(ChromeRenderViewTest, SendForms);
+ FRIEND_TEST_ALL_PREFIXES(ChromeRenderViewTest, SendDynamicForms);
FRIEND_TEST_ALL_PREFIXES(ChromeRenderViewTest, ShowAutofillWarning);
FRIEND_TEST_ALL_PREFIXES(PasswordAutofillAgentTest, WaitUsername);
FRIEND_TEST_ALL_PREFIXES(PasswordAutofillAgentTest, SuggestionAccept);