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 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
    349