Make some things that return never-null pointers return references instead.
[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 "HTMLNames.h"
28 #include "LiveNodeList.h"
29 #include "MutationObserver.h"
30 #include "MutationObserverRegistration.h"
31 #include "Page.h"
32 #include "QualifiedName.h"
33 #include "TagNodeList.h"
34 #if ENABLE(VIDEO_TRACK)
35 #include "TextTrack.h"
36 #endif
37 #include <wtf/HashSet.h>
38 #include <wtf/OwnPtr.h>
39 #include <wtf/PassOwnPtr.h>
40 #include <wtf/text/AtomicString.h>
41 #include <wtf/text/StringHash.h>
42
43 namespace WebCore {
44
45 class LabelsNodeList;
46 class RadioNodeList;
47 class TreeScope;
48
49 class NodeListsNodeData {
50     WTF_MAKE_NONCOPYABLE(NodeListsNodeData); WTF_MAKE_FAST_ALLOCATED;
51 public:
52     void clearChildNodeListCache()
53     {
54         if (m_childNodeList)
55             m_childNodeList->invalidateCache();
56     }
57
58     PassRefPtr<ChildNodeList> ensureChildNodeList(Node* node)
59     {
60         if (m_childNodeList)
61             return m_childNodeList;
62         RefPtr<ChildNodeList> list = ChildNodeList::create(node);
63         m_childNodeList = list.get();
64         return list.release();
65     }
66
67     void removeChildNodeList(ChildNodeList* list)
68     {
69         ASSERT(m_childNodeList = list);
70         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
71             return;
72         m_childNodeList = 0;
73     }
74
75     template <typename StringType>
76     struct NodeListCacheMapEntryHash {
77         static unsigned hash(const std::pair<unsigned char, StringType>& entry)
78         {
79             return DefaultHash<StringType>::Hash::hash(entry.second) + entry.first;
80         }
81         static bool equal(const std::pair<unsigned char, StringType>& a, const std::pair<unsigned char, StringType>& b) { return a == b; }
82         static const bool safeToCompareToEmptyOrDeleted = DefaultHash<StringType>::Hash::safeToCompareToEmptyOrDeleted;
83     };
84
85     typedef HashMap<std::pair<unsigned char, AtomicString>, LiveNodeListBase*, NodeListCacheMapEntryHash<AtomicString> > NodeListAtomicNameCacheMap;
86     typedef HashMap<std::pair<unsigned char, String>, LiveNodeListBase*, NodeListCacheMapEntryHash<String> > NodeListNameCacheMap;
87     typedef HashMap<QualifiedName, TagNodeList*> TagNodeListCacheNS;
88
89     template<typename T>
90     PassRefPtr<T> addCacheWithAtomicName(Node* node, CollectionType collectionType, const AtomicString& name)
91     {
92         NodeListAtomicNameCacheMap::AddResult result = m_atomicNameCaches.add(namedNodeListKey(collectionType, name), 0);
93         if (!result.isNewEntry)
94             return static_cast<T*>(result.iterator->value);
95
96         RefPtr<T> list = T::create(node, collectionType, name);
97         result.iterator->value = list.get();
98         return list.release();
99     }
100
101     // FIXME: This function should be renamed since it doesn't have an atomic name.
102     template<typename T>
103     PassRefPtr<T> addCacheWithAtomicName(Node* node, CollectionType collectionType)
104     {
105         NodeListAtomicNameCacheMap::AddResult result = m_atomicNameCaches.add(namedNodeListKey(collectionType, starAtom), 0);
106         if (!result.isNewEntry)
107             return static_cast<T*>(result.iterator->value);
108
109         RefPtr<T> list = T::create(node, collectionType);
110         result.iterator->value = list.get();
111         return list.release();
112     }
113
114     template<typename T>
115     T* cacheWithAtomicName(CollectionType collectionType)
116     {
117         return static_cast<T*>(m_atomicNameCaches.get(namedNodeListKey(collectionType, starAtom)));
118     }
119
120     template<typename T>
121     PassRefPtr<T> addCacheWithName(Node* node, CollectionType collectionType, const String& name)
122     {
123         NodeListNameCacheMap::AddResult result = m_nameCaches.add(namedNodeListKey(collectionType, name), 0);
124         if (!result.isNewEntry)
125             return static_cast<T*>(result.iterator->value);
126
127         RefPtr<T> list = T::create(node, name);
128         result.iterator->value = list.get();
129         return list.release();
130     }
131
132     PassRefPtr<TagNodeList> addCacheWithQualifiedName(Node* node, const AtomicString& namespaceURI, const AtomicString& localName)
133     {
134         QualifiedName name(nullAtom, localName, namespaceURI);
135         TagNodeListCacheNS::AddResult result = m_tagNodeListCacheNS.add(name, 0);
136         if (!result.isNewEntry)
137             return result.iterator->value;
138
139         RefPtr<TagNodeList> list = TagNodeList::create(node, namespaceURI, localName);
140         result.iterator->value = list.get();
141         return list.release();
142     }
143
144     void removeCacheWithAtomicName(LiveNodeListBase* list, CollectionType collectionType, const AtomicString& name = starAtom)
145     {
146         ASSERT(list == m_atomicNameCaches.get(namedNodeListKey(collectionType, name)));
147         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
148             return;
149         m_atomicNameCaches.remove(namedNodeListKey(collectionType, name));
150     }
151
152     void removeCacheWithName(LiveNodeListBase* list, CollectionType collectionType, const String& name)
153     {
154         ASSERT(list == m_nameCaches.get(namedNodeListKey(collectionType, name)));
155         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
156             return;
157         m_nameCaches.remove(namedNodeListKey(collectionType, name));
158     }
159
160     void removeCacheWithQualifiedName(LiveNodeList* list, const AtomicString& namespaceURI, const AtomicString& localName)
161     {
162         QualifiedName name(nullAtom, localName, namespaceURI);
163         ASSERT(list == m_tagNodeListCacheNS.get(name));
164         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
165             return;
166         m_tagNodeListCacheNS.remove(name);
167     }
168
169     static PassOwnPtr<NodeListsNodeData> create()
170     {
171         return adoptPtr(new NodeListsNodeData);
172     }
173
174     void invalidateCaches(const QualifiedName* attrName = 0);
175     bool isEmpty() const
176     {
177         return m_atomicNameCaches.isEmpty() && m_nameCaches.isEmpty() && m_tagNodeListCacheNS.isEmpty();
178     }
179
180     void adoptTreeScope()
181     {
182         invalidateCaches();
183     }
184
185     void adoptDocument(Document* oldDocument, Document* newDocument)
186     {
187         invalidateCaches();
188
189         if (oldDocument != newDocument) {
190             NodeListAtomicNameCacheMap::const_iterator atomicNameCacheEnd = m_atomicNameCaches.end();
191             for (NodeListAtomicNameCacheMap::const_iterator it = m_atomicNameCaches.begin(); it != atomicNameCacheEnd; ++it) {
192                 LiveNodeListBase* list = it->value;
193                 oldDocument->unregisterNodeList(list);
194                 newDocument->registerNodeList(list);
195             }
196
197             NodeListNameCacheMap::const_iterator nameCacheEnd = m_nameCaches.end();
198             for (NodeListNameCacheMap::const_iterator it = m_nameCaches.begin(); it != nameCacheEnd; ++it) {
199                 LiveNodeListBase* list = it->value;
200                 oldDocument->unregisterNodeList(list);
201                 newDocument->registerNodeList(list);
202             }
203
204             TagNodeListCacheNS::const_iterator tagEnd = m_tagNodeListCacheNS.end();
205             for (TagNodeListCacheNS::const_iterator it = m_tagNodeListCacheNS.begin(); it != tagEnd; ++it) {
206                 LiveNodeListBase* list = it->value;
207                 ASSERT(!list->isRootedAtDocument());
208                 oldDocument->unregisterNodeList(list);
209                 newDocument->registerNodeList(list);
210             }
211         }
212     }
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 class NodeRareData : public NodeRareDataBase {
252     WTF_MAKE_NONCOPYABLE(NodeRareData); WTF_MAKE_FAST_ALLOCATED;
253 public:
254     static PassOwnPtr<NodeRareData> create(RenderObject* renderer) { return adoptPtr(new NodeRareData(renderer)); }
255
256     void clearNodeLists() { m_nodeLists.clear(); }
257     NodeListsNodeData* nodeLists() const { return m_nodeLists.get(); }
258     NodeListsNodeData& ensureNodeLists()
259     {
260         if (!m_nodeLists)
261             m_nodeLists = NodeListsNodeData::create();
262         return *m_nodeLists;
263     }
264
265     NodeMutationObserverData* mutationObserverData() { return m_mutationObserverData.get(); }
266     NodeMutationObserverData& ensureMutationObserverData()
267     {
268         if (!m_mutationObserverData)
269             m_mutationObserverData = NodeMutationObserverData::create();
270         return *m_mutationObserverData;
271     }
272
273     unsigned connectedSubframeCount() const { return m_connectedFrameCount; }
274     void incrementConnectedSubframeCount(unsigned amount)
275     {
276         m_connectedFrameCount += amount;
277     }
278     void decrementConnectedSubframeCount(unsigned amount)
279     {
280         ASSERT(m_connectedFrameCount);
281         ASSERT(amount <= m_connectedFrameCount);
282         m_connectedFrameCount -= amount;
283     }
284
285 protected:
286     NodeRareData(RenderObject* renderer)
287         : NodeRareDataBase(renderer)
288         , m_connectedFrameCount(0)
289     { }
290
291 private:
292     unsigned m_connectedFrameCount : 10; // Must fit Page::maxNumberOfFrames.
293
294     OwnPtr<NodeListsNodeData> m_nodeLists;
295     OwnPtr<NodeMutationObserverData> m_mutationObserverData;
296 };
297
298 inline bool NodeListsNodeData::deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(Node* ownerNode)
299 {
300     ASSERT(ownerNode);
301     ASSERT(ownerNode->nodeLists() == this);
302     if ((m_childNodeList ? 1 : 0) + m_atomicNameCaches.size() + m_nameCaches.size() + m_tagNodeListCacheNS.size() != 1)
303         return false;
304     ownerNode->clearNodeLists();
305     return true;
306 }
307
308 // Ensure the 10 bits reserved for the m_connectedFrameCount cannot overflow
309 COMPILE_ASSERT(Page::maxNumberOfFrames < 1024, Frame_limit_should_fit_in_rare_data_count);
310
311 } // namespace WebCore
312
313 #endif // NodeRareData_h