summaryrefslogtreecommitdiff
path: root/Source/WebCore/html/FormAssociatedElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/html/FormAssociatedElement.cpp')
-rw-r--r--Source/WebCore/html/FormAssociatedElement.cpp83
1 files changed, 55 insertions, 28 deletions
diff --git a/Source/WebCore/html/FormAssociatedElement.cpp b/Source/WebCore/html/FormAssociatedElement.cpp
index 44ee0507a..0cbe029b3 100644
--- a/Source/WebCore/html/FormAssociatedElement.cpp
+++ b/Source/WebCore/html/FormAssociatedElement.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-2016 Apple Inc. All rights reserved.
* (C) 2006 Alexey Proskuryakov (ap@nypop.com)
*
* This library is free software; you can redistribute it and/or
@@ -44,13 +44,14 @@ public:
FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement&);
private:
- virtual void idTargetChanged() override;
+ void idTargetChanged() override;
FormAssociatedElement& m_element;
};
-FormAssociatedElement::FormAssociatedElement()
+FormAssociatedElement::FormAssociatedElement(HTMLFormElement* form)
: m_form(nullptr)
+ , m_formSetByParser(form)
{
}
@@ -59,47 +60,67 @@ FormAssociatedElement::~FormAssociatedElement()
setForm(nullptr);
}
-void FormAssociatedElement::didMoveToNewDocument(Document* oldDocument)
+void FormAssociatedElement::didMoveToNewDocument(Document&)
{
HTMLElement& element = asHTMLElement();
- if (oldDocument && element.fastHasAttribute(formAttr))
+ if (element.hasAttributeWithoutSynchronization(formAttr) && element.isConnected())
resetFormAttributeTargetObserver();
}
void FormAssociatedElement::insertedInto(ContainerNode& insertionPoint)
{
- resetFormOwner();
- if (!insertionPoint.inDocument())
+ HTMLElement& element = asHTMLElement();
+ if (m_formSetByParser) {
+ // The form could have been removed by a script during parsing.
+ if (m_formSetByParser->isConnected())
+ setForm(m_formSetByParser);
+ m_formSetByParser = nullptr;
+ }
+
+ if (m_form && element.rootElement() != m_form->rootElement())
+ setForm(nullptr);
+
+ if (!insertionPoint.isConnected())
return;
- HTMLElement& element = asHTMLElement();
- if (element.fastHasAttribute(formAttr))
+ if (element.hasAttributeWithoutSynchronization(formAttr))
resetFormAttributeTargetObserver();
}
+// Compute the highest ancestor instead of calling Node::rootNode in removedFrom / formRemovedFromTree
+// since isConnected flag on some form associated elements may not have been updated yet.
+static Node* computeRootNode(Node& node)
+{
+ Node* current = &node;
+ Node* parent = current;
+ while ((current = current->parentNode()))
+ parent = current;
+ return parent;
+}
+
void FormAssociatedElement::removedFrom(ContainerNode& insertionPoint)
{
HTMLElement& element = asHTMLElement();
- if (insertionPoint.inDocument() && element.fastHasAttribute(formAttr))
+ if (insertionPoint.isConnected() && element.hasAttributeWithoutSynchronization(formAttr))
m_formAttributeTargetObserver = nullptr;
// If the form and element are both in the same tree, preserve the connection to the form.
// Otherwise, null out our form and remove ourselves from the form's list of elements.
- if (m_form && element.highestAncestor() != m_form->highestAncestor())
- setForm(0);
+ if (m_form && computeRootNode(element) != computeRootNode(*m_form))
+ setForm(nullptr);
}
HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* element, HTMLFormElement* currentAssociatedForm)
{
- const AtomicString& formId(element->fastGetAttribute(formAttr));
- if (!formId.isNull() && element->inDocument()) {
+ const AtomicString& formId(element->attributeWithoutSynchronization(formAttr));
+ if (!formId.isNull() && element->isConnected()) {
// The HTML5 spec says that the element should be associated with
// the first element in the document to have an ID that equal to
// the value of form attribute, so we put the result of
// treeScope().getElementById() over the given element.
- HTMLFormElement* newForm = 0;
+ HTMLFormElement* newForm = nullptr;
Element* newFormCandidate = element->treeScope().getElementById(formId);
- if (newFormCandidate && isHTMLFormElement(newFormCandidate))
- newForm = toHTMLFormElement(newFormCandidate);
+ if (is<HTMLFormElement>(newFormCandidate))
+ newForm = downcast<HTMLFormElement>(newFormCandidate);
return newForm;
}
@@ -112,8 +133,8 @@ HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* el
void FormAssociatedElement::formRemovedFromTree(const Node* formRoot)
{
ASSERT(m_form);
- if (asHTMLElement().highestAncestor() != formRoot)
- setForm(0);
+ if (computeRootNode(asHTMLElement()) != formRoot)
+ setForm(nullptr);
}
void FormAssociatedElement::setForm(HTMLFormElement* newForm)
@@ -143,7 +164,7 @@ void FormAssociatedElement::formWillBeDestroyed()
if (!m_form)
return;
willChangeForm();
- m_form = 0;
+ m_form = nullptr;
didChangeForm();
}
@@ -152,30 +173,30 @@ void FormAssociatedElement::resetFormOwner()
HTMLFormElement* originalForm = m_form;
setForm(findAssociatedForm(&asHTMLElement(), m_form));
HTMLElement& element = asHTMLElement();
- if (m_form && m_form != originalForm && m_form->inDocument())
+ if (m_form && m_form != originalForm && m_form->isConnected())
element.document().didAssociateFormControl(&element);
}
void FormAssociatedElement::formAttributeChanged()
{
HTMLElement& element = asHTMLElement();
- if (!element.fastHasAttribute(formAttr)) {
+ if (!element.hasAttributeWithoutSynchronization(formAttr)) {
// The form attribute removed. We need to reset form owner here.
HTMLFormElement* originalForm = m_form;
setForm(HTMLFormElement::findClosestFormAncestor(element));
- if (m_form && m_form != originalForm && m_form->inDocument())
+ if (m_form && m_form != originalForm && m_form->isConnected())
element.document().didAssociateFormControl(&element);
m_formAttributeTargetObserver = nullptr;
} else {
resetFormOwner();
- if (element.inDocument())
+ if (element.isConnected())
resetFormAttributeTargetObserver();
}
}
bool FormAssociatedElement::customError() const
{
- return asHTMLElement().willValidate() && !m_customValidationMessage.isEmpty();
+ return willValidate() && !m_customValidationMessage.isEmpty();
}
bool FormAssociatedElement::hasBadInput() const
@@ -203,6 +224,11 @@ bool FormAssociatedElement::stepMismatch() const
return false;
}
+bool FormAssociatedElement::tooShort() const
+{
+ return false;
+}
+
bool FormAssociatedElement::tooLong() const
{
return false;
@@ -213,10 +239,10 @@ bool FormAssociatedElement::typeMismatch() const
return false;
}
-bool FormAssociatedElement::valid() const
+bool FormAssociatedElement::isValid() const
{
bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
- || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError();
+ || tooShort() || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError();
return !someError;
}
@@ -242,7 +268,8 @@ void FormAssociatedElement::setCustomValidity(const String& error)
void FormAssociatedElement::resetFormAttributeTargetObserver()
{
- m_formAttributeTargetObserver = std::make_unique<FormAttributeTargetObserver>(asHTMLElement().fastGetAttribute(formAttr), *this);
+ ASSERT_WITH_SECURITY_IMPLICATION(asHTMLElement().isConnected());
+ m_formAttributeTargetObserver = std::make_unique<FormAttributeTargetObserver>(asHTMLElement().attributeWithoutSynchronization(formAttr), *this);
}
void FormAssociatedElement::formAttributeTargetChanged()