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