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