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