1 | /* |
2 | * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
3 | * (C) 1999 Antti Koivisto (koivisto@kde.org) |
4 | * (C) 2001 Dirk Mueller (mueller@kde.org) |
5 | * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. |
6 | * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) |
7 | * (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> |
8 | * Copyright (C) 2011 Andreas Kling (kling@webkit.org) |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
20 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
27 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | * |
31 | */ |
32 | |
33 | #include "config.h" |
34 | #include "EventListenerMap.h" |
35 | |
36 | #include "Event.h" |
37 | #include "EventTarget.h" |
38 | #include <wtf/MainThread.h> |
39 | #include <wtf/StdLibExtras.h> |
40 | #include <wtf/Vector.h> |
41 | |
42 | |
43 | namespace WebCore { |
44 | |
45 | #ifndef NDEBUG |
46 | void EventListenerMap::assertNoActiveIterators() const |
47 | { |
48 | ASSERT(!m_activeIteratorCount); |
49 | } |
50 | #endif |
51 | |
52 | EventListenerMap::EventListenerMap() |
53 | { |
54 | } |
55 | |
56 | bool EventListenerMap::containsCapturing(const AtomicString& eventType) const |
57 | { |
58 | auto* listeners = find(eventType); |
59 | if (!listeners) |
60 | return false; |
61 | |
62 | for (auto& eventListener : *listeners) { |
63 | if (eventListener->useCapture()) |
64 | return true; |
65 | } |
66 | return false; |
67 | } |
68 | |
69 | bool EventListenerMap::containsActive(const AtomicString& eventType) const |
70 | { |
71 | auto* listeners = find(eventType); |
72 | if (!listeners) |
73 | return false; |
74 | |
75 | for (auto& eventListener : *listeners) { |
76 | if (!eventListener->isPassive()) |
77 | return true; |
78 | } |
79 | return false; |
80 | } |
81 | |
82 | void EventListenerMap::clear() |
83 | { |
84 | auto locker = holdLock(m_lock); |
85 | |
86 | assertNoActiveIterators(); |
87 | |
88 | for (auto& entry : m_entries) { |
89 | for (auto& listener : *entry.second) |
90 | listener->markAsRemoved(); |
91 | } |
92 | |
93 | m_entries.clear(); |
94 | } |
95 | |
96 | Vector<AtomicString> EventListenerMap::eventTypes() const |
97 | { |
98 | Vector<AtomicString> types; |
99 | types.reserveInitialCapacity(m_entries.size()); |
100 | |
101 | for (auto& entry : m_entries) |
102 | types.uncheckedAppend(entry.first); |
103 | |
104 | return types; |
105 | } |
106 | |
107 | static inline size_t findListener(const EventListenerVector& listeners, EventListener& listener, bool useCapture) |
108 | { |
109 | for (size_t i = 0; i < listeners.size(); ++i) { |
110 | auto& registeredListener = listeners[i]; |
111 | if (registeredListener->callback() == listener && registeredListener->useCapture() == useCapture) |
112 | return i; |
113 | } |
114 | return notFound; |
115 | } |
116 | |
117 | void EventListenerMap::replace(const AtomicString& eventType, EventListener& oldListener, Ref<EventListener>&& newListener, const RegisteredEventListener::Options& options) |
118 | { |
119 | auto locker = holdLock(m_lock); |
120 | |
121 | assertNoActiveIterators(); |
122 | |
123 | auto* listeners = find(eventType); |
124 | ASSERT(listeners); |
125 | size_t index = findListener(*listeners, oldListener, options.capture); |
126 | ASSERT(index != notFound); |
127 | auto& registeredListener = listeners->at(index); |
128 | registeredListener->markAsRemoved(); |
129 | registeredListener = RegisteredEventListener::create(WTFMove(newListener), options); |
130 | } |
131 | |
132 | bool EventListenerMap::add(const AtomicString& eventType, Ref<EventListener>&& listener, const RegisteredEventListener::Options& options) |
133 | { |
134 | auto locker = holdLock(m_lock); |
135 | |
136 | assertNoActiveIterators(); |
137 | |
138 | if (auto* listeners = find(eventType)) { |
139 | if (findListener(*listeners, listener, options.capture) != notFound) |
140 | return false; // Duplicate listener. |
141 | listeners->append(RegisteredEventListener::create(WTFMove(listener), options)); |
142 | return true; |
143 | } |
144 | |
145 | auto listeners = std::make_unique<EventListenerVector>(); |
146 | listeners->uncheckedAppend(RegisteredEventListener::create(WTFMove(listener), options)); |
147 | m_entries.append({ eventType, WTFMove(listeners) }); |
148 | return true; |
149 | } |
150 | |
151 | static bool removeListenerFromVector(EventListenerVector& listeners, EventListener& listener, bool useCapture) |
152 | { |
153 | size_t indexOfRemovedListener = findListener(listeners, listener, useCapture); |
154 | if (UNLIKELY(indexOfRemovedListener == notFound)) |
155 | return false; |
156 | |
157 | listeners[indexOfRemovedListener]->markAsRemoved(); |
158 | listeners.remove(indexOfRemovedListener); |
159 | return true; |
160 | } |
161 | |
162 | bool EventListenerMap::remove(const AtomicString& eventType, EventListener& listener, bool useCapture) |
163 | { |
164 | auto locker = holdLock(m_lock); |
165 | |
166 | assertNoActiveIterators(); |
167 | |
168 | for (unsigned i = 0; i < m_entries.size(); ++i) { |
169 | if (m_entries[i].first == eventType) { |
170 | bool wasRemoved = removeListenerFromVector(*m_entries[i].second, listener, useCapture); |
171 | if (m_entries[i].second->isEmpty()) |
172 | m_entries.remove(i); |
173 | return wasRemoved; |
174 | } |
175 | } |
176 | |
177 | return false; |
178 | } |
179 | |
180 | EventListenerVector* EventListenerMap::find(const AtomicString& eventType) const |
181 | { |
182 | for (auto& entry : m_entries) { |
183 | if (entry.first == eventType) |
184 | return entry.second.get(); |
185 | } |
186 | |
187 | return nullptr; |
188 | } |
189 | |
190 | static void removeFirstListenerCreatedFromMarkup(EventListenerVector& listenerVector) |
191 | { |
192 | bool foundListener = listenerVector.removeFirstMatching([] (const auto& registeredListener) { |
193 | if (registeredListener->callback().wasCreatedFromMarkup()) { |
194 | registeredListener->markAsRemoved(); |
195 | return true; |
196 | } |
197 | return false; |
198 | }); |
199 | ASSERT_UNUSED(foundListener, foundListener); |
200 | } |
201 | |
202 | void EventListenerMap::removeFirstEventListenerCreatedFromMarkup(const AtomicString& eventType) |
203 | { |
204 | auto locker = holdLock(m_lock); |
205 | |
206 | assertNoActiveIterators(); |
207 | |
208 | for (unsigned i = 0; i < m_entries.size(); ++i) { |
209 | if (m_entries[i].first == eventType) { |
210 | removeFirstListenerCreatedFromMarkup(*m_entries[i].second); |
211 | if (m_entries[i].second->isEmpty()) |
212 | m_entries.remove(i); |
213 | return; |
214 | } |
215 | } |
216 | } |
217 | |
218 | static void copyListenersNotCreatedFromMarkupToTarget(const AtomicString& eventType, EventListenerVector& listenerVector, EventTarget* target) |
219 | { |
220 | for (auto& registeredListener : listenerVector) { |
221 | // Event listeners created from markup have already been transfered to the shadow tree during cloning. |
222 | if (registeredListener->callback().wasCreatedFromMarkup()) |
223 | continue; |
224 | target->addEventListener(eventType, registeredListener->callback(), registeredListener->useCapture()); |
225 | } |
226 | } |
227 | |
228 | void EventListenerMap::copyEventListenersNotCreatedFromMarkupToTarget(EventTarget* target) |
229 | { |
230 | for (auto& entry : m_entries) |
231 | copyListenersNotCreatedFromMarkupToTarget(entry.first, *entry.second, target); |
232 | } |
233 | |
234 | EventListenerIterator::EventListenerIterator(EventTarget* target) |
235 | { |
236 | ASSERT(target); |
237 | EventTargetData* data = target->eventTargetData(); |
238 | |
239 | if (!data) |
240 | return; |
241 | |
242 | m_map = &data->eventListenerMap; |
243 | |
244 | #ifndef NDEBUG |
245 | m_map->m_activeIteratorCount++; |
246 | #endif |
247 | } |
248 | |
249 | EventListenerIterator::EventListenerIterator(EventListenerMap* map) |
250 | { |
251 | m_map = map; |
252 | |
253 | #ifndef NDEBUG |
254 | m_map->m_activeIteratorCount++; |
255 | #endif |
256 | } |
257 | |
258 | #ifndef NDEBUG |
259 | EventListenerIterator::~EventListenerIterator() |
260 | { |
261 | if (m_map) |
262 | m_map->m_activeIteratorCount--; |
263 | } |
264 | #endif |
265 | |
266 | EventListener* EventListenerIterator::nextListener() |
267 | { |
268 | if (!m_map) |
269 | return nullptr; |
270 | |
271 | for (; m_entryIndex < m_map->m_entries.size(); ++m_entryIndex) { |
272 | EventListenerVector& listeners = *m_map->m_entries[m_entryIndex].second; |
273 | if (m_index < listeners.size()) |
274 | return &listeners[m_index++]->callback(); |
275 | m_index = 0; |
276 | } |
277 | |
278 | return nullptr; |
279 | } |
280 | |
281 | } // namespace WebCore |
282 | |