summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/renderer')
-rw-r--r--chrome/renderer/form_manager.cc117
-rw-r--r--chrome/renderer/form_manager.h9
-rw-r--r--chrome/renderer/form_manager_unittest.cc50
-rw-r--r--chrome/renderer/render_view.cc22
4 files changed, 146 insertions, 52 deletions
diff --git a/chrome/renderer/form_manager.cc b/chrome/renderer/form_manager.cc
index 3d313b6..5bd22e5 100644
--- a/chrome/renderer/form_manager.cc
+++ b/chrome/renderer/form_manager.cc
@@ -5,6 +5,7 @@
#include "chrome/renderer/form_manager.h"
#include "base/logging.h"
+#include "base/scoped_vector.h"
#include "base/string_util.h"
#include "base/stl_util-inl.h"
#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h"
@@ -58,9 +59,9 @@ void FormManager::WebFormControlElementToFormField(
const WebFormControlElement& element, FormField* field) {
DCHECK(field);
- // TODO(jhawkins): LabelForElement. Returning an empty label temporarily to
- // diagnose a perf issue.
- field->set_label(string16());
+ // The label is not officially part of a WebFormControlElement; however, the
+ // labels for all form control elements are scraped from the DOM and set in
+ // WebFormElementToFormData.
field->set_name(element.nameForAutofill());
field->set_form_control_type(element.formControlType());
@@ -104,6 +105,13 @@ bool FormManager::WebFormElementToFormData(const WebFormElement& element,
if (!form->action.is_valid())
form->action = GURL(element.action());
+ // A map from a FormField's name to the FormField itself.
+ std::map<string16, FormField*> name_map;
+
+ // The extracted FormFields. We use pointers so we can store them in
+ // |name_map|.
+ ScopedVector<FormField> form_fields;
+
WebVector<WebFormControlElement> control_elements;
element.getFormControlElements(control_elements);
for (size_t i = 0; i < control_elements.size(); ++i) {
@@ -120,12 +128,46 @@ bool FormManager::WebFormElementToFormData(const WebFormElement& element,
if (requirements & REQUIRE_ELEMENTS_ENABLED && !control_element.isEnabled())
continue;
- FormField field;
- WebFormControlElementToFormField(control_element, &field);
- form->fields.push_back(field);
+ // Create a new FormField, fill it out and map it to the field's name.
+ FormField* field = new FormField;
+ WebFormControlElementToFormField(control_element, field);
+ form_fields.push_back(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;
+ }
+
+ // Don't extract field labels if we have no fields.
+ if (form_fields.empty())
+ return false;
+
+ // Loop through the label elements inside the form element. For each label
+ // element, get the corresponding form control element, use the form control
+ // 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
+ // innerText() of the label element.
+ WebNodeList labels = element.getElementsByTagName("label");
+ for (unsigned i = 0; i < labels.length(); ++i) {
+ WebLabelElement label = labels.item(i).toElement<WebLabelElement>();
+ WebFormControlElement field_element =
+ label.correspondingControl().toElement<WebFormControlElement>();
+ if (field_element.isNull() || !field_element.isFormControlElement())
+ continue;
+
+ std::map<string16, FormField*>::iterator iter =
+ name_map.find(field_element.nameForAutofill());
+ if (iter != name_map.end())
+ iter->second->set_label(label.innerText());
}
- return !form->fields.empty();
+ // Copy the created FormFields into the resulting FormData object.
+ for (ScopedVector<FormField>::const_iterator iter = form_fields.begin();
+ iter != form_fields.end(); ++iter) {
+ form->fields.push_back(**iter);
+ }
+
+ return true;
}
void FormManager::ExtractForms(const WebFrame* frame) {
@@ -145,9 +187,7 @@ void FormManager::ExtractForms(const WebFrame* frame) {
form_elements->form_element.getFormControlElements(control_elements);
for (size_t j = 0; j < control_elements.size(); ++j) {
WebFormControlElement element = control_elements[j];
- // TODO(jhawkins): Remove this check when we have labels.
- if (!element.nameForAutofill().isEmpty())
- form_elements->control_elements[element.nameForAutofill()] = element;
+ form_elements->control_elements.push_back(element);
}
form_elements_map_[frame].push_back(form_elements);
@@ -160,19 +200,13 @@ void FormManager::GetForms(RequirementsMask requirements,
for (WebFrameFormElementMap::iterator iter = form_elements_map_.begin();
iter != form_elements_map_.end(); ++iter) {
- const WebFrame* frame = iter->first;
-
for (std::vector<FormElement*>::iterator form_iter = iter->second.begin();
form_iter != iter->second.end(); ++form_iter) {
- FormElement* form_element = *form_iter;
-
- if (requirements & REQUIRE_AUTOCOMPLETE &&
- !form_element->form_element.autoComplete())
- continue;
-
FormData form;
- FormElementToFormData(frame, form_element, requirements, &form);
- forms->push_back(form);
+ if (WebFormElementToFormData((*form_iter)->form_element,
+ requirements,
+ &form))
+ forms->push_back(form);
}
}
}
@@ -254,10 +288,13 @@ bool FormManager::FindFormWithFormControlElement(
iter != forms.end(); ++iter) {
const FormElement* form_element = *iter;
- if (form_element->control_elements.find(element.nameForAutofill()) !=
- form_element->control_elements.end()) {
- FormElementToFormData(frame, form_element, requirements, form);
- return true;
+ for (std::vector<WebFormControlElement>::const_iterator iter =
+ form_element->control_elements.begin();
+ iter != form_element->control_elements.end(); ++iter) {
+ if (iter->nameForAutofill() == element.nameForAutofill()) {
+ WebFormElementToFormData(form_element->form_element, requirements, form);
+ return true;
+ }
}
}
@@ -267,10 +304,8 @@ bool FormManager::FindFormWithFormControlElement(
bool FormManager::FillForm(const FormData& form) {
FormElement* form_element = NULL;
- // Frame loop.
for (WebFrameFormElementMap::iterator iter = form_elements_map_.begin();
iter != form_elements_map_.end(); ++iter) {
- // Form loop.
for (std::vector<FormElement*>::iterator form_iter = iter->second.begin();
form_iter != iter->second.end(); ++form_iter) {
// TODO(dhollowa): matching on form name here which is not guaranteed to
@@ -293,23 +328,27 @@ bool FormManager::FillForm(const FormData& form) {
DCHECK(form_element->control_elements.size() == form.fields.size());
- size_t i = 0;
- for (FormControlElementMap::iterator iter =
- form_element->control_elements.begin();
- iter != form_element->control_elements.end(); ++iter, ++i) {
- DCHECK_EQ(form.fields[i].name(), iter->second.nameForAutofill());
+ for (size_t i = 0; i < form.fields.size(); ++i) {
+ WebFormControlElement* element = &form_element->control_elements[i];
+
+ // It's possible that nameForAutofill() is empty if the form control element
+ // has no name or ID. In that case, iter->nameForAutofill() must also be
+ // empty.
+ if (form.fields[i].name().empty())
+ DCHECK(element->nameForAutofill().isEmpty());
+ else
+ DCHECK_EQ(form.fields[i].name(), element->nameForAutofill());
if (!form.fields[i].value().empty() &&
- iter->second.formControlType() != WebString::fromUTF8("submit")) {
- if (iter->second.formControlType() == WebString::fromUTF8("text")) {
- WebInputElement input_element =
- iter->second.toElement<WebInputElement>();
+ element->formControlType() != WebString::fromUTF8("submit")) {
+ if (element->formControlType() == WebString::fromUTF8("text")) {
+ WebInputElement input_element = element->toElement<WebInputElement>();
input_element.setValue(form.fields[i].value());
input_element.setAutofilled(true);
- } else if (iter->second.formControlType() ==
+ } else if (element->formControlType() ==
WebString::fromUTF8("select-one")) {
WebSelectElement select_element =
- iter->second.toElement<WebSelectElement>();
+ element->toElement<WebSelectElement>();
select_element.setValue(form.fields[i].value());
}
}
@@ -346,10 +385,10 @@ bool FormManager::FormElementToFormData(const WebFrame* frame,
form->action = GURL(form_element->form_element.action());
// Form elements loop.
- for (FormControlElementMap::const_iterator element_iter =
+ for (std::vector<WebFormControlElement>::const_iterator element_iter =
form_element->control_elements.begin();
element_iter != form_element->control_elements.end(); ++element_iter) {
- WebFormControlElement control_element = element_iter->second;
+ const WebFormControlElement& control_element = *element_iter;
if (requirements & REQUIRE_AUTOCOMPLETE &&
control_element.formControlType() == WebString::fromUTF8("text")) {
diff --git a/chrome/renderer/form_manager.h b/chrome/renderer/form_manager.h
index a410294..3842450 100644
--- a/chrome/renderer/form_manager.h
+++ b/chrome/renderer/form_manager.h
@@ -85,15 +85,10 @@ class FormManager {
void Reset();
private:
- // A map of WebFormControlElements keyed by each element's name.
- typedef std::map<string16, WebKit::WebFormControlElement>
- FormControlElementMap;
-
- // Stores the WebFormElement and the map of form control elements for each
- // form.
+ // Stores the WebFormElement and the form control elements for a form.
struct FormElement {
WebKit::WebFormElement form_element;
- FormControlElementMap control_elements;
+ std::vector<WebKit::WebFormControlElement> control_elements;
};
// A map of vectors of FormElements keyed by the WebFrame containing each
diff --git a/chrome/renderer/form_manager_unittest.cc b/chrome/renderer/form_manager_unittest.cc
index 4b6b05a..f6fb5a0 100644
--- a/chrome/renderer/form_manager_unittest.cc
+++ b/chrome/renderer/form_manager_unittest.cc
@@ -422,8 +422,7 @@ TEST_F(FormManagerTest, Reset) {
ASSERT_EQ(0U, forms.size());
}
-// http://crbug.com/40306
-TEST_F(FormManagerTest, DISABLED_Labels) {
+TEST_F(FormManagerTest, Labels) {
LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\">"
" <LABEL for=\"firstname\"> First name: </LABEL>"
" <INPUT type=\"text\" id=\"firstname\" value=\"John\"/>"
@@ -466,6 +465,53 @@ TEST_F(FormManagerTest, DISABLED_Labels) {
fields[2]);
}
+// This test is different from FormManagerTest.Labels in that the label elements
+// for= attribute is set to the name of the form control element it is a label
+// for instead of the id of the form control element. This is invalid because
+// the for= attribute must be set to the id of the form control element.
+TEST_F(FormManagerTest, InvalidLabels) {
+ LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\">"
+ " <LABEL for=\"firstname\"> First name: </LABEL>"
+ " <INPUT type=\"text\" name=\"firstname\" value=\"John\"/>"
+ " <LABEL for=\"lastname\"> Last name: </LABEL>"
+ " <INPUT type=\"text\" name=\"lastname\" value=\"Smith\"/>"
+ " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>"
+ "</FORM>");
+
+ WebFrame* web_frame = GetMainFrame();
+ ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame);
+
+ FormManager form_manager;
+ form_manager.ExtractForms(web_frame);
+
+ std::vector<FormData> forms;
+ form_manager.GetForms(FormManager::REQUIRE_NONE, &forms);
+ ASSERT_EQ(1U, forms.size());
+
+ const FormData& form = forms[0];
+ EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
+ EXPECT_EQ(GURL(web_frame->url()), form.origin);
+ EXPECT_EQ(GURL("http://cnn.com"), form.action);
+
+ const std::vector<FormField>& fields = form.fields;
+ ASSERT_EQ(3U, fields.size());
+ EXPECT_EQ(FormField(string16(),
+ ASCIIToUTF16("firstname"),
+ ASCIIToUTF16("John"),
+ ASCIIToUTF16("text")),
+ fields[0]);
+ EXPECT_EQ(FormField(string16(),
+ ASCIIToUTF16("lastname"),
+ ASCIIToUTF16("Smith"),
+ ASCIIToUTF16("text")),
+ fields[1]);
+ EXPECT_EQ(FormField(string16(),
+ ASCIIToUTF16("reply-send"),
+ ASCIIToUTF16("Send"),
+ ASCIIToUTF16("submit")),
+ fields[2]);
+}
+
// http://crbug.com/40306
TEST_F(FormManagerTest, DISABLED_LabelsInferredFromText) {
LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\">"
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 0527889..cd649e7 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -1952,10 +1952,24 @@ void RenderView::queryAutofillSuggestions(const WebNode& node,
static int query_counter = 0;
autofill_query_id_ = query_counter++;
autofill_query_node_ = node;
- const WebKit::WebInputElement input_element =
- node.toConstElement<WebInputElement>();
- Send(new ViewHostMsg_QueryFormFieldAutofill(
- routing_id_, autofill_query_id_, FormField(input_element)));
+
+ const WebFormControlElement& element =
+ node.toConstElement<WebFormControlElement>();
+
+ FormData form;
+ if (!form_manager_.FindFormWithFormControlElement(element,
+ FormManager::REQUIRE_NONE,
+ &form))
+ return;
+
+ // TODO(jhawkins): This is very slow. Add a label cache to FormManager.
+ for (std::vector<FormField>::const_iterator iter = form.fields.begin();
+ iter != form.fields.end(); ++iter) {
+ if (iter->name() == element.nameForAutofill()) {
+ Send(new ViewHostMsg_QueryFormFieldAutofill(
+ routing_id_, autofill_query_id_, *iter));
+ }
+ }
}
void RenderView::removeAutofillSuggestions(const WebString& name,