edc3719595f40d701b2ce8f53a2553c65f0dbd59
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/dom/ChildNodeList.h"
26 #include "core/dom/EmptyNodeList.h"
27 #include "core/dom/LiveNodeList.h"
28 #include "core/dom/MutationObserverRegistration.h"
29 #include "core/dom/QualifiedName.h"
30 #include "core/dom/TagCollection.h"
31 #include "core/page/Page.h"
32 #include "platform/heap/Handle.h"
33 #include "wtf/HashSet.h"
34 #include "wtf/OwnPtr.h"
35 #include "wtf/PassOwnPtr.h"
36 #include "wtf/text/AtomicString.h"
37 #include "wtf/text/StringHash.h"
38
39 namespace WebCore {
40
41 class LabelsNodeList;
42 class RadioNodeList;
43 class TreeScope;
44
45 class NodeListsNodeData FINAL : public NoBaseWillBeGarbageCollectedFinalized<NodeListsNodeData> {
46     WTF_MAKE_NONCOPYABLE(NodeListsNodeData);
47     WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
48 public:
49     void clearChildNodeListCache()
50     {
51         if (m_childNodeList && m_childNodeList->isChildNodeList())
52             toChildNodeList(m_childNodeList)->invalidateCache();
53     }
54
55     PassRefPtrWillBeRawPtr<ChildNodeList> ensureChildNodeList(ContainerNode& node)
56     {
57         if (m_childNodeList)
58             return toChildNodeList(m_childNodeList);
59         RefPtrWillBeRawPtr<ChildNodeList> list = ChildNodeList::create(node);
60         m_childNodeList = list.get();
61         return list.release();
62     }
63
64     PassRefPtrWillBeRawPtr<EmptyNodeList> ensureEmptyChildNodeList(Node& node)
65     {
66         if (m_childNodeList)
67             return toEmptyNodeList(m_childNodeList);
68         RefPtrWillBeRawPtr<EmptyNodeList> list = EmptyNodeList::create(node);
69         m_childNodeList = list.get();
70         return list.release();
71     }
72
73 #if !ENABLE(OILPAN)
74     void removeChildNodeList(ChildNodeList* list)
75     {
76         ASSERT(m_childNodeList == list);
77         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
78             return;
79         m_childNodeList = nullptr;
80     }
81
82     void removeEmptyChildNodeList(EmptyNodeList* list)
83     {
84         ASSERT(m_childNodeList == list);
85         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
86             return;
87         m_childNodeList = nullptr;
88     }
89 #endif
90
91     struct NodeListAtomicCacheMapEntryHash {
92         static unsigned hash(const std::pair<unsigned char, StringImpl*>& entry)
93         {
94             return DefaultHash<StringImpl*>::Hash::hash(entry.second) + entry.first;
95         }
96         static bool equal(const std::pair<unsigned char, StringImpl*>& a, const std::pair<unsigned char, StringImpl*>& b) { return a == b; }
97         static const bool safeToCompareToEmptyOrDeleted = DefaultHash<StringImpl*>::Hash::safeToCompareToEmptyOrDeleted;
98     };
99
100     // Oilpan: keep a weak reference to the collection objects.
101     // Explicit object unregistration in a non-Oilpan setting
102     // on object destruction is replaced by the garbage collector
103     // clearing out their weak reference.
104     typedef WillBeHeapHashMap<std::pair<unsigned char, StringImpl*>, RawPtrWillBeWeakMember<LiveNodeListBase>, NodeListAtomicCacheMapEntryHash> NodeListAtomicNameCacheMap;
105     typedef WillBeHeapHashMap<QualifiedName, RawPtrWillBeWeakMember<TagCollection> > TagCollectionCacheNS;
106
107     template<typename T>
108     PassRefPtrWillBeRawPtr<T> addCache(ContainerNode& node, CollectionType collectionType, const AtomicString& name)
109     {
110         NodeListAtomicNameCacheMap::AddResult result = m_atomicNameCaches.add(namedNodeListKey(collectionType, name), nullptr);
111         if (!result.isNewEntry) {
112 #if ENABLE(OILPAN)
113             return static_cast<T*>(result.storedValue->value.get());
114 #else
115             return static_cast<T*>(result.storedValue->value);
116 #endif
117         }
118
119         RefPtrWillBeRawPtr<T> list = T::create(node, collectionType, name);
120         result.storedValue->value = list.get();
121         return list.release();
122     }
123
124     template<typename T>
125     PassRefPtrWillBeRawPtr<T> addCache(ContainerNode& node, CollectionType collectionType)
126     {
127         NodeListAtomicNameCacheMap::AddResult result = m_atomicNameCaches.add(namedNodeListKey(collectionType, starAtom), nullptr);
128         if (!result.isNewEntry) {
129 #if ENABLE(OILPAN)
130             return static_cast<T*>(result.storedValue->value.get());
131 #else
132             return static_cast<T*>(result.storedValue->value);
133 #endif
134         }
135
136         RefPtrWillBeRawPtr<T> list = T::create(node, collectionType);
137         result.storedValue->value = list.get();
138         return list.release();
139     }
140
141     template<typename T>
142     T* cached(CollectionType collectionType)
143     {
144         return static_cast<T*>(m_atomicNameCaches.get(namedNodeListKey(collectionType, starAtom)));
145     }
146
147     PassRefPtrWillBeRawPtr<TagCollection> addCache(ContainerNode& node, const AtomicString& namespaceURI, const AtomicString& localName)
148     {
149         QualifiedName name(nullAtom, localName, namespaceURI);
150         TagCollectionCacheNS::AddResult result = m_tagCollectionCacheNS.add(name, nullptr);
151         if (!result.isNewEntry)
152             return result.storedValue->value;
153
154         RefPtrWillBeRawPtr<TagCollection> list = TagCollection::create(node, namespaceURI, localName);
155         result.storedValue->value = list.get();
156         return list.release();
157     }
158
159 #if !ENABLE(OILPAN)
160     void removeCache(LiveNodeListBase* list, CollectionType collectionType, const AtomicString& name = starAtom)
161     {
162         ASSERT(list == m_atomicNameCaches.get(namedNodeListKey(collectionType, name)));
163         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
164             return;
165         m_atomicNameCaches.remove(namedNodeListKey(collectionType, name));
166     }
167
168     void removeCache(LiveNodeListBase* list, const AtomicString& namespaceURI, const AtomicString& localName)
169     {
170         QualifiedName name(nullAtom, localName, namespaceURI);
171         ASSERT(list == m_tagCollectionCacheNS.get(name));
172         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
173             return;
174         m_tagCollectionCacheNS.remove(name);
175     }
176 #endif
177
178     static PassOwnPtrWillBeRawPtr<NodeListsNodeData> create()
179     {
180         return adoptPtrWillBeNoop(new NodeListsNodeData);
181     }
182
183     void invalidateCaches(const QualifiedName* attrName = 0);
184
185     bool isEmpty() const
186     {
187         return !m_childNodeList && m_atomicNameCaches.isEmpty() && m_tagCollectionCacheNS.isEmpty();
188     }
189
190     void adoptTreeScope()
191     {
192         invalidateCaches();
193     }
194
195     void adoptDocument(Document& oldDocument, Document& newDocument)
196     {
197         ASSERT(oldDocument != newDocument);
198
199         NodeListAtomicNameCacheMap::const_iterator atomicNameCacheEnd = m_atomicNameCaches.end();
200         for (NodeListAtomicNameCacheMap::const_iterator it = m_atomicNameCaches.begin(); it != atomicNameCacheEnd; ++it) {
201             LiveNodeListBase* list = it->value;
202             list->didMoveToDocument(oldDocument, newDocument);
203         }
204
205         TagCollectionCacheNS::const_iterator tagEnd = m_tagCollectionCacheNS.end();
206         for (TagCollectionCacheNS::const_iterator it = m_tagCollectionCacheNS.begin(); it != tagEnd; ++it) {
207             LiveNodeListBase* list = it->value;
208             ASSERT(!list->isRootedAtDocument());
209             list->didMoveToDocument(oldDocument, newDocument);
210         }
211     }
212
213     void trace(Visitor*);
214
215 private:
216     NodeListsNodeData()
217         : m_childNodeList(nullptr)
218     { }
219
220     std::pair<unsigned char, StringImpl*> namedNodeListKey(CollectionType type, const AtomicString& name)
221     {
222         // Holding the raw StringImpl is safe because |name| is retained by the NodeList and the NodeList
223         // is reponsible for removing itself from the cache on deletion.
224         return std::pair<unsigned char, StringImpl*>(type, name.impl());
225     }
226
227 #if !ENABLE(OILPAN)
228     bool deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(Node&);
229 #endif
230
231     // Can be a ChildNodeList or an EmptyNodeList.
232     RawPtrWillBeWeakMember<NodeList> m_childNodeList;
233     NodeListAtomicNameCacheMap m_atomicNameCaches;
234     TagCollectionCacheNS m_tagCollectionCacheNS;
235 };
236
237 class NodeMutationObserverData FINAL : public NoBaseWillBeGarbageCollected<NodeMutationObserverData> {
238     WTF_MAKE_NONCOPYABLE(NodeMutationObserverData);
239     WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
240 public:
241     WillBeHeapVector<OwnPtrWillBeMember<MutationObserverRegistration> > registry;
242     WillBeHeapHashSet<RawPtrWillBeMember<MutationObserverRegistration> > transientRegistry;
243
244     static PassOwnPtrWillBeRawPtr<NodeMutationObserverData> create()
245     {
246         return adoptPtrWillBeNoop(new NodeMutationObserverData);
247     }
248
249     void trace(Visitor* visitor)
250     {
251         visitor->trace(registry);
252         visitor->trace(transientRegistry);
253     }
254
255 private:
256     NodeMutationObserverData() { }
257 };
258
259 class NodeRareData : public NoBaseWillBeGarbageCollectedFinalized<NodeRareData>, public NodeRareDataBase {
260     WTF_MAKE_NONCOPYABLE(NodeRareData);
261     WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
262 public:
263     static NodeRareData* create(RenderObject* renderer)
264     {
265         return new NodeRareData(renderer);
266     }
267
268     void clearNodeLists() { m_nodeLists.clear(); }
269     NodeListsNodeData* nodeLists() const { return m_nodeLists.get(); }
270     NodeListsNodeData& ensureNodeLists()
271     {
272         if (!m_nodeLists)
273             m_nodeLists = NodeListsNodeData::create();
274         return *m_nodeLists;
275     }
276
277     NodeMutationObserverData* mutationObserverData() { return m_mutationObserverData.get(); }
278     NodeMutationObserverData& ensureMutationObserverData()
279     {
280         if (!m_mutationObserverData)
281             m_mutationObserverData = NodeMutationObserverData::create();
282         return *m_mutationObserverData;
283     }
284
285     unsigned connectedSubframeCount() const { return m_connectedFrameCount; }
286     void incrementConnectedSubframeCount(unsigned amount)
287     {
288         m_connectedFrameCount += amount;
289     }
290     void decrementConnectedSubframeCount(unsigned amount)
291     {
292         ASSERT(m_connectedFrameCount);
293         ASSERT(amount <= m_connectedFrameCount);
294         m_connectedFrameCount -= amount;
295     }
296
297     bool hasElementFlag(ElementFlags mask) const { return m_elementFlags & mask; }
298     void setElementFlag(ElementFlags mask, bool value) { m_elementFlags = (m_elementFlags & ~mask) | (-(int32_t)value & mask); }
299     void clearElementFlag(ElementFlags mask) { m_elementFlags &= ~mask; }
300
301     bool hasRestyleFlag(DynamicRestyleFlags mask) const { return m_restyleFlags & mask; }
302     void setRestyleFlag(DynamicRestyleFlags mask) { m_restyleFlags |= mask; RELEASE_ASSERT(m_restyleFlags); }
303     bool hasRestyleFlags() const { return m_restyleFlags; }
304     void clearRestyleFlags() { m_restyleFlags = 0; }
305
306     enum {
307         ConnectedFrameCountBits = 10, // Must fit Page::maxNumberOfFrames.
308     };
309
310     void trace(Visitor*);
311
312     void traceAfterDispatch(Visitor*);
313     void finalizeGarbageCollectedObject();
314
315 protected:
316     explicit NodeRareData(RenderObject* renderer)
317         : NodeRareDataBase(renderer)
318         , m_connectedFrameCount(0)
319         , m_elementFlags(0)
320         , m_restyleFlags(0)
321         , m_isElementRareData(false)
322     { }
323
324 private:
325     OwnPtrWillBeMember<NodeListsNodeData> m_nodeLists;
326     OwnPtrWillBeMember<NodeMutationObserverData> m_mutationObserverData;
327
328     unsigned m_connectedFrameCount : ConnectedFrameCountBits;
329     unsigned m_elementFlags : NumberOfElementFlags;
330     unsigned m_restyleFlags : NumberOfDynamicRestyleFlags;
331 protected:
332     unsigned m_isElementRareData : 1;
333 };
334
335 #if !ENABLE(OILPAN)
336 inline bool NodeListsNodeData::deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(Node& ownerNode)
337 {
338     ASSERT(ownerNode.nodeLists() == this);
339     if ((m_childNodeList ? 1 : 0) + m_atomicNameCaches.size() + m_tagCollectionCacheNS.size() != 1)
340         return false;
341     ownerNode.clearNodeLists();
342     return true;
343 }
344 #endif
345
346 } // namespace WebCore
347
348 #endif // NodeRareData_h