Generate bindings code for EventTarget.addEventListener() / removeEventListener()
[WebKit-https.git] / Source / WebCore / dom / EventTarget.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  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26  * 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
32 #include "config.h"
33 #include "EventTarget.h"
34
35 #include "ExceptionCode.h"
36 #include "InspectorInstrumentation.h"
37 #include "NoEventDispatchAssertion.h"
38 #include "ScriptController.h"
39 #include "WebKitAnimationEvent.h"
40 #include "WebKitTransitionEvent.h"
41 #include <wtf/MainThread.h>
42 #include <wtf/NeverDestroyed.h>
43 #include <wtf/Ref.h>
44 #include <wtf/StdLibExtras.h>
45 #include <wtf/Vector.h>
46
47 using namespace WTF;
48
49 namespace WebCore {
50
51 EventTargetData::EventTargetData()
52 {
53 }
54
55 EventTargetData::~EventTargetData()
56 {
57 }
58
59 EventTarget::~EventTarget()
60 {
61 }
62
63 Node* EventTarget::toNode()
64 {
65     return 0;
66 }
67
68 DOMWindow* EventTarget::toDOMWindow()
69 {
70     return 0;
71 }
72
73 bool EventTarget::isMessagePort() const
74 {
75     return false;
76 }
77
78 bool EventTarget::addEventListener(const AtomicString& eventType, Ref<EventListener>&& listener, bool useCapture)
79 {
80     return ensureEventTargetData().eventListenerMap.add(eventType, WTFMove(listener), useCapture);
81 }
82
83 void EventTarget::addEventListenerForBindings(const AtomicString& eventType, RefPtr<EventListener>&& listener, bool useCapture)
84 {
85     // FIXME: listener is not supposed to be nullable.
86     if (!listener)
87         return;
88     addEventListener(eventType, listener.releaseNonNull(), useCapture);
89 }
90
91 void EventTarget::removeEventListenerForBindings(const AtomicString& eventType, RefPtr<EventListener>&& listener, bool useCapture)
92 {
93     // FIXME: listener is not supposed to be nullable.
94     if (!listener)
95         return;
96     removeEventListener(eventType, *listener, useCapture);
97 }
98
99 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener& listener, bool useCapture)
100 {
101     EventTargetData* d = eventTargetData();
102     if (!d)
103         return false;
104
105     size_t indexOfRemovedListener;
106
107     if (!d->eventListenerMap.remove(eventType, listener, useCapture, indexOfRemovedListener))
108         return false;
109
110     // Notify firing events planning to invoke the listener at 'index' that
111     // they have one less listener to invoke.
112     if (!d->firingEventIterators)
113         return true;
114     for (auto& firingIterator : *d->firingEventIterators) {
115         if (eventType != firingIterator.eventType)
116             continue;
117
118         if (indexOfRemovedListener >= firingIterator.size)
119             continue;
120
121         --firingIterator.size;
122         if (indexOfRemovedListener <= firingIterator.iterator)
123             --firingIterator.iterator;
124     }
125
126     return true;
127 }
128
129 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, RefPtr<EventListener>&& listener)
130 {
131     clearAttributeEventListener(eventType);
132     if (!listener)
133         return false;
134     return addEventListener(eventType, listener.releaseNonNull(), false);
135 }
136
137 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType)
138 {
139     for (auto& eventListener : getEventListeners(eventType)) {
140         if (eventListener.listener->isAttribute())
141             return eventListener.listener.get();
142     }
143     return 0;
144 }
145
146 bool EventTarget::clearAttributeEventListener(const AtomicString& eventType)
147 {
148     EventListener* listener = getAttributeEventListener(eventType);
149     if (!listener)
150         return false;
151     return removeEventListener(eventType, *listener, false);
152 }
153
154 bool EventTarget::dispatchEventForBindings(Event* event, ExceptionCode& ec)
155 {
156     if (!event) {
157         ec = TypeError;
158         return false;
159     }
160
161     event->setUntrusted();
162
163     if (!event->isInitialized() || event->isBeingDispatched()) {
164         ec = INVALID_STATE_ERR;
165         return false;
166     }
167
168     if (!scriptExecutionContext())
169         return false;
170
171     return dispatchEvent(*event);
172 }
173
174 bool EventTarget::dispatchEvent(Event& event)
175 {
176     ASSERT(event.isInitialized());
177     ASSERT(!event.isBeingDispatched());
178
179     event.setTarget(this);
180     event.setCurrentTarget(this);
181     event.setEventPhase(Event::AT_TARGET);
182     bool defaultPrevented = fireEventListeners(event);
183     event.setEventPhase(0);
184     return defaultPrevented;
185 }
186
187 void EventTarget::uncaughtExceptionInEventHandler()
188 {
189 }
190
191 static const AtomicString& legacyType(const Event& event)
192 {
193     if (event.type() == eventNames().animationendEvent)
194         return eventNames().webkitAnimationEndEvent;
195
196     if (event.type() == eventNames().animationstartEvent)
197         return eventNames().webkitAnimationStartEvent;
198
199     if (event.type() == eventNames().animationiterationEvent)
200         return eventNames().webkitAnimationIterationEvent;
201
202     if (event.type() == eventNames().transitionendEvent)
203         return eventNames().webkitTransitionEndEvent;
204
205     if (event.type() == eventNames().wheelEvent)
206         return eventNames().mousewheelEvent;
207
208     return emptyAtom;
209 }
210
211 bool EventTarget::fireEventListeners(Event& event)
212 {
213     ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
214     ASSERT(event.isInitialized());
215
216     EventTargetData* d = eventTargetData();
217     if (!d)
218         return true;
219
220     EventListenerVector* legacyListenersVector = nullptr;
221     const AtomicString& legacyTypeName = legacyType(event);
222     if (!legacyTypeName.isEmpty())
223         legacyListenersVector = d->eventListenerMap.find(legacyTypeName);
224
225     EventListenerVector* listenersVector = d->eventListenerMap.find(event.type());
226
227     if (listenersVector)
228         fireEventListeners(event, d, *listenersVector);
229     else if (legacyListenersVector) {
230         AtomicString typeName = event.type();
231         event.setType(legacyTypeName);
232         fireEventListeners(event, d, *legacyListenersVector);
233         event.setType(typeName);
234     }
235
236     return !event.defaultPrevented();
237 }
238         
239 void EventTarget::fireEventListeners(Event& event, EventTargetData* d, EventListenerVector& entry)
240 {
241     Ref<EventTarget> protectedThis(*this);
242
243     // Fire all listeners registered for this event. Don't fire listeners removed during event dispatch.
244     // Also, don't fire event listeners added during event dispatch. Conveniently, all new event listeners will be added
245     // after or at index |size|, so iterating up to (but not including) |size| naturally excludes new event listeners.
246
247     size_t i = 0;
248     size_t size = entry.size();
249     if (!d->firingEventIterators)
250         d->firingEventIterators = std::make_unique<FiringEventIteratorVector>();
251     d->firingEventIterators->append(FiringEventIterator(event.type(), i, size));
252
253     ScriptExecutionContext* context = scriptExecutionContext();
254     Document* document = nullptr;
255     InspectorInstrumentationCookie willDispatchEventCookie;
256     if (is<Document>(context)) {
257         document = downcast<Document>(context);
258         willDispatchEventCookie = InspectorInstrumentation::willDispatchEvent(*document, event, size > 0);
259     }
260
261     for (; i < size; ++i) {
262         RegisteredEventListener& registeredListener = entry[i];
263         if (event.eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
264             continue;
265         if (event.eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture)
266             continue;
267
268         // If stopImmediatePropagation has been called, we just break out immediately, without
269         // handling any more events on this target.
270         if (event.immediatePropagationStopped())
271             break;
272
273         InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, event);
274         // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
275         // event listeners, even though that violates some versions of the DOM spec.
276         registeredListener.listener->handleEvent(context, &event);
277         InspectorInstrumentation::didHandleEvent(cookie);
278     }
279     d->firingEventIterators->removeLast();
280
281     if (document)
282         InspectorInstrumentation::didDispatchEvent(willDispatchEventCookie);
283 }
284
285 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType)
286 {
287     auto* data = eventTargetData();
288     auto* listenerVector = data ? data->eventListenerMap.find(eventType) : nullptr;
289     static NeverDestroyed<EventListenerVector> emptyVector;
290     return listenerVector ? *listenerVector : emptyVector.get();
291 }
292
293 void EventTarget::removeAllEventListeners()
294 {
295     EventTargetData* d = eventTargetData();
296     if (!d)
297         return;
298     d->eventListenerMap.clear();
299
300     // Notify firing events planning to invoke the listener at 'index' that
301     // they have one less listener to invoke.
302     if (d->firingEventIterators) {
303         for (auto& firingEventIterator : *d->firingEventIterators) {
304             firingEventIterator.iterator = 0;
305             firingEventIterator.size = 0;
306         }
307     }
308 }
309
310 } // namespace WebCore