Replace 0 and NULL with nullptr in WebCore/dom.
[WebKit-https.git] / Source / WebCore / dom / NodeRareData.h
1 /*
2  * Copyright (C) 2008, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 David Smith <catfish.man@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  */
21
22 #ifndef NodeRareData_h
23 #define NodeRareData_h
24
25 #include "ChildNodeList.h"
26 #include "ClassCollection.h"
27 #include "DOMSettableTokenList.h"
28 #include "HTMLCollection.h"
29 #include "HTMLNames.h"
30 #include "LiveNodeList.h"
31 #include "MutationObserver.h"
32 #include "MutationObserverRegistration.h"
33 #include "Page.h"
34 #include "QualifiedName.h"
35 #include "TagCollection.h"
36 #include <wtf/HashSet.h>
37 #include <wtf/text/AtomicString.h>
38
39 #if ENABLE(VIDEO_TRACK)
40 #include "TextTrack.h"
41 #endif
42
43 namespace WebCore {
44
45 class LabelsNodeList;
46 class RadioNodeList;
47 class TreeScope;
48
49 template <class ListType> struct NodeListTypeIdentifier;
50 template <> struct NodeListTypeIdentifier<NameNodeList> { static int value() { return 0; } };
51 template <> struct NodeListTypeIdentifier<RadioNodeList> { static int value() { return 1; } };
52 template <> struct NodeListTypeIdentifier<LabelsNodeList> { static int value() { return 2; } };
53
54 class NodeListsNodeData {
55     WTF_MAKE_NONCOPYABLE(NodeListsNodeData); WTF_MAKE_FAST_ALLOCATED;
56 public:
57     NodeListsNodeData()
58         : m_childNodeList(nullptr)
59         , m_emptyChildNodeList(nullptr)
60     {
61     }
62
63     void clearChildNodeListCache()
64     {
65         if (m_childNodeList)
66             m_childNodeList->invalidateCache();
67     }
68
69     Ref<ChildNodeList> ensureChildNodeList(ContainerNode& node)
70     {
71         ASSERT(!m_emptyChildNodeList);
72         if (m_childNodeList)
73             return *m_childNodeList;
74         auto list = ChildNodeList::create(node);
75         m_childNodeList = list.ptr();
76         return list;
77     }
78
79     void removeChildNodeList(ChildNodeList* list)
80     {
81         ASSERT(m_childNodeList == list);
82         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
83             return;
84         m_childNodeList = nullptr;
85     }
86
87     Ref<EmptyNodeList> ensureEmptyChildNodeList(Node& node)
88     {
89         ASSERT(!m_childNodeList);
90         if (m_emptyChildNodeList)
91             return *m_emptyChildNodeList;
92         auto list = EmptyNodeList::create(node);
93         m_emptyChildNodeList = list.ptr();
94         return list;
95     }
96
97     void removeEmptyChildNodeList(EmptyNodeList* list)
98     {
99         ASSERT(m_emptyChildNodeList == list);
100         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
101             return;
102         m_emptyChildNodeList = nullptr;
103     }
104
105     struct NodeListCacheMapEntryHash {
106         static unsigned hash(const std::pair<unsigned char, AtomicString>& entry)
107         {
108             return DefaultHash<AtomicString>::Hash::hash(entry.second) + entry.first;
109         }
110         static bool equal(const std::pair<unsigned char, AtomicString>& a, const std::pair<unsigned char, AtomicString>& b) { return a.first == b.first && DefaultHash<AtomicString>::Hash::equal(a.second, b.second); }
111         static const bool safeToCompareToEmptyOrDeleted = DefaultHash<AtomicString>::Hash::safeToCompareToEmptyOrDeleted;
112     };
113
114     typedef HashMap<std::pair<unsigned char, AtomicString>, LiveNodeList*, NodeListCacheMapEntryHash> NodeListAtomicNameCacheMap;
115     typedef HashMap<std::pair<unsigned char, AtomicString>, HTMLCollection*, NodeListCacheMapEntryHash> CollectionCacheMap;
116     typedef HashMap<QualifiedName, TagCollection*> TagCollectionCacheNS;
117
118     template<typename T, typename ContainerType>
119     ALWAYS_INLINE Ref<T> addCacheWithAtomicName(ContainerType& container, const AtomicString& name)
120     {
121         NodeListAtomicNameCacheMap::AddResult result = m_atomicNameCaches.fastAdd(namedNodeListKey<T>(name), nullptr);
122         if (!result.isNewEntry)
123             return static_cast<T&>(*result.iterator->value);
124
125         auto list = T::create(container, name);
126         result.iterator->value = &list.get();
127         return list;
128     }
129
130     ALWAYS_INLINE Ref<TagCollection> addCachedCollectionWithQualifiedName(ContainerNode& node, const AtomicString& namespaceURI, const AtomicString& localName)
131     {
132         QualifiedName name(nullAtom, localName, namespaceURI);
133         TagCollectionCacheNS::AddResult result = m_tagCollectionCacheNS.fastAdd(name, nullptr);
134         if (!result.isNewEntry)
135             return *result.iterator->value;
136
137         auto list = TagCollection::create(node, namespaceURI, localName);
138         result.iterator->value = list.ptr();
139         return list;
140     }
141
142     template<typename T, typename ContainerType>
143     ALWAYS_INLINE Ref<T> addCachedCollection(ContainerType& container, CollectionType collectionType, const AtomicString& name)
144     {
145         CollectionCacheMap::AddResult result = m_cachedCollections.fastAdd(namedCollectionKey(collectionType, name), nullptr);
146         if (!result.isNewEntry)
147             return static_cast<T&>(*result.iterator->value);
148
149         auto list = T::create(container, collectionType, name);
150         result.iterator->value = &list.get();
151         return list;
152     }
153
154     template<typename T, typename ContainerType>
155     ALWAYS_INLINE Ref<T> addCachedCollection(ContainerType& container, CollectionType collectionType)
156     {
157         CollectionCacheMap::AddResult result = m_cachedCollections.fastAdd(namedCollectionKey(collectionType, starAtom), nullptr);
158         if (!result.isNewEntry)
159             return static_cast<T&>(*result.iterator->value);
160
161         auto list = T::create(container, collectionType);
162         result.iterator->value = &list.get();
163         return list;
164     }
165
166     template<typename T>
167     T* cachedCollection(CollectionType collectionType)
168     {
169         return static_cast<T*>(m_cachedCollections.get(namedCollectionKey(collectionType, starAtom)));
170     }
171
172     template <class NodeListType>
173     void removeCacheWithAtomicName(NodeListType* list, const AtomicString& name = starAtom)
174     {
175         ASSERT(list == m_atomicNameCaches.get(namedNodeListKey<NodeListType>(name)));
176         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
177             return;
178         m_atomicNameCaches.remove(namedNodeListKey<NodeListType>(name));
179     }
180
181     void removeCachedCollectionWithQualifiedName(HTMLCollection& collection, const AtomicString& namespaceURI, const AtomicString& localName)
182     {
183         QualifiedName name(nullAtom, localName, namespaceURI);
184         ASSERT(&collection == m_tagCollectionCacheNS.get(name));
185         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(collection.ownerNode()))
186             return;
187         m_tagCollectionCacheNS.remove(name);
188     }
189
190     void removeCachedCollection(HTMLCollection* collection, const AtomicString& name = starAtom)
191     {
192         ASSERT(collection == m_cachedCollections.get(namedCollectionKey(collection->type(), name)));
193         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(collection->ownerNode()))
194             return;
195         m_cachedCollections.remove(namedCollectionKey(collection->type(), name));
196     }
197
198     void invalidateCaches(const QualifiedName* attrName = nullptr);
199     bool isEmpty() const
200     {
201         return m_atomicNameCaches.isEmpty() && m_cachedCollections.isEmpty() && m_tagCollectionCacheNS.isEmpty();
202     }
203
204     void adoptTreeScope()
205     {
206         invalidateCaches();
207     }
208
209     void adoptDocument(Document* oldDocument, Document* newDocument)
210     {
211         ASSERT(oldDocument);
212         if (oldDocument == newDocument) {
213             invalidateCaches();
214             return;
215         }
216
217         for (auto& cache : m_atomicNameCaches.values())
218             cache->invalidateCache(*oldDocument);
219
220         for (auto& list : m_tagCollectionCacheNS.values()) {
221             ASSERT(!list->isRootedAtDocument());
222             list->invalidateCache(*oldDocument);
223         }
224
225         for (auto& collection : m_cachedCollections.values())
226             collection->invalidateCache(*oldDocument);
227     }
228
229 private:
230     std::pair<unsigned char, AtomicString> namedCollectionKey(CollectionType type, const AtomicString& name)
231     {
232         return std::pair<unsigned char, AtomicString>(type, name);
233     }
234
235     template <class NodeListType>
236     std::pair<unsigned char, AtomicString> namedNodeListKey(const AtomicString& name)
237     {
238         return std::pair<unsigned char, AtomicString>(NodeListTypeIdentifier<NodeListType>::value(), name);
239     }
240
241     bool deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(Node&);
242
243     // These two are currently mutually exclusive and could be unioned. Not very important as this class is large anyway.
244     ChildNodeList* m_childNodeList;
245     EmptyNodeList* m_emptyChildNodeList;
246
247     NodeListAtomicNameCacheMap m_atomicNameCaches;
248     TagCollectionCacheNS m_tagCollectionCacheNS;
249     CollectionCacheMap m_cachedCollections;
250 };
251
252 class NodeMutationObserverData {
253     WTF_MAKE_NONCOPYABLE(NodeMutationObserverData); WTF_MAKE_FAST_ALLOCATED;
254 public:
255     Vector<std::unique_ptr<MutationObserverRegistration>> registry;
256     HashSet<MutationObserverRegistration*> transientRegistry;
257
258     NodeMutationObserverData() { }
259 };
260
261 class NodeRareData : public NodeRareDataBase {
262     WTF_MAKE_NONCOPYABLE(NodeRareData); WTF_MAKE_FAST_ALLOCATED;
263 public:
264     NodeRareData(RenderObject* renderer)
265         : NodeRareDataBase(renderer)
266         , m_connectedFrameCount(0)
267     { }
268
269     void clearNodeLists() { m_nodeLists = nullptr; }
270     NodeListsNodeData* nodeLists() const { return m_nodeLists.get(); }
271     NodeListsNodeData& ensureNodeLists()
272     {
273         if (!m_nodeLists)
274             m_nodeLists = std::make_unique<NodeListsNodeData>();
275         return *m_nodeLists;
276     }
277
278     NodeMutationObserverData* mutationObserverData() { return m_mutationObserverData.get(); }
279     NodeMutationObserverData& ensureMutationObserverData()
280     {
281         if (!m_mutationObserverData)
282             m_mutationObserverData = std::make_unique<NodeMutationObserverData>();
283         return *m_mutationObserverData;
284     }
285
286     unsigned connectedSubframeCount() const { return m_connectedFrameCount; }
287     void incrementConnectedSubframeCount(unsigned amount)
288     {
289         m_connectedFrameCount += amount;
290     }
291     void decrementConnectedSubframeCount(unsigned amount)
292     {
293         ASSERT(m_connectedFrameCount);
294         ASSERT(amount <= m_connectedFrameCount);
295         m_connectedFrameCount -= amount;
296     }
297
298 private:
299     unsigned m_connectedFrameCount : 10; // Must fit Page::maxNumberOfFrames.
300
301     std::unique_ptr<NodeListsNodeData> m_nodeLists;
302     std::unique_ptr<NodeMutationObserverData> m_mutationObserverData;
303 };
304
305 inline bool NodeListsNodeData::deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(Node& ownerNode)
306 {
307     ASSERT(ownerNode.nodeLists() == this);
308     if ((m_childNodeList ? 1 : 0) + (m_emptyChildNodeList ? 1 : 0) + m_atomicNameCaches.size()
309         + m_tagCollectionCacheNS.size() + m_cachedCollections.size() != 1)
310         return false;
311     ownerNode.clearNodeLists();
312     return true;
313 }
314
315 inline NodeRareData* Node::rareData() const
316 {
317     ASSERT_WITH_SECURITY_IMPLICATION(hasRareData());
318     return static_cast<NodeRareData*>(m_data.m_rareData);
319 }
320
321 inline NodeRareData& Node::ensureRareData()
322 {
323     if (!hasRareData())
324         materializeRareData();
325     return *rareData();
326 }
327
328 // Ensure the 10 bits reserved for the m_connectedFrameCount cannot overflow
329 static_assert(Page::maxNumberOfFrames < 1024, "Frame limit should fit in rare data count");
330
331 } // namespace WebCore
332
333 #endif // NodeRareData_h