2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
26 #include "CollectionIndexCache.h"
27 #include "CollectionTraversal.h"
29 #include "ElementDescendantIterator.h"
30 #include "HTMLNames.h"
32 #include <wtf/Forward.h>
38 static bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType, const QualifiedName&);
40 class LiveNodeList : public NodeList {
42 LiveNodeList(ContainerNode& ownerNode, NodeListInvalidationType);
43 virtual ~LiveNodeList();
45 virtual bool elementMatches(Element&) const = 0;
46 virtual bool isRootedAtDocument() const = 0;
48 ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); }
49 ContainerNode& ownerNode() const { return m_ownerNode; }
50 ALWAYS_INLINE void invalidateCacheForAttribute(const QualifiedName& attrName) const
52 if (shouldInvalidateTypeOnAttributeChange(invalidationType(), attrName))
55 virtual void invalidateCacheForDocument(Document&) const = 0;
56 void invalidateCache() const { invalidateCacheForDocument(document()); }
58 bool isRegisteredForInvalidationAtDocument() const { return m_isRegisteredForInvalidationAtDocument; }
59 void setRegisteredForInvalidationAtDocument(bool f) { m_isRegisteredForInvalidationAtDocument = f; }
62 Document& document() const { return m_ownerNode->document(); }
65 bool isLiveNodeList() const final { return true; }
67 ContainerNode& rootNode() const;
69 Ref<ContainerNode> m_ownerNode;
71 const unsigned m_invalidationType;
72 bool m_isRegisteredForInvalidationAtDocument;
75 template <class NodeListType>
76 class CachedLiveNodeList : public LiveNodeList {
78 virtual ~CachedLiveNodeList();
80 unsigned length() const final { return m_indexCache.nodeCount(nodeList()); }
81 Element* item(unsigned offset) const override { return m_indexCache.nodeAt(nodeList(), offset); }
83 // For CollectionIndexCache
84 ElementDescendantIterator collectionBegin() const { return CollectionTraversal<CollectionTraversalType::Descendants>::begin(nodeList(), rootNode()); }
85 ElementDescendantIterator collectionLast() const { return CollectionTraversal<CollectionTraversalType::Descendants>::last(nodeList(), rootNode()); }
86 ElementDescendantIterator collectionEnd() const { return ElementDescendantIterator(); }
87 void collectionTraverseForward(ElementDescendantIterator& current, unsigned count, unsigned& traversedCount) const { CollectionTraversal<CollectionTraversalType::Descendants>::traverseForward(nodeList(), current, count, traversedCount); }
88 void collectionTraverseBackward(ElementDescendantIterator& current, unsigned count) const { CollectionTraversal<CollectionTraversalType::Descendants>::traverseBackward(nodeList(), current, count); }
89 bool collectionCanTraverseBackward() const { return true; }
90 void willValidateIndexCache() const { document().registerNodeListForInvalidation(const_cast<CachedLiveNodeList<NodeListType>&>(*this)); }
92 void invalidateCacheForDocument(Document&) const final;
93 size_t memoryCost() const final
95 // memoryCost() may be invoked concurrently from a GC thread, and we need to be careful
96 // about what data we access here and how. Accessing m_indexCache is safe because
97 // because it doesn't involve any pointer chasing.
98 return m_indexCache.memoryCost();
102 CachedLiveNodeList(ContainerNode& rootNode, NodeListInvalidationType);
105 NodeListType& nodeList() { return static_cast<NodeListType&>(*this); }
106 const NodeListType& nodeList() const { return static_cast<const NodeListType&>(*this); }
108 ContainerNode& rootNode() const;
110 mutable CollectionIndexCache<NodeListType, ElementDescendantIterator> m_indexCache;
113 ALWAYS_INLINE bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType type, const QualifiedName& attrName)
116 case InvalidateOnClassAttrChange:
117 return attrName == HTMLNames::classAttr;
118 case InvalidateOnNameAttrChange:
119 return attrName == HTMLNames::nameAttr;
120 case InvalidateOnIdNameAttrChange:
121 return attrName == HTMLNames::idAttr || attrName == HTMLNames::nameAttr;
122 case InvalidateOnForTypeAttrChange:
123 return attrName == HTMLNames::forAttr || attrName == HTMLNames::typeAttr;
124 case InvalidateForFormControls:
125 return attrName == HTMLNames::nameAttr || attrName == HTMLNames::idAttr || attrName == HTMLNames::forAttr
126 || attrName == HTMLNames::formAttr || attrName == HTMLNames::typeAttr;
127 case InvalidateOnHRefAttrChange:
128 return attrName == HTMLNames::hrefAttr;
129 case DoNotInvalidateOnAttributeChanges:
131 case InvalidateOnAnyAttrChange:
137 template <class NodeListType>
138 CachedLiveNodeList<NodeListType>::CachedLiveNodeList(ContainerNode& ownerNode, NodeListInvalidationType invalidationType)
139 : LiveNodeList(ownerNode, invalidationType)
140 , m_indexCache(nodeList())
144 template <class NodeListType>
145 CachedLiveNodeList<NodeListType>::~CachedLiveNodeList()
147 if (m_indexCache.hasValidCache(nodeList()))
148 document().unregisterNodeListForInvalidation(*this);
151 template <class NodeListType>
152 inline ContainerNode& CachedLiveNodeList<NodeListType>::rootNode() const
154 if (nodeList().isRootedAtDocument() && ownerNode().isConnected())
155 return ownerNode().document();
160 template <class NodeListType>
161 void CachedLiveNodeList<NodeListType>::invalidateCacheForDocument(Document& document) const
163 if (!m_indexCache.hasValidCache(nodeList()))
165 document.unregisterNodeListForInvalidation(const_cast<NodeListType&>(nodeList()));
166 m_indexCache.invalidate(nodeList());
169 } // namespace WebCore