Rename Node::childNodeCount() to countChildNodes() and avoid inefficient uses
[WebKit-https.git] / Source / WebCore / dom / ContainerNode.h
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, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #ifndef ContainerNode_h
25 #define ContainerNode_h
26
27 #include "ExceptionCodePlaceholder.h"
28 #include "Node.h"
29
30 #include <wtf/OwnPtr.h>
31 #include <wtf/Vector.h>
32
33 namespace WebCore {
34
35 class FloatPoint;
36 class QualifiedName;
37 class RenderElement;
38
39 typedef void (*NodeCallback)(Node&, unsigned);
40
41 namespace Private { 
42     template<class GenericNode, class GenericNodeContainer>
43     void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&);
44 };
45
46 class NoEventDispatchAssertion {
47 public:
48     NoEventDispatchAssertion()
49     {
50 #ifndef NDEBUG
51         if (!isMainThread())
52             return;
53         s_count++;
54 #endif
55     }
56
57     ~NoEventDispatchAssertion()
58     {
59 #ifndef NDEBUG
60         if (!isMainThread())
61             return;
62         ASSERT(s_count);
63         s_count--;
64 #endif
65     }
66
67 #ifndef NDEBUG
68     static bool isEventDispatchForbidden()
69     {
70         if (!isMainThread())
71             return false;
72         return s_count;
73     }
74 #endif
75
76 private:
77 #ifndef NDEBUG
78     static unsigned s_count;
79 #endif
80 };
81
82 class ContainerNode : public Node {
83 public:
84     virtual ~ContainerNode();
85
86     Node* firstChild() const { return m_firstChild; }
87     static ptrdiff_t firstChildMemoryOffset() { return OBJECT_OFFSETOF(ContainerNode, m_firstChild); }
88     Node* lastChild() const { return m_lastChild; }
89     bool hasChildNodes() const { return m_firstChild; }
90     bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); }
91
92     bool directChildNeedsStyleRecalc() const { return getFlag(DirectChildNeedsStyleRecalcFlag); }
93     void setDirectChildNeedsStyleRecalc() { setFlag(DirectChildNeedsStyleRecalcFlag); }
94
95     WEBCORE_EXPORT unsigned countChildNodes() const;
96     WEBCORE_EXPORT Node* childNode(unsigned index) const;
97
98     bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& = ASSERT_NO_EXCEPTION);
99     bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& = ASSERT_NO_EXCEPTION);
100     WEBCORE_EXPORT bool removeChild(Node* child, ExceptionCode& = ASSERT_NO_EXCEPTION);
101     WEBCORE_EXPORT bool appendChild(PassRefPtr<Node> newChild, ExceptionCode& = ASSERT_NO_EXCEPTION);
102
103     // These methods are only used during parsing.
104     // They don't send DOM mutation events or handle reparenting.
105     // However, arbitrary code may be run by beforeload handlers.
106     void parserAppendChild(PassRefPtr<Node>);
107     void parserRemoveChild(Node&);
108     void parserInsertBefore(PassRefPtr<Node> newChild, Node* refChild);
109
110     void removeChildren();
111     void takeAllChildrenFrom(ContainerNode*);
112
113     void cloneChildNodes(ContainerNode* clone);
114
115     virtual LayoutRect boundingBox() const override;
116
117     enum ChildChangeType { ElementInserted, ElementRemoved, TextInserted, TextRemoved, TextChanged, AllChildrenRemoved, NonContentsChildChanged };
118     enum ChildChangeSource { ChildChangeSourceParser, ChildChangeSourceAPI };
119     struct ChildChange {
120         ChildChangeType type;
121         Element* previousSiblingElement;
122         Element* nextSiblingElement;
123         ChildChangeSource source;
124     };
125     virtual void childrenChanged(const ChildChange&);
126
127     void disconnectDescendantFrames();
128
129     using Node::setAttributeEventListener;
130     void setAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& value);
131
132     RenderElement* renderer() const;
133
134     Element* querySelector(const String& selectors, ExceptionCode&);
135     RefPtr<NodeList> querySelectorAll(const String& selectors, ExceptionCode&);
136
137     PassRefPtr<NodeList> getElementsByTagName(const AtomicString&);
138     PassRefPtr<NodeList> getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName);
139     PassRefPtr<NodeList> getElementsByName(const String& elementName);
140     PassRefPtr<NodeList> getElementsByClassName(const String& classNames);
141     PassRefPtr<RadioNodeList> radioNodeList(const AtomicString&);
142
143 protected:
144     explicit ContainerNode(Document&, ConstructionType = CreateContainer);
145
146     template<class GenericNode, class GenericNodeContainer>
147     friend void appendChildToContainer(GenericNode* child, GenericNodeContainer&);
148
149     template<class GenericNode, class GenericNodeContainer>
150     friend void Private::addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&);
151
152     void removeDetachedChildren();
153     void setFirstChild(Node* child) { m_firstChild = child; }
154     void setLastChild(Node* child) { m_lastChild = child; }
155
156 private:
157     void removeBetween(Node* previousChild, Node* nextChild, Node& oldChild);
158     void insertBeforeCommon(Node& nextChild, Node& oldChild);
159
160     bool getUpperLeftCorner(FloatPoint&) const;
161     bool getLowerRightCorner(FloatPoint&) const;
162
163     void notifyChildInserted(Node& child, ChildChangeSource);
164     void notifyChildRemoved(Node& child, Node* previousSibling, Node* nextSibling, ChildChangeSource);
165
166     void updateTreeAfterInsertion(Node& child);
167
168     bool isContainerNode() const = delete;
169
170     void willRemoveChild(Node& child);
171
172     Node* m_firstChild;
173     Node* m_lastChild;
174 };
175
176 inline bool isContainerNode(const Node& node) { return node.isContainerNode(); }
177 void isContainerNode(const ContainerNode&); // Catch unnecessary runtime check of type known at compile time.
178
179 NODE_TYPE_CASTS(ContainerNode)
180
181 inline ContainerNode::ContainerNode(Document& document, ConstructionType type)
182     : Node(document, type)
183     , m_firstChild(0)
184     , m_lastChild(0)
185 {
186 }
187
188 inline unsigned Node::countChildNodes() const
189 {
190     if (!isContainerNode())
191         return 0;
192     return toContainerNode(this)->countChildNodes();
193 }
194
195 inline Node* Node::childNode(unsigned index) const
196 {
197     if (!isContainerNode())
198         return 0;
199     return toContainerNode(this)->childNode(index);
200 }
201
202 inline Node* Node::firstChild() const
203 {
204     if (!isContainerNode())
205         return 0;
206     return toContainerNode(this)->firstChild();
207 }
208
209 inline Node* Node::lastChild() const
210 {
211     if (!isContainerNode())
212         return 0;
213     return toContainerNode(this)->lastChild();
214 }
215
216 inline Node* Node::highestAncestor() const
217 {
218     Node* node = const_cast<Node*>(this);
219     Node* highest = node;
220     for (; node; node = node->parentNode())
221         highest = node;
222     return highest;
223 }
224
225 inline bool Node::needsNodeRenderingTraversalSlowPath() const
226 {
227     if (getFlag(NeedsNodeRenderingTraversalSlowPathFlag))
228         return true;
229     ContainerNode* parent = parentOrShadowHostNode();
230     return parent && parent->getFlag(NeedsNodeRenderingTraversalSlowPathFlag);
231 }
232
233 inline bool Node::isTreeScope() const
234 {
235     return &treeScope().rootNode() == this;
236 }
237
238 // This constant controls how much buffer is initially allocated
239 // for a Node Vector that is used to store child Nodes of a given Node.
240 // FIXME: Optimize the value.
241 const int initialNodeVectorSize = 11;
242 typedef Vector<Ref<Node>, initialNodeVectorSize> NodeVector;
243
244 inline void getChildNodes(Node& node, NodeVector& nodes)
245 {
246     ASSERT(nodes.isEmpty());
247     for (Node* child = node.firstChild(); child; child = child->nextSibling())
248         nodes.append(*child);
249 }
250
251 class ChildNodesLazySnapshot {
252     WTF_MAKE_NONCOPYABLE(ChildNodesLazySnapshot);
253     WTF_MAKE_FAST_ALLOCATED;
254 public:
255     explicit ChildNodesLazySnapshot(Node& parentNode)
256         : m_currentNode(parentNode.firstChild())
257         , m_currentIndex(0)
258         , m_hasSnapshot(false)
259     {
260         m_nextSnapshot = latestSnapshot;
261         latestSnapshot = this;
262     }
263
264     ALWAYS_INLINE ~ChildNodesLazySnapshot()
265     {
266         latestSnapshot = m_nextSnapshot;
267     }
268
269     // Returns 0 if there is no next Node.
270     PassRefPtr<Node> nextNode()
271     {
272         if (LIKELY(!hasSnapshot())) {
273             RefPtr<Node> node = m_currentNode.release();
274             if (node)
275                 m_currentNode = node->nextSibling();
276             return node.release();
277         }
278         if (m_currentIndex >= m_snapshot.size())
279             return 0;
280         return m_snapshot[m_currentIndex++];
281     }
282
283     void takeSnapshot()
284     {
285         if (hasSnapshot())
286             return;
287         m_hasSnapshot = true;
288         Node* node = m_currentNode.get();
289         while (node) {
290             m_snapshot.append(node);
291             node = node->nextSibling();
292         }
293     }
294
295     ChildNodesLazySnapshot* nextSnapshot() { return m_nextSnapshot; }
296     bool hasSnapshot() { return m_hasSnapshot; }
297
298     static void takeChildNodesLazySnapshot()
299     {
300         ChildNodesLazySnapshot* snapshot = latestSnapshot;
301         while (snapshot && !snapshot->hasSnapshot()) {
302             snapshot->takeSnapshot();
303             snapshot = snapshot->nextSnapshot();
304         }
305     }
306
307 private:
308     static ChildNodesLazySnapshot* latestSnapshot;
309
310     RefPtr<Node> m_currentNode;
311     unsigned m_currentIndex;
312     bool m_hasSnapshot;
313     Vector<RefPtr<Node>> m_snapshot; // Lazily instantiated.
314     ChildNodesLazySnapshot* m_nextSnapshot;
315 };
316
317 } // namespace WebCore
318
319 #endif // ContainerNode_h