c1c05f4c5cf33756060773c391aa9a20ae7f7836
[WebKit-https.git] / Source / WebCore / dom / DynamicNodeList.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 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 DynamicNodeList_h
25 #define DynamicNodeList_h
26
27 #include "CollectionType.h"
28 #include "Document.h"
29 #include "HTMLNames.h"
30 #include "NodeList.h"
31 #include <wtf/Forward.h>
32 #include <wtf/RefPtr.h>
33
34 namespace WebCore {
35
36 class Element;
37 class Node;
38
39 enum NodeListRootType {
40     NodeListIsRootedAtNode,
41     NodeListIsRootedAtDocument,
42 };
43
44 class DynamicNodeListCacheBase {
45 public:
46     enum ItemBeforeSupportType {
47         DoNotSupportItemBefore,
48         SupportItemBefore,
49     };
50
51     DynamicNodeListCacheBase(NodeListRootType rootType, NodeListInvalidationType invalidationType,
52         CollectionType collectionType = InvalidCollectionType, ItemBeforeSupportType itemBeforeSupportType = DoNotSupportItemBefore)
53         : m_cachedItem(0)
54         , m_isLengthCacheValid(false)
55         , m_isItemCacheValid(false)
56         , m_rootedAtDocument(rootType == NodeListIsRootedAtDocument)
57         , m_invalidationType(invalidationType)
58         , m_isNameCacheValid(false)
59         , m_collectionType(collectionType)
60         , m_supportsItemBefore(itemBeforeSupportType == SupportItemBefore)
61     {
62         ASSERT(m_invalidationType == static_cast<unsigned>(invalidationType));
63         ASSERT(m_collectionType == static_cast<unsigned>(collectionType));
64     }
65
66 public:
67     ALWAYS_INLINE bool isRootedAtDocument() const { return m_rootedAtDocument; }
68     ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); }
69     ALWAYS_INLINE CollectionType type() const { return static_cast<CollectionType>(m_collectionType); }
70
71     ALWAYS_INLINE void invalidateCache(const QualifiedName* attrName) const
72     {
73         if (!attrName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attrName))
74             invalidateCache();
75     }
76     void invalidateCache() const;
77
78     static bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType, const QualifiedName&);
79
80 protected:
81     bool supportsItemBefore() const { return m_supportsItemBefore; }
82
83     ALWAYS_INLINE bool isItemCacheValid() const { return m_isItemCacheValid; }
84     ALWAYS_INLINE Node* cachedItem() const { return m_cachedItem; }
85     ALWAYS_INLINE unsigned cachedItemOffset() const { return m_cachedItemOffset; }
86
87     ALWAYS_INLINE bool isLengthCacheValid() const { return m_isLengthCacheValid; }
88     ALWAYS_INLINE unsigned cachedLength() const { return m_cachedLength; }
89     ALWAYS_INLINE void setLengthCache(unsigned length) const
90     {
91         m_cachedLength = length;
92         m_isLengthCacheValid = true;
93     }
94     ALWAYS_INLINE void setItemCache(Node* item, unsigned offset) const
95     {
96         ASSERT(item);
97         m_cachedItem = item;
98         m_cachedItemOffset = offset;
99         m_isItemCacheValid = true;
100     }
101
102     bool hasNameCache() const { return m_isNameCacheValid; }
103     void setHasNameCache() const { m_isNameCacheValid = true; }
104
105 private:
106     mutable Node* m_cachedItem;
107     mutable unsigned m_cachedLength;
108     mutable unsigned m_cachedItemOffset;
109     mutable unsigned m_isLengthCacheValid : 1;
110     mutable unsigned m_isItemCacheValid : 1;
111     const unsigned m_rootedAtDocument : 1;
112     const unsigned m_invalidationType : 4;
113
114     // From HTMLCollection
115     mutable unsigned m_isNameCacheValid : 1;
116     const unsigned m_collectionType : 5;
117     const unsigned m_supportsItemBefore : 1;
118 };
119
120 ALWAYS_INLINE bool DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType type, const QualifiedName& attrName)
121 {
122     switch (type) {
123     case InvalidateOnClassAttrChange:
124         return attrName == HTMLNames::classAttr;
125     case InvalidateOnNameAttrChange:
126         return attrName == HTMLNames::nameAttr;
127     case InvalidateOnIdNameAttrChange:
128         return attrName == HTMLNames::idAttr || attrName == HTMLNames::nameAttr;
129     case InvalidateOnForAttrChange:
130         return attrName == HTMLNames::forAttr;
131     case InvalidateForFormControls:
132         return attrName == HTMLNames::nameAttr || attrName == HTMLNames::idAttr || attrName == HTMLNames::forAttr
133             || attrName == HTMLNames::formAttr || attrName == HTMLNames::typeAttr;
134     case InvalidateOnHRefAttrChange:
135         return attrName == HTMLNames::hrefAttr;
136     case InvalidateOnItemAttrChange:
137 #if ENABLE(MICRODATA)
138         return attrName == HTMLNames::itemscopeAttr || attrName == HTMLNames::itempropAttr || attrName == HTMLNames::itemtypeAttr;
139 #endif // Intentionally fall through
140     case DoNotInvalidateOnAttributeChanges:
141         return false;
142     case InvalidateOnAnyAttrChange:
143         return true;
144     }
145     return false;
146 }
147
148 class DynamicNodeList : public NodeList, public DynamicNodeListCacheBase {
149 public:
150     enum NodeListType {
151         ChildNodeListType,
152         ClassNodeListType,
153         NameNodeListType,
154         TagNodeListType,
155         RadioNodeListType,
156         LabelsNodeListType,
157         MicroDataItemListType,
158     };
159     DynamicNodeList(PassRefPtr<Node> ownerNode, NodeListRootType rootType, NodeListInvalidationType invalidationType)
160         : DynamicNodeListCacheBase(rootType, invalidationType)
161         , m_ownerNode(ownerNode)
162     { }
163     virtual ~DynamicNodeList() { }
164
165     // DOM methods & attributes for NodeList
166     virtual unsigned length() const = 0;
167     virtual Node* item(unsigned index) const = 0;
168     virtual Node* itemWithName(const AtomicString&) const;
169
170     // Other methods (not part of DOM)
171     Node* ownerNode() const { return m_ownerNode.get(); }
172
173 protected:
174     Node* rootNode() const
175     {
176         if (isRootedAtDocument() && m_ownerNode->inDocument())
177             return m_ownerNode->document();
178         return m_ownerNode.get();
179     }
180     Document* document() const { return m_ownerNode->document(); }
181     virtual bool nodeMatches(Element*) const = 0;
182
183 private:
184     virtual bool isDynamicNodeList() const OVERRIDE { return true; }
185     RefPtr<Node> m_ownerNode;
186 };
187
188 class DynamicSubtreeNodeList : public DynamicNodeList {
189 public:
190     virtual ~DynamicSubtreeNodeList()
191     {
192         document()->unregisterNodeListCache(this);
193     }
194     virtual unsigned length() const OVERRIDE;
195     virtual Node* item(unsigned index) const OVERRIDE;
196
197 protected:
198     DynamicSubtreeNodeList(PassRefPtr<Node> node, NodeListInvalidationType invalidationType, NodeListRootType rootType = NodeListIsRootedAtNode)
199         : DynamicNodeList(node, rootType, invalidationType)
200     {
201         document()->registerNodeListCache(this);
202     }
203
204 private:
205     Node* itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;
206     Node* itemBackwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;
207 };
208
209 } // namespace WebCore
210
211 #endif // DynamicNodeList_h