Rename AtomicString to AtomString
[WebKit-https.git] / Source / WebCore / html / HTMLCollection.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  * Copyright (C) 2003-2017 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 #include "config.h"
24 #include "HTMLCollection.h"
25
26 #include "CachedHTMLCollection.h"
27 #include "HTMLNames.h"
28 #include "NodeRareData.h"
29 #include <wtf/IsoMallocInlines.h>
30
31 namespace WebCore {
32
33 using namespace HTMLNames;
34
35 WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLCollection);
36
37 inline auto HTMLCollection::rootTypeFromCollectionType(CollectionType type) -> RootType
38 {
39     switch (type) {
40     case DocImages:
41     case DocApplets:
42     case DocEmbeds:
43     case DocForms:
44     case DocLinks:
45     case DocAnchors:
46     case DocScripts:
47     case DocAll:
48     case WindowNamedItems:
49     case DocumentNamedItems:
50     case DocumentAllNamedItems:
51     case FormControls:
52         return HTMLCollection::IsRootedAtDocument;
53     case AllDescendants:
54     case ByClass:
55     case ByTag:
56     case ByHTMLTag:
57     case FieldSetElements:
58     case NodeChildren:
59     case TableTBodies:
60     case TSectionRows:
61     case TableRows:
62     case TRCells:
63     case SelectOptions:
64     case SelectedOptions:
65     case DataListOptions:
66     case MapAreas:
67         return HTMLCollection::IsRootedAtNode;
68     }
69     ASSERT_NOT_REACHED();
70     return HTMLCollection::IsRootedAtNode;
71 }
72
73 static NodeListInvalidationType invalidationTypeExcludingIdAndNameAttributes(CollectionType type)
74 {
75     switch (type) {
76     case ByTag:
77     case ByHTMLTag:
78     case AllDescendants:
79     case DocImages:
80     case DocEmbeds:
81     case DocForms:
82     case DocScripts:
83     case DocAll:
84     case NodeChildren:
85     case TableTBodies:
86     case TSectionRows:
87     case TableRows:
88     case TRCells:
89     case SelectOptions:
90     case MapAreas:
91         return DoNotInvalidateOnAttributeChanges;
92     case DocApplets:
93     case SelectedOptions:
94     case DataListOptions:
95         // FIXME: We can do better some day.
96         return InvalidateOnAnyAttrChange;
97     case ByClass:
98         return InvalidateOnClassAttrChange;
99     case DocAnchors:
100         return InvalidateOnNameAttrChange;
101     case DocLinks:
102         return InvalidateOnHRefAttrChange;
103     case WindowNamedItems:
104     case DocumentNamedItems:
105     case DocumentAllNamedItems:
106         return InvalidateOnIdNameAttrChange;
107     case FieldSetElements:
108     case FormControls:
109         return InvalidateForFormControls;
110     }
111     ASSERT_NOT_REACHED();
112     return DoNotInvalidateOnAttributeChanges;
113 }
114
115 HTMLCollection::HTMLCollection(ContainerNode& ownerNode, CollectionType type)
116     : m_collectionType(type)
117     , m_invalidationType(invalidationTypeExcludingIdAndNameAttributes(type))
118     , m_rootType(rootTypeFromCollectionType(type))
119     , m_ownerNode(ownerNode)
120 {
121     ASSERT(m_rootType == static_cast<unsigned>(rootTypeFromCollectionType(type)));
122     ASSERT(m_invalidationType == static_cast<unsigned>(invalidationTypeExcludingIdAndNameAttributes(type)));
123     ASSERT(m_collectionType == static_cast<unsigned>(type));
124 }
125
126 HTMLCollection::~HTMLCollection()
127 {
128     if (hasNamedElementCache())
129         document().collectionWillClearIdNameMap(*this);
130
131     // HTMLNameCollection & ClassCollection remove cache by themselves.
132     // FIXME: We need a cleaner way to handle this.
133     switch (type()) {
134     case ByClass:
135     case ByTag:
136     case ByHTMLTag:
137     case WindowNamedItems:
138     case DocumentNamedItems:
139     case DocumentAllNamedItems:
140         break;
141     default:
142         ownerNode().nodeLists()->removeCachedCollection(this);
143     }
144 }
145
146 void HTMLCollection::invalidateCacheForDocument(Document& document)
147 {
148     if (hasNamedElementCache())
149         invalidateNamedElementCache(document);
150 }
151
152 void HTMLCollection::invalidateNamedElementCache(Document& document) const
153 {
154     ASSERT(hasNamedElementCache());
155     document.collectionWillClearIdNameMap(*this);
156     {
157         auto locker = holdLock(m_namedElementCacheAssignmentLock);
158         m_namedElementCache = nullptr;
159     }
160 }
161
162 Element* HTMLCollection::namedItemSlow(const AtomString& name) const
163 {
164     // The pathological case. We need to walk the entire subtree.
165     updateNamedElementCache();
166     ASSERT(m_namedElementCache);
167
168     if (const Vector<Element*>* idResults = m_namedElementCache->findElementsWithId(name)) {
169         if (idResults->size())
170             return idResults->at(0);
171     }
172
173     if (const Vector<Element*>* nameResults = m_namedElementCache->findElementsWithName(name)) {
174         if (nameResults->size())
175             return nameResults->at(0);
176     }
177
178     return nullptr;
179 }
180
181 // Documented in https://dom.spec.whatwg.org/#interface-htmlcollection.
182 const Vector<AtomString>& HTMLCollection::supportedPropertyNames()
183 {
184     updateNamedElementCache();
185     ASSERT(m_namedElementCache);
186
187     return m_namedElementCache->propertyNames();
188 }
189
190 bool HTMLCollection::isSupportedPropertyName(const String& name)
191 {
192     updateNamedElementCache();
193     ASSERT(m_namedElementCache);
194     
195     if (m_namedElementCache->findElementsWithId(name))
196         return true;
197     if (m_namedElementCache->findElementsWithName(name))
198         return true;
199
200     return false;
201 }
202
203 void HTMLCollection::updateNamedElementCache() const
204 {
205     if (hasNamedElementCache())
206         return;
207
208     auto cache = std::make_unique<CollectionNamedElementCache>();
209
210     unsigned size = length();
211     for (unsigned i = 0; i < size; ++i) {
212         Element& element = *item(i);
213         const AtomString& id = element.getIdAttribute();
214         if (!id.isEmpty())
215             cache->appendToIdCache(id, element);
216         if (!is<HTMLElement>(element))
217             continue;
218         const AtomString& name = element.getNameAttribute();
219         if (!name.isEmpty() && id != name && (type() != DocAll || nameShouldBeVisibleInDocumentAll(downcast<HTMLElement>(element))))
220             cache->appendToNameCache(name, element);
221     }
222
223     setNamedItemCache(WTFMove(cache));
224 }
225
226 Vector<Ref<Element>> HTMLCollection::namedItems(const AtomString& name) const
227 {
228     // FIXME: This non-virtual function can't possibly be doing the correct thing for
229     // any derived class that overrides the virtual namedItem function.
230
231     Vector<Ref<Element>> elements;
232
233     if (name.isEmpty())
234         return elements;
235
236     updateNamedElementCache();
237     ASSERT(m_namedElementCache);
238
239     auto* elementsWithId = m_namedElementCache->findElementsWithId(name);
240     auto* elementsWithName = m_namedElementCache->findElementsWithName(name);
241
242     elements.reserveInitialCapacity((elementsWithId ? elementsWithId->size() : 0) + (elementsWithName ? elementsWithName->size() : 0));
243
244     if (elementsWithId) {
245         for (auto& element : *elementsWithId)
246             elements.uncheckedAppend(*element);
247     }
248     if (elementsWithName) {
249         for (auto& element : *elementsWithName)
250             elements.uncheckedAppend(*element);
251     }
252
253     return elements;
254 }
255
256 } // namespace WebCore