summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-05 01:30:49 +0000
committerjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-05 01:30:49 +0000
commit3a60d2349854d9594b33aa119a390e39eee96f68 (patch)
tree117e6ae2250a0c222f8067573c418730163b9b97
parent696bdc8641a331f9260aed274387888d512a882e (diff)
downloadchromium_src-3a60d2349854d9594b33aa119a390e39eee96f68.zip
chromium_src-3a60d2349854d9594b33aa119a390e39eee96f68.tar.gz
chromium_src-3a60d2349854d9594b33aa119a390e39eee96f68.tar.bz2
Implement FormManager, a class that manages forms in a RenderView.
BUG=18201 TEST=FormManagerTest Review URL: http://codereview.chromium.org/577009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38157 0039d316-1c4b-4281-b951-d872f2087c98
-rwxr-xr-xchrome/chrome_renderer.gypi2
-rwxr-xr-xchrome/chrome_tests.gypi1
-rw-r--r--chrome/renderer/form_manager.cc184
-rw-r--r--chrome/renderer/form_manager.h84
-rw-r--r--chrome/renderer/form_manager_unittest.cc346
-rw-r--r--webkit/glue/form_data.h11
6 files changed, 628 insertions, 0 deletions
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index 1a41678..77252ba 100755
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -81,6 +81,8 @@
'renderer/external_host_bindings.h',
'renderer/external_extension.cc',
'renderer/external_extension.h',
+ 'renderer/form_manager.cc',
+ 'renderer/form_manager.h',
'renderer/localized_error.cc',
'renderer/localized_error.h',
'renderer/navigation_state.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 10d4e45..246e8f0 100755
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -847,6 +847,7 @@
'common/worker_thread_ticker_unittest.cc',
'common/zip_unittest.cc',
'renderer/audio_message_filter_unittest.cc',
+ 'renderer/form_manager_unittest.cc',
'renderer/media/audio_renderer_impl_unittest.cc',
'renderer/extensions/extension_api_client_unittest.cc',
'renderer/extensions/json_schema_unittest.cc',
diff --git a/chrome/renderer/form_manager.cc b/chrome/renderer/form_manager.cc
new file mode 100644
index 0000000..afea244
--- /dev/null
+++ b/chrome/renderer/form_manager.cc
@@ -0,0 +1,184 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/form_manager.h"
+
+#include "base/logging.h"
+#include "base/stl_util-inl.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebNode.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebVector.h"
+
+using WebKit::WebFormElement;
+using WebKit::WebFrame;
+using WebKit::WebInputElement;
+using WebKit::WebNode;
+using WebKit::WebString;
+using WebKit::WebVector;
+
+FormManager::FormManager() {
+}
+
+FormManager::~FormManager() {
+ Reset();
+}
+
+void FormManager::ExtractForms(WebFrame* frame) {
+ // Reset the vector of FormElements for this frame.
+ ResetFrame(frame);
+
+ WebVector<WebFormElement> web_forms;
+ frame->forms(web_forms);
+
+ // Form loop.
+ for (size_t i = 0; i < web_forms.size(); ++i) {
+ FormElement* form_elements = new FormElement;
+ form_elements->form_element = web_forms[i];
+
+ // Form elements loop.
+ WebVector<WebInputElement> input_elements;
+ form_elements->form_element.getInputElements(input_elements);
+ for (size_t j = 0; j < input_elements.size(); ++j) {
+ WebInputElement element = input_elements[j];
+ form_elements->input_elements[element.nameForAutofill()] = element;
+ }
+
+ form_elements_map_[frame].push_back(form_elements);
+ }
+}
+
+void FormManager::GetForms(std::vector<FormData>* forms,
+ RequirementsMask requirements) {
+ // Frame loop.
+ for (WebFrameFormElementMap::iterator iter = form_elements_map_.begin();
+ iter != form_elements_map_.end(); ++iter) {
+ WebFrame* frame = iter->first;
+
+ // Form loop.
+ 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);
+ }
+ }
+}
+
+bool FormManager::FindForm(const WebInputElement& element, FormData* form) {
+ // Frame loop.
+ for (WebFrameFormElementMap::iterator iter = form_elements_map_.begin();
+ iter != form_elements_map_.end(); ++iter) {
+ WebFrame* frame = iter->first;
+
+ // Form loop.
+ for (std::vector<FormElement*>::iterator form_iter = iter->second.begin();
+ form_iter != iter->second.end(); ++form_iter) {
+ FormElement* form_element = *form_iter;
+
+ if (form_element->input_elements.find(element.nameForAutofill()) !=
+ form_element->input_elements.end()) {
+ FormElementToFormData(frame, form_element, REQUIRE_NONE, form);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+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) {
+ if ((*form_iter)->form_element.name() == form.name) {
+ form_element = *form_iter;
+ break;
+ }
+ }
+ }
+
+ if (!form_element)
+ return false;
+
+ DCHECK(form_element->input_elements.size() == form.elements.size());
+ DCHECK(form.elements.size() == form.values.size());
+
+ size_t i = 0;
+ for (FormInputElementMap::iterator iter =
+ form_element->input_elements.begin();
+ iter != form_element->input_elements.end(); ++iter, ++i) {
+ DCHECK(iter->second.nameForAutofill() == form.elements[i]);
+
+ iter->second.setValue(form.values[i]);
+ iter->second.setAutofilled(true);
+ }
+
+ return true;
+}
+
+void FormManager::Reset() {
+ for (WebFrameFormElementMap::iterator iter = form_elements_map_.begin();
+ iter != form_elements_map_.end(); ++iter) {
+ STLDeleteElements(&iter->second);
+ }
+ form_elements_map_.clear();
+}
+
+void FormManager::ResetFrame(WebFrame* frame) {
+ WebFrameFormElementMap::iterator iter = form_elements_map_.find(frame);
+ if (iter != form_elements_map_.end()) {
+ STLDeleteElements(&iter->second);
+ form_elements_map_.erase(iter);
+ }
+}
+
+void FormManager::FormElementToFormData(WebFrame* frame,
+ const FormElement* form_element,
+ RequirementsMask requirements,
+ FormData* form) {
+ form->name = form_element->form_element.name();
+ form->origin = frame->url();
+ form->action = frame->completeURL(form_element->form_element.action());
+
+ // If the completed ULR is not valid, just use the action we get from
+ // WebKit.
+ if (!form->action.is_valid())
+ form->action = GURL(form_element->form_element.action());
+
+ // Form elements loop.
+ for (FormInputElementMap::const_iterator element_iter =
+ form_element->input_elements.begin();
+ element_iter != form_element->input_elements.end(); ++element_iter) {
+ const WebInputElement& input_element = element_iter->second;
+
+ if (requirements & REQUIRE_AUTOCOMPLETE &&
+ !input_element.autoComplete())
+ continue;
+
+ if (requirements & REQUIRE_ELEMENTS_ENABLED &&
+ !input_element.isEnabledFormControl())
+ continue;
+
+ form->elements.push_back(input_element.nameForAutofill());
+ form->values.push_back(input_element.value());
+
+ // TODO(jhawkins): It's possible for a form to have more than one submit
+ // input element. The FormData structure probably doesn't need to keep
+ // track of the name of any submit button.
+ if (input_element.inputType() == WebInputElement::Submit)
+ form->submit = input_element.nameForAutofill();
+ }
+}
diff --git a/chrome/renderer/form_manager.h b/chrome/renderer/form_manager.h
new file mode 100644
index 0000000..209c93c
--- /dev/null
+++ b/chrome/renderer/form_manager.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_FORM_MANAGER_H_
+#define CHROME_RENDERER_FORM_MANAGER_H_
+
+#include <map>
+#include <vector>
+
+#include "base/string16.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFormElement.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebInputElement.h"
+#include "webkit/glue/form_data.h"
+
+namespace WebKit {
+class WebFrame;
+}
+
+// Manages the forms in a RenderView.
+class FormManager {
+ public:
+ // A bitfield mask for form requirements.
+ typedef enum {
+ REQUIRE_NONE = 0x0, // No requirements.
+ REQUIRE_AUTOCOMPLETE = 0x1, // Require that autocomplete != off.
+ REQUIRE_ELEMENTS_ENABLED = 0x2 // Require that disabled attribute is off.
+ } RequirementsMask;
+
+ FormManager();
+ virtual ~FormManager();
+
+ // Scans the DOM in |frame| extracting and storing forms.
+ void ExtractForms(WebKit::WebFrame* frame);
+
+ // Returns a vector of forms that match |requirements|.
+ void GetForms(std::vector<FormData>* forms, RequirementsMask requirements);
+
+ // Finds the form that contains |input_element| and returns it in |form|.
+ // Returns false if the form is not found.
+ bool FindForm(const WebKit::WebInputElement& input_element, FormData* form);
+
+ // Fills the form represented by |form|. |form| should have the name set to
+ // the name of the form to fill out, and the number of elements and values
+ // must match the number of stored elements in the form.
+ // TODO(jhawkins): Is matching on name alone good enough? It's possible to
+ // store multiple forms with the same names from different frames.
+ bool FillForm(const FormData& form);
+
+ // Resets the stored set of forms.
+ void Reset();
+
+ private:
+ // A map of WebInputElements keyed by each element's name.
+ typedef std::map<string16, WebKit::WebInputElement> FormInputElementMap;
+
+ // Stores the WebFormElement and the map of input elements for each form.
+ struct FormElement {
+ WebKit::WebFormElement form_element;
+ FormInputElementMap input_elements;
+ };
+
+ // A map of vectors of FormElements keyed by the WebFrame containing each
+ // form.
+ typedef std::map<WebKit::WebFrame*, std::vector<FormElement*> >
+ WebFrameFormElementMap;
+
+ // Resets the forms for the specified |frame|.
+ void ResetFrame(WebKit::WebFrame* frame);
+
+ // Converts a FormElement to FormData storage.
+ // TODO(jhawkins): Modify FormElement so we don't need |frame|.
+ void FormElementToFormData(WebKit::WebFrame* frame,
+ const FormElement* form_element,
+ RequirementsMask requirements,
+ FormData* form);
+
+ // The map of form elements.
+ WebFrameFormElementMap form_elements_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(FormManager);
+};
+
+#endif // CHROME_RENDERER_FORM_MANAGER_H_
diff --git a/chrome/renderer/form_manager_unittest.cc b/chrome/renderer/form_manager_unittest.cc
new file mode 100644
index 0000000..4a5e52a
--- /dev/null
+++ b/chrome/renderer/form_manager_unittest.cc
@@ -0,0 +1,346 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/form_manager.h"
+#include "chrome/test/render_view_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebElement.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebInputElement.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
+
+using WebKit::WebElement;
+using WebKit::WebFrame;
+using WebKit::WebInputElement;
+using WebKit::WebString;
+
+class FormManagerTest : public RenderViewTest {
+ public:
+ FormManagerTest() {}
+};
+
+TEST_F(FormManagerTest, ExtractForms) {
+ LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\">"
+ " <INPUT type=\"text\" id=\"firstname\" value=\"John\">"
+ " <INPUT type=\"text\" id=\"lastname\" value=\"Smith\">"
+ " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\">"
+ "</FORM>");
+
+ WebFrame* web_frame = GetMainFrame();
+ ASSERT_TRUE(web_frame);
+
+ FormManager form_manager;
+ form_manager.ExtractForms(web_frame);
+
+ std::vector<FormData> forms;
+ form_manager.GetForms(&forms, FormManager::REQUIRE_NONE);
+ 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);
+ EXPECT_EQ(ASCIIToUTF16("reply-send"), form.submit);
+
+ const std::vector<string16>& elements = form.elements;
+ ASSERT_EQ(3U, elements.size());
+ EXPECT_EQ(ASCIIToUTF16("firstname"), elements[0]);
+ EXPECT_EQ(ASCIIToUTF16("lastname"), elements[1]);
+ EXPECT_EQ(ASCIIToUTF16("reply-send"), elements[2]);
+
+ const std::vector<string16>& values = form.values;
+ ASSERT_EQ(3U, values.size());
+ EXPECT_EQ(ASCIIToUTF16("John"), values[0]);
+ EXPECT_EQ(ASCIIToUTF16("Smith"), values[1]);
+ EXPECT_EQ(ASCIIToUTF16("Send"), values[2]);
+}
+
+TEST_F(FormManagerTest, ExtractMultipleForms) {
+ LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\">"
+ " <INPUT type=\"text\" id=\"firstname\" value=\"John\">"
+ " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\">"
+ "</FORM>"
+ "<FORM name=\"TestForm2\" action=\"http://zoo.com\" method=\"post\">"
+ " <INPUT type=\"text\" id=\"lastname\" value=\"Smith\">"
+ " <INPUT type=\"submit\" name=\"second\" value=\"Submit\">"
+ "</FORM>");
+
+ WebFrame* web_frame = GetMainFrame();
+ ASSERT_TRUE(web_frame);
+
+ FormManager form_manager;
+ form_manager.ExtractForms(web_frame);
+
+ std::vector<FormData> forms;
+ form_manager.GetForms(&forms, FormManager::REQUIRE_NONE);
+ ASSERT_EQ(2U, forms.size());
+
+ // First form.
+ 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);
+ EXPECT_EQ(ASCIIToUTF16("reply-send"), form.submit);
+
+ const std::vector<string16>& elements = form.elements;
+ ASSERT_EQ(2U, elements.size());
+ EXPECT_EQ(ASCIIToUTF16("firstname"), elements[0]);
+ EXPECT_EQ(ASCIIToUTF16("reply-send"), elements[1]);
+
+ const std::vector<string16>& values = form.values;
+ ASSERT_EQ(2U, values.size());
+ EXPECT_EQ(ASCIIToUTF16("John"), values[0]);
+ EXPECT_EQ(ASCIIToUTF16("Send"), values[1]);
+
+ // Second form.
+ const FormData& form2 = forms[1];
+ EXPECT_EQ(ASCIIToUTF16("TestForm2"), form2.name);
+ EXPECT_EQ(GURL(web_frame->url()), form2.origin);
+ EXPECT_EQ(GURL("http://zoo.com"), form2.action);
+ EXPECT_EQ(ASCIIToUTF16("second"), form2.submit);
+
+ const std::vector<string16>& elements2 = form2.elements;
+ ASSERT_EQ(2U, elements2.size());
+ EXPECT_EQ(ASCIIToUTF16("lastname"), elements2[0]);
+ EXPECT_EQ(ASCIIToUTF16("second"), elements2[1]);
+
+ const std::vector<string16>& values2 = form2.values;
+ ASSERT_EQ(2U, values2.size());
+ EXPECT_EQ(ASCIIToUTF16("Smith"), values2[0]);
+ EXPECT_EQ(ASCIIToUTF16("Submit"), values2[1]);
+}
+
+TEST_F(FormManagerTest, GetFormsAutocomplete) {
+ // Form is not auto-completable due to autocomplete=off.
+ LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\""
+ " autocomplete=off>"
+ " <INPUT type=\"text\" id=\"firstname\" value=\"John\">"
+ " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\">"
+ "</FORM>");
+
+ WebFrame* web_frame = GetMainFrame();
+ ASSERT_TRUE(web_frame);
+
+ FormManager form_manager;
+ form_manager.ExtractForms(web_frame);
+
+ // Verify that we did load the forms.
+ std::vector<FormData> forms;
+ form_manager.GetForms(&forms, FormManager::REQUIRE_NONE);
+ ASSERT_EQ(1U, forms.size());
+
+ // autocomplete=off and we're requiring autocomplete, so no forms returned.
+ forms.clear();
+ form_manager.GetForms(&forms, FormManager::REQUIRE_AUTOCOMPLETE);
+ ASSERT_EQ(0U, forms.size());
+
+ // The firstname element is not auto-completable due to autocomplete=off.
+ LoadHTML("<FORM name=\"TestForm\" action=\"http://abc.com\" method=\"post\">"
+ " <INPUT type=\"text\" id=\"firstname\" value=\"John\""
+ " autocomplete=off>"
+ " <INPUT type=\"text\" id=\"lastname\" value=\"Smith\">"
+ " <INPUT type=\"submit\" name=\"reply\" value=\"Send\">"
+ "</FORM>");
+
+ web_frame = GetMainFrame();
+ ASSERT_TRUE(web_frame);
+
+ form_manager.Reset();
+ form_manager.ExtractForms(web_frame);
+
+ forms.clear();
+ form_manager.GetForms(&forms, FormManager::REQUIRE_AUTOCOMPLETE);
+ 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://abc.com"), form.action);
+ EXPECT_EQ(ASCIIToUTF16("reply"), form.submit);
+
+ const std::vector<string16>& elements = form.elements;
+ ASSERT_EQ(2U, elements.size());
+ EXPECT_EQ(ASCIIToUTF16("lastname"), elements[0]);
+ EXPECT_EQ(ASCIIToUTF16("reply"), elements[1]);
+
+ const std::vector<string16>& values = form.values;
+ ASSERT_EQ(2U, values.size());
+ EXPECT_EQ(ASCIIToUTF16("Smith"), values[0]);
+ EXPECT_EQ(ASCIIToUTF16("Send"), values[1]);
+}
+
+TEST_F(FormManagerTest, GetFormsElementsEnabled) {
+ // The firstname element is not enabled due to disabled being set.
+ LoadHTML("<FORM name=\"TestForm\" action=\"http://xyz.com\" method=\"post\">"
+ " <INPUT disabled type=\"text\" id=\"firstname\" value=\"John\">"
+ " <INPUT type=\"text\" id=\"lastname\" value=\"Smith\">"
+ " <INPUT type=\"submit\" name=\"submit\" value=\"Send\">"
+ "</FORM>");
+
+ WebFrame* web_frame = GetMainFrame();
+ ASSERT_TRUE(web_frame);
+
+ FormManager form_manager;
+ form_manager.ExtractForms(web_frame);
+
+ std::vector<FormData> forms;
+ form_manager.GetForms(&forms, FormManager::REQUIRE_ELEMENTS_ENABLED);
+ 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://xyz.com"), form.action);
+ EXPECT_EQ(ASCIIToUTF16("submit"), form.submit);
+
+ const std::vector<string16>& elements = form.elements;
+ ASSERT_EQ(2U, elements.size());
+ EXPECT_EQ(ASCIIToUTF16("lastname"), elements[0]);
+ EXPECT_EQ(ASCIIToUTF16("submit"), elements[1]);
+
+ const std::vector<string16>& values = form.values;
+ ASSERT_EQ(2U, values.size());
+ EXPECT_EQ(ASCIIToUTF16("Smith"), values[0]);
+ EXPECT_EQ(ASCIIToUTF16("Send"), values[1]);
+}
+
+TEST_F(FormManagerTest, FindForm) {
+ LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">"
+ " <INPUT type=\"text\" id=\"firstname\" value=\"John\">"
+ " <INPUT type=\"text\" id=\"lastname\" value=\"Smith\">"
+ " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\">"
+ "</FORM>");
+
+ WebFrame* web_frame = GetMainFrame();
+ ASSERT_TRUE(web_frame);
+
+ FormManager form_manager;
+ form_manager.ExtractForms(web_frame);
+
+ // Verify that we have the form.
+ std::vector<FormData> forms;
+ form_manager.GetForms(&forms, FormManager::REQUIRE_NONE);
+ ASSERT_EQ(1U, forms.size());
+
+ // Get the input element we want to find.
+ WebElement element =
+ web_frame->document().getElementById(WebString::fromUTF8("firstname"));
+ WebInputElement input_element = element.toElement<WebInputElement>();
+
+ // Find the form and verify it's the correct form.
+ FormData form;
+ EXPECT_TRUE(form_manager.FindForm(input_element, &form));
+ EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
+ EXPECT_EQ(GURL(web_frame->url()), form.origin);
+ EXPECT_EQ(GURL("http://buh.com"), form.action);
+ EXPECT_EQ(ASCIIToUTF16("reply-send"), form.submit);
+
+ const std::vector<string16>& elements = form.elements;
+ ASSERT_EQ(3U, elements.size());
+ EXPECT_EQ(ASCIIToUTF16("firstname"), elements[0]);
+ EXPECT_EQ(ASCIIToUTF16("lastname"), elements[1]);
+ EXPECT_EQ(ASCIIToUTF16("reply-send"), elements[2]);
+
+ const std::vector<string16>& values = form.values;
+ ASSERT_EQ(3U, values.size());
+ EXPECT_EQ(ASCIIToUTF16("John"), values[0]);
+ EXPECT_EQ(ASCIIToUTF16("Smith"), values[1]);
+ EXPECT_EQ(ASCIIToUTF16("Send"), values[2]);
+}
+
+TEST_F(FormManagerTest, FillForm) {
+ LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">"
+ " <INPUT type=\"text\" id=\"firstname\">"
+ " <INPUT type=\"text\" id=\"lastname\">"
+ " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\">"
+ "</FORM>");
+
+ WebFrame* web_frame = GetMainFrame();
+ ASSERT_TRUE(web_frame);
+
+ FormManager form_manager;
+ form_manager.ExtractForms(web_frame);
+
+ // Verify that we have the form.
+ std::vector<FormData> forms;
+ form_manager.GetForms(&forms, FormManager::REQUIRE_NONE);
+ ASSERT_EQ(1U, forms.size());
+
+ // Get the input element we want to find.
+ WebElement element =
+ web_frame->document().getElementById(WebString::fromUTF8("firstname"));
+ WebInputElement input_element = element.toElement<WebInputElement>();
+
+ // Find the form that contains the input element.
+ FormData form;
+ EXPECT_TRUE(form_manager.FindForm(input_element, &form));
+ EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
+ EXPECT_EQ(GURL(web_frame->url()), form.origin);
+ EXPECT_EQ(GURL("http://buh.com"), form.action);
+ EXPECT_EQ(ASCIIToUTF16("reply-send"), form.submit);
+
+ const std::vector<string16>& elements = form.elements;
+ ASSERT_EQ(3U, elements.size());
+ EXPECT_EQ(ASCIIToUTF16("firstname"), elements[0]);
+ EXPECT_EQ(ASCIIToUTF16("lastname"), elements[1]);
+ EXPECT_EQ(ASCIIToUTF16("reply-send"), elements[2]);
+
+ // Verify that the text fields have no values.
+ const std::vector<string16>& values = form.values;
+ ASSERT_EQ(3U, values.size());
+ EXPECT_EQ(string16(), values[0]);
+ EXPECT_EQ(string16(), values[1]);
+ EXPECT_EQ(ASCIIToUTF16("Send"), values[2]);
+
+ // Fill the form.
+ form.values[0] = ASCIIToUTF16("Wyatt");
+ form.values[1] = ASCIIToUTF16("Earp");
+ EXPECT_TRUE(form_manager.FillForm(form));
+
+ // Find the newly-filled form that contains the input element.
+ FormData form2;
+ EXPECT_TRUE(form_manager.FindForm(input_element, &form2));
+ EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
+ EXPECT_EQ(GURL(web_frame->url()), form2.origin);
+ EXPECT_EQ(GURL("http://buh.com"), form2.action);
+ EXPECT_EQ(ASCIIToUTF16("reply-send"), form2.submit);
+
+ const std::vector<string16>& elements2 = form2.elements;
+ ASSERT_EQ(3U, elements2.size());
+ EXPECT_EQ(ASCIIToUTF16("firstname"), elements2[0]);
+ EXPECT_EQ(ASCIIToUTF16("lastname"), elements2[1]);
+ EXPECT_EQ(ASCIIToUTF16("reply-send"), elements2[2]);
+
+ // Verify that the text fields have no values.
+ const std::vector<string16>& values2 = form2.values;
+ ASSERT_EQ(3U, values2.size());
+ EXPECT_EQ(ASCIIToUTF16("Wyatt"), values2[0]);
+ EXPECT_EQ(ASCIIToUTF16("Earp"), values2[1]);
+ EXPECT_EQ(ASCIIToUTF16("Send"), values2[2]);
+}
+
+TEST_F(FormManagerTest, Reset) {
+ LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\">"
+ " <INPUT type=\"text\" id=\"firstname\" value=\"John\">"
+ " <INPUT type=\"text\" id=\"lastname\" value=\"Smith\">"
+ " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\">"
+ "</FORM>");
+
+ WebFrame* web_frame = GetMainFrame();
+ ASSERT_TRUE(web_frame);
+
+ FormManager form_manager;
+ form_manager.ExtractForms(web_frame);
+
+ std::vector<FormData> forms;
+ form_manager.GetForms(&forms, FormManager::REQUIRE_NONE);
+ ASSERT_EQ(1U, forms.size());
+
+ // There should be no forms after the call to Reset.
+ form_manager.Reset();
+
+ forms.clear();
+ form_manager.GetForms(&forms, FormManager::REQUIRE_NONE);
+ ASSERT_EQ(0U, forms.size());
+}
diff --git a/webkit/glue/form_data.h b/webkit/glue/form_data.h
index 8c5876c..02e0096 100644
--- a/webkit/glue/form_data.h
+++ b/webkit/glue/form_data.h
@@ -11,6 +11,17 @@
// Holds information about a form to be filled and/or submitted.
struct FormData {
+ FormData() {}
+ FormData(const FormData& data)
+ : name(data.name),
+ origin(data.origin),
+ action(data.action),
+ elements(data.elements),
+ values(data.values),
+ submit(data.submit) {}
+
+ // The name of the form.
+ string16 name;
// The URL (minus query parameters) containing the form
GURL origin;
// The action target of the form