diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/html/HTMLFormControlElement.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/html/HTMLFormControlElement.cpp')
-rw-r--r-- | Source/WebCore/html/HTMLFormControlElement.cpp | 426 |
1 files changed, 279 insertions, 147 deletions
diff --git a/Source/WebCore/html/HTMLFormControlElement.cpp b/Source/WebCore/html/HTMLFormControlElement.cpp index e61022993..a9c144dad 100644 --- a/Source/WebCore/html/HTMLFormControlElement.cpp +++ b/Source/WebCore/html/HTMLFormControlElement.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2004-2017 Apple Inc. All rights reserved. * (C) 2006 Alexey Proskuryakov (ap@nypop.com) * * This library is free software; you can redistribute it and/or @@ -25,12 +25,14 @@ #include "config.h" #include "HTMLFormControlElement.h" -#include "Attribute.h" +#include "Autofill.h" +#include "ControlStates.h" +#include "ElementAncestorIterator.h" #include "Event.h" #include "EventHandler.h" #include "EventNames.h" -#include "FeatureObserver.h" #include "Frame.h" +#include "FrameView.h" #include "HTMLFieldSetElement.h" #include "HTMLFormElement.h" #include "HTMLInputElement.h" @@ -38,6 +40,7 @@ #include "HTMLTextAreaElement.h" #include "RenderBox.h" #include "RenderTheme.h" +#include "StyleTreeResolver.h" #include "ValidationMessage.h" #include <wtf/Ref.h> #include <wtf/Vector.h> @@ -48,11 +51,12 @@ using namespace HTMLNames; HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form) : LabelableElement(tagName, document) + , FormAssociatedElement(form) , m_disabled(false) , m_isReadOnly(false) , m_isRequired(false) , m_valueMatchesRenderer(false) - , m_ancestorDisabledState(AncestorDisabledStateUnknown) + , m_disabledByAncestorFieldset(false) , m_dataListAncestorState(Unknown) , m_willValidateInitialized(false) , m_willValidate(true) @@ -60,17 +64,19 @@ HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Doc , m_wasChangedSinceLastFormControlChangeEvent(false) , m_hasAutofocused(false) { - setForm(form ? form : HTMLFormElement::findClosestFormAncestor(*this)); setHasCustomStyleResolveCallbacks(); } HTMLFormControlElement::~HTMLFormControlElement() { + // The calls willChangeForm() and didChangeForm() are virtual, we want the + // form to be reset while this object still exists. + setForm(nullptr); } String HTMLFormControlElement::formEnctype() const { - const AtomicString& formEnctypeAttr = fastGetAttribute(formenctypeAttr); + const AtomicString& formEnctypeAttr = attributeWithoutSynchronization(formenctypeAttr); if (formEnctypeAttr.isNull()) return emptyString(); return FormSubmission::Attributes::parseEncodingType(formEnctypeAttr); @@ -78,12 +84,12 @@ String HTMLFormControlElement::formEnctype() const void HTMLFormControlElement::setFormEnctype(const String& value) { - setAttribute(formenctypeAttr, value); + setAttributeWithoutSynchronization(formenctypeAttr, value); } String HTMLFormControlElement::formMethod() const { - const AtomicString& formMethodAttr = fastGetAttribute(formmethodAttr); + auto& formMethodAttr = attributeWithoutSynchronization(formmethodAttr); if (formMethodAttr.isNull()) return emptyString(); return FormSubmission::Attributes::methodString(FormSubmission::Attributes::parseMethodType(formMethodAttr)); @@ -91,96 +97,113 @@ String HTMLFormControlElement::formMethod() const void HTMLFormControlElement::setFormMethod(const String& value) { - setAttribute(formmethodAttr, value); + setAttributeWithoutSynchronization(formmethodAttr, value); } bool HTMLFormControlElement::formNoValidate() const { - return fastHasAttribute(formnovalidateAttr); + return hasAttributeWithoutSynchronization(formnovalidateAttr); } -void HTMLFormControlElement::updateAncestorDisabledState() const +String HTMLFormControlElement::formAction() const { - HTMLFieldSetElement* fieldSetAncestor = 0; - ContainerNode* legendAncestor = 0; - for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) { - if (!legendAncestor && ancestor->hasTagName(legendTag)) - legendAncestor = ancestor; - if (ancestor->hasTagName(fieldsetTag)) { - fieldSetAncestor = toHTMLFieldSetElement(ancestor); - break; + const AtomicString& value = attributeWithoutSynchronization(formactionAttr); + if (value.isEmpty()) + return document().url(); + return getURLAttribute(formactionAttr); +} + +void HTMLFormControlElement::setFormAction(const AtomicString& value) +{ + setAttributeWithoutSynchronization(formactionAttr, value); +} + +bool HTMLFormControlElement::computeIsDisabledByFieldsetAncestor() const +{ + Element* previousAncestor = nullptr; + for (Element* ancestor = parentElement(); ancestor; ancestor = ancestor->parentElement()) { + if (is<HTMLFieldSetElement>(*ancestor) && ancestor->hasAttributeWithoutSynchronization(disabledAttr)) { + HTMLFieldSetElement& fieldSetAncestor = downcast<HTMLFieldSetElement>(*ancestor); + bool isInFirstLegend = is<HTMLLegendElement>(previousAncestor) && previousAncestor == fieldSetAncestor.legend(); + return !isInFirstLegend; } + previousAncestor = ancestor; } - m_ancestorDisabledState = (fieldSetAncestor && fieldSetAncestor->isDisabledFormControl() && !(legendAncestor && legendAncestor == fieldSetAncestor->legend())) ? AncestorDisabledStateDisabled : AncestorDisabledStateEnabled; + return false; } -void HTMLFormControlElement::ancestorDisabledStateWasChanged() +void HTMLFormControlElement::setAncestorDisabled(bool isDisabled) { - m_ancestorDisabledState = AncestorDisabledStateUnknown; - disabledAttributeChanged(); + ASSERT(computeIsDisabledByFieldsetAncestor() == isDisabled); + bool oldValue = m_disabledByAncestorFieldset; + m_disabledByAncestorFieldset = isDisabled; + if (oldValue != m_disabledByAncestorFieldset) + disabledStateChanged(); } void HTMLFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value) { - if (name == formAttr) { + if (name == formAttr) formAttributeChanged(); - FeatureObserver::observe(&document(), FeatureObserver::FormAttribute); - } else if (name == disabledAttr) { - bool oldDisabled = m_disabled; - m_disabled = !value.isNull(); - if (oldDisabled != m_disabled) - disabledAttributeChanged(); + else if (name == disabledAttr) { + if (canBeActuallyDisabled()) { + bool oldDisabled = m_disabled; + m_disabled = !value.isNull(); + if (oldDisabled != m_disabled) + disabledAttributeChanged(); + } } else if (name == readonlyAttr) { bool wasReadOnly = m_isReadOnly; m_isReadOnly = !value.isNull(); - if (wasReadOnly != m_isReadOnly) { - setNeedsWillValidateCheck(); - setNeedsStyleRecalc(); - if (renderer() && renderer()->style().hasAppearance()) - renderer()->theme().stateChanged(renderer(), ReadOnlyState); - } + if (wasReadOnly != m_isReadOnly) + readOnlyAttributeChanged(); } else if (name == requiredAttr) { bool wasRequired = m_isRequired; m_isRequired = !value.isNull(); if (wasRequired != m_isRequired) requiredAttributeChanged(); - FeatureObserver::observe(&document(), FeatureObserver::RequiredAttribute); - } else if (name == autofocusAttr) { - HTMLElement::parseAttribute(name, value); - FeatureObserver::observe(&document(), FeatureObserver::AutoFocusAttribute); } else HTMLElement::parseAttribute(name, value); } void HTMLFormControlElement::disabledAttributeChanged() { + disabledStateChanged(); +} + +void HTMLFormControlElement::disabledStateChanged() +{ setNeedsWillValidateCheck(); - didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled); + invalidateStyleForSubtree(); if (renderer() && renderer()->style().hasAppearance()) - renderer()->theme().stateChanged(renderer(), EnabledState); + renderer()->theme().stateChanged(*renderer(), ControlStates::EnabledState); +} + +void HTMLFormControlElement::readOnlyAttributeChanged() +{ + setNeedsWillValidateCheck(); + invalidateStyleForSubtree(); } void HTMLFormControlElement::requiredAttributeChanged() { - setNeedsValidityCheck(); + updateValidity(); // Style recalculation is needed because style selectors may include // :required and :optional pseudo-classes. - setNeedsStyleRecalc(); + invalidateStyleForSubtree(); } static bool shouldAutofocus(HTMLFormControlElement* element) { if (!element->renderer()) return false; - if (!element->fastHasAttribute(autofocusAttr)) + if (!element->hasAttributeWithoutSynchronization(autofocusAttr)) return false; - if (!element->inDocument() || !element->document().renderView()) - return false; - if (element->document().ignoreAutofocus()) + if (!element->isConnected() || !element->document().renderView()) return false; if (element->document().isSandboxed(SandboxAutomaticFeatures)) { // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. - element->document().addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked autofocusing on a form control because the form's frame is sandboxed and the 'allow-scripts' permission is not set."); + element->document().addConsoleMessage(MessageSource::Security, MessageLevel::Error, ASCIILiteral("Blocked autofocusing on a form control because the form's frame is sandboxed and the 'allow-scripts' permission is not set.")); return false; } if (element->hasAutofocused()) @@ -188,26 +211,20 @@ static bool shouldAutofocus(HTMLFormControlElement* element) // FIXME: Should this set of hasTagName checks be replaced by a // virtual member function? - if (isHTMLInputElement(element)) - return !toHTMLInputElement(element)->isInputTypeHidden(); + if (is<HTMLInputElement>(*element)) + return !downcast<HTMLInputElement>(*element).isInputTypeHidden(); if (element->hasTagName(selectTag)) return true; if (element->hasTagName(keygenTag)) return true; if (element->hasTagName(buttonTag)) return true; - if (isHTMLTextAreaElement(element)) + if (is<HTMLTextAreaElement>(*element)) return true; return false; } -static void focusPostAttach(Node& element, unsigned) -{ - toElement(element).focus(); - element.deref(); -} - void HTMLFormControlElement::didAttachRenderers() { // The call to updateFromElement() needs to go after the call through @@ -218,34 +235,76 @@ void HTMLFormControlElement::didAttachRenderers() if (shouldAutofocus(this)) { setAutofocused(); - ref(); - queuePostAttachCallback(focusPostAttach, *this); + + RefPtr<HTMLFormControlElement> element = this; + auto* frameView = document().view(); + if (frameView && frameView->isInLayout()) { + frameView->queuePostLayoutCallback([element] { + element->focus(); + }); + } else { + Style::queuePostResolutionCallback([element] { + element->focus(); + }); + } } } -void HTMLFormControlElement::didMoveToNewDocument(Document* oldDocument) +void HTMLFormControlElement::didMoveToNewDocument(Document& oldDocument) { FormAssociatedElement::didMoveToNewDocument(oldDocument); HTMLElement::didMoveToNewDocument(oldDocument); } +static void addInvalidElementToAncestorFromInsertionPoint(const HTMLFormControlElement& element, ContainerNode* insertionPoint) +{ + if (!is<Element>(insertionPoint)) + return; + + for (auto& ancestor : lineageOfType<HTMLFieldSetElement>(downcast<Element>(*insertionPoint))) + ancestor.addInvalidDescendant(element); +} + +static void removeInvalidElementToAncestorFromInsertionPoint(const HTMLFormControlElement& element, ContainerNode* insertionPoint) +{ + if (!is<Element>(insertionPoint)) + return; + + for (auto& ancestor : lineageOfType<HTMLFieldSetElement>(downcast<Element>(*insertionPoint))) + ancestor.removeInvalidDescendant(element); +} + Node::InsertionNotificationRequest HTMLFormControlElement::insertedInto(ContainerNode& insertionPoint) { - m_ancestorDisabledState = AncestorDisabledStateUnknown; m_dataListAncestorState = Unknown; setNeedsWillValidateCheck(); + if (willValidate() && !isValidFormControlElement()) + addInvalidElementToAncestorFromInsertionPoint(*this, &insertionPoint); + if (document().hasDisabledFieldsetElement()) + setAncestorDisabled(computeIsDisabledByFieldsetAncestor()); HTMLElement::insertedInto(insertionPoint); FormAssociatedElement::insertedInto(insertionPoint); - return InsertionDone; + return InsertionShouldCallFinishedInsertingSubtree; +} + +void HTMLFormControlElement::finishedInsertingSubtree() +{ + resetFormOwner(); } void HTMLFormControlElement::removedFrom(ContainerNode& insertionPoint) { + bool wasMatchingInvalidPseudoClass = willValidate() && !isValidFormControlElement(); + m_validationMessage = nullptr; - m_ancestorDisabledState = AncestorDisabledStateUnknown; + if (m_disabledByAncestorFieldset) + setAncestorDisabled(computeIsDisabledByFieldsetAncestor()); m_dataListAncestorState = Unknown; HTMLElement::removedFrom(insertionPoint); FormAssociatedElement::removedFrom(insertionPoint); + + if (wasMatchingInvalidPseudoClass) + removeInvalidElementToAncestorFromInsertionPoint(*this, &insertionPoint); } void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed) @@ -267,19 +326,12 @@ void HTMLFormControlElement::dispatchFormControlChangeEvent() void HTMLFormControlElement::dispatchFormControlInputEvent() { setChangedSinceLastFormControlChangeEvent(true); - HTMLElement::dispatchInputEvent(); + dispatchInputEvent(); } bool HTMLFormControlElement::isDisabledFormControl() const { - if (m_disabled) - return true; - - if (m_ancestorDisabledState == AncestorDisabledStateUnknown) - updateAncestorDisabledState(); - if (m_ancestorDisabledState == AncestorDisabledStateDisabled) - return true; - return HTMLElement::isDisabledFormControl(); + return m_disabled || m_disabledByAncestorFieldset; } bool HTMLFormControlElement::isRequired() const @@ -287,18 +339,17 @@ bool HTMLFormControlElement::isRequired() const return m_isRequired; } -static void updateFromElementCallback(Node& node, unsigned) -{ - if (auto renderer = toHTMLFormControlElement(node).renderer()) - renderer->updateFromElement(); -} - void HTMLFormControlElement::didRecalcStyle(Style::Change) { // updateFromElement() can cause the selection to change, and in turn // trigger synchronous layout, so it must not be called during style recalc. - if (renderer()) - queuePostAttachCallback(updateFromElementCallback, *this); + if (renderer()) { + RefPtr<HTMLFormControlElement> element = this; + Style::queuePostResolutionCallback([element]{ + if (auto* renderer = element->renderer()) + renderer->updateFromElement(); + }); + } } bool HTMLFormControlElement::supportsFocus() const @@ -310,19 +361,18 @@ bool HTMLFormControlElement::isFocusable() const { // If there's a renderer, make sure the size isn't empty, but if there's no renderer, // it might still be focusable if it's in a canvas subtree (handled in Node::isFocusable). - if (renderer() && (!renderer()->isBox() || toRenderBox(renderer())->size().isEmpty())) + if (renderer() && (!is<RenderBox>(*renderer()) || downcast<RenderBox>(*renderer()).size().isEmpty())) return false; // HTMLElement::isFocusable handles visibility and calls suportsFocus which // will cover the disabled case. return HTMLElement::isFocusable(); } -bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const +bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent& event) const { - if (isFocusable()) - if (document().frame()) - return document().frame()->eventHandler().tabsToAllFormControls(event); - return false; + return isFocusable() + && document().frame() + && document().frame()->eventHandler().tabsToAllFormControls(event); } bool HTMLFormControlElement::isMouseFocusable() const @@ -334,13 +384,23 @@ bool HTMLFormControlElement::isMouseFocusable() const #endif } -short HTMLFormControlElement::tabIndex() const +bool HTMLFormControlElement::matchesValidPseudoClass() const +{ + return willValidate() && isValidFormControlElement(); +} + +bool HTMLFormControlElement::matchesInvalidPseudoClass() const +{ + return willValidate() && !isValidFormControlElement(); +} + +int HTMLFormControlElement::tabIndex() const { // Skip the supportsFocus check in HTMLElement. return Element::tabIndex(); } -bool HTMLFormControlElement::recalcWillValidate() const +bool HTMLFormControlElement::computeWillValidate() const { if (m_dataListAncestorState == Unknown) { for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) { @@ -359,16 +419,14 @@ bool HTMLFormControlElement::willValidate() const { if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) { m_willValidateInitialized = true; - bool newWillValidate = recalcWillValidate(); - if (m_willValidate != newWillValidate) { + bool newWillValidate = computeWillValidate(); + if (m_willValidate != newWillValidate) m_willValidate = newWillValidate; - const_cast<HTMLFormControlElement*>(this)->setNeedsValidityCheck(); - } } else { // If the following assertion fails, setNeedsWillValidateCheck() is not - // called correctly when something which changes recalcWillValidate() result + // called correctly when something which changes computeWillValidate() result // is updated. - ASSERT(m_willValidate == recalcWillValidate()); + ASSERT(m_willValidate == computeWillValidate()); } return m_willValidate; } @@ -376,13 +434,24 @@ bool HTMLFormControlElement::willValidate() const void HTMLFormControlElement::setNeedsWillValidateCheck() { // We need to recalculate willValidate immediately because willValidate change can causes style change. - bool newWillValidate = recalcWillValidate(); + bool newWillValidate = computeWillValidate(); if (m_willValidateInitialized && m_willValidate == newWillValidate) return; + + bool wasValid = m_isValid; + m_willValidateInitialized = true; m_willValidate = newWillValidate; - setNeedsValidityCheck(); - setNeedsStyleRecalc(); + + updateValidity(); + invalidateStyleForSubtree(); + + if (!m_willValidate && !wasValid) { + removeInvalidElementToAncestorFromInsertionPoint(*this, parentNode()); + if (HTMLFormElement* form = this->form()) + form->removeInvalidAssociatedFormControlIfNeeded(*this); + } + if (!m_willValidate) hideVisibleValidationMessage(); } @@ -396,7 +465,7 @@ void HTMLFormControlElement::updateVisibleValidationMessage() if (renderer() && willValidate()) message = validationMessage().stripWhiteSpace(); if (!m_validationMessage) - m_validationMessage = ValidationMessage::create(this); + m_validationMessage = std::make_unique<ValidationMessage>(this); m_validationMessage->updateValidationMessage(message); } @@ -406,35 +475,97 @@ void HTMLFormControlElement::hideVisibleValidationMessage() m_validationMessage->requestToHideMessage(); } -bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement>>* unhandledInvalidControls) +bool HTMLFormControlElement::checkValidity(Vector<RefPtr<HTMLFormControlElement>>* unhandledInvalidControls) { if (!willValidate() || isValidFormControlElement()) return true; // An event handler can deref this object. - Ref<HTMLFormControlElement> protect(*this); + Ref<HTMLFormControlElement> protectedThis(*this); Ref<Document> originalDocument(document()); bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true)); - if (needsDefaultAction && unhandledInvalidControls && inDocument() && &originalDocument.get() == &document()) + if (needsDefaultAction && unhandledInvalidControls && isConnected() && originalDocument.ptr() == &document()) unhandledInvalidControls->append(this); return false; } -bool HTMLFormControlElement::isValidFormControlElement() +bool HTMLFormControlElement::reportValidity() { - // If the following assertion fails, setNeedsValidityCheck() is not called + Vector<RefPtr<HTMLFormControlElement>> elements; + if (checkValidity(&elements)) + return true; + + if (elements.isEmpty()) + return false; + + // Needs to update layout now because we'd like to call isFocusable(), which + // has !renderer()->needsLayout() assertion. + document().updateLayoutIgnorePendingStylesheets(); + + if (isConnected() && isFocusable()) { + focusAndShowValidationMessage(); + return false; + } + + if (document().frame()) { + String message = makeString("An invalid form control with name='", name(), "' is not focusable."); + document().addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, message); + } + + return false; +} + +void HTMLFormControlElement::focusAndShowValidationMessage() +{ + // Calling focus() will scroll the element into view. + focus(); + updateVisibleValidationMessage(); +} + +inline bool HTMLFormControlElement::isValidFormControlElement() const +{ + // If the following assertion fails, updateValidity() is not called // correctly when something which changes validity is updated. - ASSERT(m_isValid == valid()); + ASSERT(m_isValid == isValid()); return m_isValid; } -void HTMLFormControlElement::setNeedsValidityCheck() +void HTMLFormControlElement::willChangeForm() +{ + if (HTMLFormElement* form = this->form()) + form->removeInvalidAssociatedFormControlIfNeeded(*this); + FormAssociatedElement::willChangeForm(); +} + +void HTMLFormControlElement::didChangeForm() { - bool newIsValid = valid(); - if (willValidate() && newIsValid != m_isValid) { + FormAssociatedElement::didChangeForm(); + if (HTMLFormElement* form = this->form()) { + if (m_willValidateInitialized && m_willValidate && !isValidFormControlElement()) + form->registerInvalidAssociatedFormControl(*this); + } +} + +void HTMLFormControlElement::updateValidity() +{ + bool willValidate = this->willValidate(); + bool wasValid = m_isValid; + + m_isValid = isValid(); + + if (willValidate && m_isValid != wasValid) { // Update style for pseudo classes such as :valid :invalid. - setNeedsStyleRecalc(); + invalidateStyleForSubtree(); + + if (!m_isValid) { + addInvalidElementToAncestorFromInsertionPoint(*this, parentNode()); + if (HTMLFormElement* form = this->form()) + form->registerInvalidAssociatedFormControl(*this); + } else { + removeInvalidElementToAncestorFromInsertionPoint(*this, parentNode()); + if (HTMLFormElement* form = this->form()) + form->removeInvalidAssociatedFormControlIfNeeded(*this); + } } - m_isValid = newIsValid; // Updates only if this control already has a validtion message. if (m_validationMessage && m_validationMessage->isVisible()) { @@ -447,7 +578,7 @@ void HTMLFormControlElement::setNeedsValidityCheck() void HTMLFormControlElement::setCustomValidity(const String& error) { FormAssociatedElement::setCustomValidity(error); - setNeedsValidityCheck(); + updateValidity(); } bool HTMLFormControlElement::validationMessageShadowTreeContains(const Node& node) const @@ -455,68 +586,69 @@ bool HTMLFormControlElement::validationMessageShadowTreeContains(const Node& nod return m_validationMessage && m_validationMessage->shadowTreeContains(node); } -void HTMLFormControlElement::dispatchBlurEvent(PassRefPtr<Element> newFocusedElement) +void HTMLFormControlElement::dispatchBlurEvent(RefPtr<Element>&& newFocusedElement) { - HTMLElement::dispatchBlurEvent(newFocusedElement); + HTMLElement::dispatchBlurEvent(WTFMove(newFocusedElement)); hideVisibleValidationMessage(); } -HTMLFormElement* HTMLFormControlElement::virtualForm() const -{ - return FormAssociatedElement::form(); -} - -bool HTMLFormControlElement::isDefaultButtonForForm() const -{ - return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this; -} - #if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE) -// FIXME: We should look to share these methods with class HTMLFormElement instead of duplicating them. -bool HTMLFormControlElement::autocorrect() const +// FIXME: We should look to share this code with class HTMLFormElement instead of duplicating the logic. + +bool HTMLFormControlElement::shouldAutocorrect() const { - const AtomicString& autocorrectValue = fastGetAttribute(autocorrectAttr); + const AtomicString& autocorrectValue = attributeWithoutSynchronization(autocorrectAttr); if (!autocorrectValue.isEmpty()) - return !equalIgnoringCase(autocorrectValue, "off"); + return !equalLettersIgnoringASCIICase(autocorrectValue, "off"); if (HTMLFormElement* form = this->form()) - return form->autocorrect(); + return form->shouldAutocorrect(); return true; } -void HTMLFormControlElement::setAutocorrect(bool autocorrect) +AutocapitalizeType HTMLFormControlElement::autocapitalizeType() const { - setAttribute(autocorrectAttr, autocorrect ? AtomicString("on", AtomicString::ConstructFromLiteral) : AtomicString("off", AtomicString::ConstructFromLiteral)); -} - -WebAutocapitalizeType HTMLFormControlElement::autocapitalizeType() const -{ - WebAutocapitalizeType type = autocapitalizeTypeForAttributeValue(fastGetAttribute(autocapitalizeAttr)); - if (type == WebAutocapitalizeTypeDefault) { + AutocapitalizeType type = HTMLElement::autocapitalizeType(); + if (type == AutocapitalizeTypeDefault) { if (HTMLFormElement* form = this->form()) return form->autocapitalizeType(); } return type; } -const AtomicString& HTMLFormControlElement::autocapitalize() const +#endif + +HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node) +{ + for (; node; node = node->parentNode()) { + if (is<HTMLFormControlElement>(*node)) + return downcast<HTMLFormControlElement>(node); + } + return nullptr; +} + +String HTMLFormControlElement::autocomplete() const { - return stringForAutocapitalizeType(autocapitalizeType()); + return autofillData().idlExposedValue; } -void HTMLFormControlElement::setAutocapitalize(const AtomicString& value) +void HTMLFormControlElement::setAutocomplete(const String& value) { - setAttribute(autocapitalizeAttr, value); + setAttributeWithoutSynchronization(autocompleteAttr, value); } -#endif -HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node) +AutofillMantle HTMLFormControlElement::autofillMantle() const { - for (; node; node = node->parentNode()) { - if (node->isElementNode() && toElement(node)->isFormControlElement()) - return toHTMLFormControlElement(node); - } - return 0; + return is<HTMLInputElement>(*this) && downcast<HTMLInputElement>(this)->isInputTypeHidden() ? AutofillMantle::Anchor : AutofillMantle::Expectation; +} + +AutofillData HTMLFormControlElement::autofillData() const +{ + // FIXME: We could cache the AutofillData if we we had an efficient way to invalidate the cache when + // the autofill mantle changed (due to a type change on an <input> element) or the element's form + // owner's autocomplete attribute changed or the form owner itself changed. + + return AutofillData::createFromHTMLFormControlElement(*this); } } // namespace Webcore |