diff options
Diffstat (limited to 'Source/WebCore/html/FormAssociatedElement.cpp')
-rw-r--r-- | Source/WebCore/html/FormAssociatedElement.cpp | 83 |
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() |