Rename LiveNodeLists / HTMLCollections's nodeMatches() to elementMatches()
[WebKit-https.git] / Source / WebCore / dom / DocumentOrderedMap.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "DocumentOrderedMap.h"
33
34 #include "ElementIterator.h"
35 #include "HTMLImageElement.h"
36 #include "HTMLLabelElement.h"
37 #include "HTMLMapElement.h"
38 #include "HTMLNameCollection.h"
39
40 namespace WebCore {
41
42 using namespace HTMLNames;
43
44 inline bool keyMatchesId(const AtomicStringImpl& key, const Element& element)
45 {
46     return element.getIdAttribute().impl() == &key;
47 }
48
49 inline bool keyMatchesName(const AtomicStringImpl& key, const Element& element)
50 {
51     return element.getNameAttribute().impl() == &key;
52 }
53
54 inline bool keyMatchesMapName(const AtomicStringImpl& key, const Element& element)
55 {
56     return isHTMLMapElement(element) && toHTMLMapElement(element).getName().impl() == &key;
57 }
58
59 inline bool keyMatchesLowercasedMapName(const AtomicStringImpl& key, const Element& element)
60 {
61     return isHTMLMapElement(element) && toHTMLMapElement(element).getName().lower().impl() == &key;
62 }
63
64 inline bool keyMatchesLowercasedUsemap(const AtomicStringImpl& key, const Element& element)
65 {
66     // FIXME: HTML5 specification says we should match both image and object elements.
67     return isHTMLImageElement(element) && toHTMLImageElement(element).matchesLowercasedUsemap(key);
68 }
69
70 inline bool keyMatchesLabelForAttribute(const AtomicStringImpl& key, const Element& element)
71 {
72     return isHTMLLabelElement(element) && element.getAttribute(forAttr).impl() == &key;
73 }
74
75 inline bool keyMatchesWindowNamedItem(const AtomicStringImpl& key, const Element& element)
76 {
77     return WindowNameCollection::elementMatches(const_cast<Element*>(&element), &key);
78 }
79
80 inline bool keyMatchesDocumentNamedItem(const AtomicStringImpl& key, const Element& element)
81 {
82     return DocumentNameCollection::elementMatches(const_cast<Element*>(&element), &key);
83 }
84
85 void DocumentOrderedMap::clear()
86 {
87     m_map.clear();
88 }
89
90 void DocumentOrderedMap::add(const AtomicStringImpl& key, Element& element, const TreeScope& treeScope)
91 {
92     UNUSED_PARAM(treeScope);
93     ASSERT_WITH_SECURITY_IMPLICATION(element.isInTreeScope());
94     ASSERT_WITH_SECURITY_IMPLICATION(treeScope.rootNode().containsIncludingShadowDOM(&element));
95     if (!element.isInTreeScope())
96         return;
97     Map::AddResult addResult = m_map.add(&key, MapEntry(&element));
98     if (addResult.isNewEntry)
99         return;
100
101     MapEntry& entry = addResult.iterator->value;
102     ASSERT_WITH_SECURITY_IMPLICATION(entry.count);
103     entry.element = nullptr;
104     entry.count++;
105     entry.orderedList.clear();
106 }
107
108 void DocumentOrderedMap::remove(const AtomicStringImpl& key, Element& element)
109 {
110     m_map.checkConsistency();
111     auto it = m_map.find(&key);
112     ASSERT_WITH_SECURITY_IMPLICATION(it != m_map.end());
113     if (it == m_map.end())
114         return;
115     MapEntry& entry = it->value;
116
117     ASSERT_WITH_SECURITY_IMPLICATION(entry.count);
118     if (entry.count == 1) {
119         ASSERT_WITH_SECURITY_IMPLICATION(!entry.element || entry.element == &element);
120         m_map.remove(it);
121     } else {
122         if (entry.element == &element)
123             entry.element = nullptr;
124         entry.count--;
125         entry.orderedList.clear(); // FIXME: Remove the element instead if there are only few items left.
126     }
127 }
128
129 template<bool keyMatches(const AtomicStringImpl&, const Element&)>
130 inline Element* DocumentOrderedMap::get(const AtomicStringImpl& key, const TreeScope& scope) const
131 {
132     m_map.checkConsistency();
133
134     auto it = m_map.find(&key);
135     if (it == m_map.end())
136         return nullptr;
137
138     MapEntry& entry = it->value;
139     ASSERT(entry.count);
140     if (entry.element) {
141         ASSERT_WITH_SECURITY_IMPLICATION(entry.element->isInTreeScope());
142         ASSERT_WITH_SECURITY_IMPLICATION(&entry.element->treeScope() == &scope);
143         return entry.element;
144     }
145
146     // We know there's at least one node that matches; iterate to find the first one.
147     for (auto& element : descendantsOfType<Element>(scope.rootNode())) {
148         if (!keyMatches(key, element))
149             continue;
150         entry.element = &element;
151         ASSERT_WITH_SECURITY_IMPLICATION(element.isInTreeScope());
152         ASSERT_WITH_SECURITY_IMPLICATION(&element.treeScope() == &scope);
153         return &element;
154     }
155     ASSERT_NOT_REACHED();
156     return nullptr;
157 }
158
159 Element* DocumentOrderedMap::getElementById(const AtomicStringImpl& key, const TreeScope& scope) const
160 {
161     return get<keyMatchesId>(key, scope);
162 }
163
164 Element* DocumentOrderedMap::getElementByName(const AtomicStringImpl& key, const TreeScope& scope) const
165 {
166     return get<keyMatchesName>(key, scope);
167 }
168
169 HTMLMapElement* DocumentOrderedMap::getElementByMapName(const AtomicStringImpl& key, const TreeScope& scope) const
170 {
171     return toHTMLMapElement(get<keyMatchesMapName>(key, scope));
172 }
173
174 HTMLMapElement* DocumentOrderedMap::getElementByLowercasedMapName(const AtomicStringImpl& key, const TreeScope& scope) const
175 {
176     return toHTMLMapElement(get<keyMatchesLowercasedMapName>(key, scope));
177 }
178
179 HTMLImageElement* DocumentOrderedMap::getElementByLowercasedUsemap(const AtomicStringImpl& key, const TreeScope& scope) const
180 {
181     return toHTMLImageElement(get<keyMatchesLowercasedUsemap>(key, scope));
182 }
183
184 HTMLLabelElement* DocumentOrderedMap::getElementByLabelForAttribute(const AtomicStringImpl& key, const TreeScope& scope) const
185 {
186     return toHTMLLabelElement(get<keyMatchesLabelForAttribute>(key, scope));
187 }
188
189 Element* DocumentOrderedMap::getElementByWindowNamedItem(const AtomicStringImpl& key, const TreeScope& scope) const
190 {
191     return get<keyMatchesWindowNamedItem>(key, scope);
192 }
193
194 Element* DocumentOrderedMap::getElementByDocumentNamedItem(const AtomicStringImpl& key, const TreeScope& scope) const
195 {
196     return get<keyMatchesDocumentNamedItem>(key, scope);
197 }
198
199 const Vector<Element*>* DocumentOrderedMap::getAllElementsById(const AtomicStringImpl& key, const TreeScope& scope) const
200 {
201     m_map.checkConsistency();
202
203     auto it = m_map.find(&key);
204     if (it == m_map.end())
205         return nullptr;
206
207     MapEntry& entry = it->value;
208     ASSERT_WITH_SECURITY_IMPLICATION(entry.count);
209     if (!entry.count)
210         return nullptr;
211
212     if (entry.orderedList.isEmpty()) {
213         entry.orderedList.reserveCapacity(entry.count);
214         auto elementDescandents = descendantsOfType<Element>(scope.rootNode());
215         auto it = entry.element ? elementDescandents.beginAt(*entry.element) : elementDescandents.begin();
216         auto end = elementDescandents.end();
217         for (; it != end; ++it) {
218             auto& element = *it;
219             if (!keyMatchesId(key, element))
220                 continue;
221             entry.orderedList.append(&element);
222         }
223         ASSERT(entry.orderedList.size() == entry.count);
224     }
225
226     return &entry.orderedList;
227 }
228
229 } // namespace WebCore