summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/autofill/autofill_browsertest.cc89
-rw-r--r--chrome/browser/autofill/autofill_manager.cc331
-rw-r--r--chrome/browser/autofill/autofill_manager.h52
-rw-r--r--chrome/browser/autofill/autofill_manager_unittest.cc4
-rw-r--r--chrome/browser/autofill/form_structure.cc15
-rw-r--r--chrome/renderer/autofill/autofill_agent.cc39
-rw-r--r--chrome/renderer/autofill/form_manager.cc579
-rw-r--r--chrome/renderer/autofill/form_manager.h118
-rw-r--r--chrome/renderer/autofill/form_manager_browsertest.cc553
9 files changed, 809 insertions, 971 deletions
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index 22603c9..16bdb70 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -431,6 +431,95 @@ IN_PROC_BROWSER_TEST_F(AutofillTest, AutofillFormWithRepeatedField) {
ExpectFieldValue(L"state_freeform", "");
}
+// Test that we can Autofill dynamically generated forms.
+IN_PROC_BROWSER_TEST_F(AutofillTest, DynamicFormFill) {
+ CreateTestProfile();
+
+ // Load the test page.
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(),
+ GURL(std::string(kDataURIPrefix) +
+ "<form id=\"form\" action=\"http://www.example.com/\""
+ " method=\"POST\"></form>"
+ "<script>"
+ "function AddElement(name, label) {"
+ " var form = document.getElementById('form');"
+ ""
+ " var label_text = document.createTextNode(label);"
+ " var label_element = document.createElement('label');"
+ " label_element.setAttribute('for', name);"
+ " label_element.appendChild(label_text);"
+ " form.appendChild(label_element);"
+ ""
+ " if (name === 'state' || name === 'country') {"
+ " var select_element = document.createElement('select');"
+ " select_element.setAttribute('id', name);"
+ " select_element.setAttribute('name', name);"
+ ""
+ " /* Add an empty selected option. */"
+ " var default_option = new Option('--', '', true);"
+ " select_element.appendChild(default_option);"
+ ""
+ " /* Add the other options. */"
+ " if (name == 'state') {"
+ " var option1 = new Option('California', 'CA');"
+ " select_element.appendChild(option1);"
+ " var option2 = new Option('Texas', 'TX');"
+ " select_element.appendChild(option2);"
+ " } else {"
+ " var option1 = new Option('Canada', 'CA');"
+ " select_element.appendChild(option1);"
+ " var option2 = new Option('United States', 'US');"
+ " select_element.appendChild(option2);"
+ " }"
+ ""
+ " form.appendChild(select_element);"
+ " } else {"
+ " var input_element = document.createElement('input');"
+ " input_element.setAttribute('id', name);"
+ " input_element.setAttribute('name', name);"
+ ""
+ " /* Add the onFocus listener to the 'firstname' field. */"
+ " if (name === 'firstname') {"
+ " input_element.setAttribute("
+ " 'onFocus', 'domAutomationController.send(true)');"
+ " }"
+ ""
+ " form.appendChild(input_element);"
+ " }"
+ ""
+ " form.appendChild(document.createElement('br'));"
+ "};"
+ ""
+ "function BuildForm() {"
+ " var elements = ["
+ " ['firstname', 'First name:'],"
+ " ['lastname', 'Last name:'],"
+ " ['address1', 'Address line 1:'],"
+ " ['address2', 'Address line 2:'],"
+ " ['city', 'City:'],"
+ " ['state', 'State:'],"
+ " ['zip', 'ZIP code:'],"
+ " ['country', 'Country:'],"
+ " ['phone', 'Phone number:'],"
+ " ];"
+ ""
+ " for (var i = 0; i < elements.length; i++) {"
+ " var name = elements[i][0];"
+ " var label = elements[i][1];"
+ " AddElement(name, label);"
+ " }"
+ "};"
+ "</script>")));
+
+ // Dynamically construct the form.
+ ASSERT_TRUE(ui_test_utils::ExecuteJavaScript(render_view_host(), L"",
+ L"BuildForm();"));
+
+ // Invoke Autofill.
+ TryBasicFormFill();
+}
+
// Test that form filling works after reloading the current page.
// This test brought to you by http://crbug.com/69204
#if defined(OS_MACOSX)
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc
index 97d68b1..1542d8b 100644
--- a/chrome/browser/autofill/autofill_manager.cc
+++ b/chrome/browser/autofill/autofill_manager.cc
@@ -67,6 +67,10 @@ const double kAutofillNegativeUploadRateDefaultValue = 0.20;
const size_t kMaxRecentFormSignaturesToRemember = 3;
+// Set a conservative upper bound on the number of forms we are willing to
+// cache, simply to prevent unbounded memory consumption.
+const size_t kMaxFormCacheSize = 100;
+
const string16::value_type kCreditCardPrefix[] = {'*', 0};
// Removes duplicate suggestions whilst preserving their original order.
@@ -106,36 +110,12 @@ void RemoveDuplicateSuggestions(std::vector<string16>* values,
bool SectionIsAutofilled(const FormStructure* form_structure,
const webkit_glue::FormData& form,
const string16& section) {
- // TODO(isherman): It would be nice to share most of this code with the loop
- // in |OnFillAutofillFormData()|, but I don't see a particularly clean way to
- // do that.
-
- // The list of fields in |form_structure| and |form.fields| often match
- // directly and we can fill these corresponding fields; however, when the
- // |form_structure| and |form.fields| do not match directly we search
- // ahead in the |form_structure| for the matching field.
- for (size_t i = 0, j = 0;
- i < form_structure->field_count() && j < form.fields.size();
- j++) {
- size_t k = i;
-
- // Search forward in the |form_structure| for a corresponding field.
- while (k < form_structure->field_count() &&
- (form_structure->field(k)->section() != section ||
- *form_structure->field(k) != form.fields[j])) {
- k++;
- }
-
- // If we didn't find a match, continue on to the next |form| field.
- if (k >= form_structure->field_count())
- continue;
-
- if (form.fields[j].is_autofilled)
+ DCHECK_EQ(form_structure->field_count(), form.fields.size());
+ for (size_t i = 0; i < form_structure->field_count(); ++i) {
+ if (form_structure->field(i)->section() == section &&
+ form.fields[i].is_autofilled) {
return true;
-
- // We found a matching field in the |form_structure|, so on the next
- // iteration we should proceed to the next |form_structure| field.
- ++i;
+ }
}
return false;
@@ -368,7 +348,7 @@ void AutofillManager::OnTextFieldDidChange(const FormData& form,
const TimeTicks& timestamp) {
FormStructure* form_structure = NULL;
AutofillField* autofill_field = NULL;
- if (!FindCachedFormAndField(form, field, &form_structure, &autofill_field))
+ if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field))
return;
if (!user_did_type_) {
@@ -405,7 +385,7 @@ void AutofillManager::OnQueryFormFieldAutofill(
AutofillField* autofill_field = NULL;
if (GetHost(
personal_data_->profiles(), personal_data_->credit_cards(), &host) &&
- FindCachedFormAndField(form, field, &form_structure, &autofill_field) &&
+ GetCachedFormAndField(form, field, &form_structure, &autofill_field) &&
// Don't send suggestions for forms that aren't auto-fillable.
form_structure->IsAutofillable(false)) {
AutofillFieldType type = autofill_field->type();
@@ -481,52 +461,22 @@ void AutofillManager::OnFillAutofillFormData(int query_id,
int unique_id) {
const std::vector<AutofillProfile*>& profiles = personal_data_->profiles();
const std::vector<CreditCard*>& credit_cards = personal_data_->credit_cards();
+ const AutofillProfile* profile = NULL;
+ const CreditCard* credit_card = NULL;
+ size_t variant = 0;
RenderViewHost* host = NULL;
FormStructure* form_structure = NULL;
AutofillField* autofill_field = NULL;
- if (!GetHost(profiles, credit_cards, &host) ||
- !FindCachedFormAndField(form, field, &form_structure, &autofill_field))
+ if (!GetProfileOrCreditCard(unique_id, profiles, credit_cards, &profile,
+ &credit_card, &variant) ||
+ !GetHost(profiles, credit_cards, &host) ||
+ !GetCachedFormAndField(form, field, &form_structure, &autofill_field))
return;
DCHECK(host);
DCHECK(form_structure);
DCHECK(autofill_field);
-
- // Unpack the |unique_id| into component parts.
- GUIDPair cc_guid;
- GUIDPair profile_guid;
- UnpackGUIDs(unique_id, &cc_guid, &profile_guid);
- DCHECK(!guid::IsValidGUID(cc_guid.first) ||
- !guid::IsValidGUID(profile_guid.first));
-
- // Find the profile that matches the |profile_id|, if one is specified.
- const AutofillProfile* profile = NULL;
- if (guid::IsValidGUID(profile_guid.first)) {
- for (std::vector<AutofillProfile*>::const_iterator iter = profiles.begin();
- iter != profiles.end(); ++iter) {
- if ((*iter)->guid() == profile_guid.first) {
- profile = *iter;
- break;
- }
- }
- DCHECK(profile);
- }
-
- // Find the credit card that matches the |cc_id|, if one is specified.
- const CreditCard* credit_card = NULL;
- if (guid::IsValidGUID(cc_guid.first)) {
- for (std::vector<CreditCard*>::const_iterator iter = credit_cards.begin();
- iter != credit_cards.end(); ++iter) {
- if ((*iter)->guid() == cc_guid.first) {
- credit_card = *iter;
- break;
- }
- }
- DCHECK(credit_card);
- }
-
- if (!profile && !credit_card)
- return;
+ DCHECK(profile || credit_card);
FormData result = form;
@@ -540,8 +490,7 @@ void AutofillManager::OnFillAutofillFormData(int query_id,
if (profile) {
DCHECK_NE(AutofillType::CREDIT_CARD,
AutofillType(field_type).group());
- FillFormField(*profile, *autofill_field, profile_guid.second,
- &(*iter));
+ FillFormField(*profile, *autofill_field, variant, &(*iter));
} else {
DCHECK_EQ(AutofillType::CREDIT_CARD,
AutofillType(field_type).group());
@@ -560,30 +509,14 @@ void AutofillManager::OnFillAutofillFormData(int query_id,
return;
}
- // The list of fields in |form_structure| and |result.fields| often match
- // directly and we can fill these corresponding fields; however, when the
- // |form_structure| and |result.fields| do not match directly we search
- // ahead in the |form_structure| for the matching field.
- // See unit tests: AutofillManagerTest.FormChangesRemoveField and
- // AutofillManagerTest.FormChangesAddField for usage.
- for (size_t i = 0, j = 0;
- i < form_structure->field_count() && j < result.fields.size();
- j++) {
- size_t k = i;
-
- // Search forward in the |form_structure| for a corresponding field.
- while (k < form_structure->field_count() &&
- (form_structure->field(k)->section() != autofill_field->section() ||
- *form_structure->field(k) != result.fields[j])) {
- k++;
- }
-
- // If we've found a match then fill the |result| field with the found
- // field in the |form_structure|.
- if (k >= form_structure->field_count())
+ DCHECK_EQ(form_structure->field_count(), form.fields.size());
+ for (size_t i = 0; i < form_structure->field_count(); ++i) {
+ if (form_structure->field(i)->section() != autofill_field->section())
continue;
- const AutofillField* cached_field = form_structure->field(k);
+ DCHECK_EQ(*form_structure->field(i), result.fields[i]);
+
+ const AutofillField* cached_field = form_structure->field(i);
AutofillFieldType field_type = cached_field->type();
FieldTypeGroup field_group_type = AutofillType(field_type).group();
if (field_group_type != AutofillType::NO_GROUP) {
@@ -592,25 +525,20 @@ void AutofillManager::OnFillAutofillFormData(int query_id,
// If the field being filled is the field that the user initiated the
// fill from, then take the multi-profile "variant" into account.
// Otherwise fill with the default (zeroth) variant.
- if (result.fields[j] == field) {
- FillFormField(*profile, *cached_field, profile_guid.second,
- &result.fields[j]);
+ if (result.fields[i] == field) {
+ FillFormField(*profile, *cached_field, variant, &result.fields[i]);
} else {
- FillFormField(*profile, *cached_field, 0, &result.fields[j]);
+ FillFormField(*profile, *cached_field, 0, &result.fields[i]);
}
} else {
DCHECK_EQ(AutofillType::CREDIT_CARD, field_group_type);
- FillCreditCardFormField(*credit_card, field_type, &result.fields[j]);
+ FillCreditCardFormField(*credit_card, field_type, &result.fields[i]);
}
// Mark the cached field as autofilled, so that we can detect when a user
// edits an autofilled field (for metrics).
- form_structure->field(k)->is_autofilled = true;
+ form_structure->field(i)->is_autofilled = true;
}
-
- // We found a matching field in the |form_structure|, so on the next
- // iteration we should proceed to the next |form_structure| field.
- ++i;
}
autofilled_form_signatures_.push_front(form_structure->FormSignature());
@@ -679,16 +607,7 @@ void AutofillManager::OnLoadedServerPredictions(
*metric_logger_);
// If the corresponding flag is set, annotate forms with the predicted types.
- RenderViewHost* host = tab_contents()->render_view_host();
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kShowAutofillTypePredictions) || !host) {
- return;
- }
-
- std::vector<FormDataPredictions> forms;
- FormStructure::GetFieldTypePredictions(form_structures_.get(), &forms);
- host->Send(new AutofillMsg_FieldTypePredictionsAvailable(host->routing_id(),
- forms));
+ SendAutofillTypePredictions(form_structures_.get());
}
void AutofillManager::OnUploadedPossibleFieldTypes() {
@@ -735,6 +654,22 @@ void AutofillManager::DeterminePossibleFieldTypesForUpload(
}
}
+void AutofillManager::SendAutofillTypePredictions(
+ const std::vector<FormStructure*>& forms) const {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kShowAutofillTypePredictions))
+ return;
+
+ RenderViewHost* host = tab_contents()->render_view_host();
+ if (!host)
+ return;
+
+ std::vector<FormDataPredictions> type_predictions;
+ FormStructure::GetFieldTypePredictions(forms, &type_predictions);
+ host->Send(new AutofillMsg_FieldTypePredictionsAvailable(host->routing_id(),
+ type_predictions));
+}
+
void AutofillManager::ImportFormData(const FormStructure& submitted_form) {
const CreditCard* imported_credit_card;
if (!personal_data_->ImportFormData(submitted_form, &imported_credit_card))
@@ -824,13 +759,63 @@ bool AutofillManager::GetHost(const std::vector<AutofillProfile*>& profiles,
return true;
}
+bool AutofillManager::GetProfileOrCreditCard(
+ int unique_id,
+ const std::vector<AutofillProfile*>& profiles,
+ const std::vector<CreditCard*>& credit_cards,
+ const AutofillProfile** profile,
+ const CreditCard** credit_card,
+ size_t* variant) const {
+ // Unpack the |unique_id| into component parts.
+ GUIDPair credit_card_guid;
+ GUIDPair profile_guid;
+ UnpackGUIDs(unique_id, &credit_card_guid, &profile_guid);
+ DCHECK(!guid::IsValidGUID(credit_card_guid.first) ||
+ !guid::IsValidGUID(profile_guid.first));
+
+ // Find the profile that matches the |profile_guid|, if one is specified.
+ if (guid::IsValidGUID(profile_guid.first)) {
+ for (std::vector<AutofillProfile*>::const_iterator iter = profiles.begin();
+ iter != profiles.end(); ++iter) {
+ if ((*iter)->guid() == profile_guid.first) {
+ *profile = *iter;
+ break;
+ }
+ }
+ DCHECK(*profile);
+
+ *variant = profile_guid.second;
+ }
+
+ // Find the credit card that matches the |credit_card_guid|, if specified.
+ if (guid::IsValidGUID(credit_card_guid.first)) {
+ for (std::vector<CreditCard*>::const_iterator iter = credit_cards.begin();
+ iter != credit_cards.end(); ++iter) {
+ if ((*iter)->guid() == credit_card_guid.first) {
+ *credit_card = *iter;
+ break;
+ }
+ }
+ DCHECK(*credit_card);
+
+ *variant = credit_card_guid.second;
+ }
+
+ return (*profile) || (*credit_card);
+}
+
bool AutofillManager::FindCachedForm(const FormData& form,
FormStructure** form_structure) const {
// Find the FormStructure that corresponds to |form|.
+ // Scan backward through the cached |form_structures_|, as updated versions of
+ // forms are added to the back of the list, whereas original versions of these
+ // forms might appear toward the beginning of the list. The communication
+ // protocol with the crowdsourcing server does not permit us to discard the
+ // original versions of the forms.
*form_structure = NULL;
- for (std::vector<FormStructure*>::const_iterator iter =
- form_structures_.begin();
- iter != form_structures_.end(); ++iter) {
+ for (std::vector<FormStructure*>::const_reverse_iterator iter =
+ form_structures_.rbegin();
+ iter != form_structures_.rend(); ++iter) {
if (**iter == form) {
*form_structure = *iter;
break;
@@ -843,13 +828,22 @@ bool AutofillManager::FindCachedForm(const FormData& form,
return true;
}
-bool AutofillManager::FindCachedFormAndField(const FormData& form,
- const FormField& field,
- FormStructure** form_structure,
- AutofillField** autofill_field) {
+bool AutofillManager::GetCachedFormAndField(const FormData& form,
+ const FormField& field,
+ FormStructure** form_structure,
+ AutofillField** autofill_field) {
// Find the FormStructure that corresponds to |form|.
- if (!FindCachedForm(form, form_structure))
+ // If we do not have this form in our cache but it is parseable, we'll add it
+ // in the call to |UpdateCachedForm()|.
+ if (!FindCachedForm(form, form_structure) &&
+ (form_structures_.size() >= kMaxFormCacheSize ||
+ !FormStructure(form).ShouldBeParsed(false))) {
return false;
+ }
+
+ // Update the cached form to reflect any dynamic changes to the form data, if
+ // necessary.
+ UpdateCachedForm(form, *form_structure, form_structure);
// No data to return if there are no auto-fillable fields.
if (!(*form_structure)->autofill_count())
@@ -866,19 +860,66 @@ bool AutofillManager::FindCachedFormAndField(const FormData& form,
}
}
- if (!(*autofill_field))
- return false;
-
+ // We always update the cache, so we should be guaranteed to find the field.
+ DCHECK(*autofill_field);
return true;
}
-void AutofillManager::GetProfileSuggestions(FormStructure* form,
- const FormField& field,
- AutofillFieldType type,
- std::vector<string16>* values,
- std::vector<string16>* labels,
- std::vector<string16>* icons,
- std::vector<int>* unique_ids) {
+void AutofillManager::UpdateCachedForm(const FormData& live_form,
+ const FormStructure* cached_form,
+ FormStructure** updated_form) {
+ bool needs_update =
+ (!cached_form ||
+ live_form.fields.size() != cached_form->field_count());
+ for (size_t i = 0; !needs_update && i < cached_form->field_count(); ++i) {
+ needs_update = *cached_form->field(i) != live_form.fields[i];
+ }
+
+ if (!needs_update)
+ return;
+
+ // Add the new or updated form to our cache.
+ DCHECK(form_structures_.size() < kMaxFormCacheSize);
+ form_structures_.push_back(new FormStructure(live_form));
+ *updated_form = *form_structures_.rbegin();
+ (*updated_form)->DetermineHeuristicTypes();
+
+ // If we have cached data, propagate it to the updated form.
+ if (cached_form) {
+ std::map<string16, const AutofillField*> cached_fields;
+ for (size_t i = 0; i < cached_form->field_count(); ++i) {
+ const AutofillField* field = cached_form->field(i);
+ cached_fields[field->unique_name()] = field;
+ }
+
+ for (size_t i = 0; i < (*updated_form)->field_count(); ++i) {
+ AutofillField* field = (*updated_form)->field(i);
+ std::map<string16, const AutofillField*>::iterator cached_field =
+ cached_fields.find(field->unique_name());
+ if (cached_field != cached_fields.end()) {
+ field->set_server_type(cached_field->second->server_type());
+ field->is_autofilled = cached_field->second->is_autofilled;
+ }
+ }
+
+ // Note: We _must not_ remove the original version of the cached form from
+ // the list of |form_structures_|. Otherwise, we break parsing of the
+ // crowdsourcing server's response to our query.
+ }
+
+ // Annotate the updated form with its predicted types.
+ std::vector<FormStructure*> forms(1, *updated_form);
+ SendAutofillTypePredictions(forms);
+}
+
+void AutofillManager::GetProfileSuggestions(
+ FormStructure* form,
+ const FormField& field,
+ AutofillFieldType type,
+ std::vector<string16>* values,
+ std::vector<string16>* labels,
+ std::vector<string16>* icons,
+ std::vector<int>* unique_ids) const {
const std::vector<AutofillProfile*>& profiles = personal_data_->profiles();
if (!field.is_autofilled) {
std::vector<AutofillProfile*> matched_profiles;
@@ -959,13 +1000,14 @@ void AutofillManager::GetProfileSuggestions(FormStructure* form,
}
}
-void AutofillManager::GetCreditCardSuggestions(FormStructure* form,
- const FormField& field,
- AutofillFieldType type,
- std::vector<string16>* values,
- std::vector<string16>* labels,
- std::vector<string16>* icons,
- std::vector<int>* unique_ids) {
+void AutofillManager::GetCreditCardSuggestions(
+ FormStructure* form,
+ const FormField& field,
+ AutofillFieldType type,
+ std::vector<string16>* values,
+ std::vector<string16>* labels,
+ std::vector<string16>* icons,
+ std::vector<int>* unique_ids) const {
for (std::vector<CreditCard*>::const_iterator iter =
personal_data_->credit_cards().begin();
iter != personal_data_->credit_cards().end(); ++iter) {
@@ -1099,9 +1141,14 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
if (!form_structures_.empty())
metric_logger_->LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED);
+
+ // For the |non_queryable_forms|, we have all the field type info we're ever
+ // going to get about them. For the other forms, we'll wait until we get a
+ // response from the server.
+ SendAutofillTypePredictions(non_queryable_forms);
}
-int AutofillManager::GUIDToID(const GUIDPair& guid) {
+int AutofillManager::GUIDToID(const GUIDPair& guid) const {
static int last_id = 1;
if (!guid::IsValidGUID(guid.first))
@@ -1117,7 +1164,7 @@ int AutofillManager::GUIDToID(const GUIDPair& guid) {
}
}
-const AutofillManager::GUIDPair AutofillManager::IDToGUID(int id) {
+const AutofillManager::GUIDPair AutofillManager::IDToGUID(int id) const {
if (id == 0)
return GUIDPair(std::string(), 0);
@@ -1134,7 +1181,7 @@ const AutofillManager::GUIDPair AutofillManager::IDToGUID(int id) {
// profile IDs into a single integer. Credit card IDs are sent in the high
// word and profile IDs are sent in the low word.
int AutofillManager::PackGUIDs(const GUIDPair& cc_guid,
- const GUIDPair& profile_guid) {
+ const GUIDPair& profile_guid) const {
int cc_id = GUIDToID(cc_guid);
int profile_id = GUIDToID(profile_guid);
@@ -1149,7 +1196,7 @@ int AutofillManager::PackGUIDs(const GUIDPair& cc_guid,
// high word and profile IDs are stored in the low word.
void AutofillManager::UnpackGUIDs(int id,
GUIDPair* cc_guid,
- GUIDPair* profile_guid) {
+ GUIDPair* profile_guid) const {
int cc_id = id >> std::numeric_limits<unsigned short>::digits &
std::numeric_limits<unsigned short>::max();
int profile_id = id & std::numeric_limits<unsigned short>::max();
diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h
index 986c801..21ded1c 100644
--- a/chrome/browser/autofill/autofill_manager.h
+++ b/chrome/browser/autofill/autofill_manager.h
@@ -102,13 +102,13 @@ class AutofillManager : public TabContentsObserver,
// Maps GUIDs to and from IDs that are used to identify profiles and credit
// cards sent to and from the renderer process.
- virtual int GUIDToID(const GUIDPair& guid);
- virtual const GUIDPair IDToGUID(int id);
+ virtual int GUIDToID(const GUIDPair& guid) const;
+ virtual const GUIDPair IDToGUID(int id) const;
// Methods for packing and unpacking credit card and profile IDs for sending
// and receiving to and from the renderer process.
- int PackGUIDs(const GUIDPair& cc_guid, const GUIDPair& profile_guid);
- void UnpackGUIDs(int id, GUIDPair* cc_guid, GUIDPair* profile_guid);
+ int PackGUIDs(const GUIDPair& cc_guid, const GUIDPair& profile_guid) const;
+ void UnpackGUIDs(int id, GUIDPair* cc_guid, GUIDPair* profile_guid) const;
private:
void OnFormSubmitted(const webkit_glue::FormData& form,
@@ -136,19 +136,36 @@ class AutofillManager : public TabContentsObserver,
const std::vector<CreditCard*>& credit_cards,
RenderViewHost** host) const WARN_UNUSED_RESULT;
+ // Unpacks |unique_id| and fills |profile| or |credit_card| with the
+ // appropriate data source. Returns false if the unpacked id cannot be found.
+ bool GetProfileOrCreditCard(int unique_id,
+ const std::vector<AutofillProfile*>& profiles,
+ const std::vector<CreditCard*>& credit_cards,
+ const AutofillProfile** profile,
+ const CreditCard** credit_card,
+ size_t* variant) const WARN_UNUSED_RESULT;
+
// Fills |form_structure| cached element corresponding to |form|.
// Returns false if the cached element was not found.
bool FindCachedForm(const webkit_glue::FormData& form,
FormStructure** form_structure) const WARN_UNUSED_RESULT;
// Fills |form_structure| and |autofill_field| with the cached elements
- // corresponding to |form| and |field|. Returns false if the cached elements
- // were not found.
- bool FindCachedFormAndField(
- const webkit_glue::FormData& form,
- const webkit_glue::FormField& field,
- FormStructure** form_structure,
- AutofillField** autofill_field) WARN_UNUSED_RESULT;
+ // corresponding to |form| and |field|. This might have the side-effect of
+ // updating the cache. Returns false if the |form| is not autofillable, or if
+ // it is not already present in the cache and the cache is full.
+ bool GetCachedFormAndField(const webkit_glue::FormData& form,
+ const webkit_glue::FormField& field,
+ FormStructure** form_structure,
+ AutofillField** autofill_field) WARN_UNUSED_RESULT;
+
+ // Re-parses |live_form| and adds the result to |form_structures_|.
+ // |cached_form| should be a pointer to the existing version of the form, or
+ // NULL if no cached version exists. The updated form is then written into
+ // |updated_form|.
+ void UpdateCachedForm(const webkit_glue::FormData& live_form,
+ const FormStructure* cached_form,
+ FormStructure** updated_form);
// Returns a list of values from the stored profiles that match |type| and the
// value of |field| and returns the labels of the matching profiles. |labels|
@@ -159,7 +176,7 @@ class AutofillManager : public TabContentsObserver,
std::vector<string16>* values,
std::vector<string16>* labels,
std::vector<string16>* icons,
- std::vector<int>* unique_ids);
+ std::vector<int>* unique_ids) const;
// Returns a list of values from the stored credit cards that match |type| and
// the value of |field| and returns the labels of the matching credit cards.
@@ -169,7 +186,7 @@ class AutofillManager : public TabContentsObserver,
std::vector<string16>* values,
std::vector<string16>* labels,
std::vector<string16>* icons,
- std::vector<int>* unique_ids);
+ std::vector<int>* unique_ids) const;
// Set |field|'s value based on |type| and contents of the |credit_card|.
void FillCreditCardFormField(const CreditCard& credit_card,
@@ -206,6 +223,11 @@ class AutofillManager : public TabContentsObserver,
void UpdateInitialInteractionTimestamp(
const base::TimeTicks& interaction_timestamp);
+ // Send our current field type predictions to the renderer.
+ // This is a no-op if the appropriate command-line flag is not set.
+ void SendAutofillTypePredictions(
+ const std::vector<FormStructure*>& forms) const;
+
// The owning TabContentsWrapper.
TabContentsWrapper* tab_contents_wrapper_;
@@ -250,8 +272,8 @@ class AutofillManager : public TabContentsObserver,
ScopedVector<FormStructure> form_structures_;
// GUID to ID mapping. We keep two maps to convert back and forth.
- std::map<GUIDPair, int> guid_id_map_;
- std::map<int, GUIDPair> id_guid_map_;
+ mutable std::map<GUIDPair, int> guid_id_map_;
+ mutable std::map<int, GUIDPair> id_guid_map_;
friend class AutofillManagerTest;
friend class FormStructureBrowserTest;
diff --git a/chrome/browser/autofill/autofill_manager_unittest.cc b/chrome/browser/autofill/autofill_manager_unittest.cc
index 8804aa7..03a77df 100644
--- a/chrome/browser/autofill/autofill_manager_unittest.cc
+++ b/chrome/browser/autofill/autofill_manager_unittest.cc
@@ -442,7 +442,7 @@ class TestAutofillManager : public AutofillManager {
return PackGUIDs(IDToGUID(credit_card_id), GUIDPair(std::string(), 0));
}
- virtual int GUIDToID(const GUIDPair& guid) OVERRIDE {
+ virtual int GUIDToID(const GUIDPair& guid) const OVERRIDE {
if (guid.first.empty())
return 0;
@@ -452,7 +452,7 @@ class TestAutofillManager : public AutofillManager {
return id;
}
- virtual const GUIDPair IDToGUID(int id) OVERRIDE {
+ virtual const GUIDPair IDToGUID(int id) const OVERRIDE {
EXPECT_TRUE(id >= 0);
if (id <= 0)
return GUIDPair(std::string(), 0);
diff --git a/chrome/browser/autofill/form_structure.cc b/chrome/browser/autofill/form_structure.cc
index 90250bf..0bbe1db 100644
--- a/chrome/browser/autofill/form_structure.cc
+++ b/chrome/browser/autofill/form_structure.cc
@@ -279,8 +279,9 @@ FormStructure::FormStructure(const FormData& form)
server_experiment_id_("no server response"),
has_author_specified_types_(false) {
// Copy the form fields.
- std::vector<webkit_glue::FormField>::const_iterator field;
- for (field = form.fields.begin();
+ std::map<string16, size_t> unique_names;
+ for (std::vector<webkit_glue::FormField>::const_iterator field =
+ form.fields.begin();
field != form.fields.end(); field++) {
// Add all supported form fields (including with empty names) to the
// signature. This is a requirement for Autofill servers.
@@ -288,8 +289,14 @@ FormStructure::FormStructure(const FormData& form)
form_signature_field_names_.append(UTF16ToUTF8(field->name));
// Generate a unique name for this field by appending a counter to the name.
- string16 unique_name = field->name +
- base::IntToString16(fields_.size() + 1);
+ // Make sure to prepend the counter with a non-numeric digit so that we are
+ // guaranteed to avoid collisions.
+ if (!unique_names.count(field->name))
+ unique_names[field->name] = 1;
+ else
+ ++unique_names[field->name];
+ string16 unique_name = field->name + ASCIIToUTF16("_") +
+ base::IntToString16(unique_names[field->name]);
fields_.push_back(new AutofillField(*field, unique_name));
}
diff --git a/chrome/renderer/autofill/autofill_agent.cc b/chrome/renderer/autofill/autofill_agent.cc
index 98334d7..d18d9b4 100644
--- a/chrome/renderer/autofill/autofill_agent.cc
+++ b/chrome/renderer/autofill/autofill_agent.cc
@@ -78,7 +78,7 @@ void AutofillAgent::DidFinishDocumentLoad(WebFrame* frame) {
// The document has now been fully loaded. Scan for forms to be sent up to
// the browser.
std::vector<webkit_glue::FormData> forms;
- form_manager_.ExtractForms(frame, &forms);
+ form_manager_.ExtractForms(*frame, &forms);
if (!forms.empty()) {
Send(new AutofillHostMsg_FormsSeen(routing_id(), forms,
@@ -87,11 +87,11 @@ void AutofillAgent::DidFinishDocumentLoad(WebFrame* frame) {
}
void AutofillAgent::FrameDetached(WebFrame* frame) {
- form_manager_.ResetFrame(frame);
+ form_manager_.ResetFrame(*frame);
}
void AutofillAgent::FrameWillClose(WebFrame* frame) {
- form_manager_.ResetFrame(frame);
+ form_manager_.ResetFrame(*frame);
}
void AutofillAgent::WillSubmitForm(WebFrame* frame,
@@ -99,10 +99,12 @@ void AutofillAgent::WillSubmitForm(WebFrame* frame,
FormData form_data;
if (FormManager::WebFormElementToFormData(
form,
+ WebFormControlElement(),
FormManager::REQUIRE_AUTOCOMPLETE,
static_cast<FormManager::ExtractMask>(
FormManager::EXTRACT_VALUE | FormManager::EXTRACT_OPTION_TEXT),
- &form_data)) {
+ &form_data,
+ NULL)) {
Send(new AutofillHostMsg_FormSubmitted(routing_id(), form_data,
base::TimeTicks::Now()));
}
@@ -137,7 +139,8 @@ void AutofillAgent::didAcceptAutofillSuggestion(const WebNode& node,
} else if (suggestions_clear_index_ != -1 &&
index == static_cast<unsigned>(suggestions_clear_index_)) {
// User selected 'Clear form'.
- form_manager_.ClearFormWithNode(node);
+ DCHECK(node == autofill_query_element_);
+ form_manager_.ClearFormWithElement(autofill_query_element_);
} else if (!unique_id) {
// User selected an Autocomplete entry, so we fill directly.
WebInputElement element = node.toConst<WebInputElement>();
@@ -167,7 +170,9 @@ void AutofillAgent::didSelectAutofillSuggestion(const WebNode& node,
}
void AutofillAgent::didClearAutofillSelection(const WebNode& node) {
- form_manager_.ClearPreviewedFormWithNode(node, was_query_node_autofilled_);
+ DCHECK(node == autofill_query_element_);
+ FormManager::ClearPreviewedFormWithElement(autofill_query_element_,
+ was_query_node_autofilled_);
}
void AutofillAgent::removeAutocompleteSuggestion(const WebString& name,
@@ -276,7 +281,7 @@ void AutofillAgent::OnSuggestionsReturned(int query_id,
// The form has been auto-filled, so give the user the chance to clear the
// form. Append the 'Clear form' menu item.
if (has_autofill_item &&
- form_manager_.FormWithNodeIsAutofilled(autofill_query_element_)) {
+ FormManager::FormWithElementIsAutofilled(autofill_query_element_)) {
v.push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM));
l.push_back(string16());
i.push_back(string16());
@@ -316,12 +321,12 @@ void AutofillAgent::OnFormDataFilled(int query_id,
switch (autofill_action_) {
case AUTOFILL_FILL:
- form_manager_.FillForm(form, autofill_query_element_);
+ FormManager::FillForm(form, autofill_query_element_);
Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id(),
base::TimeTicks::Now()));
break;
case AUTOFILL_PREVIEW:
- form_manager_.PreviewForm(form, autofill_query_element_);
+ FormManager::PreviewForm(form, autofill_query_element_);
Send(new AutofillHostMsg_DidPreviewAutofillFormData(routing_id()));
break;
default:
@@ -415,20 +420,8 @@ bool AutofillAgent::FindFormAndFieldForNode(const WebNode& node,
webkit_glue::FormData* form,
webkit_glue::FormField* field) {
const WebInputElement& element = node.toConst<WebInputElement>();
- if (!form_manager_.FindFormWithFormControlElement(element, form))
- return false;
-
- FormManager::WebFormControlElementToFormField(element,
- FormManager::EXTRACT_VALUE,
- field);
-
- // WebFormControlElementToFormField does not scrape the DOM for the field
- // label, so find the label here.
- // TODO(isherman): Add form and field identities so we can use the cached form
- // data in FormManager.
- field->label = FormManager::LabelForElement(element);
-
- return true;
+ return
+ FormManager::FindFormAndFieldForFormControlElement(element, form, field);
}
} // namespace autofill
diff --git a/chrome/renderer/autofill/form_manager.cc b/chrome/renderer/autofill/form_manager.cc
index 3465f93..99e2f8e 100644
--- a/chrome/renderer/autofill/form_manager.cc
+++ b/chrome/renderer/autofill/form_manager.cc
@@ -457,35 +457,62 @@ typedef void (*Callback)(WebKit::WebFormControlElement*,
const webkit_glue::FormField*,
bool);
+// Fills |autofillable_elements| with all the auto-fillable form control
+// elements in |form_element|.
+void ExtractAutofillableElements(
+ const WebFormElement& form_element,
+ std::vector<WebFormControlElement>* autofillable_elements) {
+ WebVector<WebFormControlElement> control_elements;
+ form_element.getFormControlElements(control_elements);
+
+ autofillable_elements->clear();
+ for (size_t i = 0; i < control_elements.size(); ++i) {
+ WebFormControlElement element = control_elements[i];
+ if (!IsAutofillableElement(element))
+ continue;
+
+ autofillable_elements->push_back(element);
+ }
+}
+
// For each autofillable field in |data| that matches a field in the |form|,
// the |callback| is invoked with the corresponding |form| field data.
-void ForEachMatchingFormField(
- std::vector<WebKit::WebFormControlElement>* control_elements,
- const WebNode& node,
- const FormData& data,
- Callback callback) {
+void ForEachMatchingFormField(const WebFormElement& form_element,
+ const WebElement& initiating_element,
+ const FormData& data,
+ Callback callback) {
+ std::vector<WebFormControlElement> control_elements;
+ ExtractAutofillableElements(form_element, &control_elements);
+
+ if (control_elements.size() != data.fields.size()) {
+ // This case should be reachable only for pathological websites, which add
+ // or remove form fields while the user is interacting with the Autofill
+ // popup. I (isherman) am not aware of any such websites, and so am
+ // optimistically including a NOTREACHED(). If you ever trip this check,
+ // please file a bug against me.
+ NOTREACHED();
+ return;
+ }
+
// It's possible that the site has injected fields into the form after the
// page has loaded, so we can't assert that the size of the cached control
// elements is equal to the size of the fields in |form|. Fortunately, the
// one case in the wild where this happens, paypal.com signup form, the fields
// are appended to the end of the form and are not visible.
- for (size_t i = 0, j = 0;
- i < control_elements->size() && j < data.fields.size();
- ++i) {
- WebFormControlElement* element = &(*control_elements)[i];
- string16 element_name(element->nameForAutofill());
-
- // Search forward in the |form| for a corresponding field.
- size_t k = j;
- while (k < data.fields.size() && element_name != data.fields[k].name)
- k++;
-
- if (k >= data.fields.size())
+ for (size_t i = 0; i < control_elements.size(); ++i) {
+ WebFormControlElement* element = &control_elements[i];
+
+ if (string16(element->nameForAutofill()) != data.fields[i].name) {
+ // This case should be reachable only for pathological websites, which
+ // rename form fields while the user is interacting with the Autofill
+ // popup. I (isherman) am not aware of any such websites, and so am
+ // optimistically including a NOTREACHED(). If you ever trip this check,
+ // please file a bug against me.
+ NOTREACHED();
continue;
+ }
- DCHECK_EQ(data.fields[k].name, element_name);
-
- bool is_initiating_node = false;
+ bool is_initiating_element = (*element == initiating_element);
const WebInputElement* input_element = toWebInputElement(element);
if (IsTextInput(input_element)) {
@@ -494,11 +521,9 @@ void ForEachMatchingFormField(
if (!input_element->autoComplete())
continue;
- is_initiating_node = (*input_element == node);
-
// Only autofill empty fields and the field that initiated the filling,
// i.e. the field the user is currently editing and interacting with.
- if (!is_initiating_node && !input_element->value().isEmpty())
+ if (!is_initiating_element && !input_element->value().isEmpty())
continue;
}
@@ -506,10 +531,7 @@ void ForEachMatchingFormField(
!element->isFocusable())
continue;
- callback(element, &data.fields[k], is_initiating_node);
-
- // We found a matching form field so move on to the next.
- ++j;
+ callback(element, &data.fields[i], is_initiating_element);
}
}
@@ -573,12 +595,6 @@ void PreviewFormField(WebKit::WebFormControlElement* field,
namespace autofill {
-struct FormManager::FormElement {
- WebKit::WebFormElement form_element;
- std::vector<WebKit::WebFormControlElement> control_elements;
- std::vector<string16> control_values;
-};
-
FormManager::FormManager() {
}
@@ -659,50 +675,30 @@ void FormManager::WebFormControlElementToFormField(
}
// static
-string16 FormManager::LabelForElement(const WebFormControlElement& element) {
- // Don't scrape labels for elements we can't possibly autofill anyway.
- if (!IsAutofillableElement(element))
- return string16();
-
- WebNodeList labels = element.document().getElementsByTagName("label");
- for (unsigned i = 0; i < labels.length(); ++i) {
- WebLabelElement label = labels.item(i).to<WebLabelElement>();
- WebElement corresponding_control = label.correspondingControl();
- if (corresponding_control == element ||
- (corresponding_control.isNull() &&
- label.getAttribute("for") == element.nameForAutofill())) {
- return FindChildText(label);
- }
- }
-
- // Infer the label from context if not found in label element.
- return InferLabelForElement(element);
-}
-
-// static
-bool FormManager::WebFormElementToFormData(const WebFormElement& element,
- RequirementsMask requirements,
- ExtractMask extract_mask,
- FormData* form) {
- DCHECK(form);
-
- const WebFrame* frame = element.document().frame();
+bool FormManager::WebFormElementToFormData(
+ const WebKit::WebFormElement& form_element,
+ const WebKit::WebFormControlElement& form_control_element,
+ RequirementsMask requirements,
+ ExtractMask extract_mask,
+ webkit_glue::FormData* form,
+ webkit_glue::FormField* field) {
+ const WebFrame* frame = form_element.document().frame();
if (!frame)
return false;
- if (requirements & REQUIRE_AUTOCOMPLETE && !element.autoComplete())
+ if (requirements & REQUIRE_AUTOCOMPLETE && !form_element.autoComplete())
return false;
- form->name = GetFormIdentifier(element);
- form->method = element.method();
+ form->name = GetFormIdentifier(form_element);
+ form->method = form_element.method();
form->origin = frame->document().url();
- form->action = frame->document().completeURL(element.action());
- form->user_submitted = element.wasUserSubmitted();
+ form->action = frame->document().completeURL(form_element.action());
+ form->user_submitted = form_element.wasUserSubmitted();
// If the completed URL is not valid, just use the action we get from
// WebKit.
if (!form->action.is_valid())
- form->action = GURL(element.action());
+ form->action = GURL(form_element.action());
// A map from a FormField's name to the FormField itself.
std::map<string16, FormField*> name_map;
@@ -712,7 +708,7 @@ bool FormManager::WebFormElementToFormData(const WebFormElement& element,
ScopedVector<FormField> form_fields;
WebVector<WebFormControlElement> control_elements;
- element.getFormControlElements(control_elements);
+ form_element.getFormControlElements(control_elements);
// A vector of bools that indicate whether each field in the form meets the
// requirements and thus will be in the resulting |form|.
@@ -733,13 +729,13 @@ bool FormManager::WebFormElementToFormData(const WebFormElement& element,
continue;
// Create a new FormField, fill it out and map it to the field's name.
- FormField* field = new FormField;
- WebFormControlElementToFormField(control_element, extract_mask, field);
- form_fields.push_back(field);
+ FormField* form_field = new FormField;
+ WebFormControlElementToFormField(control_element, extract_mask, form_field);
+ form_fields.push_back(form_field);
// TODO(jhawkins): A label element is mapped to a form control element's id.
// field->name() will contain the id only if the name does not exist. Add
// an id() method to WebFormControlElement and use that here.
- name_map[field->name] = field;
+ name_map[form_field->name] = form_field;
fields_extracted[i] = true;
}
@@ -752,7 +748,7 @@ bool FormManager::WebFormElementToFormData(const WebFormElement& element,
// element's name as a key into the <name, FormField> map to find the
// previously created FormField and set the FormField's label to the
// label.firstChild().nodeValue() of the label element.
- WebNodeList labels = element.getElementsByTagName("label");
+ WebNodeList labels = form_element.getElementsByTagName("label");
for (unsigned i = 0; i < labels.length(); ++i) {
WebLabelElement label = labels.item(i).to<WebLabelElement>();
WebFormControlElement field_element =
@@ -798,6 +794,9 @@ bool FormManager::WebFormElementToFormData(const WebFormElement& element,
if (form_fields[field_idx]->label.empty())
form_fields[field_idx]->label = InferLabelForElement(control_element);
+ if (field && form_control_element == control_element)
+ *field = *form_fields[field_idx];
+
++field_idx;
}
@@ -810,50 +809,156 @@ bool FormManager::WebFormElementToFormData(const WebFormElement& element,
return true;
}
-void FormManager::ExtractForms(const WebFrame* frame,
+// static
+bool FormManager::FindFormAndFieldForFormControlElement(
+ const WebFormControlElement& element,
+ FormData* form,
+ webkit_glue::FormField* field) {
+ const WebFormElement form_element = element.form();
+ if (form_element.isNull())
+ return false;
+
+ ExtractMask extract_mask =
+ static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
+ return WebFormElementToFormData(form_element,
+ element,
+ REQUIRE_NONE,
+ extract_mask,
+ form,
+ field);
+}
+
+// static
+void FormManager::FillForm(const FormData& form,
+ const WebInputElement& element) {
+ WebFormElement form_element = element.form();
+ if (form_element.isNull())
+ return;
+
+ ForEachMatchingFormField(form_element,
+ element,
+ form,
+ &FillFormField);
+}
+
+// static
+void FormManager::PreviewForm(const FormData& form,
+ const WebInputElement& element) {
+ WebFormElement form_element = element.form();
+ if (form_element.isNull())
+ return;
+
+ ForEachMatchingFormField(form_element,
+ element,
+ form,
+ &PreviewFormField);
+}
+
+// static
+bool FormManager::ClearPreviewedFormWithElement(const WebInputElement& element,
+ bool was_autofilled) {
+ WebFormElement form_element = element.form();
+ if (form_element.isNull())
+ return false;
+
+ std::vector<WebFormControlElement> control_elements;
+ ExtractAutofillableElements(form_element, &control_elements);
+ for (size_t i = 0; i < control_elements.size(); ++i) {
+ // Only text input elements can be previewed.
+ WebInputElement* input_element = toWebInputElement(&control_elements[i]);
+ if (!IsTextInput(input_element))
+ continue;
+
+ // If the input element is not auto-filled, we did not preview it, so there
+ // is nothing to reset.
+ if (!input_element->isAutofilled())
+ continue;
+
+ // There might be unrelated elements in this form which have already been
+ // auto-filled. For example, the user might have already filled the address
+ // part of a form and now be dealing with the credit card section. We only
+ // want to reset the auto-filled status for fields that were previewed.
+ if (input_element->suggestedValue().isEmpty())
+ continue;
+
+ // Clear the suggested value. For the initiating node, also restore the
+ // original value.
+ input_element->setSuggestedValue(WebString());
+ bool is_initiating_node = (element == *input_element);
+ if (is_initiating_node)
+ input_element->setAutofilled(was_autofilled);
+ else
+ input_element->setAutofilled(false);
+
+ // Clearing the suggested value in the focused node (above) can cause
+ // selection to be lost. We force selection range to restore the text
+ // cursor.
+ if (is_initiating_node) {
+ int length = input_element->value().length();
+ input_element->setSelectionRange(length, length);
+ }
+ }
+
+ return true;
+}
+
+// static
+bool FormManager::FormWithElementIsAutofilled(const WebInputElement& element) {
+ WebFormElement form_element = element.form();
+ if (form_element.isNull())
+ return false;
+
+ std::vector<WebFormControlElement> control_elements;
+ ExtractAutofillableElements(form_element, &control_elements);
+ for (size_t i = 0; i < control_elements.size(); ++i) {
+ WebInputElement* input_element = toWebInputElement(&control_elements[i]);
+ if (!IsTextInput(input_element))
+ continue;
+
+ if (input_element->isAutofilled())
+ return true;
+ }
+
+ return false;
+}
+
+void FormManager::ExtractForms(const WebFrame& frame,
std::vector<FormData>* forms) {
// Reset the vector of FormElements for this frame.
ResetFrame(frame);
+ web_frames_.insert(&frame);
WebVector<WebFormElement> web_forms;
- frame->document().forms(web_forms);
+ frame.document().forms(web_forms);
size_t num_fields_seen = 0;
for (size_t i = 0; i < web_forms.size(); ++i) {
- // Owned by |form_elements_|.
- FormElement* form_element = new FormElement;
- form_element->form_element = web_forms[i];
+ WebFormElement form_element = web_forms[i];
- WebVector<WebFormControlElement> control_elements;
- form_element->form_element.getFormControlElements(control_elements);
+ std::vector<WebFormControlElement> control_elements;
+ ExtractAutofillableElements(form_element, &control_elements);
for (size_t j = 0; j < control_elements.size(); ++j) {
WebFormControlElement element = control_elements[j];
- if (!IsAutofillableElement(element))
- continue;
-
- form_element->control_elements.push_back(element);
// Save original values of <select> elements so we can restore them
// when |ClearFormWithNode()| is invoked.
if (IsSelectElement(element)) {
- form_element->control_values.push_back(
- element.toConst<WebSelectElement>().value());
- } else {
- form_element->control_values.push_back(string16());
+ const WebSelectElement select_element =
+ element.toConst<WebSelectElement>();
+ initial_select_values_.insert(std::make_pair(select_element,
+ select_element.value()));
}
}
- form_elements_.push_back(form_element);
-
// To avoid overly expensive computation, we impose both a minimum and a
// maximum number of allowable fields.
- if (form_element->control_elements.size() < kRequiredAutofillFields ||
- form_element->control_elements.size() > kMaxParseableFields)
+ if (control_elements.size() < kRequiredAutofillFields ||
+ control_elements.size() > kMaxParseableFields)
continue;
FormData form;
- WebFormElementToFormData(
- form_element->form_element, REQUIRE_NONE, EXTRACT_VALUE, &form);
+ WebFormElementToFormData(form_element, WebFormControlElement(),
+ REQUIRE_NONE, EXTRACT_VALUE, &form, NULL);
num_fields_seen += form.fields.size();
if (num_fields_seen > kMaxParseableFields)
@@ -864,112 +969,36 @@ void FormManager::ExtractForms(const WebFrame* frame,
}
}
-bool FormManager::FindFormWithFormControlElement(
- const WebFormControlElement& element,
- FormData* form) {
- DCHECK(form);
-
- const WebFrame* frame = element.document().frame();
- if (!frame)
- return false;
-
- for (FormElementList::const_iterator iter = form_elements_.begin();
- iter != form_elements_.end(); ++iter) {
- const FormElement* form_element = *iter;
+void FormManager::ResetFrame(const WebFrame& frame) {
+ web_frames_.erase(&frame);
- if (form_element->form_element.document().frame() != frame)
- continue;
-
- for (std::vector<WebFormControlElement>::const_iterator iter =
- form_element->control_elements.begin();
- iter != form_element->control_elements.end(); ++iter) {
- if (iter->nameForAutofill() == element.nameForAutofill()) {
- ExtractMask extract_mask =
- static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
- return WebFormElementToFormData(form_element->form_element,
- REQUIRE_NONE,
- extract_mask,
- form);
- }
- }
+ std::vector<WebSelectElement> to_delete;
+ for (std::map<const WebSelectElement, string16>::const_iterator it =
+ initial_select_values_.begin();
+ it != initial_select_values_.end(); ++it) {
+ WebFormElement form_element = it->first.form();
+ if (form_element.isNull() || form_element.document().frame() == &frame)
+ to_delete.push_back(it->first);
}
- return false;
-}
-
-void FormManager::FillForm(const FormData& form, const WebNode& node) {
- FormElement* form_element = NULL;
- if (!FindCachedFormElement(form, &form_element))
- return;
-
- ForEachMatchingFormField(&form_element->control_elements,
- node,
- form,
- &FillFormField);
-}
-
-void FormManager::PreviewForm(const FormData& form, const WebNode& node) {
- FormElement* form_element = NULL;
- if (!FindCachedFormElement(form, &form_element))
- return;
-
- ForEachMatchingFormField(&form_element->control_elements,
- node,
- form,
- &PreviewFormField);
-}
-
-bool FormManager::ShowPredictions(const FormDataPredictions& form) {
- FormElement* form_element = NULL;
- if (!FindCachedFormElement(form.data, &form_element))
- return false;
-
- DCHECK_EQ(form.data.fields.size(), form.fields.size());
- for (size_t i = 0, j = 0;
- i < form_element->control_elements.size() && j < form.fields.size();
- ++i) {
- WebFormControlElement* element = &form_element->control_elements[i];
- string16 element_name(element->nameForAutofill());
-
- // Search forward in the |form| for a corresponding field.
- size_t k = j;
- while (k < form.fields.size() && element_name != form.data.fields[k].name)
- k++;
-
- if (k >= form.fields.size())
- continue;
-
- DCHECK_EQ(form.data.fields[k].name, element_name);
-
- std::string placeholder = form.fields[k].overall_type;
- string16 title = l10n_util::GetStringFUTF16(
- IDS_AUTOFILL_SHOW_PREDICTIONS_TITLE,
- UTF8ToUTF16(form.fields[k].heuristic_type),
- UTF8ToUTF16(form.fields[k].server_type),
- UTF8ToUTF16(form.fields[k].signature),
- UTF8ToUTF16(form.signature),
- UTF8ToUTF16(form.experiment_id));
- if (!element->hasAttribute("placeholder"))
- element->setAttribute("placeholder", WebString(UTF8ToUTF16(placeholder)));
- element->setAttribute("title", WebString(title));
-
- // We found a matching form field so move on to the next.
- ++j;
+ for (std::vector<WebSelectElement>::const_iterator it =
+ to_delete.begin();
+ it != to_delete.end(); ++it) {
+ initial_select_values_.erase(*it);
}
-
- return true;
}
-bool FormManager::ClearFormWithNode(const WebNode& node) {
- FormElement* form_element = NULL;
- if (!FindCachedFormElementWithNode(node, &form_element))
+bool FormManager::ClearFormWithElement(const WebInputElement& element) {
+ WebFormElement form_element = element.form();
+ if (form_element.isNull())
return false;
- for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
- WebFormControlElement element = form_element->control_elements[i];
- WebInputElement* input_element = toWebInputElement(&element);
+ std::vector<WebFormControlElement> control_elements;
+ ExtractAutofillableElements(form_element, &control_elements);
+ for (size_t i = 0; i < control_elements.size(); ++i) {
+ WebFormControlElement control_element = control_elements[i];
+ WebInputElement* input_element = toWebInputElement(&control_element);
if (IsTextInput(input_element)) {
-
// We don't modify the value of disabled fields.
if (!input_element->isEnabled())
continue;
@@ -979,15 +1008,19 @@ bool FormManager::ClearFormWithNode(const WebNode& node) {
// Clearing the value in the focused node (above) can cause selection
// to be lost. We force selection range to restore the text cursor.
- if (node == *input_element) {
+ if (element == *input_element) {
int length = input_element->value().length();
input_element->setSelectionRange(length, length);
}
} else {
- DCHECK(IsSelectElement(element));
- WebSelectElement select_element = element.to<WebSelectElement>();
- if (select_element.value() != form_element->control_values[i]) {
- select_element.setValue(form_element->control_values[i]);
+ DCHECK(IsSelectElement(control_element));
+ WebSelectElement select_element = control_element.to<WebSelectElement>();
+
+ std::map<const WebSelectElement, string16>::const_iterator
+ initial_value_iter = initial_select_values_.find(select_element);
+ if (initial_value_iter != initial_select_values_.end() &&
+ select_element.value() != initial_value_iter->second) {
+ select_element.setValue(initial_value_iter->second);
select_element.dispatchFormControlChangeEvent();
}
}
@@ -996,121 +1029,71 @@ bool FormManager::ClearFormWithNode(const WebNode& node) {
return true;
}
-bool FormManager::ClearPreviewedFormWithNode(const WebNode& node,
- bool was_autofilled) {
- FormElement* form_element = NULL;
- if (!FindCachedFormElementWithNode(node, &form_element))
- return false;
-
- for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
- WebInputElement* input_element =
- toWebInputElement(&form_element->control_elements[i]);
- // Only text input elements can be previewed.
- if (!IsTextInput(input_element))
- continue;
-
- // If the input element has not been auto-filled, FormManager has not
- // previewed this field, so we have nothing to reset.
- if (!input_element->isAutofilled())
- continue;
-
- // There might be unrelated elements in this form which have already been
- // auto-filled. For example, the user might have already filled the address
- // part of a form and now be dealing with the credit card section. We only
- // want to reset the auto-filled status for fields that were previewed.
- if (input_element->suggestedValue().isEmpty())
- continue;
-
- // Clear the suggested value. For the initiating node, also restore the
- // original value.
- input_element->setSuggestedValue(WebString());
- bool is_initiating_node = (node == *input_element);
- if (is_initiating_node)
- input_element->setAutofilled(was_autofilled);
- else
- input_element->setAutofilled(false);
+bool FormManager::ShowPredictions(const FormDataPredictions& form) {
+ DCHECK_EQ(form.data.fields.size(), form.fields.size());
- // Clearing the suggested value in the focused node (above) can cause
- // selection to be lost. We force selection range to restore the text
- // cursor.
- if (is_initiating_node) {
- int length = input_element->value().length();
- input_element->setSelectionRange(length, length);
+ // Find the form.
+ bool found_form = false;
+ WebFormElement form_element;
+ for (std::set<const WebFrame*>::const_iterator it = web_frames_.begin();
+ it != web_frames_.end() && !found_form; ++it) {
+ WebVector<WebFormElement> web_forms;
+ (*it)->document().forms(web_forms);
+
+ for (size_t i = 0; i < web_forms.size(); ++i) {
+ form_element = web_forms[i];
+
+ // Note: matching on the form name here which is not guaranteed to be
+ // unique for the page, nor is it guaranteed to be non-empty. Ideally, we
+ // would have a way to uniquely identify the form cross-process. For now,
+ // we'll check form name and form action for identity.
+ // Also note that WebString() == WebString(string16()) does not evaluate
+ // to |true| -- WebKit distinguishes between a "null" string (lhs) and an
+ // "empty" string (rhs). We don't want that distinction, so forcing to
+ // string16.
+ string16 element_name = GetFormIdentifier(form_element);
+ GURL action(form_element.document().completeURL(form_element.action()));
+ if (element_name == form.data.name && action == form.data.action) {
+ found_form = true;
+ break;
+ }
}
}
- return true;
-}
-
-void FormManager::ResetFrame(const WebFrame* frame) {
- FormElementList::iterator iter = form_elements_.begin();
- while (iter != form_elements_.end()) {
- if ((*iter)->form_element.document().frame() == frame)
- iter = form_elements_.erase(iter);
- else
- ++iter;
- }
-}
-
-bool FormManager::FormWithNodeIsAutofilled(const WebNode& node) {
- FormElement* form_element = NULL;
- if (!FindCachedFormElementWithNode(node, &form_element))
+ if (!found_form)
return false;
- for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
- WebInputElement* input_element =
- toWebInputElement(&form_element->control_elements[i]);
- if (!IsTextInput(input_element))
- continue;
-
- if (input_element->isAutofilled())
- return true;
+ std::vector<WebFormControlElement> control_elements;
+ ExtractAutofillableElements(form_element, &control_elements);
+ if (control_elements.size() != form.fields.size()) {
+ // Keep things simple. Don't show predictions for forms that were modified
+ // between page load and the server's response to our query.
+ return false;
}
- return false;
-}
+ for (size_t i = 0; i < control_elements.size(); ++i) {
+ WebFormControlElement* element = &control_elements[i];
-bool FormManager::FindCachedFormElementWithNode(const WebNode& node,
- FormElement** form_element) {
- for (FormElementList::const_iterator form_iter = form_elements_.begin();
- form_iter != form_elements_.end(); ++form_iter) {
- for (std::vector<WebFormControlElement>::const_iterator iter =
- (*form_iter)->control_elements.begin();
- iter != (*form_iter)->control_elements.end(); ++iter) {
- if (*iter == node) {
- *form_element = *form_iter;
- return true;
- }
+ if (string16(element->nameForAutofill()) != form.data.fields[i].name) {
+ // Keep things simple. Don't show predictions for elements whose names
+ // were modified between page load and the server's response to our query.
+ continue;
}
- }
-
- return false;
-}
-bool FormManager::FindCachedFormElement(const FormData& form,
- FormElement** form_element) {
- for (FormElementList::iterator form_iter = form_elements_.begin();
- form_iter != form_elements_.end(); ++form_iter) {
- // TODO(dhollowa): matching on form name here which is not guaranteed to
- // be unique for the page, nor is it guaranteed to be non-empty. Need to
- // find a way to uniquely identify the form cross-process. For now we'll
- // check form name and form action for identity.
- // http://crbug.com/37990 test file sample8.html.
- // Also note that WebString() == WebString(string16()) does not evaluate to
- // |true| -- WebKit distinguishes between a "null" string (lhs) and an
- // "empty" string (rhs). We don't want that distinction, so forcing to
- // string16.
- string16 element_name = GetFormIdentifier((*form_iter)->form_element);
- GURL action(
- (*form_iter)->form_element.document().completeURL(
- (*form_iter)->form_element.action()));
- if (element_name == form.name && action == form.action) {
- *form_element = *form_iter;
- return true;
- }
+ std::string placeholder = form.fields[i].overall_type;
+ string16 title = l10n_util::GetStringFUTF16(
+ IDS_AUTOFILL_SHOW_PREDICTIONS_TITLE,
+ UTF8ToUTF16(form.fields[i].heuristic_type),
+ UTF8ToUTF16(form.fields[i].server_type),
+ UTF8ToUTF16(form.fields[i].signature),
+ UTF8ToUTF16(form.signature),
+ UTF8ToUTF16(form.experiment_id));
+ if (!element->hasAttribute("placeholder"))
+ element->setAttribute("placeholder", WebString(UTF8ToUTF16(placeholder)));
+ element->setAttribute("title", WebString(title));
}
- return false;
+ return true;
}
} // namespace autofill
diff --git a/chrome/renderer/autofill/form_manager.h b/chrome/renderer/autofill/form_manager.h
index b32dcb5..cc8f570 100644
--- a/chrome/renderer/autofill/form_manager.h
+++ b/chrome/renderer/autofill/form_manager.h
@@ -7,6 +7,7 @@
#pragma once
#include <map>
+#include <set>
#include <vector>
#include "base/callback_old.h"
@@ -23,6 +24,8 @@ struct FormField;
namespace WebKit {
class WebFormControlElement;
class WebFrame;
+class WebInputElement;
+class WebSelectElement;
} // namespace WebKit
namespace autofill {
@@ -61,86 +64,75 @@ class FormManager {
ExtractMask extract_mask,
webkit_glue::FormField* field);
- // Returns the corresponding label for |element|. WARNING: This method can
- // potentially be very slow. Do not use during any code paths where the page
- // is loading.
- // TODO(isherman): Refactor autofill_agent.cc not to require this method to be
- // exposed.
- static string16 LabelForElement(const WebKit::WebFormControlElement& element);
-
- // Fills out a FormData object from a given WebFormElement. If |get_values|
- // is true, the fields in |form| will have the values filled out. If
- // |get_options| is true, the fields in |form will have select options filled
- // out. Returns true if |form| is filled out; it's possible that |element|
- // won't meet the requirements in |requirements|. This also returns false if
- // there are no fields in |form|.
- static bool WebFormElementToFormData(const WebKit::WebFormElement& element,
- RequirementsMask requirements,
- ExtractMask extract_mask,
- webkit_glue::FormData* form);
-
- // Scans the DOM in |frame| extracting and storing forms.
- // Returns a vector of the extracted forms.
- void ExtractForms(const WebKit::WebFrame* frame,
- std::vector<webkit_glue::FormData>* forms);
+ // Fills |form| with the FormData object corresponding to the |form_element|.
+ // If |field| is non-NULL, also fills |field| with the FormField object
+ // corresponding to the |form_control_element|.
+ // |extract_mask| controls what data is extracted.
+ // Returns true if |form| is filled out; it's possible that the |form_element|
+ // won't meet the |requirements|. Also returns false if there are no fields
+ // in the |form|.
+ static bool WebFormElementToFormData(
+ const WebKit::WebFormElement& form_element,
+ const WebKit::WebFormControlElement& form_control_element,
+ RequirementsMask requirements,
+ ExtractMask extract_mask,
+ webkit_glue::FormData* form,
+ webkit_glue::FormField* field);
- // Finds the form that contains |element| and returns it in |form|. Returns
- // false if the form is not found.
- bool FindFormWithFormControlElement(
+ // Finds the form that contains |element| and returns it in |form|. Fills
+ // |field| with the |FormField| representation for element.
+ // Returns false if the form is not found.
+ static bool FindFormAndFieldForFormControlElement(
const WebKit::WebFormControlElement& element,
- webkit_glue::FormData* form);
+ webkit_glue::FormData* form,
+ webkit_glue::FormField* field);
- // Fills the form represented by |form|. |node| is the input element that
+ // Fills the form represented by |form|. |element| is the input element that
// initiated the auto-fill process.
- void FillForm(const webkit_glue::FormData& form, const WebKit::WebNode& node);
-
- // Previews the form represented by |form|. |node| is the input element that
- // initiated the preview process.
- void PreviewForm(const webkit_glue::FormData& form,
- const WebKit::WebNode &node);
-
- // For each field in the |form|, sets the field's placeholder text to the
- // field's overall predicted type. Also sets the title to include the field's
- // heuristic type, server type, and signature; as well as the form's signature
- // and the experiment id for the server predictions.
- bool ShowPredictions(const webkit_glue::FormDataPredictions& form);
+ static void FillForm(const webkit_glue::FormData& form,
+ const WebKit::WebInputElement& element);
- // Clears the values of all input elements in the form that contains |node|.
- // Returns false if the form is not found.
- bool ClearFormWithNode(const WebKit::WebNode& node);
+ // Previews the form represented by |form|. |element| is the input element
+ // that initiated the preview process.
+ static void PreviewForm(const webkit_glue::FormData& form,
+ const WebKit::WebInputElement& element);
// Clears the placeholder values and the auto-filled background for any fields
// in the form containing |node| that have been previewed. Resets the
// autofilled state of |node| to |was_autofilled|. Returns false if the form
// is not found.
- bool ClearPreviewedFormWithNode(const WebKit::WebNode& node,
- bool was_autofilled);
-
- // Resets the forms for the specified |frame|.
- void ResetFrame(const WebKit::WebFrame* frame);
+ static bool ClearPreviewedFormWithElement(
+ const WebKit::WebInputElement& element,
+ bool was_autofilled);
// Returns true if |form| has any auto-filled fields.
- bool FormWithNodeIsAutofilled(const WebKit::WebNode& node);
+ static bool FormWithElementIsAutofilled(
+ const WebKit::WebInputElement& element);
- private:
- // Stores the WebFormElement and the form control elements for a form.
- // Original form values are stored so when we clear a form we can reset
- // <select> elements to their original value.
- struct FormElement;
+ // Scans the DOM in |frame| extracting and storing forms.
+ // Returns a vector of the extracted forms.
+ void ExtractForms(const WebKit::WebFrame& frame,
+ std::vector<webkit_glue::FormData>* forms);
- // Type for cache of FormElement objects.
- typedef ScopedVector<FormElement> FormElementList;
+ // Resets the forms for the specified |frame|.
+ void ResetFrame(const WebKit::WebFrame& frame);
- // Finds the cached FormElement that contains |node|.
- bool FindCachedFormElementWithNode(const WebKit::WebNode& node,
- FormElement** form_element);
+ // Clears the values of all input elements in the form that contains
+ // |element|. Returns false if the form is not found.
+ bool ClearFormWithElement(const WebKit::WebInputElement& element);
- // Uses the data in |form| to find the cached FormElement.
- bool FindCachedFormElement(const webkit_glue::FormData& form,
- FormElement** form_element);
+ // For each field in the |form|, sets the field's placeholder text to the
+ // field's overall predicted type. Also sets the title to include the field's
+ // heuristic type, server type, and signature; as well as the form's signature
+ // and the experiment id for the server predictions.
+ bool ShowPredictions(const webkit_glue::FormDataPredictions& form);
+
+ private:
+ // The cached web frames.
+ std::set<const WebKit::WebFrame*> web_frames_;
- // The cached FormElement objects.
- FormElementList form_elements_;
+ // The cached initial values for <select> elements.
+ std::map<const WebKit::WebSelectElement, string16> initial_select_values_;
DISALLOW_COPY_AND_ASSIGN(FormManager);
};
diff --git a/chrome/renderer/autofill/form_manager_browsertest.cc b/chrome/renderer/autofill/form_manager_browsertest.cc
index c28d548..fefcef0 100644
--- a/chrome/renderer/autofill/form_manager_browsertest.cc
+++ b/chrome/renderer/autofill/form_manager_browsertest.cc
@@ -69,7 +69,7 @@ class FormManagerTest : public RenderViewTest {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
const FormData& form = forms[0];
@@ -463,14 +463,19 @@ TEST_F(FormManagerTest, WebFormControlElementToFormFieldAutocompletetype) {
TEST_F(FormManagerTest, WebFormElementToFormData) {
LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\">"
+ " <LABEL for=\"firstname\">First name:</LABEL>"
" <INPUT type=\"text\" id=\"firstname\" value=\"John\"/>"
+ " <LABEL for=\"lastname\">Last name:</LABEL>"
" <INPUT type=\"text\" id=\"lastname\" value=\"Smith\"/>"
+ " <LABEL for=\"state\">State:</LABEL>"
" <SELECT id=\"state\"/>"
" <OPTION value=\"CA\">California</OPTION>"
" <OPTION value=\"TX\">Texas</OPTION>"
" </SELECT>"
// The below inputs should be ignored
+ " <LABEL for=\"notvisible\">Hidden:</LABEL>"
" <INPUT type=\"hidden\" id=\"notvisible\" value=\"apple\"/>"
+ " <LABEL for=\"password\">Password:</LABEL>"
" <INPUT type=\"password\" id=\"password\" value=\"secret\"/>"
" <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>"
"</FORM>");
@@ -482,11 +487,17 @@ TEST_F(FormManagerTest, WebFormElementToFormData) {
frame->document().forms(forms);
ASSERT_EQ(1U, forms.size());
+ WebElement element = frame->document().getElementById("firstname");
+ WebInputElement input_element = element.to<WebInputElement>();
+
FormData form;
+ FormField field;
EXPECT_TRUE(FormManager::WebFormElementToFormData(forms[0],
+ input_element,
FormManager::REQUIRE_NONE,
FormManager::EXTRACT_VALUE,
- &form));
+ &form,
+ &field));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://cnn.com"), form.action);
@@ -497,18 +508,21 @@ TEST_F(FormManagerTest, WebFormElementToFormData) {
FormField expected;
expected.name = ASCIIToUTF16("firstname");
expected.value = ASCIIToUTF16("John");
+ expected.label = ASCIIToUTF16("First name:");
expected.form_control_type = ASCIIToUTF16("text");
expected.max_length = WebInputElement::defaultMaxLength();
EXPECT_FORM_FIELD_EQUALS(expected, fields[0]);
expected.name = ASCIIToUTF16("lastname");
expected.value = ASCIIToUTF16("Smith");
+ expected.label = ASCIIToUTF16("Last name:");
expected.form_control_type = ASCIIToUTF16("text");
expected.max_length = WebInputElement::defaultMaxLength();
EXPECT_FORM_FIELD_EQUALS(expected, fields[1]);
expected.name = ASCIIToUTF16("state");
expected.value = ASCIIToUTF16("CA");
+ expected.label = ASCIIToUTF16("State:");
expected.form_control_type = ASCIIToUTF16("select-one");
expected.max_length = 0;
EXPECT_FORM_FIELD_EQUALS(expected, fields[2]);
@@ -543,7 +557,7 @@ TEST_F(FormManagerTest, ExtractMultipleForms) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(2U, forms.size());
// First form.
@@ -606,7 +620,7 @@ TEST_F(FormManagerTest, ExtractFormsTooFewFields) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
EXPECT_EQ(0U, forms.size());
}
@@ -631,10 +645,11 @@ TEST_F(FormManagerTest, WebFormElementToFormDataAutocomplete) {
FormData form;
EXPECT_TRUE(FormManager::WebFormElementToFormData(
- web_form, FormManager::REQUIRE_NONE, FormManager::EXTRACT_NONE, &form));
+ web_form, WebFormControlElement(), FormManager::REQUIRE_NONE,
+ FormManager::EXTRACT_NONE, &form, NULL));
EXPECT_FALSE(FormManager::WebFormElementToFormData(
- web_form, FormManager::REQUIRE_AUTOCOMPLETE, FormManager::EXTRACT_NONE,
- &form));
+ web_form, WebFormControlElement(), FormManager::REQUIRE_AUTOCOMPLETE,
+ FormManager::EXTRACT_NONE, &form, NULL));
}
{
@@ -659,8 +674,8 @@ TEST_F(FormManagerTest, WebFormElementToFormDataAutocomplete) {
FormData form;
EXPECT_TRUE(FormManager::WebFormElementToFormData(
- web_form, FormManager::REQUIRE_AUTOCOMPLETE, FormManager::EXTRACT_VALUE,
- &form));
+ web_form, WebFormControlElement(), FormManager::REQUIRE_AUTOCOMPLETE,
+ FormManager::EXTRACT_VALUE, &form, NULL));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
@@ -707,8 +722,8 @@ TEST_F(FormManagerTest, WebFormElementToFormDataEnabled) {
FormData form;
EXPECT_TRUE(FormManager::WebFormElementToFormData(
- web_form, FormManager::REQUIRE_ENABLED, FormManager::EXTRACT_VALUE,
- &form));
+ web_form, WebFormControlElement(), FormManager::REQUIRE_ENABLED,
+ FormManager::EXTRACT_VALUE, &form, NULL));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
@@ -747,7 +762,7 @@ TEST_F(FormManagerTest, FindForm) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
// Get the input element we want to find.
@@ -756,8 +771,10 @@ TEST_F(FormManagerTest, FindForm) {
// Find the form and verify it's the correct form.
FormData form;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form));
+ FormField field;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://buh.com"), form.action);
@@ -772,6 +789,7 @@ TEST_F(FormManagerTest, FindForm) {
expected.name = ASCIIToUTF16("firstname");
expected.value = ASCIIToUTF16("John");
EXPECT_FORM_FIELD_EQUALS(expected, fields[0]);
+ EXPECT_FORM_FIELD_EQUALS(expected, field);
expected.name = ASCIIToUTF16("lastname");
expected.value = ASCIIToUTF16("Smith");
@@ -802,7 +820,7 @@ TEST_F(FormManagerTest, FillForm) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
// Get the input element we want to find.
@@ -811,8 +829,10 @@ TEST_F(FormManagerTest, FillForm) {
// Find the form that contains the input element.
FormData form;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form));
+ FormField field;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://buh.com"), form.action);
@@ -933,7 +953,7 @@ TEST_F(FormManagerTest, FAILS_PreviewForm) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
// Get the input element we want to find.
@@ -942,8 +962,10 @@ TEST_F(FormManagerTest, FAILS_PreviewForm) {
// Find the form that contains the input element.
FormData form;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form));
+ FormField field;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://buh.com"), form.action);
@@ -1888,7 +1910,7 @@ TEST_F(FormManagerTest, FillFormMaxLength) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
// Get the input element we want to find.
@@ -1897,8 +1919,10 @@ TEST_F(FormManagerTest, FillFormMaxLength) {
// Find the form that contains the input element.
FormData form;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form));
+ FormField field;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://buh.com"), form.action);
@@ -1928,12 +1952,15 @@ TEST_F(FormManagerTest, FillFormMaxLength) {
form.fields[0].value = ASCIIToUTF16("Brother");
form.fields[1].value = ASCIIToUTF16("Jonathan");
form.fields[2].value = ASCIIToUTF16("brotherj@example.com");
- form_manager.FillForm(form, WebNode());
+ form_manager.FillForm(form, input_element);
// Find the newly-filled form that contains the input element.
FormData form2;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form2));
+ FormField field2;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form2,
+ &field2));
+
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
EXPECT_EQ(GURL("http://buh.com"), form2.action);
@@ -1978,7 +2005,7 @@ TEST_F(FormManagerTest, FillFormNegativeMaxLength) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
// Get the input element we want to find.
@@ -1987,8 +2014,10 @@ TEST_F(FormManagerTest, FillFormNegativeMaxLength) {
// Find the form that contains the input element.
FormData form;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form));
+ FormField field;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://buh.com"), form.action);
@@ -2013,12 +2042,15 @@ TEST_F(FormManagerTest, FillFormNegativeMaxLength) {
form.fields[0].value = ASCIIToUTF16("Brother");
form.fields[1].value = ASCIIToUTF16("Jonathan");
form.fields[2].value = ASCIIToUTF16("brotherj@example.com");
- form_manager.FillForm(form, WebNode());
+ form_manager.FillForm(form, input_element);
// Find the newly-filled form that contains the input element.
FormData form2;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form2));
+ FormField field2;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form2,
+ &field2));
+
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
EXPECT_EQ(GURL("http://buh.com"), form2.action);
@@ -2039,340 +2071,6 @@ TEST_F(FormManagerTest, FillFormNegativeMaxLength) {
EXPECT_FORM_FIELD_EQUALS(expected, fields[2]);
}
-// This test sends a FormData object to FillForm with more fields than are in
-// the cached WebFormElement. In this case, we only fill out the fields that
-// match between the FormData object and the WebFormElement.
-TEST_F(FormManagerTest, FillFormMoreFormDataFields) {
- LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">"
- " <INPUT type=\"text\" id=\"firstname\"/>"
- " <INPUT type=\"text\" id=\"middlename\"/>"
- " <INPUT type=\"text\" id=\"lastname\"/>"
- " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>"
- "</FORM>");
-
- WebFrame* web_frame = GetMainFrame();
- ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame);
-
- FormManager form_manager;
- std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
- ASSERT_EQ(1U, forms.size());
-
- // After the field modification, the fields in |form| will look like:
- // prefix
- // firstname
- // hidden
- // middlename
- // second
- // lastname
- // postfix
- FormData* form = &forms[0];
-
- FormField field1;
- field1.name = ASCIIToUTF16("prefix");
- field1.form_control_type = ASCIIToUTF16("text");
- field1.max_length = WebInputElement::defaultMaxLength();
- form->fields.insert(form->fields.begin(), field1);
-
- FormField field2;
- field2.name = ASCIIToUTF16("hidden");
- field2.form_control_type = ASCIIToUTF16("text");
- field2.max_length = WebInputElement::defaultMaxLength();
- form->fields.insert(form->fields.begin() + 2, field2);
-
- FormField field3;
- field3.name = ASCIIToUTF16("second");
- field3.form_control_type = ASCIIToUTF16("text");
- field3.max_length = WebInputElement::defaultMaxLength();
- form->fields.insert(form->fields.begin() + 4, field3);
-
- FormField field4;
- field4.name = ASCIIToUTF16("postfix");
- field4.form_control_type = ASCIIToUTF16("text");
- field4.max_length = WebInputElement::defaultMaxLength();
- form->fields.insert(form->fields.begin() + 6, field4);
-
- // Fill the form.
- form->fields[0].value = ASCIIToUTF16("Alpha");
- form->fields[1].value = ASCIIToUTF16("Brother");
- form->fields[2].value = ASCIIToUTF16("Abracadabra");
- form->fields[3].value = ASCIIToUTF16("Joseph");
- form->fields[4].value = ASCIIToUTF16("Beta");
- form->fields[5].value = ASCIIToUTF16("Jonathan");
- form->fields[6].value = ASCIIToUTF16("Omega");
- form_manager.FillForm(*form, WebNode());
-
- // Get the input element we want to find.
- WebElement element = web_frame->document().getElementById("firstname");
- WebInputElement input_element = element.to<WebInputElement>();
-
- // Find the newly-filled form that contains the input element.
- FormData form2;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form2));
- EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
- EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
- EXPECT_EQ(GURL("http://buh.com"), form2.action);
-
- const std::vector<FormField>& fields = form2.fields;
- ASSERT_EQ(3U, fields.size());
-
- FormField expected;
- expected.form_control_type = ASCIIToUTF16("text");
- expected.max_length = WebInputElement::defaultMaxLength();
- expected.is_autofilled = true;
-
- expected.name = ASCIIToUTF16("firstname");
- expected.value = ASCIIToUTF16("Brother");
- EXPECT_FORM_FIELD_EQUALS(expected, fields[0]);
-
- expected.name = ASCIIToUTF16("middlename");
- expected.value = ASCIIToUTF16("Joseph");
- EXPECT_FORM_FIELD_EQUALS(expected, fields[1]);
-
- expected.name = ASCIIToUTF16("lastname");
- expected.value = ASCIIToUTF16("Jonathan");
- EXPECT_FORM_FIELD_EQUALS(expected, fields[2]);
-}
-
-// This test sends a FormData object to FillForm with fewer fields than are in
-// the cached WebFormElement. In this case, we only fill out the fields that
-// match between the FormData object and the WebFormElement.
-TEST_F(FormManagerTest, FillFormFewerFormDataFields) {
- LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">"
- " <INPUT type=\"text\" id=\"prefix\"/>"
- " <INPUT type=\"text\" id=\"firstname\"/>"
- " <INPUT type=\"text\" id=\"hidden\"/>"
- " <INPUT type=\"text\" id=\"middlename\"/>"
- " <INPUT type=\"text\" id=\"second\"/>"
- " <INPUT type=\"text\" id=\"lastname\"/>"
- " <INPUT type=\"text\" id=\"postfix\"/>"
- " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>"
- "</FORM>");
-
- WebFrame* web_frame = GetMainFrame();
- ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame);
-
- FormManager form_manager;
- std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
- ASSERT_EQ(1U, forms.size());
-
- // After the field modification, the fields in |form| will look like:
- // firstname
- // middlename
- // lastname
- FormData* form = &forms[0];
- form->fields.erase(form->fields.begin());
- form->fields.erase(form->fields.begin() + 1);
- form->fields.erase(form->fields.begin() + 2);
- form->fields.erase(form->fields.begin() + 3);
-
- // Fill the form.
- form->fields[0].value = ASCIIToUTF16("Brother");
- form->fields[1].value = ASCIIToUTF16("Joseph");
- form->fields[2].value = ASCIIToUTF16("Jonathan");
- form_manager.FillForm(*form, WebNode());
-
- // Get the input element we want to find.
- WebElement element = web_frame->document().getElementById("firstname");
- WebInputElement input_element = element.to<WebInputElement>();
-
- // Find the newly-filled form that contains the input element.
- FormData form2;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form2));
- EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
- EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
- EXPECT_EQ(GURL("http://buh.com"), form2.action);
-
- const std::vector<FormField>& fields = form2.fields;
- ASSERT_EQ(7U, fields.size());
-
- FormField expected;
- expected.form_control_type = ASCIIToUTF16("text");
- expected.max_length = WebInputElement::defaultMaxLength();
-
- expected.name = ASCIIToUTF16("prefix");
- expected.value = string16();
- expected.is_autofilled = false;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[0]);
-
- expected.name = ASCIIToUTF16("firstname");
- expected.value = ASCIIToUTF16("Brother");
- expected.is_autofilled = true;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[1]);
-
- expected.name = ASCIIToUTF16("hidden");
- expected.value = string16();
- expected.is_autofilled = false;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[2]);
-
- expected.name = ASCIIToUTF16("middlename");
- expected.value = ASCIIToUTF16("Joseph");
- expected.is_autofilled = true;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[3]);
-
- expected.name = ASCIIToUTF16("second");
- expected.value = string16();
- expected.is_autofilled = false;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[4]);
-
- expected.name = ASCIIToUTF16("lastname");
- expected.value = ASCIIToUTF16("Jonathan");
- expected.is_autofilled = true;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[5]);
-
- expected.name = ASCIIToUTF16("postfix");
- expected.value = string16();
- expected.is_autofilled = false;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[6]);
-}
-
-// This test sends a FormData object to FillForm with a field changed from
-// those in the cached WebFormElement. In this case, we only fill out the
-// fields that match between the FormData object and the WebFormElement.
-TEST_F(FormManagerTest, FillFormChangedFormDataFields) {
- LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">"
- " <INPUT type=\"text\" id=\"firstname\"/>"
- " <INPUT type=\"text\" id=\"middlename\"/>"
- " <INPUT type=\"text\" id=\"lastname\"/>"
- " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>"
- "</FORM>");
-
- WebFrame* web_frame = GetMainFrame();
- ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame);
-
- FormManager form_manager;
- std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
- ASSERT_EQ(1U, forms.size());
-
- // After the field modification, the fields in |form| will look like:
- // firstname
- // middlename
- // lastname
- FormData* form = &forms[0];
-
- // Fill the form.
- form->fields[0].value = ASCIIToUTF16("Brother");
- form->fields[1].value = ASCIIToUTF16("Joseph");
- form->fields[2].value = ASCIIToUTF16("Jonathan");
-
- // Alter the label and name used for matching.
- form->fields[1].label = ASCIIToUTF16("bogus");
- form->fields[1].name = ASCIIToUTF16("bogus");
-
- form_manager.FillForm(*form, WebNode());
-
- // Get the input element we want to find.
- WebElement element = web_frame->document().getElementById("firstname");
- WebInputElement input_element = element.to<WebInputElement>();
-
- // Find the newly-filled form that contains the input element.
- FormData form2;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form2));
- EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
- EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
- EXPECT_EQ(GURL("http://buh.com"), form2.action);
-
- const std::vector<FormField>& fields = form2.fields;
- ASSERT_EQ(3U, fields.size());
-
- FormField expected;
- expected.form_control_type = ASCIIToUTF16("text");
- expected.max_length = WebInputElement::defaultMaxLength();
-
- expected.name = ASCIIToUTF16("firstname");
- expected.value = ASCIIToUTF16("Brother");
- expected.is_autofilled = true;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[0]);
-
- expected.name = ASCIIToUTF16("middlename");
- expected.value = ASCIIToUTF16("");
- expected.is_autofilled = false;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[1]);
-
- expected.name = ASCIIToUTF16("lastname");
- expected.value = ASCIIToUTF16("Jonathan");
- expected.is_autofilled = true;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[2]);
-}
-
-// This test sends a FormData object to FillForm with fewer fields than are in
-// the cached WebFormElement. In this case, we only fill out the fields that
-// match between the FormData object and the WebFormElement.
-TEST_F(FormManagerTest, FillFormExtraFieldInCache) {
- LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">"
- " <INPUT type=\"text\" id=\"firstname\"/>"
- " <INPUT type=\"text\" id=\"middlename\"/>"
- " <INPUT type=\"text\" id=\"lastname\"/>"
- " <INPUT type=\"text\" id=\"postfix\"/>"
- " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>"
- "</FORM>");
-
- WebFrame* web_frame = GetMainFrame();
- ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame);
-
- FormManager form_manager;
- std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
- ASSERT_EQ(1U, forms.size());
-
- // After the field modification, the fields in |form| will look like:
- // firstname
- // middlename
- // lastname
- FormData* form = &forms[0];
- form->fields.pop_back();
-
- // Fill the form.
- form->fields[0].value = ASCIIToUTF16("Brother");
- form->fields[1].value = ASCIIToUTF16("Joseph");
- form->fields[2].value = ASCIIToUTF16("Jonathan");
- form_manager.FillForm(*form, WebNode());
-
- // Get the input element we want to find.
- WebElement element = web_frame->document().getElementById("firstname");
- WebInputElement input_element = element.to<WebInputElement>();
-
- // Find the newly-filled form that contains the input element.
- FormData form2;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form2));
- EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
- EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
- EXPECT_EQ(GURL("http://buh.com"), form2.action);
-
- const std::vector<FormField>& fields = form2.fields;
- ASSERT_EQ(4U, fields.size());
-
- FormField expected;
- expected.form_control_type = ASCIIToUTF16("text");
- expected.max_length = WebInputElement::defaultMaxLength();
-
- expected.name = ASCIIToUTF16("firstname");
- expected.value = ASCIIToUTF16("Brother");
- expected.is_autofilled = true;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[0]);
-
- expected.name = ASCIIToUTF16("middlename");
- expected.value = ASCIIToUTF16("Joseph");
- expected.is_autofilled = true;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[1]);
-
- expected.name = ASCIIToUTF16("lastname");
- expected.value = ASCIIToUTF16("Jonathan");
- expected.is_autofilled = true;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[2]);
-
- expected.name = ASCIIToUTF16("postfix");
- expected.value = string16();
- expected.is_autofilled = false;
- EXPECT_FORM_FIELD_EQUALS(expected, fields[3]);
-}
-
TEST_F(FormManagerTest, FillFormEmptyName) {
LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">"
" <INPUT type=\"text\" id=\"firstname\"/>"
@@ -2386,7 +2084,7 @@ TEST_F(FormManagerTest, FillFormEmptyName) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
// Get the input element we want to find.
@@ -2395,8 +2093,10 @@ TEST_F(FormManagerTest, FillFormEmptyName) {
// Find the form that contains the input element.
FormData form;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form));
+ FormField field;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://buh.com"), form.action);
@@ -2421,12 +2121,15 @@ TEST_F(FormManagerTest, FillFormEmptyName) {
form.fields[0].value = ASCIIToUTF16("Wyatt");
form.fields[1].value = ASCIIToUTF16("Earp");
form.fields[2].value = ASCIIToUTF16("wyatt@example.com");
- form_manager.FillForm(form, WebNode());
+ form_manager.FillForm(form, input_element);
// Find the newly-filled form that contains the input element.
FormData form2;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form2));
+ FormField field2;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form2,
+ &field2));
+
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
EXPECT_EQ(GURL("http://buh.com"), form2.action);
@@ -2469,7 +2172,7 @@ TEST_F(FormManagerTest, FillFormEmptyFormNames) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(2U, forms.size());
// Get the input element we want to find.
@@ -2478,8 +2181,10 @@ TEST_F(FormManagerTest, FillFormEmptyFormNames) {
// Find the form that contains the input element.
FormData form;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form));
+ FormField field;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field));
EXPECT_EQ(string16(), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://abc.com"), form.action);
@@ -2507,12 +2212,15 @@ TEST_F(FormManagerTest, FillFormEmptyFormNames) {
form.fields[0].value = ASCIIToUTF16("Red");
form.fields[1].value = ASCIIToUTF16("Yellow");
form.fields[2].value = ASCIIToUTF16("Also Yellow");
- form_manager.FillForm(form, WebNode());
+ form_manager.FillForm(form, input_element);
// Find the newly-filled form that contains the input element.
FormData form2;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form2));
+ FormField field2;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form2,
+ &field2));
+
EXPECT_EQ(string16(), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
EXPECT_EQ(GURL("http://abc.com"), form2.action);
@@ -2559,9 +2267,11 @@ TEST_F(FormManagerTest, ThreePartPhone) {
FormData form;
EXPECT_TRUE(FormManager::WebFormElementToFormData(forms[0],
+ WebFormControlElement(),
FormManager::REQUIRE_NONE,
FormManager::EXTRACT_VALUE,
- &form));
+ &form,
+ NULL));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://cnn.com"), form.action);
@@ -2616,9 +2326,11 @@ TEST_F(FormManagerTest, MaxLengthFields) {
FormData form;
EXPECT_TRUE(FormManager::WebFormElementToFormData(forms[0],
+ WebFormControlElement(),
FormManager::REQUIRE_NONE,
FormManager::EXTRACT_VALUE,
- &form));
+ &form,
+ NULL));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://cnn.com"), form.action);
@@ -2678,7 +2390,7 @@ TEST_F(FormManagerTest, FAILS_FillFormNonEmptyField) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
// Get the input element we want to find.
@@ -2690,8 +2402,10 @@ TEST_F(FormManagerTest, FAILS_FillFormNonEmptyField) {
// Find the form that contains the input element.
FormData form;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form));
+ FormField field;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://buh.com"), form.action);
@@ -2731,8 +2445,11 @@ TEST_F(FormManagerTest, FAILS_FillFormNonEmptyField) {
// Find the newly-filled form that contains the input element.
FormData form2;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(input_element,
- &form2));
+ FormField field2;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(input_element,
+ &form2,
+ &field2));
+
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
EXPECT_EQ(GURL("http://buh.com"), form2.action);
@@ -2775,7 +2492,7 @@ TEST_F(FormManagerTest, ClearFormWithNode) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
// Set the auto-filled attribute on the firstname element.
@@ -2789,14 +2506,17 @@ TEST_F(FormManagerTest, ClearFormWithNode) {
notenabled.setValue(WebString::fromUTF8("no clear"));
// Clear the form.
- EXPECT_TRUE(form_manager.ClearFormWithNode(firstname));
+ EXPECT_TRUE(form_manager.ClearFormWithElement(firstname));
// Verify that the auto-filled attribute has been turned off.
EXPECT_FALSE(firstname.isAutofilled());
// Verify the form is cleared.
FormData form2;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(firstname, &form2));
+ FormField field2;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(firstname,
+ &form2,
+ &field2));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
EXPECT_EQ(GURL("http://buh.com"), form2.action);
@@ -2848,7 +2568,7 @@ TEST_F(FormManagerTest, ClearFormWithNodeContainingSelectOne) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
// Set the auto-filled attribute on the firstname element.
@@ -2862,14 +2582,17 @@ TEST_F(FormManagerTest, ClearFormWithNodeContainingSelectOne) {
select_element.setValue(WebString::fromUTF8("AK"));
// Clear the form.
- EXPECT_TRUE(form_manager.ClearFormWithNode(firstname));
+ EXPECT_TRUE(form_manager.ClearFormWithElement(firstname));
// Verify that the auto-filled attribute has been turned off.
EXPECT_FALSE(firstname.isAutofilled());
// Verify the form is cleared.
FormData form2;
- EXPECT_TRUE(form_manager.FindFormWithFormControlElement(firstname, &form2));
+ FormField field2;
+ EXPECT_TRUE(FormManager::FindFormAndFieldForFormControlElement(firstname,
+ &form2,
+ &field2));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
EXPECT_EQ(GURL("http://buh.com"), form2.action);
@@ -2902,7 +2625,7 @@ TEST_F(FormManagerTest, ClearFormWithNodeContainingSelectOne) {
EXPECT_EQ(0, firstname.selectionEnd());
}
-TEST_F(FormManagerTest, ClearPreviewedFormWithNode) {
+TEST_F(FormManagerTest, ClearPreviewedFormWithElement) {
LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">"
" <INPUT type=\"text\" id=\"firstname\" value=\"Wyatt\"/>"
" <INPUT type=\"text\" id=\"lastname\"/>"
@@ -2917,7 +2640,7 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithNode) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
// Set the auto-filled attribute.
@@ -2944,7 +2667,7 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithNode) {
phone.setSuggestedValue(ASCIIToUTF16("650-777-9999"));
// Clear the previewed fields.
- EXPECT_TRUE(form_manager.ClearPreviewedFormWithNode(lastname, false));
+ EXPECT_TRUE(FormManager::ClearPreviewedFormWithElement(lastname, false));
// Fields with empty suggestions suggestions are not modified.
EXPECT_EQ(ASCIIToUTF16("Wyatt"), firstname.value());
@@ -2985,7 +2708,7 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithNonEmptyInitiatingNode) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
// Set the auto-filled attribute.
@@ -3014,7 +2737,7 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithNonEmptyInitiatingNode) {
phone.setSuggestedValue(ASCIIToUTF16("650-777-9999"));
// Clear the previewed fields.
- EXPECT_TRUE(form_manager.ClearPreviewedFormWithNode(firstname, false));
+ EXPECT_TRUE(FormManager::ClearPreviewedFormWithElement(firstname, false));
// Fields with non-empty values are restored.
EXPECT_EQ(ASCIIToUTF16("W"), firstname.value());
@@ -3053,7 +2776,7 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithAutofilledInitiatingNode) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
// Set the auto-filled attribute.
@@ -3081,7 +2804,7 @@ TEST_F(FormManagerTest, ClearPreviewedFormWithAutofilledInitiatingNode) {
phone.setSuggestedValue(ASCIIToUTF16("650-777-9999"));
// Clear the previewed fields.
- EXPECT_TRUE(form_manager.ClearPreviewedFormWithNode(firstname, true));
+ EXPECT_TRUE(FormManager::ClearPreviewedFormWithElement(firstname, true));
// Fields with non-empty values are restored.
EXPECT_EQ(ASCIIToUTF16("W"), firstname.value());
@@ -3120,39 +2843,19 @@ TEST_F(FormManagerTest, FormWithNodeIsAutofilled) {
FormManager form_manager;
std::vector<FormData> forms;
- form_manager.ExtractForms(web_frame, &forms);
+ form_manager.ExtractForms(*web_frame, &forms);
ASSERT_EQ(1U, forms.size());
WebInputElement firstname =
web_frame->document().getElementById("firstname").to<WebInputElement>();
// Auto-filled attribute not set yet.
- EXPECT_FALSE(form_manager.FormWithNodeIsAutofilled(firstname));
+ EXPECT_FALSE(FormManager::FormWithElementIsAutofilled(firstname));
// Set the auto-filled attribute.
firstname.setAutofilled(true);
- EXPECT_TRUE(form_manager.FormWithNodeIsAutofilled(firstname));
-}
-
-TEST_F(FormManagerTest, LabelForElementHidden) {
- LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\">"
- " <LABEL for=\"firstname\"> First name: </LABEL>"
- " <INPUT type=\"hidden\" id=\"firstname\" value=\"John\"/>"
- " <LABEL for=\"lastname\"> Last name: </LABEL>"
- " <INPUT type=\"hidden\" id=\"lastname\" value=\"Smith\"/>"
- " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>"
- "</FORM>");
-
- WebFrame* web_frame = GetMainFrame();
- ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame);
-
- WebElement e = web_frame->document().getElementById("firstname");
- WebFormControlElement firstname = e.to<WebFormControlElement>();
-
- // Hidden form control element should not have a label set.
- FormManager form_manager;
- EXPECT_EQ(string16(), form_manager.LabelForElement(firstname));
+ EXPECT_TRUE(FormManager::FormWithElementIsAutofilled(firstname));
}
// If we have multiple labels per id, the labels concatenated into label string.
@@ -3215,10 +2918,10 @@ TEST_F(FormManagerTest, SelectOneAsText) {
// Extract the country select-one value as text.
EXPECT_TRUE(FormManager::WebFormElementToFormData(
- forms[0], FormManager::REQUIRE_NONE,
+ forms[0], WebFormControlElement(), FormManager::REQUIRE_NONE,
static_cast<FormManager::ExtractMask>(FormManager::EXTRACT_VALUE |
FormManager::EXTRACT_OPTION_TEXT),
- &form));
+ &form, NULL));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://cnn.com"), form.action);
@@ -3249,9 +2952,11 @@ TEST_F(FormManagerTest, SelectOneAsText) {
form.fields.clear();
// Extract the country select-one value as value.
EXPECT_TRUE(FormManager::WebFormElementToFormData(forms[0],
+ WebFormControlElement(),
FormManager::REQUIRE_NONE,
FormManager::EXTRACT_VALUE,
- &form));
+ &form,
+ NULL));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://cnn.com"), form.action);