diff options
author | Ben Murdoch <benm@google.com> | 2010-11-19 18:26:32 +0000 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-11-22 11:52:42 +0000 |
commit | b28419a5ffabcf97496897d7084446af4ac8dd39 (patch) | |
tree | c0c123987b9cd3fb044583472d3919efda607a93 /WebKit | |
parent | d092aa01bda0438a170f0587bbb99b9970e6d27d (diff) | |
download | external_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')
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; |