Rename LiveNodeLists / HTMLCollections's nodeMatches() to elementMatches()
[WebKit-https.git] / Source / WebCore / dom / LiveNodeList.h
1 /*
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, 2006-2007, 2013-2014 Apple Inc. All rights reserved.
6  *
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.
11  *
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.
16  *
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.
21  *
22  */
23
24 #ifndef LiveNodeList_h
25 #define LiveNodeList_h
26
27 #include "CollectionIndexCache.h"
28 #include "CollectionType.h"
29 #include "Document.h"
30 #include "ElementDescendantIterator.h"
31 #include "HTMLNames.h"
32 #include "NodeList.h"
33 #include <wtf/Forward.h>
34 #include <wtf/RefPtr.h>
35
36 namespace WebCore {
37
38 class Element;
39
40 static bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType, const QualifiedName&);
41
42 class LiveNodeList : public NodeList {
43 public:
44     LiveNodeList(ContainerNode& ownerNode, NodeListInvalidationType);
45     virtual ~LiveNodeList();
46
47     virtual Node* namedItem(const AtomicString&) const override final;
48
49     virtual bool elementMatches(Element*) const = 0;
50     virtual bool isRootedAtDocument() const = 0;
51
52     ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); }
53     ContainerNode& ownerNode() const { return const_cast<ContainerNode&>(m_ownerNode.get()); }
54     ALWAYS_INLINE void invalidateCacheForAttribute(const QualifiedName* attrName) const
55     {
56         if (!attrName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attrName))
57             invalidateCache(document());
58     }
59     virtual void invalidateCache(Document&) const = 0;
60
61     bool isRegisteredForInvalidationAtDocument() const { return m_isRegisteredForInvalidationAtDocument; }
62     void setRegisteredForInvalidationAtDocument(bool f) { m_isRegisteredForInvalidationAtDocument = f; }
63
64 protected:
65     Document& document() const { return m_ownerNode->document(); }
66
67 private:
68     virtual bool isLiveNodeList() const override final { return true; }
69
70     ContainerNode& rootNode() const;
71
72     Ref<ContainerNode> m_ownerNode;
73
74     const unsigned m_invalidationType;
75     bool m_isRegisteredForInvalidationAtDocument;
76 };
77
78 template <class NodeListType>
79 class CachedLiveNodeList : public LiveNodeList {
80 public:
81     virtual ~CachedLiveNodeList();
82
83     virtual unsigned length() const override final;
84     virtual Node* item(unsigned offset) const override final;
85
86     // For CollectionIndexCache
87     ElementDescendantIterator collectionBegin() const;
88     ElementDescendantIterator collectionLast() const;
89     ElementDescendantIterator collectionEnd() const { return ElementDescendantIterator(); }
90     void collectionTraverseForward(ElementDescendantIterator&, unsigned count, unsigned& traversedCount) const;
91     void collectionTraverseBackward(ElementDescendantIterator&, unsigned count) const;
92     bool collectionCanTraverseBackward() const { return true; }
93     void willValidateIndexCache() const;
94
95     virtual void invalidateCache(Document&) const;
96     virtual size_t memoryCost() const override;
97
98 protected:
99     CachedLiveNodeList(ContainerNode& rootNode, NodeListInvalidationType);
100
101 private:
102     ContainerNode& rootNode() const;
103
104     mutable CollectionIndexCache<NodeListType, ElementDescendantIterator> m_indexCache;
105 };
106
107 ALWAYS_INLINE bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType type, const QualifiedName& attrName)
108 {
109     switch (type) {
110     case InvalidateOnClassAttrChange:
111         return attrName == HTMLNames::classAttr;
112     case InvalidateOnNameAttrChange:
113         return attrName == HTMLNames::nameAttr;
114     case InvalidateOnIdNameAttrChange:
115         return attrName == HTMLNames::idAttr || attrName == HTMLNames::nameAttr;
116     case InvalidateOnForAttrChange:
117         return attrName == HTMLNames::forAttr;
118     case InvalidateForFormControls:
119         return attrName == HTMLNames::nameAttr || attrName == HTMLNames::idAttr || attrName == HTMLNames::forAttr
120             || attrName == HTMLNames::formAttr || attrName == HTMLNames::typeAttr;
121     case InvalidateOnHRefAttrChange:
122         return attrName == HTMLNames::hrefAttr;
123     case DoNotInvalidateOnAttributeChanges:
124         return false;
125     case InvalidateOnAnyAttrChange:
126         return true;
127     }
128     return false;
129 }
130
131 template <class NodeListType>
132 CachedLiveNodeList<NodeListType>::CachedLiveNodeList(ContainerNode& ownerNode, NodeListInvalidationType invalidationType)
133     : LiveNodeList(ownerNode, invalidationType)
134     , m_indexCache(static_cast<NodeListType&>(*this))
135 {
136 }
137
138 template <class NodeListType>
139 CachedLiveNodeList<NodeListType>::~CachedLiveNodeList()
140 {
141     auto& nodeList = static_cast<const NodeListType&>(*this);
142     if (m_indexCache.hasValidCache(nodeList))
143         document().unregisterNodeListForInvalidation(*this);
144 }
145
146 template <class NodeListType>
147 inline ContainerNode& CachedLiveNodeList<NodeListType>::rootNode() const
148 {
149     if (static_cast<const NodeListType&>(*this).isRootedAtDocument() && ownerNode().inDocument())
150         return ownerNode().document();
151
152     return ownerNode();
153 }
154
155 template <class NodeListType>
156 ElementDescendantIterator CachedLiveNodeList<NodeListType>::collectionBegin() const
157 {
158     auto& nodeList = static_cast<const NodeListType&>(*this);
159     auto descendants = elementDescendants(rootNode());
160     auto end = descendants.end();
161     for (auto it = descendants.begin(); it != end; ++it) {
162         if (nodeList.elementMatches(&*it))
163             return it;
164     }
165     return end;
166 }
167
168 template <class NodeListType>
169 ElementDescendantIterator CachedLiveNodeList<NodeListType>::collectionLast() const
170 {
171     auto& nodeList = static_cast<const NodeListType&>(*this);
172     auto descendants = elementDescendants(rootNode());
173     auto end = descendants.end();
174     for (auto it = descendants.last(); it != end; --it) {
175         if (nodeList.elementMatches(&*it))
176             return it;
177     }
178     return end;
179 }
180
181 template <class NodeListType>
182 void CachedLiveNodeList<NodeListType>::collectionTraverseForward(ElementDescendantIterator& current, unsigned count, unsigned& traversedCount) const
183 {
184     auto& nodeList = static_cast<const NodeListType&>(*this);
185     ASSERT(nodeList.elementMatches(&*current));
186     auto end = collectionEnd();
187     for (traversedCount = 0; traversedCount < count; ++traversedCount) {
188         do {
189             ++current;
190             if (current == end)
191                 return;
192         } while (!nodeList.elementMatches(&*current));
193     }
194 }
195
196 template <class NodeListType>
197 void CachedLiveNodeList<NodeListType>::collectionTraverseBackward(ElementDescendantIterator& current, unsigned count) const
198 {
199     auto& nodeList = static_cast<const NodeListType&>(*this);
200     ASSERT(nodeList.elementMatches(&*current));
201     auto end = collectionEnd();
202     for (; count; --count) {
203         do {
204             --current;
205             if (current == end)
206                 return;
207         } while (!nodeList.elementMatches(&*current));
208     }
209 }
210
211 template <class NodeListType>
212 void CachedLiveNodeList<NodeListType>::willValidateIndexCache() const
213 {
214     document().registerNodeListForInvalidation(const_cast<NodeListType&>(static_cast<const NodeListType&>(*this)));
215 }
216
217 template <class NodeListType>
218 void CachedLiveNodeList<NodeListType>::invalidateCache(Document& document) const
219 {
220     auto& nodeList = static_cast<const NodeListType&>(*this);
221     if (!m_indexCache.hasValidCache(nodeList))
222         return;
223     document.unregisterNodeListForInvalidation(const_cast<NodeListType&>(nodeList));
224     m_indexCache.invalidate(nodeList);
225 }
226
227 template <class NodeListType>
228 unsigned CachedLiveNodeList<NodeListType>::length() const
229 {
230     return m_indexCache.nodeCount(static_cast<const NodeListType&>(*this));
231 }
232
233 template <class NodeListType>
234 Node* CachedLiveNodeList<NodeListType>::item(unsigned offset) const
235 {
236     return m_indexCache.nodeAt(static_cast<const NodeListType&>(*this), offset);
237 }
238
239 template <class NodeListType>
240 size_t CachedLiveNodeList<NodeListType>::memoryCost() const
241 {
242     return m_indexCache.memoryCost();
243 }
244
245 } // namespace WebCore
246
247 #endif // LiveNodeList_h