Node.appendChild(null) / replaceChild(null, null) / removeChild(null) / insertBefore...
[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-2015 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 "CollectionType.h"
28 #include "ExceptionCodePlaceholder.h"
29 #include "Node.h"
30
31 namespace WebCore {
32
33 class HTMLCollection;
34 class NodeList;
35 class NodeOrString;
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 #if !ASSERT_DISABLED
51         if (!isMainThread())
52             return;
53         ++s_count;
54 #endif
55     }
56
57     NoEventDispatchAssertion(const NoEventDispatchAssertion&)
58         : NoEventDispatchAssertion()
59     {
60     }
61
62     ~NoEventDispatchAssertion()
63     {
64 #if !ASSERT_DISABLED
65         if (!isMainThread())
66             return;
67         ASSERT(s_count);
68         s_count--;
69 #endif
70     }
71
72     static bool isEventDispatchForbidden()
73     {
74 #if ASSERT_DISABLED
75         return false;
76 #else
77         return isMainThread() && s_count;
78 #endif
79     }
80
81 #if !ASSERT_DISABLED
82
83 private:
84     WEBCORE_EXPORT static unsigned s_count;
85
86 #endif
87 };
88
89 class ContainerNode : public Node {
90 public:
91     virtual ~ContainerNode();
92
93     Node* firstChild() const { return m_firstChild; }
94     static ptrdiff_t firstChildMemoryOffset() { return OBJECT_OFFSETOF(ContainerNode, m_firstChild); }
95     Node* lastChild() const { return m_lastChild; }
96     bool hasChildNodes() const { return m_firstChild; }
97     bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); }
98
99     bool directChildNeedsStyleRecalc() const { return getFlag(DirectChildNeedsStyleRecalcFlag); }
100     void setDirectChildNeedsStyleRecalc() { setFlag(DirectChildNeedsStyleRecalcFlag); }
101
102     WEBCORE_EXPORT unsigned countChildNodes() const;
103     WEBCORE_EXPORT Node* traverseToChildAt(unsigned) const;
104
105     bool insertBefore(Ref<Node>&& newChild, Node* refChild, ExceptionCode& = ASSERT_NO_EXCEPTION);
106     bool replaceChild(Ref<Node>&& newChild, Node& oldChild, ExceptionCode& = ASSERT_NO_EXCEPTION);
107     WEBCORE_EXPORT bool removeChild(Node& child, ExceptionCode& = ASSERT_NO_EXCEPTION);
108     WEBCORE_EXPORT bool appendChild(Ref<Node>&& newChild, ExceptionCode& = ASSERT_NO_EXCEPTION);
109
110     // These methods are only used during parsing.
111     // They don't send DOM mutation events or handle reparenting.
112     // However, arbitrary code may be run by beforeload handlers.
113     void parserAppendChild(PassRefPtr<Node>);
114     void parserRemoveChild(Node&);
115     void parserInsertBefore(PassRefPtr<Node> newChild, Node* refChild);
116
117     void removeChildren();
118     void takeAllChildrenFrom(ContainerNode*);
119
120     void cloneChildNodes(ContainerNode& clone);
121
122     enum ChildChangeType { ElementInserted, ElementRemoved, TextInserted, TextRemoved, TextChanged, AllChildrenRemoved, NonContentsChildChanged };
123     enum ChildChangeSource { ChildChangeSourceParser, ChildChangeSourceAPI };
124     struct ChildChange {
125         ChildChangeType type;
126         Element* previousSiblingElement;
127         Element* nextSiblingElement;
128         ChildChangeSource source;
129     };
130     virtual void childrenChanged(const ChildChange&);
131
132     void disconnectDescendantFrames();
133
134     using Node::setAttributeEventListener;
135     void setAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& value);
136
137     RenderElement* renderer() const;
138
139     // Return a bounding box in absolute coordinates enclosing this node and all its descendants.
140     // This gives the area within which events may get handled by a hander registered on this node.
141     virtual LayoutRect absoluteEventHandlerBounds(bool& /* includesFixedPositionElements */) { return LayoutRect(); }
142
143     Element* querySelector(const String& selectors, ExceptionCode&);
144     RefPtr<NodeList> querySelectorAll(const String& selectors, ExceptionCode&);
145
146     Ref<HTMLCollection> getElementsByTagName(const AtomicString&);
147     RefPtr<NodeList> getElementsByTagNameForObjC(const AtomicString&);
148     Ref<HTMLCollection> getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName);
149     RefPtr<NodeList> getElementsByTagNameNSForObjC(const AtomicString& namespaceURI, const AtomicString& localName);
150     Ref<NodeList> getElementsByName(const String& elementName);
151     Ref<HTMLCollection> getElementsByClassName(const AtomicString& classNames);
152     Ref<NodeList> getElementsByClassNameForObjC(const AtomicString& classNames);
153     Ref<RadioNodeList> radioNodeList(const AtomicString&);
154
155     // From the ParentNode interface - https://dom.spec.whatwg.org/#interface-parentnode
156     Ref<HTMLCollection> children();
157     Element* firstElementChild() const;
158     Element* lastElementChild() const;
159     unsigned childElementCount() const;
160     void append(Vector<NodeOrString>&&, ExceptionCode&);
161     void prepend(Vector<NodeOrString>&&, ExceptionCode&);
162
163 protected:
164     explicit ContainerNode(Document&, ConstructionType = CreateContainer);
165
166     template<class GenericNode, class GenericNodeContainer>
167     friend void appendChildToContainer(GenericNode* child, GenericNodeContainer&);
168
169     template<class GenericNode, class GenericNodeContainer>
170     friend void Private::addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&);
171
172     void removeDetachedChildren();
173     void setFirstChild(Node* child) { m_firstChild = child; }
174     void setLastChild(Node* child) { m_lastChild = child; }
175
176     HTMLCollection* cachedHTMLCollection(CollectionType);
177
178 private:
179     void removeBetween(Node* previousChild, Node* nextChild, Node& oldChild);
180     void insertBeforeCommon(Node& nextChild, Node& oldChild);
181
182     void notifyChildInserted(Node& child, ChildChangeSource);
183     void notifyChildRemoved(Node& child, Node* previousSibling, Node* nextSibling, ChildChangeSource);
184
185     void updateTreeAfterInsertion(Node& child);
186
187     bool isContainerNode() const = delete;
188
189     void willRemoveChild(Node& child);
190
191     Node* m_firstChild;
192     Node* m_lastChild;
193 };
194
195 inline ContainerNode::ContainerNode(Document& document, ConstructionType type)
196     : Node(document, type)
197     , m_firstChild(0)
198     , m_lastChild(0)
199 {
200 }
201
202 inline unsigned Node::countChildNodes() const
203 {
204     if (!is<ContainerNode>(*this))
205         return 0;
206     return downcast<ContainerNode>(*this).countChildNodes();
207 }
208
209 inline Node* Node::traverseToChildAt(unsigned index) const
210 {
211     if (!is<ContainerNode>(*this))
212         return nullptr;
213     return downcast<ContainerNode>(*this).traverseToChildAt(index);
214 }
215
216 inline Node* Node::firstChild() const
217 {
218     if (!is<ContainerNode>(*this))
219         return nullptr;
220     return downcast<ContainerNode>(*this).firstChild();
221 }
222
223 inline Node* Node::lastChild() const
224 {
225     if (!is<ContainerNode>(*this))
226         return nullptr;
227     return downcast<ContainerNode>(*this).lastChild();
228 }
229
230 inline Node* Node::highestAncestor() const
231 {
232     Node* node = const_cast<Node*>(this);
233     Node* highest = node;
234     for (; node; node = node->parentNode())
235         highest = node;
236     return highest;
237 }
238
239 inline bool Node::needsNodeRenderingTraversalSlowPath() const
240 {
241     if (getFlag(NeedsNodeRenderingTraversalSlowPathFlag))
242         return true;
243     ContainerNode* parent = parentOrShadowHostNode();
244     return parent && parent->getFlag(NeedsNodeRenderingTraversalSlowPathFlag);
245 }
246
247 inline bool Node::isTreeScope() const
248 {
249     return &treeScope().rootNode() == this;
250 }
251
252 // This constant controls how much buffer is initially allocated
253 // for a Node Vector that is used to store child Nodes of a given Node.
254 // FIXME: Optimize the value.
255 const int initialNodeVectorSize = 11;
256 typedef Vector<Ref<Node>, initialNodeVectorSize> NodeVector;
257
258 inline void getChildNodes(Node& node, NodeVector& nodes)
259 {
260     ASSERT(nodes.isEmpty());
261     for (Node* child = node.firstChild(); child; child = child->nextSibling())
262         nodes.append(*child);
263 }
264
265 class ChildNodesLazySnapshot {
266     WTF_MAKE_NONCOPYABLE(ChildNodesLazySnapshot);
267     WTF_MAKE_FAST_ALLOCATED;
268 public:
269     explicit ChildNodesLazySnapshot(Node& parentNode)
270         : m_currentNode(parentNode.firstChild())
271         , m_currentIndex(0)
272         , m_hasSnapshot(false)
273     {
274         m_nextSnapshot = latestSnapshot;
275         latestSnapshot = this;
276     }
277
278     ALWAYS_INLINE ~ChildNodesLazySnapshot()
279     {
280         latestSnapshot = m_nextSnapshot;
281     }
282
283     // Returns 0 if there is no next Node.
284     RefPtr<Node> nextNode()
285     {
286         if (LIKELY(!hasSnapshot())) {
287             RefPtr<Node> node = m_currentNode.release();
288             if (node)
289                 m_currentNode = node->nextSibling();
290             return node.release();
291         }
292         if (m_currentIndex >= m_snapshot.size())
293             return 0;
294         return m_snapshot[m_currentIndex++];
295     }
296
297     void takeSnapshot()
298     {
299         if (hasSnapshot())
300             return;
301         m_hasSnapshot = true;
302         Node* node = m_currentNode.get();
303         while (node) {
304             m_snapshot.append(node);
305             node = node->nextSibling();
306         }
307     }
308
309     ChildNodesLazySnapshot* nextSnapshot() { return m_nextSnapshot; }
310     bool hasSnapshot() { return m_hasSnapshot; }
311
312     static void takeChildNodesLazySnapshot()
313     {
314         ChildNodesLazySnapshot* snapshot = latestSnapshot;
315         while (snapshot && !snapshot->hasSnapshot()) {
316             snapshot->takeSnapshot();
317             snapshot = snapshot->nextSnapshot();
318         }
319     }
320
321 private:
322     static ChildNodesLazySnapshot* latestSnapshot;
323
324     RefPtr<Node> m_currentNode;
325     unsigned m_currentIndex;
326     bool m_hasSnapshot;
327     Vector<RefPtr<Node>> m_snapshot; // Lazily instantiated.
328     ChildNodesLazySnapshot* m_nextSnapshot;
329 };
330
331 } // namespace WebCore
332
333 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ContainerNode)
334     static bool isType(const WebCore::Node& node) { return node.isContainerNode(); }
335 SPECIALIZE_TYPE_TRAITS_END()
336
337 #endif // ContainerNode_h