summaryrefslogtreecommitdiffstats
path: root/WebKit/android/WebCoreSupport/autofill
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2010-11-16 15:33:28 +0000
committerBen Murdoch <benm@google.com>2010-11-16 19:28:40 +0000
commit915ace8187ca47eaaf936d7891ab71cfc69e50f0 (patch)
tree7086cbdcdf18c0681ec078dd4ba3809971edf8a2 /WebKit/android/WebCoreSupport/autofill
parentc171aa015a0cbeab69fa359835f7c82f269d6111 (diff)
downloadexternal_webkit-915ace8187ca47eaaf936d7891ab71cfc69e50f0.zip
external_webkit-915ace8187ca47eaaf936d7891ab71cfc69e50f0.tar.gz
external_webkit-915ace8187ca47eaaf936d7891ab71cfc69e50f0.tar.bz2
Merge autofill files after last Chromium merge
Merge by hand the files that have been gotked implementing AutoFill on Android. This classes use WebCore types rather than the Chrome WebKit API types that the code would normally use. This brings the files up to date with the last external/chromium merge to r63472 and updates their usages in line with that so that the feature continues to work as intended. Change-Id: Ic110873dc48c59555f0db76e7ad0c138c2fe96f2
Diffstat (limited to 'WebKit/android/WebCoreSupport/autofill')
-rw-r--r--WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp87
-rw-r--r--WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h42
-rw-r--r--WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp830
-rw-r--r--WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h237
-rw-r--r--WebKit/android/WebCoreSupport/autofill/StringUtils.h73
-rw-r--r--WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp18
-rw-r--r--WebKit/android/WebCoreSupport/autofill/WebAutoFill.h4
7 files changed, 786 insertions, 505 deletions
diff --git a/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp b/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp
index 00213a1..07f8338 100644
--- a/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp
@@ -28,45 +28,66 @@
#include "FormFieldAndroid.h"
#include "ChromiumIncludes.h"
+#include "Element.h"
#include "HTMLFormControlElement.h"
#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HTMLOptionElement.h"
#include "HTMLSelectElement.h"
+#include "StringUtils.h"
+#include <wtf/Vector.h>
-// TODO: This file is taken from chromium/webkit/glue/form_field.h and
+using WebCore::Element;
+using WebCore::HTMLFormControlElement;
+using WebCore::HTMLInputElement;
+using WebCore::HTMLOptionElement;
+using WebCore::HTMLSelectElement;
+
+using namespace WebCore::HTMLNames;
+
+// TODO: This file is taken from chromium/webkit/glue/form_field.cc and
// customised to use WebCore types rather than WebKit API types. It would
// be nice and would ease future merge pain if the two could be combined.
namespace webkit_glue {
+
FormField::FormField()
: size_(0) {
}
-FormField::FormField(WebCore::HTMLFormControlElement& element)
+// TODO: This constructor should probably be deprecated and the
+// functionality moved to FormManager.
+FormField::FormField(const HTMLFormControlElement& element)
: size_(0) {
- name_ = string16(element.name().characters());
+ name_ = nameForAutoFill(element);
// TODO: Extract the field label. For now we just use the field
// name.
label_ = name_;
- form_control_type_ = string16(element.type().characters());
- if (form_control_type_ == ASCIIToUTF16("text")) {
- WebCore::HTMLInputElement* input_element = static_cast<WebCore::HTMLInputElement*>(&element);
- value_ = string16(input_element->value().characters());
- size_ = input_element->size();
- } else if (form_control_type_ == ASCIIToUTF16("select-one")) {
- WebCore::HTMLSelectElement* select_element = static_cast<WebCore::HTMLSelectElement*>(&element);
- value_ = string16(select_element->value().characters());
+ form_control_type_ = formControlType(element);
+ if (form_control_type_ == kText) {
+ const HTMLInputElement& input_element = static_cast<const HTMLInputElement&>(element);
+ value_ = WTFStringToString16(input_element.value());
+ size_ = input_element.size();
+ } else if (form_control_type_ == kSelectOne) {
+ const HTMLSelectElement& const_select_element = static_cast<const HTMLSelectElement&>(element);
+ HTMLSelectElement& select_element = const_cast<HTMLSelectElement&>(const_select_element);
+ value_ = WTFStringToString16(select_element.value());
+
+ // For select-one elements copy option strings.
+ WTF::Vector<Element*> list_items = select_element.listItems();
+ option_strings_.reserve(list_items.size());
+ for (size_t i = 0; i < list_items.size(); ++i) {
+ if (list_items[i]->hasTagName(optionTag))
+ option_strings_.push_back(WTFStringToString16(static_cast<HTMLOptionElement*>(list_items[i])->value()));
+ }
}
TrimWhitespace(value_, TRIM_LEADING, &value_);
}
-FormField::FormField(const string16& label,
- const string16& name,
- const string16& value,
- const string16& form_control_type,
- int size)
+FormField::FormField(const string16& label, const string16& name, const string16& value, const string16& form_control_type, int size)
: label_(label),
name_(name),
value_(value),
@@ -74,7 +95,41 @@ FormField::FormField(const string16& label,
size_(size) {
}
+FormField::~FormField() {
+}
+
+bool FormField::operator==(const FormField& field) const {
+ // A FormField stores a value, but the value is not part of the identity of
+ // the field, so we don't want to compare the values.
+ return (label_ == field.label_ &&
+ name_ == field.name_ &&
+ form_control_type_ == field.form_control_type_ &&
+ size_ == field.size_);
+}
+
bool FormField::operator!=(const FormField& field) const {
return !operator==(field);
}
+
+bool FormField::StrictlyEqualsHack(const FormField& field) const {
+ return (label_ == field.label_ &&
+ name_ == field.name_ &&
+ value_ == field.value_ &&
+ form_control_type_ == field.form_control_type_ &&
+ size_ == field.size_);
+}
+
+std::ostream& operator<<(std::ostream& os, const FormField& field) {
+ return os
+ << UTF16ToUTF8(field.label())
+ << " "
+ << UTF16ToUTF8(field.name())
+ << " "
+ << UTF16ToUTF8(field.value())
+ << " "
+ << UTF16ToUTF8(field.form_control_type())
+ << " "
+ << field.size();
+}
+
} // namespace webkit_glue
diff --git a/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h b/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h
index 51bb24b..8fb13a1 100644
--- a/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h
+++ b/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h
@@ -30,7 +30,7 @@
#include <base/string16.h>
#include <vector>
-// TODO: This file is taken from chromium/webkit/glue/form_field.cc and
+// TODO: This file is taken from chromium/webkit/glue/form_field.h and
// customised to use WebCore types rather than WebKit API types. It would
// be nice and would ease future merge pain if the two could be combined.
@@ -44,12 +44,9 @@ namespace webkit_glue {
class FormField {
public:
FormField();
- explicit FormField(WebCore::HTMLFormControlElement& element);
- FormField(const string16& label,
- const string16& name,
- const string16& value,
- const string16& form_control_type,
- int size);
+ explicit FormField(const WebCore::HTMLFormControlElement& element);
+ FormField(const string16& label, const string16& name, const string16& value, const string16& form_control_type, int size);
+ virtual ~FormField();
const string16& label() const { return label_; }
const string16& name() const { return name_; }
@@ -58,25 +55,26 @@ public:
int size() const { return size_; }
// Returns option string for elements for which they make sense (select-one,
// for example) for the rest of elements return an empty array.
- const std::vector<string16>& option_strings() const {
- return option_strings_;
- }
-
+ const std::vector<string16>& option_strings() const { return option_strings_; }
void set_label(const string16& label) { label_ = label; }
void set_name(const string16& name) { name_ = name; }
void set_value(const string16& value) { value_ = value; }
- void set_form_control_type(const string16& form_control_type) {
- form_control_type_ = form_control_type;
- }
+ void set_form_control_type(const string16& form_control_type) { form_control_type_ = form_control_type; }
void set_size(int size) { size_ = size; }
- void set_option_strings(const std::vector<string16>& strings) {
- option_strings_ = strings;
- }
+ void set_option_strings(const std::vector<string16>& strings) { option_strings_ = strings; }
+ // Equality tests for identity which does not include |value_| or |size_|.
+ // Use |StrictlyEqualsHack| method to test all members.
+ // TODO: These operators need to be revised when we implement field
+ // ids.
bool operator==(const FormField& field) const;
bool operator!=(const FormField& field) const;
+ // Test equality of all data members.
+ // TODO: This will be removed when we implement field ids.
+ bool StrictlyEqualsHack(const FormField& field) const;
+
private:
string16 label_;
string16 name_;
@@ -86,14 +84,8 @@ private:
std::vector<string16> option_strings_;
};
-inline bool FormField::operator==(const FormField& field) const {
- // A FormField stores a value, but the value is not part of the identity of
- // the field, so we don't want to compare the values.
- return (label_ == field.label_ &&
- name_ == field.name_ &&
- form_control_type_ == field.form_control_type_);
-
-}
+// So we can compare FormFields with EXPECT_EQ().
+std::ostream& operator<<(std::ostream& os, const FormField& field);
} // namespace webkit_glue
diff --git a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
index 8f0467b..bec6042 100644
--- a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
@@ -27,18 +27,24 @@
#include "config.h"
#include "FormManagerAndroid.h"
+#include "DocumentLoader.h"
+#include "Element.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "HTMLCollection.h"
#include "HTMLFormControlElement.h"
#include "HTMLFormElement.h"
-#include "HTMLTextAreaElement.h"
#include "HTMLInputElement.h"
#include "HTMLLabelElement.h"
#include "HTMLNames.h"
+#include "HTMLOptionElement.h"
#include "HTMLSelectElement.h"
+#include "Node.h"
#include "NodeList.h"
#include "HTMLCollection.h"
#include "FormFieldAndroid.h"
#include "QualifiedName.h"
-
+#include "StringUtils.h"
// TODO: This file is taken from chromium/chrome/renderer/form_manager.cc and
// customised to use WebCore types rather than WebKit API types. It would be
@@ -46,10 +52,13 @@
using webkit_glue::FormData;
using webkit_glue::FormField;
-using WebCore::HTMLElement;
+using WebCore::Element;
+using WebCore::HTMLCollection;
using WebCore::HTMLFormControlElement;
using WebCore::HTMLFormElement;
+using WebCore::HTMLInputElement;
using WebCore::HTMLLabelElement;
+using WebCore::HTMLOptionElement;
using WebCore::HTMLSelectElement;
using WebCore::Node;
using WebCore::NodeList;
@@ -67,61 +76,174 @@ namespace {
// device experience where form filling can be time consuming and frustrating.
const size_t kRequiredAutoFillFields = 2;
-string16 WTFStringToString16(const WTF::String& wtfString)
-{
- WTF::String str = wtfString;
-
- if (str.charactersWithNullTermination())
- return string16(str.charactersWithNullTermination());
- else
- return string16();
-}
-
-string16 S(const WTF::AtomicString& str)
-{
- return WTFStringToString16(str.string());
-}
-
-string16 S(const WTF::String& string)
-{
- return WTFStringToString16(string);
-}
+// The maximum length allowed for form data.
+const size_t kMaxDataLength = 1024;
// This is a helper function for the FindChildText() function.
-// Returns the node value of the descendant or sibling of |node| that is a
-// non-empty text node. This is a faster alternative to |innerText()| for
+// Returns the aggregated values of the descendants or siblings of |node| that
+// are non-empty text nodes. This is a faster alternative to |innerText()| for
// performance critical operations. It does a full depth-first search so
-// can be used when the structure is not directly known. It does not aggregate
-// the text of multiple nodes, it just returns the value of the first found.
-// "Non-empty" in this case means non-empty after the whitespace has been
-// stripped.
-string16 FindChildTextInner(const Node* node) {
+// can be used when the structure is not directly known. The text is
+// accumulated after the whitespace has been stropped. Search depth is limited
+// with the |depth| parameter.
+string16 FindChildTextInner(Node* node, int depth) {
string16 element_text;
- if (!node)
+ if (!node || depth <= 0)
return element_text;
- element_text = S(node->nodeValue());
- TrimWhitespace(element_text, TRIM_ALL, &element_text);
- if (!element_text.empty())
- return element_text;
+ string16 node_text = WTFStringToString16(node->nodeValue());
+ TrimWhitespace(node_text, TRIM_ALL, &node_text);
+ if (!node_text.empty())
+ element_text = node_text;
- element_text = FindChildTextInner(node->firstChild());
- if (!element_text.empty())
- return element_text;
+ string16 child_text = FindChildTextInner(node->firstChild(), depth-1);
+ if (!child_text.empty())
+ element_text = element_text + child_text;
- element_text = FindChildTextInner(node->nextSibling());
- if (!element_text.empty())
- return element_text;
+ string16 sibling_text = FindChildTextInner(node->nextSibling(), depth-1);
+ if (!sibling_text.empty())
+ element_text = element_text + sibling_text;
return element_text;
}
// Returns the node value of the first decendant of |element| that is a
// non-empty text node. "Non-empty" in this case means non-empty after the
-// whitespace has been stripped.
-string16 FindChildText(const HTMLElement* element) {
+// whitespace has been stripped. Search is limited to withing 10 siblings and/or
+// descendants.
+string16 FindChildText(Element* element) {
Node* child = element->firstChild();
- return FindChildTextInner(child);
+
+ const int kChildSearchDepth = 10;
+ return FindChildTextInner(child, kChildSearchDepth);
+}
+
+string16 InferLabelFromPrevious(const HTMLFormControlElement& element) {
+ string16 inferred_label;
+ Node* previous = element.previousSibling();
+ if (previous) {
+ // Eg. Some Text<input ...>
+ if (previous->isTextNode()) {
+ inferred_label = WTFStringToString16(previous->nodeValue());
+ TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label);
+ }
+
+ // If we didn't find text, check for previous paragraph.
+ // Eg. <p>Some Text</p><input ...>
+ // Note the lack of whitespace between <p> and <input> elements.
+ if (inferred_label.empty()) {
+ if (previous->isElementNode()) {
+ Element* element = static_cast<Element*>(previous);
+ if (element->hasTagName(pTag))
+ inferred_label = FindChildText(element);
+ }
+ }
+
+ // If we didn't find paragraph, check for previous paragraph to this.
+ // Eg. <p>Some Text</p> <input ...>
+ // Note the whitespace between <p> and <input> elements.
+ if (inferred_label.empty()) {
+ previous = previous->previousSibling();
+ if (previous && previous->isElementNode()) {
+ Element* element = static_cast<Element*>(previous);
+ if (element->hasTagName(pTag))
+ inferred_label = FindChildText(element);
+ }
+ }
+
+ // Look for text node prior to <img> tag.
+ // Eg. Some Text<img/><input ...>
+ if (inferred_label.empty()) {
+ while (inferred_label.empty() && previous) {
+ if (previous->isTextNode()) {
+ inferred_label = WTFStringToString16(previous->nodeValue());
+ TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label);
+ } else if (previous->isElementNode()) {
+ Element* element = static_cast<Element*>(previous);
+ if (!element->hasTagName(imgTag))
+ break;
+ } else
+ break;
+ previous = previous->previousSibling();
+ }
+ }
+ }
+ return inferred_label;
+}
+
+// Helper for |InferLabelForElement()| that infers a label, if possible, from
+// surrounding table structure.
+// Eg. <tr><td>Some Text</td><td><input ...></td></tr>
+// Eg. <tr><td><b>Some Text</b></td><td><b><input ...></b></td></tr>
+string16 InferLabelFromTable(const HTMLFormControlElement& element) {
+ string16 inferred_label;
+ Node* parent = element.parentNode();
+ while (parent && parent->isElementNode() && !static_cast<Element*>(parent)->hasTagName(tdTag))
+ parent = parent->parentNode();
+
+ if (parent && parent->isElementNode()) {
+ Element* element = static_cast<Element*>(parent);
+ if (element->hasTagName(tdTag)) {
+ Node* previous = parent->previousSibling();
+
+ // Skip by any intervening text nodes.
+ while (previous && previous->isTextNode())
+ previous = previous->previousSibling();
+
+ if (previous && previous->isElementNode()) {
+ element = static_cast<Element*>(previous);
+ if (element->hasTagName(tdTag))
+ inferred_label = FindChildText(element);
+ }
+ }
+ }
+ return inferred_label;
+}
+
+// Helper for |InferLabelForElement()| that infers a label, if possible, from
+// a surrounding definition list.
+// Eg. <dl><dt>Some Text</dt><dd><input ...></dd></dl>
+// Eg. <dl><dt><b>Some Text</b></dt><dd><b><input ...></b></dd></dl>
+string16 InferLabelFromDefinitionList(const HTMLFormControlElement& element) {
+ string16 inferred_label;
+ Node* parent = element.parentNode();
+ while (parent && parent->isElementNode() && !static_cast<Element*>(parent)->hasTagName(ddTag))
+ parent = parent->parentNode();
+
+ if (parent && parent->isElementNode()) {
+ Element* element = static_cast<Element*>(parent);
+ if (element->hasTagName(ddTag)) {
+ Node* previous = parent->previousSibling();
+
+ // Skip by any intervening text nodes.
+ while (previous && previous->isTextNode())
+ previous = previous->previousSibling();
+
+ if (previous && previous->isElementNode()) {
+ element = static_cast<Element*>(previous);
+ if (element->hasTagName(dtTag))
+ inferred_label = FindChildText(element);
+ }
+ }
+ }
+ return inferred_label;
+}
+
+void GetOptionStringsFromElement(HTMLFormControlElement* element, std::vector<string16>* option_strings) {
+ DCHECK(element);
+ DCHECK(option_strings);
+ option_strings->clear();
+ if (formControlType(*element) == kSelectOne) {
+ HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
+
+ // For select-one elements copy option strings.
+ WTF::Vector<Element*> list_items = select_element->listItems();
+ option_strings->reserve(list_items.size());
+ for (size_t i = 0; i < list_items.size(); ++i) {
+ if (list_items[i]->hasTagName(optionTag))
+ option_strings->push_back(WTFStringToString16(static_cast<HTMLOptionElement*>(list_items[i])->value()));
+ }
+ }
}
} // namespace
@@ -136,36 +258,57 @@ FormManager::~FormManager() {
}
// static
-void FormManager::HTMLFormControlElementToFormField(
- const HTMLFormControlElement& element, bool get_value, FormField* field) {
- ASSERT(field);
+void FormManager::HTMLFormControlElementToFormField(HTMLFormControlElement* element, bool get_value, bool get_options, FormField* field) {
+ DCHECK(field);
// The label is not officially part of a HTMLFormControlElement; however, the
// labels for all form control elements are scraped from the DOM and set in
// WebFormElementToFormData.
- field->set_name(S(element.name()));
- field->set_form_control_type(S(element.type()));
+ field->set_name(nameForAutoFill(*element));
+ field->set_form_control_type(formControlType(*element));
+
+ if (get_options) {
+ std::vector<string16> option_strings;
+ GetOptionStringsFromElement(element, &option_strings);
+ field->set_option_strings(option_strings);
+ }
+
+ if (formControlType(*element) == kText) {
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+ field->set_size(input_element->size());
+ }
if (!get_value)
return;
+ // TODO: In WebKit, move value() and setValue() to
+ // WebFormControlElement.
string16 value;
- if (element.type() == WTF::AtomicString("text")) {
- const WebCore::HTMLTextAreaElement* input_element = static_cast<const WebCore::HTMLTextAreaElement*>(&element);
- if (input_element->renderer())
- value = S(input_element->value());
- } else if (element.type() == WTF::AtomicString("select-one")) {
- // TODO: This is ugly. SelectElement::value() is a non-const
- // method. Look into fixing this on the WebKit side.
- HTMLFormControlElement& e = const_cast<HTMLFormControlElement&>(element);
- HTMLSelectElement& select_element = static_cast<HTMLSelectElement&>(e);
- value = S(select_element.value());
+ if (formControlType(*element) == kText ||
+ formControlType(*element) == kHidden) {
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+ value = WTFStringToString16(input_element->value());
+ } else if (formControlType(*element) == kSelectOne) {
+ HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
+ value = WTFStringToString16(select_element->value());
}
+
+ // TODO: This is a temporary stop-gap measure designed to prevent
+ // a malicious site from DOS'ing the browser with extremely large profile
+ // data. The correct solution is to parse this data asynchronously.
+ // See http://crbug.com/49332.
+ if (value.size() > kMaxDataLength)
+ value = value.substr(0, kMaxDataLength);
+
field->set_value(value);
}
// static
string16 FormManager::LabelForElement(const HTMLFormControlElement& element) {
+ // Don't scrape labels for hidden elements.
+ if (formControlType(element) == kHidden)
+ return string16();
+
RefPtr<NodeList> labels = element.document()->getElementsByTagName("label");
for (unsigned i = 0; i < labels->length(); ++i) {
Node* e = labels->item(i);
@@ -181,27 +324,26 @@ string16 FormManager::LabelForElement(const HTMLFormControlElement& element) {
}
// static
-bool FormManager::HTMLFormElementToFormData(HTMLFormElement& element,
- RequirementsMask requirements,
- bool get_values,
- FormData* form) {
- ASSERT(form);
-
- const WebCore::Document* document = element.document();
- if (!document)
+bool FormManager::HTMLFormElementToFormData(HTMLFormElement* element, RequirementsMask requirements, bool get_values, bool get_options, FormData* form) {
+ DCHECK(form);
+
+ Frame* frame = element->document()->frame();
+ if (!frame)
return false;
- if (requirements & REQUIRE_AUTOCOMPLETE && !element.autoComplete())
+ if (requirements & REQUIRE_AUTOCOMPLETE && !element->autoComplete())
return false;
- form->name = S(element.name());
- form->method = S(element.method());
- form->origin = GURL(S(document->documentURI()));
- form->action = GURL(S(document->completeURL(element.action())));
+ form->name = WTFStringToString16(element->name());
+ form->method = WTFStringToString16(element->method());
+ form->origin = GURL(WTFStringToString16(frame->loader()->documentLoader()->url().string()));
+ form->action = GURL(WTFStringToString16(frame->document()->completeURL(element->action())));
+ form->user_submitted = 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(S(element.action()));
+ form->action = GURL(WTFStringToString16(element->action()));
// A map from a FormField's name to the FormField itself.
std::map<string16, FormField*> name_map;
@@ -210,29 +352,30 @@ bool FormManager::HTMLFormElementToFormData(HTMLFormElement& element,
// |name_map|.
ScopedVector<FormField> form_fields;
- WTF::Vector<WebCore::HTMLFormControlElement*> control_elements = element.associatedElements();
+ WTF::Vector<HTMLFormControlElement*> control_elements = element->associatedElements();
// A vector of bools that indicate whether each field in the form meets the
// requirements and thus will be in the resulting |form|.
std::vector<bool> fields_extracted(control_elements.size(), false);
+
for (size_t i = 0; i < control_elements.size(); ++i) {
- const HTMLFormControlElement* control_element = control_elements[i];
+ HTMLFormControlElement* control_element = control_elements[i];
if (!(control_element->hasTagName(inputTag) || control_element->hasTagName(selectTag)))
continue;
if (requirements & REQUIRE_AUTOCOMPLETE &&
- control_element->type() == WTF::String("text")) {
+ formControlType(*control_element) == kText) {
const WebCore::HTMLInputElement* input_element = static_cast<const WebCore::HTMLInputElement*>(control_element);
if (!input_element->autoComplete())
continue;
}
- if (requirements & REQUIRE_ELEMENTS_ENABLED && !control_element->isEnabledFormControl())
+ if (requirements & REQUIRE_ENABLED && !control_element->isEnabledFormControl())
continue;
// Create a new FormField, fill it out and map it to the field's name.
FormField* field = new FormField;
- HTMLFormControlElementToFormField(*control_element, get_values, field);
+ HTMLFormControlElementToFormField(control_element, get_values, get_options, field);
form_fields.push_back(field);
// TODO: 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
@@ -250,15 +393,15 @@ bool FormManager::HTMLFormElementToFormData(HTMLFormElement& 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.
- RefPtr<WebCore::NodeList> labels = element.getElementsByTagName("label");
+ RefPtr<WebCore::NodeList> labels = element->getElementsByTagName("label");
for (unsigned i = 0; i < labels->length(); ++i) {
- WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(labels->item(i));
+ HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(labels->item(i));
HTMLFormControlElement* field_element = label->control();
if (!field_element || field_element->type() == "hidden")
continue;
std::map<string16, FormField*>::iterator iter =
- name_map.find(S(field_element->name()));
+ name_map.find(nameForAutoFill(*field_element));
if (iter != name_map.end())
iter->second->set_label(FindChildText(label));
}
@@ -267,8 +410,7 @@ bool FormManager::HTMLFormElementToFormData(HTMLFormElement& element,
// DOM. We use the |fields_extracted| vector to make sure we assign the
// extracted label to the correct field, as it's possible |form_fields| will
// not contain all of the elements in |control_elements|.
- for (size_t i = 0, field_idx = 0;
- i < control_elements.size() && field_idx < form_fields.size(); ++i) {
+ for (size_t i = 0, field_idx = 0; i < control_elements.size() && field_idx < form_fields.size(); ++i) {
// This field didn't meet the requirements, so don't try to find a label for
// it.
if (!fields_extracted[i])
@@ -276,365 +418,359 @@ bool FormManager::HTMLFormElementToFormData(HTMLFormElement& element,
const HTMLFormControlElement* control_element = control_elements[i];
if (form_fields[field_idx]->label().empty())
- form_fields[field_idx]->set_label(
- FormManager::InferLabelForElement(*control_element));
+ form_fields[field_idx]->set_label(FormManager::InferLabelForElement(*control_element));
++field_idx;
}
// Copy the created FormFields into the resulting FormData object.
- for (ScopedVector<FormField>::const_iterator iter = form_fields.begin();
- iter != form_fields.end(); ++iter) {
+ for (ScopedVector<FormField>::const_iterator iter = form_fields.begin(); iter != form_fields.end(); ++iter)
form->fields.push_back(**iter);
- }
return true;
}
-void FormManager::ExtractForms(WebCore::Document* document) {
+void FormManager::ExtractForms(Frame* frame) {
+
+ ResetFrame(frame);
- WTF::PassRefPtr<WebCore::HTMLCollection> collection = document->forms();
+ WTF::PassRefPtr<HTMLCollection> web_forms = frame->document()->forms();
- WebCore::HTMLFormElement* form;
- WebCore::HTMLInputElement* input;
- for (Node* node = collection->firstItem();
- node && !node->namespaceURI().isNull() && !node->namespaceURI().isEmpty();
- node = collection->nextItem()) {
+ for (size_t i = 0; i < web_forms->length(); ++i) {
FormElement* form_elements = new FormElement;
- form = static_cast<WebCore::HTMLFormElement*>(node);
- if (form->autoComplete()) {
- WTF::Vector<WebCore::HTMLFormControlElement*> elements = form->associatedElements();
- size_t size = elements.size();
- for (size_t i = 0; i < size; i++) {
- WebCore::HTMLFormControlElement* e = elements[i];
- if (e->hasTagName(inputTag) || e->hasTagName(selectTag))
- form_elements->control_elements.push_back(e);
- }
- form_elements->form_element = form;
+ HTMLFormElement* form_element = static_cast<HTMLFormElement*>(web_forms->item(i));
+ form_elements->form_element = form_element;
+
+ WTF::Vector<HTMLFormControlElement*> control_elements = form_element->associatedElements();
+ for (size_t j = 0; j < control_elements.size(); ++j) {
+ HTMLFormControlElement* element = control_elements[j];
+ form_elements->control_elements.push_back(element);
+
+ // Save original values of "select-one" inputs so we can restore them
+ // when |ClearFormWithNode()| is invoked.
+ if (formControlType(*element) == kSelectOne) {
+ HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
+ string16 value = WTFStringToString16(select_element->value());
+ form_elements->control_values.push_back(value);
+ } else
+ form_elements->control_values.push_back(string16());
}
- form_elements_map_[document].push_back(form_elements);
- }
-}
-void FormManager::GetForms(RequirementsMask requirements,
- std::vector<FormData>* forms) {
- ASSERT(forms);
-
- for (DocumentFormElementMap::iterator iter = form_elements_map_.begin();
- iter != form_elements_map_.end(); ++iter) {
- for (std::vector<FormElement*>::iterator form_iter = iter->second.begin();
- form_iter != iter->second.end(); ++form_iter) {
- FormData form;
- if (HTMLFormElementToFormData(*(*form_iter)->form_element,
- requirements,
- true,
- &form))
- forms->push_back(form);
- }
+ form_elements_.push_back(form_elements);
}
}
-void FormManager::GetFormsInDocument(const WebCore::Document* document,
- RequirementsMask requirements,
- std::vector<FormData>* forms) {
- ASSERT(document);
- ASSERT(forms);
-
- DocumentFormElementMap::iterator iter = form_elements_map_.find(document);
- if (iter == form_elements_map_.end())
- return;
+void FormManager::GetFormsInFrame(const Frame* frame, RequirementsMask requirements, std::vector<FormData>* forms) {
+ DCHECK(frame);
+ DCHECK(forms);
- // TODO: Factor this out and use it here and in GetForms.
- const std::vector<FormElement*>& form_elements = iter->second;
- for (std::vector<FormElement*>::const_iterator form_iter =
- form_elements.begin();
- form_iter != form_elements.end(); ++form_iter) {
+ for (FormElementList::const_iterator form_iter = form_elements_.begin(); form_iter != form_elements_.end(); ++form_iter) {
FormElement* form_element = *form_iter;
+ if (form_element->form_element->document()->frame() != frame)
+ continue;
+
// We need at least |kRequiredAutoFillFields| fields before appending this
// form to |forms|.
if (form_element->control_elements.size() < kRequiredAutoFillFields)
continue;
- if (requirements & REQUIRE_AUTOCOMPLETE &&
- !form_element->form_element->autoComplete())
+ if (requirements & REQUIRE_AUTOCOMPLETE && !form_element->form_element->autoComplete())
continue;
FormData form;
- FormElementToFormData(document, form_element, requirements, &form);
+ HTMLFormElementToFormData(form_element->form_element, requirements, true, false, &form);
if (form.fields.size() >= kRequiredAutoFillFields)
forms->push_back(form);
}
}
-bool FormManager::FindForm(const HTMLFormElement& element,
- RequirementsMask requirements,
- FormData* form) {
- ASSERT(form);
+bool FormManager::FindFormWithFormControlElement(HTMLFormControlElement* element, RequirementsMask requirements, FormData* form) {
+ DCHECK(form);
- const WebCore::Document* document = element.document();
- DocumentFormElementMap::const_iterator document_iter =
- form_elements_map_.find(document);
- if (document_iter == form_elements_map_.end())
+ const Frame* frame = element->document()->frame();
+ if (!frame)
return false;
- for (std::vector<FormElement*>::const_iterator iter =
- document_iter->second.begin();
- iter != document_iter->second.end(); ++iter) {
- if ((*iter)->form_element->name() != element.name())
+ for (FormElementList::const_iterator iter = form_elements_.begin(); iter != form_elements_.end(); ++iter) {
+ const FormElement* form_element = *iter;
+
+ if (form_element->form_element->document()->frame() != frame)
continue;
- return FormElementToFormData(document, *iter, requirements, form);
+
+ for (std::vector<HTMLFormControlElement*>::const_iterator iter = form_element->control_elements.begin(); iter != form_element->control_elements.end(); ++iter) {
+ if (nameForAutoFill(**iter) == nameForAutoFill(*element)) {
+ HTMLFormElementToFormData(form_element->form_element, requirements, true, true, form);
+ return true;
+ }
+ }
}
return false;
}
-bool FormManager::FindFormWithFormControlElement(
- const HTMLFormControlElement& element,
- RequirementsMask requirements,
- FormData* form) {
- ASSERT(form);
-
- const WebCore::Document* document = element.document();
- if (form_elements_map_.find(document) == form_elements_map_.end())
+bool FormManager::FillForm(const FormData& form, Node* node) {
+ FormElement* form_element = NULL;
+ if (!FindCachedFormElement(form, &form_element))
return false;
- const std::vector<FormElement*> forms = form_elements_map_[document];
- for (std::vector<FormElement*>::const_iterator iter = forms.begin();
- iter != forms.end(); ++iter) {
- const FormElement* form_element = *iter;
+ RequirementsMask requirements = static_cast<RequirementsMask>(REQUIRE_AUTOCOMPLETE | REQUIRE_ENABLED | REQUIRE_EMPTY);
+ ForEachMatchingFormField(form_element, node, requirements, form, NewCallback(this, &FormManager::FillFormField));
- for (std::vector<HTMLFormControlElement*>::const_iterator iter =
- form_element->control_elements.begin();
- iter != form_element->control_elements.end(); ++iter) {
- if ((*iter)->name() == element.name()) {
- HTMLFormElementToFormData(
- *form_element->form_element, requirements, true, form);
- return true;
- }
- }
- }
+ return true;
+}
- return false;
+bool FormManager::PreviewForm(const FormData& form) {
+ FormElement* form_element = NULL;
+ if (!FindCachedFormElement(form, &form_element))
+ return false;
+
+ RequirementsMask requirements = static_cast<RequirementsMask>(REQUIRE_AUTOCOMPLETE | REQUIRE_ENABLED | REQUIRE_EMPTY);
+ ForEachMatchingFormField(form_element, 0, requirements, form, NewCallback(this, &FormManager::PreviewFormField));
+
+ return true;
}
-bool FormManager::FillForm(const FormData& form) {
+bool FormManager::ClearFormWithNode(Node* node) {
FormElement* form_element = NULL;
+ if (!FindCachedFormElementWithNode(node, &form_element))
+ return false;
- for (DocumentFormElementMap::iterator iter = form_elements_map_.begin();
- iter != form_elements_map_.end(); ++iter) {
- const WebCore::Document* document = iter->first;
-
- for (std::vector<FormElement*>::iterator form_iter = iter->second.begin();
- form_iter != iter->second.end(); ++form_iter) {
- // TODO: 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 seem to
- // evaluate to |true| for some reason TBD, so forcing to string16.
- string16 element_name(S((*form_iter)->form_element->name()));
- GURL action(
- S(document->completeURL((*form_iter)->form_element->action()).string()));
- if (element_name == form.name && action == form.action) {
- form_element = *form_iter;
- break;
- }
+ for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
+ HTMLFormControlElement* element = form_element->control_elements[i];
+ if (formControlType(*element) == kText) {
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+
+ // We don't modify the value of disabled fields.
+ if (!input_element->isEnabledFormControl())
+ continue;
+
+ input_element->setValue("");
+ input_element->setAutofilled(false);
+ } else if (formControlType(*element) == kSelectOne) {
+ HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
+ select_element->setValue(form_element->control_values[i].c_str());
}
}
- if (!form_element)
+ return true;
+}
+
+bool FormManager::ClearPreviewedFormWithNode(Node* node) {
+ FormElement* form_element = NULL;
+ if (!FindCachedFormElementWithNode(node, &form_element))
return false;
- // 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; i < form_element->control_elements.size(); ++i) {
+ HTMLFormControlElement* element = form_element->control_elements[i];
- for (size_t i = 0, j = 0;
- i < form_element->control_elements.size() && j < form.fields.size();
- ++i, ++j) {
- // Once again, empty WebString != empty string16, so we have to explicitly
- // check for this case.
- if (form_element->control_elements[i]->name().length() == 0 &&
- form.fields[j].name().empty())
+ // Only input elements can be previewed.
+ if (formControlType(*element) != kText)
continue;
- // We assume that the intersection of the fields in
- // |form_element->control_elements| and |form.fields| is ordered, but it's
- // possible that one or the other sets may have more fields than the other,
- // so loop past non-matching fields in the set with more elements.
- while (S(form_element->control_elements[i]->name()) !=
- form.fields[j].name()) {
- if (form_element->control_elements.size() > form.fields.size()) {
- // We're at the end of the elements already.
- if (i + 1 == form_element->control_elements.size())
- break;
- ++i;
- } else if (form.fields.size() > form_element->control_elements.size()) {
- // We're at the end of the elements already.
- if (j + 1 == form.fields.size())
- break;
- ++j;
- } else {
- // Shouldn't get here.
- ASSERT(false);
- }
+ // If the input element has not been auto-filled, FormManager has not
+ // previewed this field, so we have nothing to reset.
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+ if (!input_element->isAutofilled())
+ continue;
+ // If the user has completed the auto-fill and the values are filled in, we
+ // don't want to reset the auto-filled status.
+ if (!input_element->value().isEmpty())
continue;
- }
- HTMLFormControlElement* element = form_element->control_elements[i];
- if (!form.fields[j].value().empty() &&
- element->type() != WTF::String("submit")) {
- if (element->type() == WTF::String("text")) {
- WebCore::HTMLInputElement* input_element = static_cast<WebCore::HTMLInputElement*>(element);
- // If the maxlength attribute contains a negative value, maxLength()
- // returns the default maxlength value.
- input_element->setValue(
- WTF::String(form.fields[j].value().substr(0, input_element->maxLength()).c_str()));
- input_element->setAutofilled(true);
- } else if (element->type() ==
- WTF::String("select-one")) {
- WebCore::HTMLSelectElement* select_element = static_cast<WebCore::HTMLSelectElement*>(element);
- select_element->setValue(WTF::String(form.fields[j].value().c_str()));
- }
+ input_element->setSuggestedValue("");
+ 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 (node == input_element) {
+ input_element->setSelectionRange(input_element->value().length(),
+ input_element->value().length());
}
}
return true;
}
-void FormManager::FillForms(const std::vector<webkit_glue::FormData>& forms) {
- for (std::vector<webkit_glue::FormData>::const_iterator iter = forms.begin();
- iter != forms.end(); ++iter) {
- FillForm(*iter);
- }
+void FormManager::Reset() {
+ STLDeleteElements(&form_elements_);
}
-void FormManager::Reset() {
- for (DocumentFormElementMap::iterator iter = form_elements_map_.begin();
- iter != form_elements_map_.end(); ++iter) {
- STLDeleteElements(&iter->second);
+void FormManager::ResetFrame(const Frame* frame) {
+ FormElementList::iterator iter = form_elements_.begin();
+ while (iter != form_elements_.end()) {
+ if ((*iter)->form_element->document()->frame() == frame) {
+ delete *iter;
+ iter = form_elements_.erase(iter);
+ } else
+ ++iter;
}
- form_elements_map_.clear();
}
-void FormManager::ResetFrame(const WebCore::Document* document) {
+bool FormManager::FormWithNodeIsAutoFilled(Node* node) {
+ FormElement* form_element = NULL;
+ if (!FindCachedFormElementWithNode(node, &form_element))
+ return false;
+
+ for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
+ HTMLFormControlElement* element = form_element->control_elements[i];
+ if (formControlType(*element) != kText)
+ continue;
- DocumentFormElementMap::iterator iter = form_elements_map_.find(document);
- if (iter != form_elements_map_.end()) {
- STLDeleteElements(&iter->second);
- form_elements_map_.erase(iter);
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+ if (input_element->isAutofilled())
+ return true;
}
+
+ return false;
}
// static
-bool FormManager::FormElementToFormData(const WebCore::Document* document,
- const FormElement* form_element,
- RequirementsMask requirements,
- FormData* form) {
- if (requirements & REQUIRE_AUTOCOMPLETE &&
- !form_element->form_element->autoComplete())
- return false;
+string16 FormManager::InferLabelForElement(const HTMLFormControlElement& element) {
+ // Don't scrape labels for hidden elements.
+ if (formControlType(element) == kHidden)
+ return string16();
- form->name = S(form_element->form_element->name());
- form->method = S(form_element->form_element->method());
- form->origin = GURL(S(document->documentURI()));
- form->action = GURL(S(document->completeURL(form_element->form_element->action())));
+ string16 inferred_label = InferLabelFromPrevious(element);
- // If the completed URL is not valid, just use the action we get from
- // WebKit.
- if (!form->action.is_valid())
- form->action = GURL(S(form_element->form_element->action()));
+ // If we didn't find a label, check for table cell case.
+ if (inferred_label.empty())
+ inferred_label = InferLabelFromTable(element);
- // Form elements loop.
- for (std::vector<HTMLFormControlElement*>::const_iterator element_iter =
- form_element->control_elements.begin();
- element_iter != form_element->control_elements.end(); ++element_iter) {
- const HTMLFormControlElement* control_element = *element_iter;
+ // If we didn't find a label, check for definition list case.
+ if (inferred_label.empty())
+ inferred_label = InferLabelFromDefinitionList(element);
- if (requirements & REQUIRE_AUTOCOMPLETE &&
- control_element->type() == WTF::String("text")) {
- const WebCore::HTMLInputElement* input_element =
- static_cast<const WebCore::HTMLInputElement*>(control_element);
- if (!input_element->autoComplete())
- continue;
+ return inferred_label;
+}
+
+bool FormManager::FindCachedFormElementWithNode(Node* node,
+ FormElement** form_element) {
+ for (FormElementList::const_iterator form_iter = form_elements_.begin(); form_iter != form_elements_.end(); ++form_iter) {
+ for (std::vector<HTMLFormControlElement*>::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 (requirements & REQUIRE_ELEMENTS_ENABLED && !control_element->isEnabledFormControl())
- continue;
+ return false;
+}
- FormField field;
- HTMLFormControlElementToFormField(*control_element, false, &field);
- form->fields.push_back(field);
+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: 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 seem to
+ // evaluate to |true| for some reason TBD, so forcing to string16.
+ string16 element_name(WTFStringToString16((*form_iter)->form_element->name()));
+ GURL action(WTFStringToString16((*form_iter)->form_element->document()->completeURL((*form_iter)->form_element->action()).string()));
+ if (element_name == form.name && action == form.action) {
+ *form_element = *form_iter;
+ return true;
+ }
}
- return true;
+ return false;
}
-// static
-string16 FormManager::InferLabelForElement(
- const HTMLFormControlElement& element) {
- string16 inferred_label;
- Node* previous = element.previousSibling();
- if (previous) {
- if (previous->isTextNode()) {
- inferred_label = S(previous->nodeValue());
- TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label);
- }
- // If we didn't find text, check for previous paragraph.
- // Eg. <p>Some Text</p><input ...>
- // Note the lack of whitespace between <p> and <input> elements.
- if (inferred_label.empty()) {
- if (previous->isElementNode()) {
- if (previous->hasTagName(pTag)) {
- inferred_label = FindChildText((HTMLElement*)previous);
- }
- }
- }
+void FormManager::ForEachMatchingFormField(FormElement* form, Node* node, RequirementsMask requirements, const FormData& data, Callback* callback) {
+ // 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 < form->control_elements.size() && j < data.fields.size(); ++i) {
+ HTMLFormControlElement* element = form->control_elements[i];
+ string16 element_name = nameForAutoFill(*element);
- // If we didn't find paragraph, check for previous paragraph to this.
- // Eg. <p>Some Text</p> <input ...>
- // Note the whitespace between <p> and <input> elements.
- if (inferred_label.empty()) {
- previous = previous->previousSibling();
- if (previous) {
- if (previous->hasTagName(pTag)) {
- inferred_label = FindChildText((HTMLElement*)previous);
- }
- }
+ if (element_name.empty())
+ continue;
+
+ // 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())
+ continue;
+
+ DCHECK_EQ(data.fields[k].name(), element_name);
+
+ // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or
+ // REQUIRE_EMPTY, which both require text form control elements, so special-
+ // case this type of element.
+ if (formControlType(*element) == kText) {
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+
+ // TODO: WebKit currently doesn't handle the autocomplete
+ // attribute for select control elements, but it probably should.
+ if (requirements & REQUIRE_AUTOCOMPLETE && !input_element->autoComplete())
+ continue;
+
+ // Don't require the node that initiated the auto-fill process to be
+ // empty. The user is typing in this field and we should complete the
+ // value when the user selects a value to fill out.
+ if (requirements & REQUIRE_EMPTY && input_element != node && !input_element->value().isEmpty())
+ continue;
}
+
+ if (requirements & REQUIRE_ENABLED && !element->isEnabledFormControl())
+ continue;
+
+ callback->Run(element, &data.fields[k]);
+
+ // We found a matching form field so move on to the next.
+ ++j;
}
- // If we didn't find paragraph, check for table cell case.
- // Eg. <tr><td>Some Text</td><td><input ...></td></tr>
- // Eg. <tr><td><b>Some Text</b></td><td><b><input ...></b></td></tr>
- if (inferred_label.empty()) {
- Node* parent = element.parentNode();
- while (parent &&
- !parent->hasTagName(tdTag))
- parent = parent->parentNode();
-
- if (parent) {
- if (parent->hasTagName(tdTag)) {
- previous = parent->previousSibling();
-
- // Skip by any intervening text nodes.
- while (previous && previous->isTextNode())
- previous = previous->previousSibling();
-
- if (previous) {
- if (previous->hasTagName(tdTag)) {
- inferred_label = FindChildText((HTMLElement*)previous);
- }
- }
- }
- }
+ delete callback;
+}
+
+void FormManager::FillFormField(HTMLFormControlElement* field, const FormField* data) {
+ // Nothing to fill.
+ if (data->value().empty())
+ return;
+
+ if (formControlType(*field) == kText) {
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(field);
+
+ // If the maxlength attribute contains a negative value, maxLength()
+ // returns the default maxlength value.
+ // TODO: The call here to |setSuggestedValue| is a work-around
+ // to a WebKit change in r67122. See http://crbug.com/56081 for details.
+ // Once the core issue is fixed in WebKit, this work-around should be
+ // removed.
+ input_element->setSuggestedValue(data->value().substr(0, input_element->maxLength()).c_str());
+ input_element->setValue(data->value().substr(0, input_element->maxLength()).c_str());
+ input_element->setAutofilled(true);
+ } else if (formControlType(*field) == kSelectOne) {
+ HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(field);
+ select_element->setValue(data->value().c_str());
}
- return inferred_label;
+}
+
+void FormManager::PreviewFormField(HTMLFormControlElement* field, const FormField* data) {
+ // Nothing to preview.
+ if (data->value().empty())
+ return;
+
+ // Only preview input fields.
+ if (formControlType(*field) != kText)
+ return;
+
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(field);
+
+ // If the maxlength attribute contains a negative value, maxLength()
+ // returns the default maxlength value.
+ input_element->setSuggestedValue(data->value().substr(0, input_element->maxLength()).c_str());
+ input_element->setAutofilled(true);
}
}
diff --git a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
index 395e651..4d85c1b 100644
--- a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
+++ b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
@@ -42,120 +42,141 @@ class FormField;
} // namespace webkit_glue
namespace WebCore {
- class HTMLFormControlElement;
- class HTMLFormElement;
- class Document;
+class Frame;
+class HTMLFormControlElement;
+class HTMLFormElement;
+class Node;
}
+using WebCore::Frame;
+using WebCore::HTMLFormControlElement;
+using WebCore::HTMLFormElement;
+using WebCore::Node;
+
namespace android {
// Manages the forms in a Document.
class FormManager {
- public:
- // A bit field mask for form requirements.
- enum RequirementsMask {
- REQUIRE_NONE = 0x0, // No requirements.
- REQUIRE_AUTOCOMPLETE = 0x1, // Require that autocomplete != off.
- REQUIRE_ELEMENTS_ENABLED = 0x2 // Require that disabled attribute is off.
- };
-
- FormManager();
- virtual ~FormManager();
-
- // Fills out a FormField object from a given WebFormControlElement.
- // If |get_value| is true, |field| will have the value set from |element|.
- static void HTMLFormControlElementToFormField(
- const WebCore::HTMLFormControlElement& element,
- bool get_value,
- 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.
- static string16 LabelForElement(const WebCore::HTMLFormControlElement& 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. 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|.
- // TODO: Remove the user of this in RenderView and move this to
- // private.
- static bool HTMLFormElementToFormData(WebCore::HTMLFormElement& element,
- RequirementsMask requirements,
- bool get_values,
- webkit_glue::FormData* form);
-
- // Scans the DOM in |document| extracting and storing forms.
- void ExtractForms(WebCore::Document* document);
-
- // Returns a vector of forms that match |requirements|.
- void GetForms(RequirementsMask requirements,
- std::vector<webkit_glue::FormData>* forms);
-
- // Returns a vector of forms in |document| that match |requirements|.
- void GetFormsInDocument(const WebCore::Document* document,
- RequirementsMask requirements,
- std::vector<webkit_glue::FormData>* forms);
-
- // Returns the cached FormData for |element|. Returns true if the form was
- // found in the cache.
- bool FindForm(const WebCore::HTMLFormElement& element,
- RequirementsMask requirements,
- webkit_glue::FormData* form);
-
- // Finds the form that contains |element| and returns it in |form|. Returns
- // false if the form is not found.
- bool FindFormWithFormControlElement(
- const WebCore::HTMLFormControlElement& element,
- RequirementsMask requirements,
- webkit_glue::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: Is matching on name alone good enough? It's possible to
- // store multiple forms with the same names from different frames.
- bool FillForm(const webkit_glue::FormData& form);
-
- // Fills all of the forms in the cache with form data from |forms|.
- void FillForms(const std::vector<webkit_glue::FormData>& forms);
-
- // Resets the stored set of forms.
- void Reset();
-
- // Resets the forms for the specified |document|.
- void ResetFrame(const WebCore::Document* document);
-
- private:
- // Stores the HTMLFormElement and the form control elements for a form.
- struct FormElement {
- WebCore::HTMLFormElement* form_element;
- std::vector<WebCore::HTMLFormControlElement*> control_elements;
- };
-
- // A map of vectors of FormElements keyed by the Document containing each
- // form.
- typedef std::map<const WebCore::Document*, std::vector<FormElement*> >
- DocumentFormElementMap;
-
- // Converts a FormElement to FormData storage. Returns false if the form does
- // not meet all the requirements in the requirements mask.
- static bool FormElementToFormData(const WebCore::Document* document,
- const FormElement* form_element,
- RequirementsMask requirements,
- webkit_glue::FormData* form);
-
- // Infers corresponding label for |element| from surrounding context in the
- // DOM. Contents of preceeding <p> tag or preceeding text element found in
- // the form.
- static string16 InferLabelForElement(
- const WebCore::HTMLFormControlElement& element);
-
- // The map of form elements.
- DocumentFormElementMap form_elements_map_;
-
- DISALLOW_COPY_AND_ASSIGN(FormManager);
+public:
+ // A bit field mask for form requirements.
+ enum RequirementsMask {
+ REQUIRE_NONE = 0x0, // No requirements.
+ REQUIRE_AUTOCOMPLETE = 0x1, // Require that autocomplete != off.
+ REQUIRE_ENABLED = 0x2, // Require that disabled attribute is off.
+ REQUIRE_EMPTY = 0x4 // Require that the fields are empty.
+ };
+
+ FormManager();
+ virtual ~FormManager();
+
+ // Fills out a FormField object from a given HTMLFormControlElement.
+ // If |get_value| is true, |field| will have the value set from |element|.
+ // If |get_options| is true, |field| will have the select options set from
+ // |element|.
+ // TODO: Use a bit-field instead of two parameters.
+ static void HTMLFormControlElementToFormField(HTMLFormControlElement* element, bool get_value, bool get_options, 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.
+ static string16 LabelForElement(const HTMLFormControlElement& 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. 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|.
+ // TODO: Remove the user of this in RenderView and move this to
+ // private.
+ static bool HTMLFormElementToFormData(HTMLFormElement* element, RequirementsMask requirements, bool get_values, bool get_options, webkit_glue::FormData* form);
+
+ // Scans the DOM in |frame| extracting and storing forms.
+ void ExtractForms(Frame* frame);
+
+ // Returns a vector of forms in |frame| that match |requirements|.
+ void GetFormsInFrame(const Frame* frame, RequirementsMask requirements, std::vector<webkit_glue::FormData>* forms);
+
+ // Finds the form that contains |element| and returns it in |form|. Returns
+ // false if the form is not found.
+ bool FindFormWithFormControlElement(HTMLFormControlElement* element, RequirementsMask requirements, webkit_glue::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. |node| is the form
+ // control element that initiated the auto-fill process.
+ // TODO: Is matching on name alone good enough? It's possible to
+ // store multiple forms with the same names from different frames.
+ bool FillForm(const webkit_glue::FormData& form, Node* node);
+
+ // Previews the form represented by |form|. Same conditions as FillForm.
+ bool PreviewForm(const webkit_glue::FormData& form);
+
+ // Clears the values of all input elements in the form that contains |node|.
+ // Returns false if the form is not found.
+ bool ClearFormWithNode(Node* node);
+
+ // Clears the placeholder values and the auto-filled background for any fields
+ // in the form containing |node| that have been previewed. Returns false if
+ // the form is not found.
+ bool ClearPreviewedFormWithNode(Node* node);
+
+ // Resets the stored set of forms.
+ void Reset();
+
+ // Resets the forms for the specified |frame|.
+ void ResetFrame(const Frame* frame);
+
+ // Returns true if |form| has any auto-filled fields.
+ bool FormWithNodeIsAutoFilled(Node* node);
+
+private:
+ // Stores the HTMLFormElement and the form control elements for a form.
+ // Original form values are stored so when we clear a form we can reset
+ // "select-one" values to their original state.
+ struct FormElement {
+ HTMLFormElement* form_element;
+ std::vector<HTMLFormControlElement*> control_elements;
+ std::vector<string16> control_values;
+ };
+
+ // Type for cache of FormElement objects.
+ typedef std::vector<FormElement*> FormElementList;
+
+ // The callback type used by ForEachMatchingFormField().
+ typedef Callback2<HTMLFormControlElement*, const webkit_glue::FormField*>::Type Callback;
+
+ // Infers corresponding label for |element| from surrounding context in the
+ // DOM. Contents of preceeding <p> tag or preceeding text element found in
+ // the form.
+ static string16 InferLabelForElement(const HTMLFormControlElement& element);
+
+ // Finds the cached FormElement that contains |node|.
+ bool FindCachedFormElementWithNode(Node* node, FormElement** form_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 |data| that matches the corresponding field in |form|
+ // and meets the |requirements|, |callback| is called with the actual
+ // WebFormControlElement and the FormField data from |form|. The field that
+ // matches |node| is not required to be empty if |requirements| includes
+ // REQUIRE_EMPTY. This method owns |callback|.
+ void ForEachMatchingFormField(FormElement* form, Node* node, RequirementsMask requirements, const webkit_glue::FormData& data, Callback* callback);
+
+ // A ForEachMatchingFormField() callback that sets |field|'s value using the
+ // value in |data|. This method also sets the autofill attribute, causing the
+ // background to be yellow.
+ void FillFormField(HTMLFormControlElement* field, const webkit_glue::FormField* data);
+
+ // A ForEachMatchingFormField() callback that sets |field|'s placeholder value
+ // using the value in |data|, causing the test to be greyed-out. This method
+ // also sets the autofill attribute, causing the background to be yellow.
+ void PreviewFormField(HTMLFormControlElement* field, const webkit_glue::FormField* data);
+
+ // The cached FormElement objects.
+ FormElementList form_elements_;
+
+ DISALLOW_COPY_AND_ASSIGN(FormManager);
};
} // namespace android
diff --git a/WebKit/android/WebCoreSupport/autofill/StringUtils.h b/WebKit/android/WebCoreSupport/autofill/StringUtils.h
new file mode 100644
index 0000000..aa408a5
--- /dev/null
+++ b/WebKit/android/WebCoreSupport/autofill/StringUtils.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2010 The Android Open Source Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef AutoFillStringUtils_h_
+#define AutoFillStringUtils_h_
+
+#include "ChromiumIncludes.h"
+#include "HTMLFormControlElement.h"
+#include <wtf/text/WTFString.h>
+
+using WebCore::HTMLFormControlElement;
+
+const string16 kText = ASCIIToUTF16("text");
+const string16 kHidden = ASCIIToUTF16("hidden");
+const string16 kSelectOne = ASCIIToUTF16("select-one");
+
+inline string16 WTFStringToString16(const WTF::String& wtfString)
+{
+ WTF::String str = wtfString;
+
+ if (str.charactersWithNullTermination())
+ return string16(str.charactersWithNullTermination());
+ else
+ return string16();
+}
+
+inline string16 nameForAutoFill(const HTMLFormControlElement& element)
+{
+ // Taken from WebKit/chromium/src/WebFormControlElement.cpp, ported
+ // to use WebCore types for accessing element properties.
+ String name = element.name();
+ String trimmedName = name.stripWhiteSpace();
+ if (!trimmedName.isEmpty())
+ return WTFStringToString16(trimmedName);
+ name = element.getIdAttribute();
+ trimmedName = name.stripWhiteSpace();
+ if (!trimmedName.isEmpty())
+ return WTFStringToString16(trimmedName);
+ return string16();
+}
+
+inline string16 formControlType(const HTMLFormControlElement& element)
+{
+ // Taken from WebKit/chromium/src/WebFormControlElement.cpp, ported
+ // to use WebCore types for accessing element properties.
+ return WTFStringToString16(element.type());
+}
+
+#endif
+
diff --git a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp
index 217bbc0..f258f2f 100644
--- a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp
+++ b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp
@@ -29,7 +29,6 @@
#if ENABLE(WEB_AUTOFILL)
#include "AutoFillHostAndroid.h"
-#include "Document.h"
#include "Frame.h"
#include "FormData.h"
#include "FormManagerAndroid.h"
@@ -75,7 +74,7 @@ WebAutoFill::~WebAutoFill()
mUniqueIdMap.clear();
}
-void WebAutoFill::searchDocument(WebCore::Document* document)
+void WebAutoFill::searchDocument(WebCore::Frame* frame)
{
// TODO: This method is called when the main frame finishes loading and
// scans the document for forms and tries to work out the type of the
@@ -94,9 +93,9 @@ void WebAutoFill::searchDocument(WebCore::Document* document)
mQueryId = 1;
mAutoFillManager->Reset();
mFormManager->Reset();
- mFormManager->ExtractForms(document);
+ mFormManager->ExtractForms(frame);
mForms.clear();
- mFormManager->GetForms(FormManager::REQUIRE_AUTOCOMPLETE, &mForms);
+ mFormManager->GetFormsInFrame(frame, FormManager::REQUIRE_AUTOCOMPLETE, &mForms);
mAutoFillManager->FormsSeen(mForms);
}
@@ -112,11 +111,11 @@ void WebAutoFill::formFieldFocused(WebCore::HTMLFormControlElement* formFieldEle
// Get the FormField from the Node.
webkit_glue::FormField formField;
- FormManager::HTMLFormControlElementToFormField(*formFieldElement, false, &formField);
+ FormManager::HTMLFormControlElementToFormField(formFieldElement, false, false, &formField);
formField.set_label(FormManager::LabelForElement(*formFieldElement));
webkit_glue::FormData* form = new webkit_glue::FormData;
- mFormManager->FindFormWithFormControlElement(*formFieldElement, FormManager::REQUIRE_AUTOCOMPLETE, form);
+ mFormManager->FindFormWithFormControlElement(formFieldElement, FormManager::REQUIRE_AUTOCOMPLETE, form);
mQueryMap[mQueryId] = form;
bool suggestions = mAutoFillManager->GetAutoFillSuggestions(mQueryId, false, formField);
@@ -159,7 +158,12 @@ void WebAutoFill::fillFormInPage(int queryId, const webkit_glue::FormData& form)
if (!enabled())
return;
- mFormManager->FillForm(form);
+ // FIXME: Pass a pointer to the Node that triggered the AutoFill flow here instead of 0.
+ // The consquence of passing 0 is that we should always fail the test in FormManader::ForEachMathcingFormField():169
+ // that says "only overwrite an elements current value if the user triggered autofill through that element"
+ // for elements that have a value already. But by a quirk of Android text views we are OK. We should still
+ // fix this though.
+ mFormManager->FillForm(form, 0);
}
bool WebAutoFill::enabled() const
diff --git a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h
index c4b63b0..f77948e 100644
--- a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h
+++ b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h
@@ -40,7 +40,7 @@ class AutoFillProfile;
class AutoFillHost;
namespace WebCore {
-class Document;
+class Frame;
class HTMLFormControlElement;
}
@@ -55,7 +55,7 @@ public:
WebAutoFill();
virtual ~WebAutoFill();
- void searchDocument(WebCore::Document*);
+ void searchDocument(WebCore::Frame*);
void formFieldFocused(WebCore::HTMLFormControlElement*);
void fillFormFields(int queryId);
void querySuccessful(int queryId, const string16& value, const string16& label, int uniqueId);