Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / NodeListsNodeData.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 NodeListsNodeData_h
23 #define NodeListsNodeData_h
24
25 #include "core/dom/ChildNodeList.h"
26 #include "core/dom/EmptyNodeList.h"
27 #include "core/dom/QualifiedName.h"
28 #include "core/dom/TagCollection.h"
29 #include "core/html/CollectionType.h"
30 #include "platform/heap/Handle.h"
31 #include "wtf/text/AtomicString.h"
32 #include "wtf/text/StringHash.h"
33
34 namespace blink {
35
36 class NodeListsNodeData final : public NoBaseWillBeGarbageCollectedFinalized<NodeListsNodeData> {
37     WTF_MAKE_NONCOPYABLE(NodeListsNodeData);
38     WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
39 public:
40     ChildNodeList* childNodeList(ContainerNode& node)
41     {
42         ASSERT_UNUSED(node, !m_childNodeList || node == m_childNodeList->virtualOwnerNode());
43         return toChildNodeList(m_childNodeList);
44     }
45
46     PassRefPtrWillBeRawPtr<ChildNodeList> ensureChildNodeList(ContainerNode& node)
47     {
48         if (m_childNodeList)
49             return toChildNodeList(m_childNodeList);
50         RefPtrWillBeRawPtr<ChildNodeList> list = ChildNodeList::create(node);
51         m_childNodeList = list.get();
52         return list.release();
53     }
54
55     PassRefPtrWillBeRawPtr<EmptyNodeList> ensureEmptyChildNodeList(Node& node)
56     {
57         if (m_childNodeList)
58             return toEmptyNodeList(m_childNodeList);
59         RefPtrWillBeRawPtr<EmptyNodeList> list = EmptyNodeList::create(node);
60         m_childNodeList = list.get();
61         return list.release();
62     }
63
64 #if !ENABLE(OILPAN)
65     void removeChildNodeList(ChildNodeList* list)
66     {
67         ASSERT(m_childNodeList == list);
68         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
69             return;
70         m_childNodeList = nullptr;
71     }
72
73     void removeEmptyChildNodeList(EmptyNodeList* list)
74     {
75         ASSERT(m_childNodeList == list);
76         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
77             return;
78         m_childNodeList = nullptr;
79     }
80 #endif
81
82     struct NodeListAtomicCacheMapEntryHash {
83         static unsigned hash(const std::pair<unsigned char, StringImpl*>& entry)
84         {
85             return DefaultHash<StringImpl*>::Hash::hash(entry.second) + entry.first;
86         }
87         static bool equal(const std::pair<unsigned char, StringImpl*>& a, const std::pair<unsigned char, StringImpl*>& b) { return a == b; }
88         static const bool safeToCompareToEmptyOrDeleted = DefaultHash<StringImpl*>::Hash::safeToCompareToEmptyOrDeleted;
89     };
90
91     // Oilpan: keep a weak reference to the collection objects.
92     // Explicit object unregistration in a non-Oilpan setting
93     // on object destruction is replaced by the garbage collector
94     // clearing out their weak reference.
95     typedef WillBeHeapHashMap<std::pair<unsigned char, StringImpl*>, RawPtrWillBeWeakMember<LiveNodeListBase>, NodeListAtomicCacheMapEntryHash> NodeListAtomicNameCacheMap;
96     typedef WillBeHeapHashMap<QualifiedName, RawPtrWillBeWeakMember<TagCollection> > TagCollectionCacheNS;
97
98     template<typename T>
99     PassRefPtrWillBeRawPtr<T> addCache(ContainerNode& node, CollectionType collectionType, const AtomicString& name)
100     {
101         NodeListAtomicNameCacheMap::AddResult result = m_atomicNameCaches.add(namedNodeListKey(collectionType, name), nullptr);
102         if (!result.isNewEntry) {
103 #if ENABLE(OILPAN)
104             return static_cast<T*>(result.storedValue->value.get());
105 #else
106             return static_cast<T*>(result.storedValue->value);
107 #endif
108         }
109
110         RefPtrWillBeRawPtr<T> list = T::create(node, collectionType, name);
111         result.storedValue->value = list.get();
112         return list.release();
113     }
114
115     template<typename T>
116     PassRefPtrWillBeRawPtr<T> addCache(ContainerNode& node, CollectionType collectionType)
117     {
118         NodeListAtomicNameCacheMap::AddResult result = m_atomicNameCaches.add(namedNodeListKey(collectionType, starAtom), nullptr);
119         if (!result.isNewEntry) {
120 #if ENABLE(OILPAN)
121             return static_cast<T*>(result.storedValue->value.get());
122 #else
123             return static_cast<T*>(result.storedValue->value);
124 #endif
125         }
126
127         RefPtrWillBeRawPtr<T> list = T::create(node, collectionType);
128         result.storedValue->value = list.get();
129         return list.release();
130     }
131
132     template<typename T>
133     T* cached(CollectionType collectionType)
134     {
135         return static_cast<T*>(m_atomicNameCaches.get(namedNodeListKey(collectionType, starAtom)));
136     }
137
138     PassRefPtrWillBeRawPtr<TagCollection> addCache(ContainerNode& node, const AtomicString& namespaceURI, const AtomicString& localName)
139     {
140         QualifiedName name(nullAtom, localName, namespaceURI);
141         TagCollectionCacheNS::AddResult result = m_tagCollectionCacheNS.add(name, nullptr);
142         if (!result.isNewEntry)
143             return result.storedValue->value;
144
145         RefPtrWillBeRawPtr<TagCollection> list = TagCollection::create(node, namespaceURI, localName);
146         result.storedValue->value = list.get();
147         return list.release();
148     }
149
150 #if !ENABLE(OILPAN)
151     void removeCache(LiveNodeListBase* list, CollectionType collectionType, const AtomicString& name = starAtom)
152     {
153         ASSERT(list == m_atomicNameCaches.get(namedNodeListKey(collectionType, name)));
154         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
155             return;
156         m_atomicNameCaches.remove(namedNodeListKey(collectionType, name));
157     }
158
159     void removeCache(LiveNodeListBase* list, const AtomicString& namespaceURI, const AtomicString& localName)
160     {
161         QualifiedName name(nullAtom, localName, namespaceURI);
162         ASSERT(list == m_tagCollectionCacheNS.get(name));
163         if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
164             return;
165         m_tagCollectionCacheNS.remove(name);
166     }
167 #endif
168
169     static PassOwnPtrWillBeRawPtr<NodeListsNodeData> create()
170     {
171         return adoptPtrWillBeNoop(new NodeListsNodeData);
172     }
173
174     void invalidateCaches(const QualifiedName* attrName = 0);
175
176     bool isEmpty() const
177     {
178         return !m_childNodeList && m_atomicNameCaches.isEmpty() && m_tagCollectionCacheNS.isEmpty();
179     }
180
181     void adoptTreeScope()
182     {
183         invalidateCaches();
184     }
185
186     void adoptDocument(Document& oldDocument, Document& newDocument)
187     {
188         ASSERT(oldDocument != newDocument);
189
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             list->didMoveToDocument(oldDocument, newDocument);
194         }
195
196         TagCollectionCacheNS::const_iterator tagEnd = m_tagCollectionCacheNS.end();
197         for (TagCollectionCacheNS::const_iterator it = m_tagCollectionCacheNS.begin(); it != tagEnd; ++it) {
198             LiveNodeListBase* list = it->value;
199             ASSERT(!list->isRootedAtDocument());
200             list->didMoveToDocument(oldDocument, newDocument);
201         }
202     }
203
204     void trace(Visitor*);
205
206 private:
207     NodeListsNodeData()
208         : m_childNodeList(nullptr)
209     { }
210
211     std::pair<unsigned char, StringImpl*> namedNodeListKey(CollectionType type, const AtomicString& name)
212     {
213         // Holding the raw StringImpl is safe because |name| is retained by the NodeList and the NodeList
214         // is reponsible for removing itself from the cache on deletion.
215         return std::pair<unsigned char, StringImpl*>(type, name.impl());
216     }
217
218 #if !ENABLE(OILPAN)
219     bool deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(Node&);
220 #endif
221
222     // Can be a ChildNodeList or an EmptyNodeList.
223     RawPtrWillBeWeakMember<NodeList> m_childNodeList;
224     NodeListAtomicNameCacheMap m_atomicNameCaches;
225     TagCollectionCacheNS m_tagCollectionCacheNS;
226 };
227
228 #if !ENABLE(OILPAN)
229 inline bool NodeListsNodeData::deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(Node& ownerNode)
230 {
231     ASSERT(ownerNode.nodeLists() == this);
232     if ((m_childNodeList ? 1 : 0) + m_atomicNameCaches.size() + m_tagCollectionCacheNS.size() != 1)
233         return false;
234     ownerNode.clearNodeLists();
235     return true;
236 }
237 #endif
238
239 template <typename Collection>
240 inline PassRefPtrWillBeRawPtr<Collection> ContainerNode::ensureCachedCollection(CollectionType type)
241 {
242     return ensureNodeLists().addCache<Collection>(*this, type);
243 }
244
245 template <typename Collection>
246 inline PassRefPtrWillBeRawPtr<Collection> ContainerNode::ensureCachedCollection(CollectionType type, const AtomicString& name)
247 {
248     return ensureNodeLists().addCache<Collection>(*this, type, name);
249 }
250
251 template <typename Collection>
252 inline PassRefPtrWillBeRawPtr<Collection> ContainerNode::ensureCachedCollection(CollectionType type, const AtomicString& namespaceURI, const AtomicString& localName)
253 {
254     ASSERT_UNUSED(type, type == TagCollectionType);
255     return ensureNodeLists().addCache(*this, namespaceURI, localName);
256 }
257
258 template <typename Collection>
259 inline Collection* ContainerNode::cachedCollection(CollectionType type)
260 {
261     NodeListsNodeData* nodeLists = this->nodeLists();
262     return nodeLists ? nodeLists->cached<Collection>(type) : 0;
263 }
264
265 } // namespace blink
266
267 #endif // NodeListsNodeData_h