3f0571e335e7796eefe5448a207a2f02a888ad4a
[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-2018 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 #pragma once
25
26 #include "CollectionType.h"
27 #include "Node.h"
28 #include <wtf/WeakPtr.h>
29
30 namespace WebCore {
31
32 class HTMLCollection;
33 class RadioNodeList;
34 class RenderElement;
35
36 const int initialNodeVectorSize = 11; // Covers 99.5%. See webkit.org/b/80706
37 typedef Vector<Ref<Node>, initialNodeVectorSize> NodeVector;
38
39 class ContainerNode : public CanMakeWeakPtr<ContainerNode>, public Node {
40     WTF_MAKE_ISO_ALLOCATED(ContainerNode);
41 public:
42     virtual ~ContainerNode();
43
44     Node* firstChild() const { return m_firstChild; }
45     static ptrdiff_t firstChildMemoryOffset() { return OBJECT_OFFSETOF(ContainerNode, m_firstChild); }
46     Node* lastChild() const { return m_lastChild; }
47     static ptrdiff_t lastChildMemoryOffset() { return OBJECT_OFFSETOF(ContainerNode, m_lastChild); }
48     bool hasChildNodes() const { return m_firstChild; }
49     bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); }
50
51     bool directChildNeedsStyleRecalc() const { return getFlag(DirectChildNeedsStyleRecalcFlag); }
52     void setDirectChildNeedsStyleRecalc() { setFlag(DirectChildNeedsStyleRecalcFlag); }
53
54     WEBCORE_EXPORT unsigned countChildNodes() const;
55     WEBCORE_EXPORT Node* traverseToChildAt(unsigned) const;
56
57     ExceptionOr<void> insertBefore(Node& newChild, Node* refChild);
58     ExceptionOr<void> replaceChild(Node& newChild, Node& oldChild);
59     WEBCORE_EXPORT ExceptionOr<void> removeChild(Node& child);
60     WEBCORE_EXPORT ExceptionOr<void> appendChild(Node& newChild);
61     void replaceAllChildren(Ref<Node>&&);
62     void replaceAllChildren(std::nullptr_t);
63
64     // These methods are only used during parsing.
65     // They don't send DOM mutation events or handle reparenting.
66     // However, arbitrary code may be run by beforeload handlers.
67     void parserAppendChild(Node&);
68     void parserRemoveChild(Node&);
69     void parserInsertBefore(Node& newChild, Node& refChild);
70
71     void removeChildren();
72
73     void takeAllChildrenFrom(ContainerNode*);
74
75     void cloneChildNodes(ContainerNode& clone);
76
77     enum ChildChangeType { ElementInserted, ElementRemoved, TextInserted, TextRemoved, TextChanged, AllChildrenRemoved, NonContentsChildRemoved, NonContentsChildInserted, AllChildrenReplaced };
78     enum class ChildChangeSource { Parser, API };
79     struct ChildChange {
80         ChildChangeType type;
81         Element* previousSiblingElement;
82         Element* nextSiblingElement;
83         ChildChangeSource source;
84
85         bool isInsertion() const
86         {
87             switch (type) {
88             case ElementInserted:
89             case TextInserted:
90             case NonContentsChildInserted:
91             case AllChildrenReplaced:
92                 return true;
93             case ElementRemoved:
94             case TextRemoved:
95             case TextChanged:
96             case AllChildrenRemoved:
97             case NonContentsChildRemoved:
98                 return false;
99             }
100             ASSERT_NOT_REACHED();
101             return false;
102         }
103     };
104     virtual void childrenChanged(const ChildChange&);
105
106     void disconnectDescendantFrames();
107
108     RenderElement* renderer() const;
109
110     // Return a bounding box in absolute coordinates enclosing this node and all its descendants.
111     // This gives the area within which events may get handled by a hander registered on this node.
112     virtual LayoutRect absoluteEventHandlerBounds(bool& /* includesFixedPositionElements */) { return LayoutRect(); }
113
114     WEBCORE_EXPORT ExceptionOr<Element*> querySelector(const String& selectors);
115     WEBCORE_EXPORT ExceptionOr<Ref<NodeList>> querySelectorAll(const String& selectors);
116
117     WEBCORE_EXPORT Ref<HTMLCollection> getElementsByTagName(const AtomicString&);
118     WEBCORE_EXPORT Ref<HTMLCollection> getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName);
119     WEBCORE_EXPORT Ref<NodeList> getElementsByName(const String& elementName);
120     WEBCORE_EXPORT Ref<HTMLCollection> getElementsByClassName(const AtomicString& classNames);
121     Ref<RadioNodeList> radioNodeList(const AtomicString&);
122
123     // From the ParentNode interface - https://dom.spec.whatwg.org/#interface-parentnode
124     WEBCORE_EXPORT Ref<HTMLCollection> children();
125     WEBCORE_EXPORT Element* firstElementChild() const;
126     WEBCORE_EXPORT Element* lastElementChild() const;
127     WEBCORE_EXPORT unsigned childElementCount() const;
128     ExceptionOr<void> append(Vector<NodeOrString>&&);
129     ExceptionOr<void> prepend(Vector<NodeOrString>&&);
130
131     ExceptionOr<void> ensurePreInsertionValidity(Node& newChild, Node* refChild);
132
133 protected:
134     explicit ContainerNode(Document&, ConstructionType = CreateContainer);
135
136     friend void addChildNodesToDeletionQueue(Node*& head, Node*& tail, ContainerNode&);
137
138     void removeDetachedChildren();
139     void setFirstChild(Node* child) { m_firstChild = child; }
140     void setLastChild(Node* child) { m_lastChild = child; }
141
142     HTMLCollection* cachedHTMLCollection(CollectionType);
143
144 private:
145     void executePreparedChildrenRemoval();
146     enum class DeferChildrenChanged { Yes, No };
147     NodeVector removeAllChildrenWithScriptAssertion(ChildChangeSource, DeferChildrenChanged = DeferChildrenChanged::No);
148     bool removeNodeWithScriptAssertion(Node&, ChildChangeSource);
149
150     void removeBetween(Node* previousChild, Node* nextChild, Node& oldChild);
151     ExceptionOr<void> appendChildWithoutPreInsertionValidityCheck(Node&);
152     void insertBeforeCommon(Node& nextChild, Node& oldChild);
153     void appendChildCommon(Node&);
154
155     void rebuildSVGExtensionsElementsIfNecessary();
156
157     bool isContainerNode() const = delete;
158
159     Node* m_firstChild { nullptr };
160     Node* m_lastChild { nullptr };
161 };
162
163 inline ContainerNode::ContainerNode(Document& document, ConstructionType type)
164     : Node(document, type)
165 {
166 }
167
168 inline unsigned Node::countChildNodes() const
169 {
170     if (!is<ContainerNode>(*this))
171         return 0;
172     return downcast<ContainerNode>(*this).countChildNodes();
173 }
174
175 inline Node* Node::traverseToChildAt(unsigned index) const
176 {
177     if (!is<ContainerNode>(*this))
178         return nullptr;
179     return downcast<ContainerNode>(*this).traverseToChildAt(index);
180 }
181
182 inline Node* Node::firstChild() const
183 {
184     if (!is<ContainerNode>(*this))
185         return nullptr;
186     return downcast<ContainerNode>(*this).firstChild();
187 }
188
189 inline Node* Node::lastChild() const
190 {
191     if (!is<ContainerNode>(*this))
192         return nullptr;
193     return downcast<ContainerNode>(*this).lastChild();
194 }
195
196 inline Node& Node::rootNode() const
197 {
198     if (isInTreeScope())
199         return treeScope().rootNode();
200     return traverseToRootNode();
201 }
202
203 inline NodeVector collectChildNodes(Node& node)
204 {
205     NodeVector children;
206     for (Node* child = node.firstChild(); child; child = child->nextSibling())
207         children.append(*child);
208     return children;
209 }
210
211 class ChildNodesLazySnapshot {
212     WTF_MAKE_NONCOPYABLE(ChildNodesLazySnapshot);
213     WTF_MAKE_FAST_ALLOCATED;
214 public:
215     explicit ChildNodesLazySnapshot(Node& parentNode)
216         : m_currentNode(parentNode.firstChild())
217         , m_currentIndex(0)
218         , m_hasSnapshot(false)
219     {
220         m_nextSnapshot = latestSnapshot;
221         latestSnapshot = this;
222     }
223
224     ALWAYS_INLINE ~ChildNodesLazySnapshot()
225     {
226         latestSnapshot = m_nextSnapshot;
227     }
228
229     // Returns 0 if there is no next Node.
230     RefPtr<Node> nextNode()
231     {
232         if (LIKELY(!hasSnapshot())) {
233             RefPtr<Node> node = WTFMove(m_currentNode);
234             if (node)
235                 m_currentNode = node->nextSibling();
236             return node;
237         }
238         if (m_currentIndex >= m_snapshot.size())
239             return nullptr;
240         return m_snapshot[m_currentIndex++];
241     }
242
243     void takeSnapshot()
244     {
245         if (hasSnapshot())
246             return;
247         m_hasSnapshot = true;
248         Node* node = m_currentNode.get();
249         while (node) {
250             m_snapshot.append(node);
251             node = node->nextSibling();
252         }
253     }
254
255     ChildNodesLazySnapshot* nextSnapshot() { return m_nextSnapshot; }
256     bool hasSnapshot() { return m_hasSnapshot; }
257
258     static void takeChildNodesLazySnapshot()
259     {
260         ChildNodesLazySnapshot* snapshot = latestSnapshot;
261         while (snapshot && !snapshot->hasSnapshot()) {
262             snapshot->takeSnapshot();
263             snapshot = snapshot->nextSnapshot();
264         }
265     }
266
267 private:
268     static ChildNodesLazySnapshot* latestSnapshot;
269
270     RefPtr<Node> m_currentNode;
271     unsigned m_currentIndex;
272     bool m_hasSnapshot;
273     Vector<RefPtr<Node>> m_snapshot; // Lazily instantiated.
274     ChildNodesLazySnapshot* m_nextSnapshot;
275 };
276
277 } // namespace WebCore
278
279 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ContainerNode)
280     static bool isType(const WebCore::Node& node) { return node.isContainerNode(); }
281 SPECIALIZE_TYPE_TRAITS_END()