66fe923526f06b3e97053887f29811fb6ba13603
[WebKit-https.git] / Source / WebCore / html / HTMLFieldSetElement.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004, 2005, 2006, 2010 Apple Inc. All rights reserved.
6  *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "config.h"
26 #include "HTMLFieldSetElement.h"
27
28 #include "ElementIterator.h"
29 #include "HTMLCollection.h"
30 #include "HTMLLegendElement.h"
31 #include "HTMLNames.h"
32 #include "HTMLObjectElement.h"
33 #include "RenderFieldset.h"
34 #include <wtf/StdLibExtras.h>
35
36 namespace WebCore {
37
38 using namespace HTMLNames;
39
40 inline HTMLFieldSetElement::HTMLFieldSetElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
41     : HTMLFormControlElement(tagName, document, form)
42     , m_documentVersion(0)
43 {
44     ASSERT(hasTagName(fieldsetTag));
45 }
46
47 PassRefPtr<HTMLFieldSetElement> HTMLFieldSetElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
48 {
49     return adoptRef(new HTMLFieldSetElement(tagName, document, form));
50 }
51
52 void HTMLFieldSetElement::invalidateDisabledStateUnder(Element* base)
53 {
54     auto formControlDescendants = descendantsOfType<HTMLFormControlElement>(base);
55     for (auto control = formControlDescendants.begin(), end = formControlDescendants.end(); control != end; ++control)
56         control->ancestorDisabledStateWasChanged();
57 }
58
59 void HTMLFieldSetElement::disabledAttributeChanged()
60 {
61     // This element must be updated before the style of nodes in its subtree gets recalculated.
62     HTMLFormControlElement::disabledAttributeChanged();
63     invalidateDisabledStateUnder(this);
64 }
65
66 void HTMLFieldSetElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
67 {
68     HTMLFormControlElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
69
70     auto legendChildren = childrenOfType<HTMLLegendElement>(this);
71     for (auto legend = legendChildren.begin(), end = legendChildren.end(); legend != end; ++legend)
72         invalidateDisabledStateUnder(&*legend);
73 }
74
75 bool HTMLFieldSetElement::supportsFocus() const
76 {
77     return HTMLElement::supportsFocus();
78 }
79
80 const AtomicString& HTMLFieldSetElement::formControlType() const
81 {
82     DEFINE_STATIC_LOCAL(const AtomicString, fieldset, ("fieldset", AtomicString::ConstructFromLiteral));
83     return fieldset;
84 }
85
86 RenderObject* HTMLFieldSetElement::createRenderer(RenderArena* arena, RenderStyle*)
87 {
88     return new (arena) RenderFieldset(this);
89 }
90
91 const HTMLLegendElement* HTMLFieldSetElement::legend() const
92 {
93     auto legendDescendants = descendantsOfType<HTMLLegendElement>(this);
94     auto firstLegend = legendDescendants.begin();
95     if (firstLegend != legendDescendants.end())
96         return &*firstLegend;
97     return nullptr;
98 }
99
100 PassRefPtr<HTMLCollection> HTMLFieldSetElement::elements()
101 {
102     return ensureCachedHTMLCollection(FormControls);
103 }
104
105 void HTMLFieldSetElement::refreshElementsIfNeeded() const
106 {
107     uint64_t docVersion = document().domTreeVersion();
108     if (m_documentVersion == docVersion)
109         return;
110
111     m_documentVersion = docVersion;
112
113     m_associatedElements.clear();
114
115     for (Element* element = ElementTraversal::firstWithin(this); element; element = ElementTraversal::next(element, this)) {
116         if (element->hasTagName(objectTag)) {
117             m_associatedElements.append(static_cast<HTMLObjectElement*>(element));
118             continue;
119         }
120
121         if (!element->isFormControlElement())
122             continue;
123
124         m_associatedElements.append(static_cast<HTMLFormControlElement*>(element));
125     }
126 }
127
128 const Vector<FormAssociatedElement*>& HTMLFieldSetElement::associatedElements() const
129 {
130     refreshElementsIfNeeded();
131     return m_associatedElements;
132 }
133
134 unsigned HTMLFieldSetElement::length() const
135 {
136     refreshElementsIfNeeded();
137     unsigned len = 0;
138     for (unsigned i = 0; i < m_associatedElements.size(); ++i)
139         if (m_associatedElements[i]->isEnumeratable())
140             ++len;
141     return len;
142 }
143
144 } // namespace