summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp6
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h25
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp325
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h25
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h2
5 files changed, 208 insertions, 175 deletions
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp b/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp
index 1116b7f..3f5970a 100644
--- a/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp
+++ b/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp
@@ -61,7 +61,7 @@ FormField::FormField()
FormField::FormField(const HTMLFormControlElement& element)
: max_length(0),
is_autofilled(false) {
- name = nameForAutoFill(element);
+ name = nameForAutofill(element);
// TODO: Extract the field label. For now we just use the field
// name.
@@ -80,10 +80,10 @@ FormField::FormField(const HTMLFormControlElement& element)
// For select-one elements copy option strings.
WTF::Vector<Element*> list_items = select_element.listItems();
- option_strings_.reserve(list_items.size());
+ 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()));
+ option_strings.push_back(WTFStringToString16(static_cast<HTMLOptionElement*>(list_items[i])->value()));
}
}
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h b/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h
index 9379c09..7367f86 100644
--- a/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h
+++ b/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h
@@ -41,26 +41,12 @@ class HTMLFormControlElement;
namespace webkit_glue {
// Stores information about a field in a form.
-class FormField {
-public:
+struct FormField {
FormField();
explicit FormField(const WebCore::HTMLFormControlElement& element);
FormField(const string16& label, const string16& name, const string16& value, const string16& form_control_type, int max_length, bool is_autofilled);
virtual ~FormField();
- string16 label;
- string16 name;
- string16 value;
- string16 form_control_type;
- int max_length;
- bool is_autofilled;
-
- // 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_; }
-
- 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
@@ -72,8 +58,13 @@ public:
// TODO: This will be removed when we implement field ids.
bool StrictlyEqualsHack(const FormField& field) const;
-private:
- std::vector<string16> option_strings_;
+ string16 label;
+ string16 name;
+ string16 value;
+ string16 form_control_type;
+ int max_length;
+ bool is_autofilled;
+ std::vector<string16> option_strings;
};
// So we can compare FormFields with EXPECT_EQ().
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
index 44a8c34..ba015e2 100644
--- a/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
+++ b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
@@ -39,6 +39,7 @@
#include "HTMLNames.h"
#include "HTMLOptionElement.h"
#include "HTMLSelectElement.h"
+#include "InputElement.h"
#include "Node.h"
#include "NodeList.h"
#include "HTMLCollection.h"
@@ -63,6 +64,7 @@ using WebCore::HTMLInputElement;
using WebCore::HTMLLabelElement;
using WebCore::HTMLOptionElement;
using WebCore::HTMLSelectElement;
+using WebCore::InputElement;
using WebCore::Node;
using WebCore::NodeList;
@@ -70,25 +72,56 @@ using namespace WebCore::HTMLNames;
namespace {
-// The number of fields required by AutoFill. Ideally we could send the forms
-// to AutoFill no matter how many fields are in the forms; however, finding the
+// Android helper function.
+HTMLInputElement* HTMLFormControlElementToHTMLInputElement(const HTMLFormControlElement& element) {
+ Node* node = const_cast<Node*>(static_cast<const Node*>(&element));
+ InputElement* input_element = node->toInputElement();
+ if (node && node->isHTMLElement())
+ return static_cast<HTMLInputElement*>(input_element);
+
+ return 0;
+}
+
+// The number of fields required by Autofill. Ideally we could send the forms
+// to Autofill no matter how many fields are in the forms; however, finding the
// label for each field is a costly operation and we can't spare the cycles if
// it's not necessary.
// Note the on ANDROID we reduce this from Chromium's 3 as it allows us to
-// autofill simple name/email forms for example. This improves the mobile
+// Autofill simple name/email forms for example. This improves the mobile
// device experience where form filling can be time consuming and frustrating.
-const size_t kRequiredAutoFillFields = 2;
+const size_t kRequiredAutofillFields = 2;
+
+// The maximum number of form fields we are willing to parse, due to
+// computational costs. This is a very conservative upper bound.
+const size_t kMaxParseableFields = 1000;
// The maximum length allowed for form data.
const size_t kMaxDataLength = 1024;
-// This is a helper function for the FindChildText() function.
-// 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. The text is
-// accumulated after the whitespace has been stropped. Search depth is limited
-// with the |depth| parameter.
+// In HTML5, all text fields except password are text input fields to
+// autocomplete.
+bool IsTextInput(const HTMLInputElement* element) {
+ if (!element)
+ return false;
+
+ return element->isTextField() && !element->isPasswordField();
+}
+
+bool IsSelectElement(const HTMLFormControlElement& element) {
+ return formControlType(element) == kSelectOne;
+}
+
+bool IsOptionElement(Element& element) {
+ return element.hasTagName(optionTag);
+}
+
+bool IsAutofillableElement(const HTMLFormControlElement& element) {
+ HTMLInputElement* html_input_element = HTMLFormControlElementToHTMLInputElement(element);
+ return html_input_element && IsTextInput(html_input_element) || IsSelectElement(element);
+}
+
+// This is a helper function for the FindChildText() function (see below).
+// Search depth is limited with the |depth| parameter.
string16 FindChildTextInner(Node* node, int depth) {
string16 element_text;
if (!node || depth <= 0)
@@ -110,10 +143,12 @@ string16 FindChildTextInner(Node* node, int depth) {
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. Search is limited to withing 10 siblings and/or
-// descendants.
+// Returns the aggregated values of the decendants or siblings of |element| 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. Whitesapce is trimmed from
+// text accumulated at descendant and sibling. Search is limited to within 10
+// siblings and/or descendants.
string16 FindChildText(Element* element) {
Node* child = element->firstChild();
@@ -121,6 +156,8 @@ string16 FindChildText(Element* element) {
return FindChildTextInner(child, kChildSearchDepth);
}
+// Helper for |InferLabelForElement()| that infers a label, if possible, from
+// a previous node of |element|.
string16 InferLabelFromPrevious(const HTMLFormControlElement& element) {
string16 inferred_label;
Node* previous = element.previousSibling();
@@ -269,23 +306,47 @@ string16 InferLabelFromDefinitionList(const HTMLFormControlElement& element) {
return inferred_label;
}
-void GetOptionStringsFromElement(HTMLFormControlElement* element, std::vector<string16>* option_strings) {
- DCHECK(element);
+// Infers corresponding label for |element| from surrounding context in the DOM.
+// Contents of preceding <p> tag or preceding text element found in the form.
+string16 InferLabelForElement(const HTMLFormControlElement& element) {
+ string16 inferred_label = InferLabelFromPrevious(element);
+
+ // If we didn't find a label, check for table cell case.
+ if (inferred_label.empty())
+ inferred_label = InferLabelFromTable(element);
+
+ // If we didn't find a label, check for div table case.
+ if (inferred_label.empty())
+ inferred_label = InferLabelFromDivTable(element);
+
+ // If we didn't find a label, check for definition list case.
+ if (inferred_label.empty())
+ inferred_label = InferLabelFromDefinitionList(element);
+
+ return inferred_label;
+}
+
+void GetOptionStringsFromElement(const HTMLSelectElement& select_element, std::vector<string16>* option_strings) {
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))
+ 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 (IsOptionElement(*list_items[i])) {
option_strings->push_back(WTFStringToString16(static_cast<HTMLOptionElement*>(list_items[i])->value()));
}
}
}
+// Returns the form's |name| attribute if non-empty; otherwise the form's |id|
+// attribute.
+const string16 GetFormIdentifier(const HTMLFormElement& form) {
+ string16 identifier = WTFStringToString16(form.name());
+ if (identifier.empty())
+ identifier = WTFStringToString16(form.getIdAttribute());
+ return identifier;
+}
+
} // namespace
namespace android {
@@ -306,36 +367,39 @@ FormManager::~FormManager() {
// static
void FormManager::HTMLFormControlElementToFormField(HTMLFormControlElement* element, ExtractMask extract_mask, FormField* field) {
DCHECK(field);
+ DCHECK(element);
// 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->name = nameForAutoFill(*element);
+ field->name = nameForAutofill(*element);
field->form_control_type = formControlType(*element);
- if (extract_mask & EXTRACT_OPTIONS) {
- std::vector<string16> option_strings;
- GetOptionStringsFromElement(element, &option_strings);
- field->set_option_strings(option_strings);
- }
+ if (!IsAutofillableElement(*element))
+ return;
+
+ HTMLInputElement* input_element = HTMLFormControlElementToHTMLInputElement(*element);
- if (formControlType(*element) == kText) {
- HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+ if (IsTextInput(input_element)) {
field->max_length = input_element->maxLength();
field->is_autofilled = input_element->isAutofilled();
+ } else if (extract_mask & EXTRACT_OPTIONS) {
+ // Set option strings on the field is available.
+ DCHECK(IsSelectElement(*element));
+ HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
+ std::vector<string16> option_strings;
+ GetOptionStringsFromElement(*select_element, &option_strings);
+ field->option_strings = option_strings;
}
if (!(extract_mask & EXTRACT_VALUE))
return;
- // TODO: In WebKit, move value() and setValue() to
- // WebFormControlElement.
string16 value;
- if (formControlType(*element) == kText ||
- formControlType(*element) == kHidden) {
- HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+ if (IsTextInput(input_element)) {
value = WTFStringToString16(input_element->value());
- } else if (formControlType(*element) == kSelectOne) {
+ } else {
+ DCHECK(IsSelectElement(*element));
HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
value = WTFStringToString16(select_element->value());
@@ -343,7 +407,7 @@ void FormManager::HTMLFormControlElementToFormField(HTMLFormControlElement* elem
if (extract_mask & EXTRACT_OPTION_TEXT) {
Vector<Element*> list_items = select_element->listItems();
for (size_t i = 0; i < list_items.size(); ++i) {
- if (list_items[i]->hasTagName(optionTag) &&
+ if (IsOptionElement(*list_items[i]) &&
WTFStringToString16(static_cast<HTMLOptionElement*>(list_items[i])->value()) == value) {
value = WTFStringToString16(static_cast<HTMLOptionElement*>(list_items[i])->text());
break;
@@ -364,22 +428,21 @@ void FormManager::HTMLFormControlElementToFormField(HTMLFormControlElement* elem
// static
string16 FormManager::LabelForElement(const HTMLFormControlElement& element) {
- // Don't scrape labels for hidden elements.
- if (formControlType(element) == kHidden)
+ // Don't scrape labels for elements we can't possible autofill anyway.
+ if (!IsAutofillableElement(element))
return string16();
RefPtr<NodeList> labels = element.document()->getElementsByTagName("label");
for (unsigned i = 0; i < labels->length(); ++i) {
Node* e = labels->item(i);
- if (e->hasTagName(labelTag)) {
- HTMLLabelElement* label = static_cast<HTMLLabelElement*>(e);
- if (label->control() == &element)
- return FindChildText(label);
- }
+ DCHECK(e->hasTagName(labelTag));
+ HTMLLabelElement* label = static_cast<HTMLLabelElement*>(e);
+ if (label->control() == &element)
+ return FindChildText(label);
}
// Infer the label from context if not found in label element.
- return FormManager::InferLabelForElement(element);
+ return InferLabelForElement(element);
}
// static
@@ -393,7 +456,7 @@ bool FormManager::HTMLFormElementToFormData(HTMLFormElement* element, Requiremen
if (requirements & REQUIRE_AUTOCOMPLETE && !element->autoComplete())
return false;
- form->name = WTFStringToString16(element->name());
+ form->name = GetFormIdentifier(*element);
form->method = WTFStringToString16(element->method());
form->origin = GURL(WTFStringToString16(frame->loader()->documentLoader()->url().string()));
form->action = GURL(WTFStringToString16(frame->document()->completeURL(element->action())));
@@ -422,15 +485,14 @@ bool FormManager::HTMLFormElementToFormData(HTMLFormElement* element, Requiremen
continue;
HTMLFormControlElement* control_element = static_cast<HTMLFormControlElement*>(control_elements[i]);
- if (!(control_element->hasTagName(inputTag) || control_element->hasTagName(selectTag)))
+
+ if(!IsAutofillableElement(*control_element))
continue;
- if (requirements & REQUIRE_AUTOCOMPLETE &&
- formControlType(*control_element) == kText) {
- const WebCore::HTMLInputElement* input_element = static_cast<const WebCore::HTMLInputElement*>(control_element);
- if (!input_element->autoComplete())
+ HTMLInputElement* input_element = HTMLFormControlElementToHTMLInputElement(*control_element);
+ if (requirements & REQUIRE_AUTOCOMPLETE && IsTextInput(input_element) &&
+ !input_element->autoComplete())
continue;
- }
if (requirements & REQUIRE_ENABLED && !control_element->isEnabledFormControl())
continue;
@@ -463,9 +525,11 @@ bool FormManager::HTMLFormElementToFormData(HTMLFormElement* element, Requiremen
continue;
std::map<string16, FormField*>::iterator iter =
- name_map.find(nameForAutoFill(*field_element));
+ name_map.find(nameForAutofill(*field_element));
+ // Concatenate labels because some sites might have multiple label
+ // candidates.
if (iter != name_map.end())
- iter->second->label = FindChildText(label);
+ iter->second->label += FindChildText(label);
}
// Loop through the form control elements, extracting the label text from the
@@ -483,7 +547,7 @@ bool FormManager::HTMLFormElementToFormData(HTMLFormElement* element, Requiremen
const HTMLFormControlElement* control_element = static_cast<HTMLFormControlElement*>(control_elements[i]);
if (form_fields[field_idx]->label.empty())
- form_fields[field_idx]->label = FormManager::InferLabelForElement(*control_element);
+ form_fields[field_idx]->label = InferLabelForElement(*control_element);
++field_idx;
@@ -502,6 +566,7 @@ void FormManager::ExtractForms(Frame* frame) {
WTF::PassRefPtr<HTMLCollection> web_forms = frame->document()->forms();
for (size_t i = 0; i < web_forms->length(); ++i) {
+ // Owned by |form_elements|.
FormElement* form_element = new FormElement;
HTMLFormElement* html_form_element = static_cast<HTMLFormElement*>(web_forms->item(i));
form_element->form_element = html_form_element;
@@ -512,14 +577,17 @@ void FormManager::ExtractForms(Frame* frame) {
continue;
HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(control_elements[j]);
+
+ if (!IsAutofillableElement(*element))
+ continue;
+
form_element->control_elements.push_back(element);
- // Save original values of "select-one" inputs so we can restore them
+ // Save original values of <select> elements so we can restore them
// when |ClearFormWithNode()| is invoked.
- if (formControlType(*element) == kSelectOne) {
+ if (IsSelectElement(*element)) {
HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
- string16 value = WTFStringToString16(select_element->value());
- form_element->control_values.push_back(value);
+ form_element->control_values.push_back(WTFStringToString16(select_element->value()));
} else
form_element->control_values.push_back(string16());
}
@@ -532,15 +600,17 @@ void FormManager::GetFormsInFrame(const Frame* frame, RequirementsMask requireme
DCHECK(frame);
DCHECK(forms);
+ size_t num_fields_seen = 0;
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)
+ // To avoid overly expensive computation, we impose both a minimum and a
+ // maximum number of allowable fields.
+ if (form_element->control_elements.size() < kRequiredAutofillFields ||
+ form_element->control_elements.size() > kMaxParseableFields)
continue;
if (requirements & REQUIRE_AUTOCOMPLETE && !form_element->form_element->autoComplete())
@@ -548,7 +618,12 @@ void FormManager::GetFormsInFrame(const Frame* frame, RequirementsMask requireme
FormData form;
HTMLFormElementToFormData(form_element->form_element.get(), requirements, EXTRACT_VALUE, &form);
- if (form.fields.size() >= kRequiredAutoFillFields)
+
+ num_fields_seen += form.fields.size();
+ if (num_fields_seen > kMaxParseableFields)
+ break;
+
+ if (form.fields.size() >= kRequiredAutofillFields)
forms->push_back(form);
}
}
@@ -568,7 +643,7 @@ bool FormManager::FindFormWithFormControlElement(HTMLFormControlElement* element
for (std::vector<RefPtr<HTMLFormControlElement> >::const_iterator iter = form_element->control_elements.begin(); iter != form_element->control_elements.end(); ++iter) {
HTMLFormControlElement* candidate = iter->get();
- if (nameForAutoFill(*candidate) == nameForAutoFill(*element)) {
+ if (nameForAutofill(*candidate) == nameForAutofill(*element)) {
ExtractMask extract_mask = static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
return HTMLFormElementToFormData(form_element->form_element.get(), requirements, extract_mask, form);
}
@@ -606,8 +681,8 @@ bool FormManager::ClearFormWithNode(Node* node) {
for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
HTMLFormControlElement* element = form_element->control_elements[i].get();
- if (formControlType(*element) == kText) {
- HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+ HTMLInputElement* input_element = HTMLFormControlElementToHTMLInputElement(*element);
+ if (IsTextInput(input_element)) {
// We don't modify the value of disabled fields.
if (!input_element->isEnabledFormControl())
@@ -621,9 +696,13 @@ bool FormManager::ClearFormWithNode(Node* node) {
int length = input_element->value().length();
input_element->setSelectionRange(length, length);
}
- } else if (formControlType(*element) == kSelectOne) {
+ } else {
+ DCHECK(IsSelectElement(*element));
HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
- select_element->setValue(form_element->control_values[i].c_str());
+ if (WTFStringToString16(select_element->value()) != form_element->control_values[i]) {
+ select_element->setValue(form_element->control_values[i].c_str());
+ select_element->dispatchFormControlChangeEvent();
+ }
}
}
@@ -637,14 +716,14 @@ bool FormManager::ClearPreviewedFormWithNode(Node* node, bool was_autofilled) {
for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
HTMLFormControlElement* element = form_element->control_elements[i].get();
+ HTMLInputElement* input_element = HTMLFormControlElementToHTMLInputElement(*element);
// Only input elements can be previewed.
- if (formControlType(*element) != kText)
+ if (!IsTextInput(input_element))
continue;
// If the input element has not been auto-filled, FormManager has not
// previewed this field, so we have nothing to reset.
- HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
if (!input_element->isAutofilled())
continue;
@@ -660,9 +739,6 @@ bool FormManager::ClearPreviewedFormWithNode(Node* node, bool was_autofilled) {
input_element->setSuggestedValue("");
bool is_initiating_node = (node == input_element);
if (is_initiating_node) {
- // Call |setValue()| to force the renderer to update the field's displayed
- // value.
- input_element->setValue(input_element->value());
input_element->setAutofilled(was_autofilled);
} else {
input_element->setAutofilled(false);
@@ -681,31 +757,30 @@ bool FormManager::ClearPreviewedFormWithNode(Node* node, bool was_autofilled) {
}
void FormManager::Reset() {
- STLDeleteElements(&form_elements_);
+ form_elements_.reset();
}
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;
+ if ((*iter)->form_element->document()->frame() == frame)
iter = form_elements_.erase(iter);
- } else
+ else
++iter;
}
}
-bool FormManager::FormWithNodeIsAutoFilled(Node* node) {
+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].get();
- if (formControlType(*element) != kText)
+ HTMLInputElement* input_element = HTMLFormControlElementToHTMLInputElement(*element);
+ if (!IsTextInput(input_element))
continue;
- HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
if (input_element->isAutofilled())
return true;
}
@@ -713,31 +788,7 @@ bool FormManager::FormWithNodeIsAutoFilled(Node* node) {
return false;
}
-// static
-string16 FormManager::InferLabelForElement(const HTMLFormControlElement& element) {
- // Don't scrape labels for hidden elements.
- if (formControlType(element) == kHidden)
- return string16();
-
- string16 inferred_label = InferLabelFromPrevious(element);
-
- // If we didn't find a label, check for table cell case.
- if (inferred_label.empty())
- inferred_label = InferLabelFromTable(element);
-
- // If we didn't find a label, check for div table case.
- if (inferred_label.empty())
- inferred_label = InferLabelFromDivTable(element);
-
- // If we didn't find a label, check for definition list case.
- if (inferred_label.empty())
- inferred_label = InferLabelFromDefinitionList(element);
-
- return inferred_label;
-}
-
-bool FormManager::FindCachedFormElementWithNode(Node* node,
- FormElement** form_element) {
+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<RefPtr<HTMLFormControlElement> >::const_iterator iter = (*form_iter)->control_elements.begin(); iter != (*form_iter)->control_elements.end(); ++iter) {
if (iter->get() == node) {
@@ -757,9 +808,11 @@ bool FormManager::FindCachedFormElement(const FormData& form, FormElement** form
// 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()));
+ // Also note that WebString() == WebString(string16()) does not evaluate to
+ // |true| -- WebKit distinguisges between a "null" string (lhs) and an
+ // "empty" string (rhs). We don't want that distinction, so forcing to
+ // string16.
+ string16 element_name = GetFormIdentifier(*(*form_iter)->form_element);
GURL action(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;
@@ -779,10 +832,7 @@ void FormManager::ForEachMatchingFormField(FormElement* form, Node* node, Requir
// 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].get();
- string16 element_name = nameForAutoFill(*element);
-
- if (element_name.empty())
- continue;
+ string16 element_name = nameForAutofill(*element);
// Search forward in the |form| for a corresponding field.
size_t k = j;
@@ -796,26 +846,22 @@ void FormManager::ForEachMatchingFormField(FormElement* form, Node* node, Requir
bool is_initiating_node = false;
- // 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);
-
+ HTMLInputElement* input_element = HTMLFormControlElementToHTMLInputElement(*element);
+ if (IsTextInput(input_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())
+ if (!input_element->autoComplete())
continue;
is_initiating_node = (input_element == node);
- // 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 && !is_initiating_node && !input_element->value().isEmpty())
+
+ // Only autofill empty fields and the firls that initiated the filling,
+ // i.e. the field the user is currently editing and interacting with.
+ if (!is_initiating_node && !input_element->value().isEmpty())
continue;
}
- if (requirements & REQUIRE_ENABLED && !element->isEnabledFormControl())
+ if (!element->isEnabledFormControl() || element->isReadOnlyFormControl() || !element->isFocusable())
continue;
callback->Run(element, &data.fields[k], is_initiating_node);
@@ -832,20 +878,24 @@ void FormManager::FillFormField(HTMLFormControlElement* field, const FormField*
if (data->value.empty())
return;
- if (formControlType(*field) == kText) {
- HTMLInputElement* input_element = static_cast<HTMLInputElement*>(field);
+ HTMLInputElement* input_element = HTMLFormControlElementToHTMLInputElement(*field);
+ if (IsTextInput(input_element)) {
// If the maxlength attribute contains a negative value, maxLength()
// returns the default maxlength value.
- input_element->setValue(data->value.substr(0, input_element->maxLength()).c_str());
+ input_element->setValue(data->value.substr(0, input_element->maxLength()).c_str(), true);
input_element->setAutofilled(true);
if (is_initiating_node) {
int length = input_element->value().length();
input_element->setSelectionRange(length, length);
}
- } else if (formControlType(*field) == kSelectOne) {
+ } else {
+ DCHECK(IsSelectElement(*field));
HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(field);
- select_element->setValue(data->value.c_str());
+ if (WTFStringToString16(select_element->value()) != data->value) {
+ select_element->setValue(data->value.c_str());
+ select_element->dispatchFormControlChangeEvent();
+ }
}
}
@@ -855,17 +905,18 @@ void FormManager::PreviewFormField(HTMLFormControlElement* field, const FormFiel
return;
// Only preview input fields.
- if (formControlType(*field) != kText)
+ HTMLInputElement* input_element = HTMLFormControlElementToHTMLInputElement(*field);
+ if (!IsTextInput(input_element))
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);
- if (is_initiating_node)
- input_element->setSelectionRange(0, input_element->suggestedValue().length());
+ if (is_initiating_node) {
+ // Select the part of the text that the user didn't type.
+ input_element->setSelectionRange(input_element->value().length(), input_element->suggestedValue().length());
+ }
}
}
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
index e844981..5e6a7da 100644
--- a/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
+++ b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
@@ -38,7 +38,7 @@
namespace webkit_glue {
struct FormData;
-class FormField;
+struct FormField;
} // namespace webkit_glue
namespace WebCore {
@@ -105,16 +105,12 @@ public:
// 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.
+ // Fills the form represented by |form|. |node| is the input element that
+ // initiated the auto-fill process.
bool FillForm(const webkit_glue::FormData& form, Node* node);
- // Previews the form represented by |form|. |node| is the form control element
- // that initiated the preview process. Same conditions as FillForm.
+ // Previews the form represented by |form|. |node| is the input element
+ // that initiated the preview process.
bool PreviewForm(const webkit_glue::FormData& form, Node* node);
// Clears the values of all input elements in the form that contains |node|.
@@ -134,25 +130,20 @@ public:
void ResetFrame(const Frame* frame);
// Returns true if |form| has any auto-filled fields.
- bool FormWithNodeIsAutoFilled(Node* node);
+ 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.
+ // <select> values to their original value.
struct FormElement;
// Type for cache of FormElement objects.
- typedef std::vector<FormElement*> FormElementList;
+ typedef ScopedVector<FormElement> FormElementList;
// The callback type used by ForEachMatchingFormField().
typedef Callback3<HTMLFormControlElement*, const webkit_glue::FormField*, bool>::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);
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h b/Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h
index aa408a5..5f18f07 100644
--- a/Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h
+++ b/Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h
@@ -47,7 +47,7 @@ inline string16 WTFStringToString16(const WTF::String& wtfString)
return string16();
}
-inline string16 nameForAutoFill(const HTMLFormControlElement& element)
+inline string16 nameForAutofill(const HTMLFormControlElement& element)
{
// Taken from WebKit/chromium/src/WebFormControlElement.cpp, ported
// to use WebCore types for accessing element properties.