From 1a5c9a0e0c938e9203e4b8890e9bc36228ff50b7 Mon Sep 17 00:00:00 2001 From: Ben Murdoch Date: Mon, 11 Jul 2011 14:29:09 +0100 Subject: Merge Chromium at r12.0.742.93: Update Autofill files in WebKit. Apply diffs to the forked copies of Chromium files we keep in external/webkit. See: http://src.chromium.org/viewvc/chrome/branches/742/src/chrome/renderer/autofill/form_manager.cc?r1=67599&r2=82248 http://src.chromium.org/viewvc/chrome/branches/742/src/chrome/renderer/autofill/form_manager.h?r1=67599&r2=82248 http://src.chromium.org/viewvc/chrome/branches/742/src/webkit/glue/form_field.cc?r1=67599&r2=82248 http://src.chromium.org/viewvc/chrome/branches/742/src/webkit/glue/form_field.h?r1=67599&r2=82248 Change-Id: If62167848d86293cb833c593afd2c0c958bafbef --- .../WebCoreSupport/autofill/FormFieldAndroid.cpp | 6 +- .../WebCoreSupport/autofill/FormFieldAndroid.h | 25 +- .../WebCoreSupport/autofill/FormManagerAndroid.cpp | 325 ++++++++++++--------- .../WebCoreSupport/autofill/FormManagerAndroid.h | 25 +- .../android/WebCoreSupport/autofill/StringUtils.h | 2 +- 5 files changed, 208 insertions(+), 175 deletions(-) (limited to 'Source/WebKit/android/WebCoreSupport') 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 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(list_items[i])->value())); + option_strings.push_back(WTFStringToString16(static_cast(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& option_strings() const { return option_strings_; } - - void set_option_strings(const std::vector& 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 option_strings_; + string16 label; + string16 name; + string16 value; + string16 form_control_type; + int max_length; + bool is_autofilled; + std::vector 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(static_cast(&element)); + InputElement* input_element = node->toInputElement(); + if (node && node->isHTMLElement()) + return static_cast(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* option_strings) { - DCHECK(element); +// Infers corresponding label for |element| from surrounding context in the DOM. +// Contents of preceding

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* option_strings) { DCHECK(option_strings); option_strings->clear(); - if (formControlType(*element) == kSelectOne) { - HTMLSelectElement* select_element = static_cast(element); - - // For select-one elements copy option strings. - WTF::Vector 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 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(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 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(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(element); + std::vector 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(element); + if (IsTextInput(input_element)) { value = WTFStringToString16(input_element->value()); - } else if (formControlType(*element) == kSelectOne) { + } else { + DCHECK(IsSelectElement(*element)); HTMLSelectElement* select_element = static_cast(element); value = WTFStringToString16(select_element->value()); @@ -343,7 +407,7 @@ void FormManager::HTMLFormControlElementToFormField(HTMLFormControlElement* elem if (extract_mask & EXTRACT_OPTION_TEXT) { Vector 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(list_items[i])->value()) == value) { value = WTFStringToString16(static_cast(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 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(e); - if (label->control() == &element) - return FindChildText(label); - } + DCHECK(e->hasTagName(labelTag)); + HTMLLabelElement* label = static_cast(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(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(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::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(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 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(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(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 values to their original value. struct FormElement; // Type for cache of FormElement objects. - typedef std::vector FormElementList; + typedef ScopedVector FormElementList; // The callback type used by ForEachMatchingFormField(). typedef Callback3::Type Callback; - // Infers corresponding label for |element| from surrounding context in the - // DOM. Contents of preceeding

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. -- cgit v1.1