diff options
author | isherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-07 21:18:32 +0000 |
---|---|---|
committer | isherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-07 21:18:32 +0000 |
commit | 829245b1c00a35df64fd0acd6f90518b2880731c (patch) | |
tree | 65d7c7ed1787649cd07d99737a013dc5c50ed574 /chrome/renderer | |
parent | 658600ecbdb63bf8997d0c87812243cc1aae670e (diff) | |
download | chromium_src-829245b1c00a35df64fd0acd6f90518b2880731c.zip chromium_src-829245b1c00a35df64fd0acd6f90518b2880731c.tar.gz chromium_src-829245b1c00a35df64fd0acd6f90518b2880731c.tar.bz2 |
Add Autofill support for dynamically updated forms (updated via JavaScript).
o Rip out most of the cache in the renderer (FormManager).
+ We still cache the set of loaded frames, so that we can show field type predictions (when the corresponding flag is enabled).
+ We also still cache the original values for <select> elements, so that we can restore these values upon clearing a form.
+ That's all that we cache!
+ This vastly simplifies the form previewing/filling loop logic.
o Update the browser process cache on the fly.
+ Whenever we look for a form in our cache, update the cache if we don't find an exact match.
+ We also preserve the original versions of cached forms, so that we do not destroy our ability to parse the crowdsourcing server's response to a query.
+ This vastly simplifies the form filling and section finding loop logic.
o Related code cleanup
+ Consolidated previously duplicated label extraction code.
+ Several member functions on the renderer side became static.
+ Const-correctness for several functions on the browser side.
+ Decomposed some functions into more manageable chunks.
+ Unique field names are guaranteed to actually be unique!
BUG=57182, 64112, 44323, 92229, 88252, 62593, 93595, 51527
TEST=interactive_ui_tests --gtest_filter=AutofillTest.DynamicFormFill
Review URL: http://codereview.chromium.org/7831032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100021 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/autofill/autofill_agent.cc | 39 | ||||
-rw-r--r-- | chrome/renderer/autofill/form_manager.cc | 579 | ||||
-rw-r--r-- | chrome/renderer/autofill/form_manager.h | 118 | ||||
-rw-r--r-- | chrome/renderer/autofill/form_manager_browsertest.cc | 553 |
4 files changed, 481 insertions, 808 deletions
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); |