summaryrefslogtreecommitdiff
path: root/Source/WebCore/html/HTMLFormControlElement.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/html/HTMLFormControlElement.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/html/HTMLFormControlElement.cpp')
-rw-r--r--Source/WebCore/html/HTMLFormControlElement.cpp426
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