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