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
43namespace WebCore {
44
45#ifndef NDEBUG
46void EventListenerMap::assertNoActiveIterators() const
47{
48 ASSERT(!m_activeIteratorCount);
49}
50#endif
51
52EventListenerMap::EventListenerMap()
53{
54}
55
56bool EventListenerMap::containsCapturing(const AtomString& 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
69bool EventListenerMap::containsActive(const AtomString& 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
82void 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
96Vector<AtomString> EventListenerMap::eventTypes() const
97{
98 Vector<AtomString> 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
107static 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
117void EventListenerMap::replace(const AtomString& 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
132bool EventListenerMap::add(const AtomString& 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
151static 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
162bool EventListenerMap::remove(const AtomString& 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
180EventListenerVector* EventListenerMap::find(const AtomString& 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
190static 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
202void EventListenerMap::removeFirstEventListenerCreatedFromMarkup(const AtomString& 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
218static void copyListenersNotCreatedFromMarkupToTarget(const AtomString& 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
228void EventListenerMap::copyEventListenersNotCreatedFromMarkupToTarget(EventTarget* target)
229{
230 for (auto& entry : m_entries)
231 copyListenersNotCreatedFromMarkupToTarget(entry.first, *entry.second, target);
232}
233
234EventListenerIterator::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
249EventListenerIterator::EventListenerIterator(EventListenerMap* map)
250{
251 m_map = map;
252
253#ifndef NDEBUG
254 m_map->m_activeIteratorCount++;
255#endif
256}
257
258#ifndef NDEBUG
259EventListenerIterator::~EventListenerIterator()
260{
261 if (m_map)
262 m_map->m_activeIteratorCount--;
263}
264#endif
265
266EventListener* 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