Remove NodeListsNodeData when it's no longer needed
[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 "DOMSettableTokenList.h"
27 #include "LiveNodeList.h"
28 #include "MutationObserver.h"
29 #include "MutationObserverRegistration.h"
30 #include "QualifiedName.h"
31 #include "TagNodeList.h"
32 #if ENABLE(VIDEO_TRACK)
33 #include "TextTrack.h"
34 #endif
35 #include <wtf/HashSet.h>
36 #include <wtf/OwnPtr.h>
37 #include <wtf/PassOwnPtr.h>
38 #include <wtf/text/AtomicString.h>
39 #include <wtf/text/StringHash.h>
40
41 #if ENABLE(MICRODATA)
42 #include "HTMLPropertiesCollection.h"
43 #include "MicroDataItemList.h"
44 #endif
45
46 namespace WebCore {
47
48 class LabelsNodeList;
49 class RadioNodeList;
50 class TreeScope;
51
52 class NodeListsNodeData {
53     WTF_MAKE_NONCOPYABLE(NodeListsNodeData); WTF_MAKE_FAST_ALLOCATED;
54 public:
55     void clearChildNodeListCache()
56     {
57         if (m_childNodeList)
58             m_childNodeList->invalidateCache();
59     }
60
61     PassRefPtr<ChildNodeList> ensureChildNodeList(Node* node)
62     {
63         if (m_childNodeList)
64             return m_childNodeList;
65         RefPtr<ChildNodeList> list = ChildNodeList::create(node);
66         m_childNodeList = list.get();
67         return list.release();
68     }
69
70     void removeChildNodeList(ChildNodeList* list)
71     {
72         ASSERT(m_childNodeList = list);
73         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
74             return;
75         m_childNodeList = 0;
76     }
77
78     template <typename StringType>
79     struct NodeListCacheMapEntryHash {
80         static unsigned hash(const std::pair<unsigned char, StringType>& entry)
81         {
82             return DefaultHash<StringType>::Hash::hash(entry.second) + entry.first;
83         }
84         static bool equal(const std::pair<unsigned char, StringType>& a, const std::pair<unsigned char, StringType>& b) { return a == b; }
85         static const bool safeToCompareToEmptyOrDeleted = DefaultHash<StringType>::Hash::safeToCompareToEmptyOrDeleted;
86     };
87
88     typedef HashMap<std::pair<unsigned char, AtomicString>, LiveNodeListBase*, NodeListCacheMapEntryHash<AtomicString> > NodeListAtomicNameCacheMap;
89     typedef HashMap<std::pair<unsigned char, String>, LiveNodeListBase*, NodeListCacheMapEntryHash<String> > NodeListNameCacheMap;
90     typedef HashMap<QualifiedName, TagNodeList*> TagNodeListCacheNS;
91
92     template<typename T>
93     PassRefPtr<T> addCacheWithAtomicName(Node* node, CollectionType collectionType, const AtomicString& name)
94     {
95         NodeListAtomicNameCacheMap::AddResult result = m_atomicNameCaches.add(namedNodeListKey(collectionType, name), 0);
96         if (!result.isNewEntry)
97             return static_cast<T*>(result.iterator->value);
98
99         RefPtr<T> list = T::create(node, collectionType, name);
100         result.iterator->value = list.get();
101         return list.release();
102     }
103
104     // FIXME: This function should be renamed since it doesn't have an atomic name.
105     template<typename T>
106     PassRefPtr<T> addCacheWithAtomicName(Node* node, CollectionType collectionType)
107     {
108         NodeListAtomicNameCacheMap::AddResult result = m_atomicNameCaches.add(namedNodeListKey(collectionType, starAtom), 0);
109         if (!result.isNewEntry)
110             return static_cast<T*>(result.iterator->value);
111
112         RefPtr<T> list = T::create(node, collectionType);
113         result.iterator->value = list.get();
114         return list.release();
115     }
116
117     template<typename T>
118     T* cacheWithAtomicName(CollectionType collectionType)
119     {
120         return static_cast<T*>(m_atomicNameCaches.get(namedNodeListKey(collectionType, starAtom)));
121     }
122
123     template<typename T>
124     PassRefPtr<T> addCacheWithName(Node* node, CollectionType collectionType, const String& name)
125     {
126         NodeListNameCacheMap::AddResult result = m_nameCaches.add(namedNodeListKey(collectionType, name), 0);
127         if (!result.isNewEntry)
128             return static_cast<T*>(result.iterator->value);
129
130         RefPtr<T> list = T::create(node, name);
131         result.iterator->value = list.get();
132         return list.release();
133     }
134
135     PassRefPtr<TagNodeList> addCacheWithQualifiedName(Node* node, const AtomicString& namespaceURI, const AtomicString& localName)
136     {
137         QualifiedName name(nullAtom, localName, namespaceURI);
138         TagNodeListCacheNS::AddResult result = m_tagNodeListCacheNS.add(name, 0);
139         if (!result.isNewEntry)
140             return result.iterator->value;
141
142         RefPtr<TagNodeList> list = TagNodeList::create(node, namespaceURI, localName);
143         result.iterator->value = list.get();
144         return list.release();
145     }
146
147     void removeCacheWithAtomicName(LiveNodeListBase* list, CollectionType collectionType, const AtomicString& name = starAtom)
148     {
149         ASSERT(list == m_atomicNameCaches.get(namedNodeListKey(collectionType, name)));
150         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
151             return;
152         m_atomicNameCaches.remove(namedNodeListKey(collectionType, name));
153     }
154
155     void removeCacheWithName(LiveNodeListBase* list, CollectionType collectionType, const String& name)
156     {
157         ASSERT(list == m_nameCaches.get(namedNodeListKey(collectionType, name)));
158         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
159             return;
160         m_nameCaches.remove(namedNodeListKey(collectionType, name));
161     }
162
163     void removeCacheWithQualifiedName(LiveNodeList* list, const AtomicString& namespaceURI, const AtomicString& localName)
164     {
165         QualifiedName name(nullAtom, localName, namespaceURI);
166         ASSERT(list == m_tagNodeListCacheNS.get(name));
167         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
168             return;
169         m_tagNodeListCacheNS.remove(name);
170     }
171
172     static PassOwnPtr<NodeListsNodeData> create()
173     {
174         return adoptPtr(new NodeListsNodeData);
175     }
176
177     void invalidateCaches(const QualifiedName* attrName = 0);
178     bool isEmpty() const
179     {
180         return m_atomicNameCaches.isEmpty() && m_nameCaches.isEmpty() && m_tagNodeListCacheNS.isEmpty();
181     }
182
183     void adoptTreeScope(Document* oldDocument, Document* newDocument)
184     {
185         invalidateCaches();
186
187         if (oldDocument != newDocument) {
188             NodeListAtomicNameCacheMap::const_iterator atomicNameCacheEnd = m_atomicNameCaches.end();
189             for (NodeListAtomicNameCacheMap::const_iterator it = m_atomicNameCaches.begin(); it != atomicNameCacheEnd; ++it) {
190                 LiveNodeListBase* list = it->value;
191                 oldDocument->unregisterNodeList(list);
192                 newDocument->registerNodeList(list);
193             }
194
195             NodeListNameCacheMap::const_iterator nameCacheEnd = m_nameCaches.end();
196             for (NodeListNameCacheMap::const_iterator it = m_nameCaches.begin(); it != nameCacheEnd; ++it) {
197                 LiveNodeListBase* list = it->value;
198                 oldDocument->unregisterNodeList(list);
199                 newDocument->registerNodeList(list);
200             }
201
202             TagNodeListCacheNS::const_iterator tagEnd = m_tagNodeListCacheNS.end();
203             for (TagNodeListCacheNS::const_iterator it = m_tagNodeListCacheNS.begin(); it != tagEnd; ++it) {
204                 LiveNodeListBase* list = it->value;
205                 ASSERT(!list->isRootedAtDocument());
206                 oldDocument->unregisterNodeList(list);
207                 newDocument->registerNodeList(list);
208             }
209         }
210     }
211
212     void reportMemoryUsage(MemoryObjectInfo*) const;
213
214 private:
215     NodeListsNodeData()
216         : m_childNodeList(0)
217     { }
218
219     std::pair<unsigned char, AtomicString> namedNodeListKey(CollectionType type, const AtomicString& name)
220     {
221         return std::pair<unsigned char, AtomicString>(type, name);
222     }
223
224     std::pair<unsigned char, String> namedNodeListKey(CollectionType type, const String& name)
225     {
226         return std::pair<unsigned char, String>(type, name);
227     }
228
229     bool deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(Node*);
230
231     // FIXME: m_childNodeList should be merged into m_atomicNameCaches or at least be shared with HTMLCollection returned by Element::children
232     // but it's tricky because invalidateCaches shouldn't invalidate this cache and adoptTreeScope shouldn't call registerNodeList or unregisterNodeList.
233     ChildNodeList* m_childNodeList;
234     NodeListAtomicNameCacheMap m_atomicNameCaches;
235     NodeListNameCacheMap m_nameCaches;
236     TagNodeListCacheNS m_tagNodeListCacheNS;
237 };
238
239 class NodeMutationObserverData {
240     WTF_MAKE_NONCOPYABLE(NodeMutationObserverData); WTF_MAKE_FAST_ALLOCATED;
241 public:
242     Vector<OwnPtr<MutationObserverRegistration> > registry;
243     HashSet<MutationObserverRegistration*> transientRegistry;
244
245     static PassOwnPtr<NodeMutationObserverData> create() { return adoptPtr(new NodeMutationObserverData); }
246
247 private:
248     NodeMutationObserverData() { }
249 };
250
251 #if ENABLE(MICRODATA)
252 class NodeMicroDataTokenLists {
253     WTF_MAKE_NONCOPYABLE(NodeMicroDataTokenLists); WTF_MAKE_FAST_ALLOCATED;
254 public:
255     static PassOwnPtr<NodeMicroDataTokenLists> create() { return adoptPtr(new NodeMicroDataTokenLists); }
256
257     DOMSettableTokenList* itemProp() const
258     {
259         if (!m_itemProp)
260             m_itemProp = DOMSettableTokenList::create();
261         return m_itemProp.get();
262     }
263
264     DOMSettableTokenList* itemRef() const
265     {
266         if (!m_itemRef)
267             m_itemRef = DOMSettableTokenList::create();
268         return m_itemRef.get();
269     }
270
271     DOMSettableTokenList* itemType() const
272     {
273         if (!m_itemType)
274             m_itemType = DOMSettableTokenList::create();
275         return m_itemType.get();
276     }
277
278 private:
279     NodeMicroDataTokenLists() { }
280
281     mutable RefPtr<DOMSettableTokenList> m_itemProp;
282     mutable RefPtr<DOMSettableTokenList> m_itemRef;
283     mutable RefPtr<DOMSettableTokenList> m_itemType;
284 };
285 #endif
286
287 class NodeRareData : public NodeRareDataBase {
288     WTF_MAKE_NONCOPYABLE(NodeRareData); WTF_MAKE_FAST_ALLOCATED;
289 public:
290     static PassOwnPtr<NodeRareData> create(RenderObject* renderer) { return adoptPtr(new NodeRareData(renderer)); }
291
292     void clearNodeLists() { m_nodeLists.clear(); }
293     NodeListsNodeData* nodeLists() const { return m_nodeLists.get(); }
294     NodeListsNodeData* ensureNodeLists()
295     {
296         if (!m_nodeLists)
297             m_nodeLists = NodeListsNodeData::create();
298         return m_nodeLists.get();
299     }
300
301     NodeMutationObserverData* mutationObserverData() { return m_mutationObserverData.get(); }
302     NodeMutationObserverData* ensureMutationObserverData()
303     {
304         if (!m_mutationObserverData)
305             m_mutationObserverData = NodeMutationObserverData::create();
306         return m_mutationObserverData.get();
307     }
308
309 #if ENABLE(MICRODATA)
310     NodeMicroDataTokenLists* ensureMicroDataTokenLists() const
311     {
312         if (!m_microDataTokenLists)
313             m_microDataTokenLists = NodeMicroDataTokenLists::create();
314         return m_microDataTokenLists.get();
315     }
316 #endif
317
318     // This member function is intentionially not virtual to avoid adding a vtable pointer.
319     void reportMemoryUsage(MemoryObjectInfo*) const;
320
321 protected:
322     NodeRareData(RenderObject* renderer)
323         : NodeRareDataBase(renderer)
324     { }
325
326 private:
327     OwnPtr<NodeListsNodeData> m_nodeLists;
328     OwnPtr<NodeMutationObserverData> m_mutationObserverData;
329
330 #if ENABLE(MICRODATA)
331     mutable OwnPtr<NodeMicroDataTokenLists> m_microDataTokenLists;
332 #endif
333 };
334
335 inline bool NodeListsNodeData::deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(Node* ownerNode)
336 {
337     ASSERT(ownerNode);
338     ASSERT(ownerNode->nodeLists() == this);
339     if ((m_childNodeList ? 1 : 0) + m_atomicNameCaches.size() + m_nameCaches.size() + m_tagNodeListCacheNS.size() != 1)
340         return false;
341     ownerNode->clearNodeLists();
342     return true;
343 }
344
345 } // namespace WebCore
346
347 #endif // NodeRareData_h