Have is<>(T*) function do a null check on the pointer argument
[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 HTMLFieldSetElement::~HTMLFieldSetElement()
48 {
49     if (fastHasAttribute(disabledAttr))
50         document().removeDisabledFieldsetElement();
51 }
52
53 PassRefPtr<HTMLFieldSetElement> HTMLFieldSetElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form)
54 {
55     return adoptRef(new HTMLFieldSetElement(tagName, document, form));
56 }
57
58 static void updateFromControlElementsAncestorDisabledStateUnder(HTMLElement& startNode, bool isDisabled)
59 {
60     HTMLFormControlElement* control;
61     if (is<HTMLFormControlElement>(startNode))
62         control = &downcast<HTMLFormControlElement>(startNode);
63     else
64         control = Traversal<HTMLFormControlElement>::firstWithin(&startNode);
65     while (control) {
66         control->setAncestorDisabled(isDisabled);
67         // Don't call setAncestorDisabled(false) on form contorls inside disabled fieldsets.
68         if (is<HTMLFieldSetElement>(*control) && control->fastHasAttribute(disabledAttr))
69             control = Traversal<HTMLFormControlElement>::nextSkippingChildren(control, &startNode);
70         else
71             control = Traversal<HTMLFormControlElement>::next(control, &startNode);
72     }
73 }
74
75 void HTMLFieldSetElement::disabledAttributeChanged()
76 {
77     if (fastHasAttribute(disabledAttr))
78         document().addDisabledFieldsetElement();
79     else
80         document().removeDisabledFieldsetElement();
81
82     HTMLFormControlElement::disabledAttributeChanged();
83 }
84
85 void HTMLFieldSetElement::disabledStateChanged()
86 {
87     // This element must be updated before the style of nodes in its subtree gets recalculated.
88     HTMLFormControlElement::disabledStateChanged();
89
90     if (disabledByAncestorFieldset())
91         return;
92
93     bool thisFieldsetIsDisabled = fastHasAttribute(disabledAttr);
94     bool hasSeenFirstLegendElement = false;
95     for (HTMLElement* control = Traversal<HTMLElement>::firstChild(this); control; control = Traversal<HTMLElement>::nextSibling(control)) {
96         if (!hasSeenFirstLegendElement && is<HTMLLegendElement>(*control)) {
97             hasSeenFirstLegendElement = true;
98             updateFromControlElementsAncestorDisabledStateUnder(*control, false /* isDisabled */);
99             continue;
100         }
101         updateFromControlElementsAncestorDisabledStateUnder(*control, thisFieldsetIsDisabled);
102     }
103 }
104
105 void HTMLFieldSetElement::childrenChanged(const ChildChange& change)
106 {
107     HTMLFormControlElement::childrenChanged(change);
108     if (!fastHasAttribute(disabledAttr))
109         return;
110
111     HTMLLegendElement* legend = Traversal<HTMLLegendElement>::firstChild(this);
112     if (!legend)
113         return;
114
115     // We only care about the first legend element (in which form contorls are not disabled by this element) changing here.
116     updateFromControlElementsAncestorDisabledStateUnder(*legend, false /* isDisabled */);
117     while ((legend = Traversal<HTMLLegendElement>::nextSibling(legend)))
118         updateFromControlElementsAncestorDisabledStateUnder(*legend, true);
119 }
120
121 void HTMLFieldSetElement::didMoveToNewDocument(Document* oldDocument)
122 {
123     HTMLFormControlElement::didMoveToNewDocument(oldDocument);
124     if (fastHasAttribute(disabledAttr)) {
125         if (oldDocument)
126             oldDocument->removeDisabledFieldsetElement();
127         document().addDisabledFieldsetElement();
128     }
129 }
130
131 bool HTMLFieldSetElement::supportsFocus() const
132 {
133     return HTMLElement::supportsFocus();
134 }
135
136 const AtomicString& HTMLFieldSetElement::formControlType() const
137 {
138     DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, fieldset, ("fieldset", AtomicString::ConstructFromLiteral));
139     return fieldset;
140 }
141
142 RenderPtr<RenderElement> HTMLFieldSetElement::createElementRenderer(PassRef<RenderStyle> style)
143 {
144     return createRenderer<RenderFieldset>(*this, WTF::move(style));
145 }
146
147 HTMLLegendElement* HTMLFieldSetElement::legend() const
148 {
149     return const_cast<HTMLLegendElement*>(childrenOfType<HTMLLegendElement>(*this).first());
150 }
151
152 PassRefPtr<HTMLCollection> HTMLFieldSetElement::elements()
153 {
154     return ensureCachedHTMLCollection(FormControls);
155 }
156
157 void HTMLFieldSetElement::refreshElementsIfNeeded() const
158 {
159     uint64_t documentVersion = document().domTreeVersion();
160     if (m_documentVersion == documentVersion)
161         return;
162
163     m_documentVersion = documentVersion;
164
165     m_associatedElements.clear();
166
167     for (auto& element : descendantsOfType<Element>(const_cast<HTMLFieldSetElement&>(*this))) {
168         if (element.hasTagName(objectTag))
169             m_associatedElements.append(&downcast<HTMLObjectElement>(element));
170         else if (is<HTMLFormControlElement>(element))
171             m_associatedElements.append(&downcast<HTMLFormControlElement>(element));
172     }
173 }
174
175 const Vector<FormAssociatedElement*>& HTMLFieldSetElement::associatedElements() const
176 {
177     refreshElementsIfNeeded();
178     return m_associatedElements;
179 }
180
181 unsigned HTMLFieldSetElement::length() const
182 {
183     refreshElementsIfNeeded();
184     unsigned length = 0;
185     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
186         if (m_associatedElements[i]->isEnumeratable())
187             ++length;
188     }
189     return length;
190 }
191
192 } // namespace