HTMLCollection should not be NodeList
[WebKit-https.git] / Source / WebCore / html / HTMLCollection.h
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #ifndef HTMLCollection_h
24 #define HTMLCollection_h
25
26 #include "CollectionType.h"
27 #include "ContainerNode.h"
28 #include "Document.h"
29 #include "HTMLNames.h"
30 #include "LiveNodeList.h"
31 #include "ScriptWrappable.h"
32 #include <wtf/Forward.h>
33 #include <wtf/HashMap.h>
34 #include <wtf/Vector.h>
35
36 namespace WebCore {
37
38 class Element;
39
40 class HTMLCollection : public ScriptWrappable, public RefCounted<HTMLCollection> {
41 public:
42     enum ItemAfterOverrideType {
43         OverridesItemAfter,
44         DoesNotOverrideItemAfter,
45     };
46
47     static PassRefPtr<HTMLCollection> create(ContainerNode& base, CollectionType);
48     virtual ~HTMLCollection();
49
50     // DOM API
51     unsigned length() const;
52     Node* item(unsigned offset) const;
53     virtual Node* namedItem(const AtomicString& name) const;
54     PassRefPtr<NodeList> tags(const String&);
55
56     // Non-DOM API
57     virtual bool hasNamedItem(const AtomicString& name) const;
58     void namedItems(const AtomicString& name, Vector<Ref<Element>>&) const;
59     bool isEmpty() const
60     {
61         if (isLengthCacheValid())
62             return !cachedLength();
63         if (isElementCacheValid())
64             return !cachedElement();
65         return !item(0);
66     }
67     bool hasExactlyOneItem() const
68     {
69         if (isLengthCacheValid())
70             return cachedLength() == 1;
71         if (isElementCacheValid())
72             return cachedElement() && !cachedElementOffset() && !item(1);
73         return item(0) && !item(1);
74     }
75
76     virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const;
77
78     Element* traverseFirstElement(unsigned& offsetInArray, ContainerNode* root) const;
79     Element* traverseForwardToOffset(unsigned offset, Element* currentElement, unsigned& currentOffset, unsigned& offsetInArray, ContainerNode* root) const;
80
81     ALWAYS_INLINE bool isRootedAtDocument() const { return m_rootType == NodeListIsRootedAtDocument; }
82     ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); }
83     ALWAYS_INLINE CollectionType type() const { return static_cast<CollectionType>(m_collectionType); }
84     ContainerNode& ownerNode() const { return const_cast<ContainerNode&>(m_ownerNode.get()); }
85     ALWAYS_INLINE void invalidateCache(const QualifiedName* attrName) const
86     {
87         if (!attrName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attrName))
88             invalidateCache();
89         else if (*attrName == HTMLNames::idAttr || *attrName == HTMLNames::nameAttr)
90             invalidateIdNameCacheMaps();
91     }
92     void invalidateCache() const;
93     void invalidateIdNameCacheMaps() const;
94
95 protected:
96     HTMLCollection(ContainerNode& base, CollectionType, ItemAfterOverrideType);
97
98     virtual void updateNameCache() const;
99
100     typedef HashMap<AtomicStringImpl*, OwnPtr<Vector<Element*>>> NodeCacheMap;
101     Vector<Element*>* idCache(const AtomicString& name) const { return m_idCache.get(name.impl()); }
102     Vector<Element*>* nameCache(const AtomicString& name) const { return m_nameCache.get(name.impl()); }
103     void appendIdCache(const AtomicString& name, Element* element) const { append(m_idCache, name, element); }
104     void appendNameCache(const AtomicString& name, Element* element) const { append(m_nameCache, name, element); }
105
106     Document& document() const { return m_ownerNode->document(); }
107     ContainerNode& rootNode() const;
108     bool overridesItemAfter() const { return m_overridesItemAfter; }
109
110     ALWAYS_INLINE bool isElementCacheValid() const { return m_isElementCacheValid; }
111     ALWAYS_INLINE Element* cachedElement() const { return m_cachedElement; }
112     ALWAYS_INLINE unsigned cachedElementOffset() const { return m_cachedElementOffset; }
113
114     ALWAYS_INLINE bool isLengthCacheValid() const { return m_isLengthCacheValid; }
115     ALWAYS_INLINE unsigned cachedLength() const { return m_cachedLength; }
116     ALWAYS_INLINE void setLengthCache(unsigned length) const
117     {
118         m_cachedLength = length;
119         m_isLengthCacheValid = true;
120     }
121     ALWAYS_INLINE void setCachedElement(Element& element, unsigned offset) const
122     {
123         m_cachedElement = &element;
124         m_cachedElementOffset = offset;
125         m_isElementCacheValid = true;
126     }
127     void setCachedElement(Element&, unsigned offset, unsigned elementsArrayOffset) const;
128
129     ALWAYS_INLINE bool isItemRefElementsCacheValid() const { return m_isItemRefElementsCacheValid; }
130     ALWAYS_INLINE void setItemRefElementsCacheValid() const { m_isItemRefElementsCacheValid = true; }
131
132     ALWAYS_INLINE NodeListRootType rootType() const { return static_cast<NodeListRootType>(m_rootType); }
133
134     bool hasNameCache() const { return m_isNameCacheValid; }
135     void setHasNameCache() const { m_isNameCacheValid = true; }
136
137 private:
138     Element* traverseNextElement(unsigned& offsetInArray, Element* previous, ContainerNode* root) const;
139
140     static void append(NodeCacheMap&, const AtomicString&, Element*);
141
142     Element* elementBeforeOrAfterCachedElement(unsigned offset, ContainerNode* root) const;
143     bool isLastItemCloserThanLastOrCachedItem(unsigned offset) const;
144     bool isFirstItemCloserThanCachedItem(unsigned offset) const;
145     Element* iterateForPreviousElement(Element* current) const;
146     Element* itemBefore(Element* previousItem) const;
147
148     Ref<ContainerNode> m_ownerNode;
149     mutable Element* m_cachedElement;
150     mutable unsigned m_cachedLength;
151     mutable unsigned m_cachedElementOffset;
152     mutable unsigned m_isLengthCacheValid : 1;
153     mutable unsigned m_isElementCacheValid : 1;
154     const unsigned m_rootType : 2;
155     const unsigned m_invalidationType : 4;
156     const unsigned m_shouldOnlyIncludeDirectChildren : 1;
157
158     // From HTMLCollection
159     mutable unsigned m_isNameCacheValid : 1;
160     const unsigned m_collectionType : 5;
161     const unsigned m_overridesItemAfter : 1;
162     mutable unsigned m_isItemRefElementsCacheValid : 1;
163
164     mutable NodeCacheMap m_idCache;
165     mutable NodeCacheMap m_nameCache;
166     mutable unsigned m_cachedElementsArrayOffset;
167 };
168
169 } // namespace
170
171 #endif