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