2 * Copyright (C) 2008, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 David Smith <catfish.man@gmail.com>
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.
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.
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.
22 #ifndef NodeRareData_h
23 #define NodeRareData_h
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"
45 class NodeListsNodeData FINAL : public NoBaseWillBeGarbageCollectedFinalized<NodeListsNodeData> {
46 WTF_MAKE_NONCOPYABLE(NodeListsNodeData);
47 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
49 void clearChildNodeListCache()
51 if (m_childNodeList && m_childNodeList->isChildNodeList())
52 toChildNodeList(m_childNodeList)->invalidateCache();
55 PassRefPtrWillBeRawPtr<ChildNodeList> ensureChildNodeList(ContainerNode& node)
58 return toChildNodeList(m_childNodeList);
59 RefPtrWillBeRawPtr<ChildNodeList> list = ChildNodeList::create(node);
60 m_childNodeList = list.get();
61 return list.release();
64 PassRefPtrWillBeRawPtr<EmptyNodeList> ensureEmptyChildNodeList(Node& node)
67 return toEmptyNodeList(m_childNodeList);
68 RefPtrWillBeRawPtr<EmptyNodeList> list = EmptyNodeList::create(node);
69 m_childNodeList = list.get();
70 return list.release();
74 void removeChildNodeList(ChildNodeList* list)
76 ASSERT(m_childNodeList == list);
77 if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
79 m_childNodeList = nullptr;
82 void removeEmptyChildNodeList(EmptyNodeList* list)
84 ASSERT(m_childNodeList == list);
85 if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
87 m_childNodeList = nullptr;
91 struct NodeListAtomicCacheMapEntryHash {
92 static unsigned hash(const std::pair<unsigned char, StringImpl*>& entry)
94 return DefaultHash<StringImpl*>::Hash::hash(entry.second) + entry.first;
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;
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;
108 PassRefPtrWillBeRawPtr<T> addCache(ContainerNode& node, CollectionType collectionType, const AtomicString& name)
110 NodeListAtomicNameCacheMap::AddResult result = m_atomicNameCaches.add(namedNodeListKey(collectionType, name), nullptr);
111 if (!result.isNewEntry) {
113 return static_cast<T*>(result.storedValue->value.get());
115 return static_cast<T*>(result.storedValue->value);
119 RefPtrWillBeRawPtr<T> list = T::create(node, collectionType, name);
120 result.storedValue->value = list.get();
121 return list.release();
125 PassRefPtrWillBeRawPtr<T> addCache(ContainerNode& node, CollectionType collectionType)
127 NodeListAtomicNameCacheMap::AddResult result = m_atomicNameCaches.add(namedNodeListKey(collectionType, starAtom), nullptr);
128 if (!result.isNewEntry) {
130 return static_cast<T*>(result.storedValue->value.get());
132 return static_cast<T*>(result.storedValue->value);
136 RefPtrWillBeRawPtr<T> list = T::create(node, collectionType);
137 result.storedValue->value = list.get();
138 return list.release();
142 T* cached(CollectionType collectionType)
144 return static_cast<T*>(m_atomicNameCaches.get(namedNodeListKey(collectionType, starAtom)));
147 PassRefPtrWillBeRawPtr<TagCollection> addCache(ContainerNode& node, const AtomicString& namespaceURI, const AtomicString& localName)
149 QualifiedName name(nullAtom, localName, namespaceURI);
150 TagCollectionCacheNS::AddResult result = m_tagCollectionCacheNS.add(name, nullptr);
151 if (!result.isNewEntry)
152 return result.storedValue->value;
154 RefPtrWillBeRawPtr<TagCollection> list = TagCollection::create(node, namespaceURI, localName);
155 result.storedValue->value = list.get();
156 return list.release();
160 void removeCache(LiveNodeListBase* list, CollectionType collectionType, const AtomicString& name = starAtom)
162 ASSERT(list == m_atomicNameCaches.get(namedNodeListKey(collectionType, name)));
163 if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
165 m_atomicNameCaches.remove(namedNodeListKey(collectionType, name));
168 void removeCache(LiveNodeListBase* list, const AtomicString& namespaceURI, const AtomicString& localName)
170 QualifiedName name(nullAtom, localName, namespaceURI);
171 ASSERT(list == m_tagCollectionCacheNS.get(name));
172 if (deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(list->ownerNode()))
174 m_tagCollectionCacheNS.remove(name);
178 static PassOwnPtrWillBeRawPtr<NodeListsNodeData> create()
180 return adoptPtrWillBeNoop(new NodeListsNodeData);
183 void invalidateCaches(const QualifiedName* attrName = 0);
187 return !m_childNodeList && m_atomicNameCaches.isEmpty() && m_tagCollectionCacheNS.isEmpty();
190 void adoptTreeScope()
195 void adoptDocument(Document& oldDocument, Document& newDocument)
197 ASSERT(oldDocument != newDocument);
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);
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);
213 void trace(Visitor*);
217 : m_childNodeList(nullptr)
220 std::pair<unsigned char, StringImpl*> namedNodeListKey(CollectionType type, const AtomicString& name)
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());
228 bool deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(Node&);
231 // Can be a ChildNodeList or an EmptyNodeList.
232 RawPtrWillBeWeakMember<NodeList> m_childNodeList;
233 NodeListAtomicNameCacheMap m_atomicNameCaches;
234 TagCollectionCacheNS m_tagCollectionCacheNS;
237 class NodeMutationObserverData FINAL : public NoBaseWillBeGarbageCollected<NodeMutationObserverData> {
238 WTF_MAKE_NONCOPYABLE(NodeMutationObserverData);
239 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
241 WillBeHeapVector<OwnPtrWillBeMember<MutationObserverRegistration> > registry;
242 WillBeHeapHashSet<RawPtrWillBeMember<MutationObserverRegistration> > transientRegistry;
244 static PassOwnPtrWillBeRawPtr<NodeMutationObserverData> create()
246 return adoptPtrWillBeNoop(new NodeMutationObserverData);
249 void trace(Visitor* visitor)
251 visitor->trace(registry);
252 visitor->trace(transientRegistry);
256 NodeMutationObserverData() { }
259 class NodeRareData : public NoBaseWillBeGarbageCollectedFinalized<NodeRareData>, public NodeRareDataBase {
260 WTF_MAKE_NONCOPYABLE(NodeRareData);
261 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
263 static NodeRareData* create(RenderObject* renderer)
265 return new NodeRareData(renderer);
268 void clearNodeLists() { m_nodeLists.clear(); }
269 NodeListsNodeData* nodeLists() const { return m_nodeLists.get(); }
270 NodeListsNodeData& ensureNodeLists()
273 m_nodeLists = NodeListsNodeData::create();
277 NodeMutationObserverData* mutationObserverData() { return m_mutationObserverData.get(); }
278 NodeMutationObserverData& ensureMutationObserverData()
280 if (!m_mutationObserverData)
281 m_mutationObserverData = NodeMutationObserverData::create();
282 return *m_mutationObserverData;
285 unsigned connectedSubframeCount() const { return m_connectedFrameCount; }
286 void incrementConnectedSubframeCount(unsigned amount)
288 m_connectedFrameCount += amount;
290 void decrementConnectedSubframeCount(unsigned amount)
292 ASSERT(m_connectedFrameCount);
293 ASSERT(amount <= m_connectedFrameCount);
294 m_connectedFrameCount -= amount;
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; }
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; }
307 ConnectedFrameCountBits = 10, // Must fit Page::maxNumberOfFrames.
310 void trace(Visitor*);
312 void traceAfterDispatch(Visitor*);
313 void finalizeGarbageCollectedObject();
316 explicit NodeRareData(RenderObject* renderer)
317 : NodeRareDataBase(renderer)
318 , m_connectedFrameCount(0)
321 , m_isElementRareData(false)
325 OwnPtrWillBeMember<NodeListsNodeData> m_nodeLists;
326 OwnPtrWillBeMember<NodeMutationObserverData> m_mutationObserverData;
328 unsigned m_connectedFrameCount : ConnectedFrameCountBits;
329 unsigned m_elementFlags : NumberOfElementFlags;
330 unsigned m_restyleFlags : NumberOfDynamicRestyleFlags;
332 unsigned m_isElementRareData : 1;
336 inline bool NodeListsNodeData::deleteThisAndUpdateNodeRareDataIfAboutToRemoveLastList(Node& ownerNode)
338 ASSERT(ownerNode.nodeLists() == this);
339 if ((m_childNodeList ? 1 : 0) + m_atomicNameCaches.size() + m_tagCollectionCacheNS.size() != 1)
341 ownerNode.clearNodeLists();
346 } // namespace WebCore
348 #endif // NodeRareData_h