summaryrefslogtreecommitdiffstats
path: root/WebKit
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2010-11-19 18:26:32 +0000
committerBen Murdoch <benm@google.com>2010-11-22 11:52:42 +0000
commitb28419a5ffabcf97496897d7084446af4ac8dd39 (patch)
treec0c123987b9cd3fb044583472d3919efda607a93 /WebKit
parentd092aa01bda0438a170f0587bbb99b9970e6d27d (diff)
downloadexternal_webkit-b28419a5ffabcf97496897d7084446af4ac8dd39.zip
external_webkit-b28419a5ffabcf97496897d7084446af4ac8dd39.tar.gz
external_webkit-b28419a5ffabcf97496897d7084446af4ac8dd39.tar.bz2
Merge Chromium at r65505: Update AutoFill files.
Bring our forked AutoFill files in line with r65505. http://src.chromium.org/viewvc/chrome?view=rev&revision=63527 http://src.chromium.org/viewvc/chrome?view=rev&revision=63797 http://src.chromium.org/viewvc/chrome?view=rev&revision=64470 http://src.chromium.org/viewvc/chrome?view=rev&revision=64572 http://src.chromium.org/viewvc/chrome?view=rev&revision=64612 http://src.chromium.org/viewvc/chrome?view=rev&revision=64691 http://src.chromium.org/viewvc/chrome?view=rev&revision=64696 Change-Id: I34755e649d1093a79ad50de53dfd1d1f9e92a584
Diffstat (limited to 'WebKit')
-rw-r--r--WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp194
-rw-r--r--WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h41
-rw-r--r--WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp2
3 files changed, 154 insertions, 83 deletions
diff --git a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
index bec6042..332e134 100644
--- a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
@@ -121,53 +121,74 @@ string16 FindChildText(Element* element) {
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 (!previous)
+ return string16();
+
+ 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() && 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()) {
+ Node* sibling = previous->previousSibling();
+ if (sibling && sibling->isElementNode()) {
+ Element* element = static_cast<Element*>(sibling);
+ if (element->hasTagName(pTag))
+ inferred_label = FindChildText(element);
}
+ }
- // 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()) {
+ // 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(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()) {
+ if (!element->hasTagName(imgTag))
+ break;
+ } else
+ break;
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
+ // Look for label node prior to <input> tag.
+ // Eg. <label>Some Text</label><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(labelTag)) {
+ inferred_label = FindChildText(element);
+ } else {
break;
- previous = previous->previousSibling();
+ }
+ } else {
+ break;
}
- }
+
+ previous = previous->previousSibling();
+ }
}
+
return inferred_label;
}
@@ -201,6 +222,24 @@ string16 InferLabelFromTable(const HTMLFormControlElement& element) {
}
// Helper for |InferLabelForElement()| that infers a label, if possible, from
+// a surrounding div table.
+// Eg. <div>Some Text<span><input ...></span></div>
+string16 InferLabelFromDivTable(const HTMLFormControlElement& element) {
+ Node* parent = element.parentNode();
+ while (parent && parent->isElementNode() && !static_cast<Element*>(parent)->hasTagName(divTag))
+ parent = parent->parentNode();
+
+ if (!parent || !parent->isElementNode())
+ return string16();
+
+ Element* e = static_cast<Element*>(parent);
+ if (!e || !e->hasTagName(divTag))
+ return string16();
+
+ return FindChildText(e);
+}
+
+// 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>
@@ -250,6 +289,12 @@ void GetOptionStringsFromElement(HTMLFormControlElement* element, std::vector<st
namespace android {
+struct FormManager::FormElement {
+ HTMLFormElement* form_element;
+ std::vector<HTMLFormControlElement*> control_elements;
+ std::vector<string16> control_values;
+};
+
FormManager::FormManager() {
}
@@ -258,7 +303,7 @@ FormManager::~FormManager() {
}
// static
-void FormManager::HTMLFormControlElementToFormField(HTMLFormControlElement* element, bool get_value, bool get_options, FormField* field) {
+void FormManager::HTMLFormControlElementToFormField(HTMLFormControlElement* element, ExtractMask extract_mask, FormField* field) {
DCHECK(field);
// The label is not officially part of a HTMLFormControlElement; however, the
@@ -267,7 +312,7 @@ void FormManager::HTMLFormControlElementToFormField(HTMLFormControlElement* elem
field->set_name(nameForAutoFill(*element));
field->set_form_control_type(formControlType(*element));
- if (get_options) {
+ if (extract_mask & EXTRACT_OPTIONS) {
std::vector<string16> option_strings;
GetOptionStringsFromElement(element, &option_strings);
field->set_option_strings(option_strings);
@@ -278,7 +323,7 @@ void FormManager::HTMLFormControlElementToFormField(HTMLFormControlElement* elem
field->set_size(input_element->size());
}
- if (!get_value)
+ if (!(extract_mask & EXTRACT_VALUE))
return;
// TODO: In WebKit, move value() and setValue() to
@@ -324,7 +369,7 @@ string16 FormManager::LabelForElement(const HTMLFormControlElement& element) {
}
// static
-bool FormManager::HTMLFormElementToFormData(HTMLFormElement* element, RequirementsMask requirements, bool get_values, bool get_options, FormData* form) {
+bool FormManager::HTMLFormElementToFormData(HTMLFormElement* element, RequirementsMask requirements, ExtractMask extract_mask, FormData* form) {
DCHECK(form);
Frame* frame = element->document()->frame();
@@ -375,7 +420,7 @@ bool FormManager::HTMLFormElementToFormData(HTMLFormElement* element, Requiremen
// Create a new FormField, fill it out and map it to the field's name.
FormField* field = new FormField;
- HTMLFormControlElementToFormField(control_element, get_values, get_options, field);
+ HTMLFormControlElementToFormField(control_element, extract_mask, 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
@@ -479,7 +524,7 @@ void FormManager::GetFormsInFrame(const Frame* frame, RequirementsMask requireme
continue;
FormData form;
- HTMLFormElementToFormData(form_element->form_element, requirements, true, false, &form);
+ HTMLFormElementToFormData(form_element->form_element, requirements, EXTRACT_VALUE, &form);
if (form.fields.size() >= kRequiredAutoFillFields)
forms->push_back(form);
}
@@ -500,7 +545,8 @@ bool FormManager::FindFormWithFormControlElement(HTMLFormControlElement* element
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);
+ ExtractMask extract_mask = static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
+ HTMLFormElementToFormData(form_element->form_element, requirements, extract_mask, form);
return true;
}
}
@@ -519,13 +565,13 @@ bool FormManager::FillForm(const FormData& form, Node* node) {
return true;
}
-bool FormManager::PreviewForm(const FormData& form) {
+bool FormManager::PreviewForm(const FormData& form, Node* node) {
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));
+ ForEachMatchingFormField(form_element, node, requirements, form, NewCallback(this, &FormManager::PreviewFormField));
return true;
}
@@ -546,6 +592,12 @@ bool FormManager::ClearFormWithNode(Node* node) {
input_element->setValue("");
input_element->setAutofilled(false);
+ // Clearing the 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) {
+ int length = input_element->value().length();
+ input_element->setSelectionRange(length, length);
+ }
} else if (formControlType(*element) == kSelectOne) {
HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
select_element->setValue(form_element->control_values[i].c_str());
@@ -573,20 +625,30 @@ bool FormManager::ClearPreviewedFormWithNode(Node* node) {
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())
+ // There might be unrelated elements in this form which have already been
+ // auto-filled. For example, the user might have already filled the address
+ // part of a form and now be dealing with the credit card section. We only
+ // want to reset the auto-filled status for fields that were previewed.
+ if (input_element->suggestedValue().isEmpty())
continue;
+ // Clear the suggested value. For the initiating node, also restore the
+ // original value.
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(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());
+ if (is_initiating_node) {
+ int length = input_element->value().length();
+ input_element->setSelectionRange(length, length);
}
}
@@ -638,6 +700,10 @@ string16 FormManager::InferLabelForElement(const HTMLFormControlElement& element
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);
@@ -703,6 +769,8 @@ void FormManager::ForEachMatchingFormField(FormElement* form, Node* node, Requir
DCHECK_EQ(data.fields[k].name(), element_name);
+ 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.
@@ -714,17 +782,18 @@ void FormManager::ForEachMatchingFormField(FormElement* form, Node* node, Requir
if (requirements & REQUIRE_AUTOCOMPLETE && !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 && input_element != node && !input_element->value().isEmpty())
+ if (requirements & REQUIRE_EMPTY && !is_initiating_node && !input_element->value().isEmpty())
continue;
}
if (requirements & REQUIRE_ENABLED && !element->isEnabledFormControl())
continue;
- callback->Run(element, &data.fields[k]);
+ callback->Run(element, &data.fields[k], is_initiating_node);
// We found a matching form field so move on to the next.
++j;
@@ -733,7 +802,7 @@ void FormManager::ForEachMatchingFormField(FormElement* form, Node* node, Requir
delete callback;
}
-void FormManager::FillFormField(HTMLFormControlElement* field, const FormField* data) {
+void FormManager::FillFormField(HTMLFormControlElement* field, const FormField* data, bool is_initiating_node) {
// Nothing to fill.
if (data->value().empty())
return;
@@ -743,20 +812,19 @@ void FormManager::FillFormField(HTMLFormControlElement* field, const FormField*
// 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);
+ if (is_initiating_node) {
+ int length = input_element->value().length();
+ input_element->setSelectionRange(length, length);
+ }
} else if (formControlType(*field) == kSelectOne) {
HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(field);
select_element->setValue(data->value().c_str());
}
}
-void FormManager::PreviewFormField(HTMLFormControlElement* field, const FormField* data) {
+void FormManager::PreviewFormField(HTMLFormControlElement* field, const FormField* data, bool is_initiating_node) {
// Nothing to preview.
if (data->value().empty())
return;
@@ -771,6 +839,8 @@ void FormManager::PreviewFormField(HTMLFormControlElement* field, const FormFiel
// 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());
}
}
diff --git a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
index 4d85c1b..b4dac83 100644
--- a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
+++ b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
@@ -60,21 +60,25 @@ 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_ENABLED = 0x2, // Require that disabled attribute is off.
- REQUIRE_EMPTY = 0x4 // Require that the fields are empty.
+ REQUIRE_NONE = 0, // No requirements.
+ REQUIRE_AUTOCOMPLETE = 1 << 0, // Require that autocomplete != off.
+ REQUIRE_ENABLED = 1 << 1, // Require that disabled attribute is off.
+ REQUIRE_EMPTY = 1 << 2, // Require that the fields are empty.
+ };
+
+ // A bit field mask to extract data from HTMLFormControlElement.
+ enum ExtractMask {
+ EXTRACT_NONE = 0,
+ EXTRACT_VALUE = 1 << 0, // Extract value from HTMLFormControlElement.
+ EXTRACT_OPTIONS = 1 << 1, // Extract options from HTMLFormControlElement.
};
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);
+ // |extract_mask|: See the enum ExtractMask above for details.
+ static void HTMLFormControlElementToFormField(HTMLFormControlElement* element, ExtractMask extract_mask, 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
@@ -88,7 +92,7 @@ public:
// 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);
+ static bool HTMLFormElementToFormData(HTMLFormElement* element, RequirementsMask requirements, ExtractMask extract_mask, webkit_glue::FormData* form);
// Scans the DOM in |frame| extracting and storing forms.
void ExtractForms(Frame* frame);
@@ -108,8 +112,9 @@ public:
// 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);
+ // Previews the form represented by |form|. |node| is the form control element
+ // that initiated the preview process. Same conditions as FillForm.
+ bool PreviewForm(const webkit_glue::FormData& form, Node* node);
// Clears the values of all input elements in the form that contains |node|.
// Returns false if the form is not found.
@@ -133,17 +138,13 @@ 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;
- };
+ struct FormElement;
// 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;
+ 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
@@ -166,12 +167,12 @@ private:
// 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);
+ void FillFormField(HTMLFormControlElement* field, const webkit_glue::FormField* data, bool is_initiating_node);
// 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);
+ void PreviewFormField(HTMLFormControlElement* field, const webkit_glue::FormField* data, bool is_initiaiting_node);
// The cached FormElement objects.
FormElementList form_elements_;
diff --git a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp
index 8bb34e3..8fc4ac3 100644
--- a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp
+++ b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp
@@ -111,7 +111,7 @@ void WebAutoFill::formFieldFocused(WebCore::HTMLFormControlElement* formFieldEle
// Get the FormField from the Node.
webkit_glue::FormField formField;
- FormManager::HTMLFormControlElementToFormField(formFieldElement, false, false, &formField);
+ FormManager::HTMLFormControlElementToFormField(formFieldElement, FormManager::EXTRACT_NONE, &formField);
formField.set_label(FormManager::LabelForElement(*formFieldElement));
webkit_glue::FormData* form = new webkit_glue::FormData;