[WTF] Add makeUnique<T>, which ensures T is fast-allocated, makeUnique / makeUniqueWi...
[WebKit-https.git] / Source / WebCore / dom / EventListenerMap.cpp
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 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
69 bool 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
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<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
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 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
132 bool 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 = makeUnique<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 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
180 EventListenerVector* 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
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 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
218 static 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
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