NodeList should not have a named getter
[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, 2013, 2014 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 "CollectionIndexCache.h"
27 #include "HTMLNames.h"
28 #include "LiveNodeList.h"
29 #include "ScriptWrappable.h"
30 #include <wtf/HashMap.h>
31
32 namespace WebCore {
33
34 class Element;
35
36 class CollectionNamedElementCache {
37 public:
38     const Vector<Element*>* findElementsWithId(const AtomicString& id) const;
39     const Vector<Element*>* findElementsWithName(const AtomicString& name) const;
40
41     void appendToIdCache(const AtomicString& id, Element&);
42     void appendToNameCache(const AtomicString& name, Element&);
43     void didPopulate();
44
45     size_t memoryCost() const;
46
47 private:
48     typedef HashMap<AtomicStringImpl*, Vector<Element*>> StringToElementsMap;
49
50     const Vector<Element*>* find(const StringToElementsMap&, const AtomicString& key) const;
51     static void append(StringToElementsMap&, const AtomicString& key, Element&);
52
53     StringToElementsMap m_idMap;
54     StringToElementsMap m_nameMap;
55
56 #if !ASSERT_DISABLED
57     bool m_didPopulate { false };
58 #endif
59 };
60
61 // HTMLCollection subclasses NodeList to maintain legacy ObjC API compatibility.
62 class HTMLCollection : public NodeList {
63 public:
64     virtual ~HTMLCollection();
65
66     // DOM API
67     virtual Element* item(unsigned index) const override = 0; // Tighten return type from NodeList::item().
68     virtual Element* namedItem(const AtomicString& name) const = 0;
69     RefPtr<NodeList> tags(const String&);
70
71     // Non-DOM API
72     Vector<Ref<Element>> namedItems(const AtomicString& name) const;
73     virtual size_t memoryCost() const override;
74
75     bool isRootedAtDocument() const;
76     NodeListInvalidationType invalidationType() const;
77     CollectionType type() const;
78     ContainerNode& ownerNode() const;
79     ContainerNode& rootNode() const;
80     void invalidateCacheForAttribute(const QualifiedName* attributeName);
81     virtual void invalidateCache(Document&);
82
83     bool hasNamedElementCache() const;
84
85 protected:
86     HTMLCollection(ContainerNode& base, CollectionType);
87
88     virtual void updateNamedElementCache() const;
89     Element* namedItemSlow(const AtomicString& name) const;
90
91     void setNamedItemCache(std::unique_ptr<CollectionNamedElementCache>) const;
92     const CollectionNamedElementCache& namedItemCaches() const;
93
94     Document& document() const;
95
96     void invalidateNamedElementCache(Document&) const;
97
98     enum RootType { IsRootedAtNode, IsRootedAtDocument };
99     static RootType rootTypeFromCollectionType(CollectionType);
100
101     Ref<ContainerNode> m_ownerNode;
102
103     mutable std::unique_ptr<CollectionNamedElementCache> m_namedElementCache;
104
105     const unsigned m_collectionType : 5;
106     const unsigned m_invalidationType : 4;
107     const unsigned m_rootType : 1;
108 };
109
110 inline ContainerNode& HTMLCollection::rootNode() const
111 {
112     if (isRootedAtDocument() && ownerNode().inDocument())
113         return ownerNode().document();
114
115     return ownerNode();
116 }
117
118 inline const Vector<Element*>* CollectionNamedElementCache::findElementsWithId(const AtomicString& id) const
119 {
120     return find(m_idMap, id);
121 }
122
123 inline const Vector<Element*>* CollectionNamedElementCache::findElementsWithName(const AtomicString& name) const
124 {
125     return find(m_nameMap, name);
126 }
127
128 inline void CollectionNamedElementCache::appendToIdCache(const AtomicString& id, Element& element)
129 {
130     return append(m_idMap, id, element);
131 }
132
133 inline void CollectionNamedElementCache::appendToNameCache(const AtomicString& name, Element& element)
134 {
135     return append(m_nameMap, name, element);
136 }
137
138 inline size_t CollectionNamedElementCache::memoryCost() const
139 {
140     return (m_idMap.size() + m_nameMap.size()) * sizeof(Element*);
141 }
142
143 inline void CollectionNamedElementCache::didPopulate()
144 {
145 #if !ASSERT_DISABLED
146     m_didPopulate = true;
147 #endif
148     if (size_t cost = memoryCost())
149         reportExtraMemoryAllocatedForCollectionIndexCache(cost);
150 }
151
152 inline const Vector<Element*>* CollectionNamedElementCache::find(const StringToElementsMap& map, const AtomicString& key) const
153 {
154     ASSERT(m_didPopulate);
155     auto it = map.find(key.impl());
156     return it != map.end() ? &it->value : nullptr;
157 }
158
159 inline void CollectionNamedElementCache::append(StringToElementsMap& map, const AtomicString& key, Element& element)
160 {
161     map.add(key.impl(), Vector<Element*>()).iterator->value.append(&element);
162 }
163
164 inline size_t HTMLCollection::memoryCost() const
165 {
166     return m_namedElementCache ? m_namedElementCache->memoryCost() : 0;
167 }
168
169 inline bool HTMLCollection::isRootedAtDocument() const
170 {
171     return m_rootType == IsRootedAtDocument;
172 }
173
174 inline NodeListInvalidationType HTMLCollection::invalidationType() const
175 {
176     return static_cast<NodeListInvalidationType>(m_invalidationType);
177 }
178
179 inline CollectionType HTMLCollection::type() const
180 {
181     return static_cast<CollectionType>(m_collectionType);
182 }
183
184 inline ContainerNode& HTMLCollection::ownerNode() const
185 {
186     return const_cast<ContainerNode&>(m_ownerNode.get());
187 }
188
189 inline Document& HTMLCollection::document() const
190 {
191     return m_ownerNode->document();
192 }
193
194 inline void HTMLCollection::invalidateCacheForAttribute(const QualifiedName* attributeName)
195 {
196     if (!attributeName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attributeName))
197         invalidateCache(document());
198     else if (hasNamedElementCache() && (*attributeName == HTMLNames::idAttr || *attributeName == HTMLNames::nameAttr))
199         invalidateNamedElementCache(document());
200 }
201
202 inline bool HTMLCollection::hasNamedElementCache() const
203 {
204     return !!m_namedElementCache;
205 }
206
207 inline void HTMLCollection::setNamedItemCache(std::unique_ptr<CollectionNamedElementCache> cache) const
208 {
209     ASSERT(cache);
210     ASSERT(!m_namedElementCache);
211     cache->didPopulate();
212     m_namedElementCache = WTF::move(cache);
213     document().collectionCachedIdNameMap(*this);
214 }
215
216 inline const CollectionNamedElementCache& HTMLCollection::namedItemCaches() const
217 {
218     ASSERT(!!m_namedElementCache);
219     return *m_namedElementCache;
220 }
221
222 } // namespace WebCore
223
224 #define SPECIALIZE_TYPE_TRAITS_HTMLCOLLECTION(ClassName, Type) \
225 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ClassName) \
226     static bool isType(const WebCore::HTMLCollection& collection) { return collection.type() == WebCore::Type; } \
227 SPECIALIZE_TYPE_TRAITS_END()
228
229 #endif // HTMLCollection_h