Home | History | Annotate | Download | only in dom
      1 /*
      2  * Copyright (C) 2008, 2010 Apple Inc. All rights reserved.
      3  * Copyright (C) 2008 David Smith <catfish.man (at) 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
    268