Use ASSERT_WITH_SECURITY_IMPLICATION() for NoEventDispatchAssertion
[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 "EventException.h"
36 #include "InspectorInstrumentation.h"
37 #include "ScriptController.h"
38 #include "WebKitAnimationEvent.h"
39 #include "WebKitTransitionEvent.h"
40 #include <wtf/MainThread.h>
41 #include <wtf/NeverDestroyed.h>
42 #include <wtf/Ref.h>
43 #include <wtf/StdLibExtras.h>
44 #include <wtf/Vector.h>
45
46 using namespace WTF;
47
48 namespace WebCore {
49
50 EventTargetData::EventTargetData()
51 {
52 }
53
54 EventTargetData::~EventTargetData()
55 {
56 }
57
58 EventTarget::~EventTarget()
59 {
60 }
61
62 Node* EventTarget::toNode()
63 {
64     return 0;
65 }
66
67 DOMWindow* EventTarget::toDOMWindow()
68 {
69     return 0;
70 }
71
72 bool EventTarget::isMessagePort() const
73 {
74     return false;
75 }
76
77 bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
78 {
79     return ensureEventTargetData().eventListenerMap.add(eventType, listener, useCapture);
80 }
81
82 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
83 {
84     EventTargetData* d = eventTargetData();
85     if (!d)
86         return false;
87
88     size_t indexOfRemovedListener;
89
90     if (!d->eventListenerMap.remove(eventType, listener, useCapture, indexOfRemovedListener))
91         return false;
92
93     // Notify firing events planning to invoke the listener at 'index' that
94     // they have one less listener to invoke.
95     if (!d->firingEventIterators)
96         return true;
97     for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
98         FiringEventIterator& firingIterator = d->firingEventIterators->at(i);
99         if (eventType != firingIterator.eventType)
100             continue;
101
102         if (indexOfRemovedListener >= firingIterator.size)
103             continue;
104
105         --firingIterator.size;
106         if (indexOfRemovedListener <= firingIterator.iterator)
107             --firingIterator.iterator;
108     }
109
110     return true;
111 }
112
113 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener)
114 {
115     clearAttributeEventListener(eventType);
116     if (!listener)
117         return false;
118     return addEventListener(eventType, listener, false);
119 }
120
121 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType)
122 {
123     const EventListenerVector& entry = getEventListeners(eventType);
124     for (size_t i = 0; i < entry.size(); ++i) {
125         if (entry[i].listener->isAttribute())
126             return entry[i].listener.get();
127     }
128     return 0;
129 }
130
131 bool EventTarget::clearAttributeEventListener(const AtomicString& eventType)
132 {
133     EventListener* listener = getAttributeEventListener(eventType);
134     if (!listener)
135         return false;
136     return removeEventListener(eventType, listener, false);
137 }
138
139 bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec)
140 {
141     if (!event || event->type().isEmpty()) {
142         ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
143         return false;
144     }
145
146     if (event->isBeingDispatched()) {
147         ec = EventException::DISPATCH_REQUEST_ERR;
148         return false;
149     }
150
151     if (!scriptExecutionContext())
152         return false;
153
154     return dispatchEvent(event);
155 }
156
157 bool EventTarget::dispatchEvent(PassRefPtr<Event> event)
158 {
159     event->setTarget(this);
160     event->setCurrentTarget(this);
161     event->setEventPhase(Event::AT_TARGET);
162     bool defaultPrevented = fireEventListeners(event.get());
163     event->setEventPhase(0);
164     return defaultPrevented;
165 }
166
167 void EventTarget::uncaughtExceptionInEventHandler()
168 {
169 }
170
171 static const AtomicString& legacyType(const Event* event)
172 {
173     if (event->type() == eventNames().animationendEvent)
174         return eventNames().webkitAnimationEndEvent;
175
176     if (event->type() == eventNames().animationstartEvent)
177         return eventNames().webkitAnimationStartEvent;
178
179     if (event->type() == eventNames().animationiterationEvent)
180         return eventNames().webkitAnimationIterationEvent;
181
182     if (event->type() == eventNames().transitionendEvent)
183         return eventNames().webkitTransitionEndEvent;
184
185     if (event->type() == eventNames().wheelEvent)
186         return eventNames().mousewheelEvent;
187
188     return emptyAtom;
189 }
190
191 bool EventTarget::fireEventListeners(Event* event)
192 {
193     ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
194     ASSERT(event && !event->type().isEmpty());
195
196     EventTargetData* d = eventTargetData();
197     if (!d)
198         return true;
199
200     EventListenerVector* legacyListenersVector = 0;
201     const AtomicString& legacyTypeName = legacyType(event);
202     if (!legacyTypeName.isEmpty())
203         legacyListenersVector = d->eventListenerMap.find(legacyTypeName);
204
205     EventListenerVector* listenersVector = d->eventListenerMap.find(event->type());
206
207     if (listenersVector)
208         fireEventListeners(event, d, *listenersVector);
209     else if (legacyListenersVector) {
210         AtomicString typeName = event->type();
211         event->setType(legacyTypeName);
212         fireEventListeners(event, d, *legacyListenersVector);
213         event->setType(typeName);
214     }
215
216     return !event->defaultPrevented();
217 }
218         
219 void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry)
220 {
221     Ref<EventTarget> protect(*this);
222
223     // Fire all listeners registered for this event. Don't fire listeners removed during event dispatch.
224     // Also, don't fire event listeners added during event dispatch. Conveniently, all new event listeners will be added
225     // after or at index |size|, so iterating up to (but not including) |size| naturally excludes new event listeners.
226
227     size_t i = 0;
228     size_t size = entry.size();
229     if (!d->firingEventIterators)
230         d->firingEventIterators = std::make_unique<FiringEventIteratorVector>();
231     d->firingEventIterators->append(FiringEventIterator(event->type(), i, size));
232
233     ScriptExecutionContext* context = scriptExecutionContext();
234     Document* document = nullptr;
235     InspectorInstrumentationCookie willDispatchEventCookie;
236     if (is<Document>(context)) {
237         document = downcast<Document>(context);
238         willDispatchEventCookie = InspectorInstrumentation::willDispatchEvent(*document, *event, size > 0);
239     }
240
241     for (; i < size; ++i) {
242         RegisteredEventListener& registeredListener = entry[i];
243         if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
244             continue;
245         if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture)
246             continue;
247
248         // If stopImmediatePropagation has been called, we just break out immediately, without
249         // handling any more events on this target.
250         if (event->immediatePropagationStopped())
251             break;
252
253         InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, *event);
254         // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
255         // event listeners, even though that violates some versions of the DOM spec.
256         registeredListener.listener->handleEvent(context, event);
257         InspectorInstrumentation::didHandleEvent(cookie);
258     }
259     d->firingEventIterators->removeLast();
260
261     if (document)
262         InspectorInstrumentation::didDispatchEvent(willDispatchEventCookie);
263 }
264
265 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType)
266 {
267     auto* data = eventTargetData();
268     auto* listenerVector = data ? data->eventListenerMap.find(eventType) : nullptr;
269     static NeverDestroyed<EventListenerVector> emptyVector;
270     return listenerVector ? *listenerVector : emptyVector.get();
271 }
272
273 void EventTarget::removeAllEventListeners()
274 {
275     EventTargetData* d = eventTargetData();
276     if (!d)
277         return;
278     d->eventListenerMap.clear();
279
280     // Notify firing events planning to invoke the listener at 'index' that
281     // they have one less listener to invoke.
282     if (d->firingEventIterators) {
283         for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
284             d->firingEventIterators->at(i).iterator = 0;
285             d->firingEventIterators->at(i).size = 0;
286         }
287     }
288 }
289
290 } // namespace WebCore