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