Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / events / 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 "core/events/EventTarget.h"
34
35 #include "RuntimeEnabledFeatures.h"
36 #include "bindings/v8/ExceptionState.h"
37 #include "core/events/Event.h"
38 #include "core/dom/ExceptionCode.h"
39 #include "core/inspector/InspectorInstrumentation.h"
40 #include "core/frame/DOMWindow.h"
41 #include "platform/UserGestureIndicator.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 MessagePort* EventTarget::toMessagePort()
72 {
73     return 0;
74 }
75
76 inline DOMWindow* EventTarget::executingWindow()
77 {
78     if (ExecutionContext* context = executionContext())
79         return context->executingWindow();
80     return 0;
81 }
82
83 bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
84 {
85     EventListener* eventListener = listener.get();
86     if (ensureEventTargetData().eventListenerMap.add(eventType, listener, useCapture)) {
87         InspectorInstrumentation::didAddEventListener(this, eventType, eventListener, useCapture);
88         return true;
89     }
90     return false;
91 }
92
93 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
94 {
95     EventTargetData* d = eventTargetData();
96     if (!d)
97         return false;
98
99     size_t indexOfRemovedListener;
100
101     if (!d->eventListenerMap.remove(eventType, listener, useCapture, indexOfRemovedListener))
102         return false;
103     InspectorInstrumentation::didRemoveEventListener(this, eventType, listener, useCapture);
104
105     // Notify firing events planning to invoke the listener at 'index' that
106     // they have one less listener to invoke.
107     if (!d->firingEventIterators)
108         return true;
109     for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
110         FiringEventIterator& firingIterator = d->firingEventIterators->at(i);
111         if (eventType != firingIterator.eventType)
112             continue;
113
114         if (indexOfRemovedListener >= firingIterator.end)
115             continue;
116
117         --firingIterator.end;
118         if (indexOfRemovedListener <= firingIterator.iterator)
119             --firingIterator.iterator;
120     }
121
122     return true;
123 }
124
125 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener)
126 {
127     clearAttributeEventListener(eventType);
128     if (!listener)
129         return false;
130     return addEventListener(eventType, listener, false);
131 }
132
133 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType)
134 {
135     const EventListenerVector& entry = getEventListeners(eventType);
136     for (size_t i = 0; i < entry.size(); ++i) {
137         EventListener* listener = entry[i].listener.get();
138         if (listener->isAttribute() && listener->belongsToTheCurrentWorld())
139             return listener;
140     }
141     return 0;
142 }
143
144 bool EventTarget::clearAttributeEventListener(const AtomicString& eventType)
145 {
146     EventListener* listener = getAttributeEventListener(eventType);
147     if (!listener)
148         return false;
149     return removeEventListener(eventType, listener, false);
150 }
151
152 bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionState& exceptionState)
153 {
154     if (!event) {
155         exceptionState.throwDOMException(InvalidStateError, "The event provided is null.");
156         return false;
157     }
158     if (event->type().isEmpty()) {
159         exceptionState.throwDOMException(InvalidStateError, "The event provided is uninitialized.");
160         return false;
161     }
162     if (event->isBeingDispatched()) {
163         exceptionState.throwDOMException(InvalidStateError, "The event is already being dispatched.");
164         return false;
165     }
166
167     if (!executionContext())
168         return false;
169
170     return dispatchEvent(event);
171 }
172
173 bool EventTarget::dispatchEvent(PassRefPtr<Event> event)
174 {
175     event->setTarget(this);
176     event->setCurrentTarget(this);
177     event->setEventPhase(Event::AT_TARGET);
178     bool defaultPrevented = fireEventListeners(event.get());
179     event->setEventPhase(0);
180     return defaultPrevented;
181 }
182
183 void EventTarget::uncaughtExceptionInEventHandler()
184 {
185 }
186
187 static const AtomicString& legacyType(const Event* event)
188 {
189     if (event->type() == EventTypeNames::transitionend)
190         return EventTypeNames::webkitTransitionEnd;
191
192     if (event->type() == EventTypeNames::animationstart)
193         return EventTypeNames::webkitAnimationStart;
194
195     if (event->type() == EventTypeNames::animationend)
196         return EventTypeNames::webkitAnimationEnd;
197
198     if (event->type() == EventTypeNames::animationiteration)
199         return EventTypeNames::webkitAnimationIteration;
200
201     if (event->type() == EventTypeNames::wheel)
202         return EventTypeNames::mousewheel;
203
204     return emptyAtom;
205 }
206
207 void EventTarget::countLegacyEvents(const AtomicString& legacyTypeName, EventListenerVector* listenersVector, EventListenerVector* legacyListenersVector)
208 {
209     UseCounter::Feature unprefixedFeature;
210     UseCounter::Feature prefixedFeature;
211     UseCounter::Feature prefixedAndUnprefixedFeature;
212     bool shouldCount = false;
213
214     if (legacyTypeName == EventTypeNames::webkitTransitionEnd) {
215         prefixedFeature = UseCounter::PrefixedTransitionEndEvent;
216         unprefixedFeature = UseCounter::UnprefixedTransitionEndEvent;
217         prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedTransitionEndEvent;
218         shouldCount = true;
219     } else if (legacyTypeName == EventTypeNames::webkitAnimationEnd) {
220         prefixedFeature = UseCounter::PrefixedAnimationEndEvent;
221         unprefixedFeature = UseCounter::UnprefixedAnimationEndEvent;
222         prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimationEndEvent;
223         shouldCount = true;
224     } else if (legacyTypeName == EventTypeNames::webkitAnimationStart) {
225         prefixedFeature = UseCounter::PrefixedAnimationStartEvent;
226         unprefixedFeature = UseCounter::UnprefixedAnimationStartEvent;
227         prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimationStartEvent;
228         shouldCount = true;
229     } else if (legacyTypeName == EventTypeNames::webkitAnimationIteration) {
230         prefixedFeature = UseCounter::PrefixedAnimationIterationEvent;
231         unprefixedFeature = UseCounter::UnprefixedAnimationIterationEvent;
232         prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimationIterationEvent;
233         shouldCount = true;
234     }
235
236     if (shouldCount) {
237         if (DOMWindow* executingWindow = this->executingWindow()) {
238             if (legacyListenersVector) {
239                 if (listenersVector)
240                     UseCounter::count(executingWindow->document(), prefixedAndUnprefixedFeature);
241                 else
242                     UseCounter::count(executingWindow->document(), prefixedFeature);
243             } else if (listenersVector) {
244                 UseCounter::count(executingWindow->document(), unprefixedFeature);
245             }
246         }
247     }
248 }
249
250 bool EventTarget::fireEventListeners(Event* event)
251 {
252     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
253     ASSERT(event && !event->type().isEmpty());
254
255     EventTargetData* d = eventTargetData();
256     if (!d)
257         return true;
258
259     EventListenerVector* legacyListenersVector = 0;
260     AtomicString legacyTypeName = legacyType(event);
261     if (!legacyTypeName.isEmpty())
262         legacyListenersVector = d->eventListenerMap.find(legacyTypeName);
263
264     EventListenerVector* listenersVector = d->eventListenerMap.find(event->type());
265     if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled() && (event->type() == EventTypeNames::animationiteration || event->type() == EventTypeNames::animationend
266         || event->type() == EventTypeNames::animationstart))
267         listenersVector = 0;
268
269     if (listenersVector) {
270         fireEventListeners(event, d, *listenersVector);
271     } else if (legacyListenersVector) {
272         AtomicString unprefixedTypeName = event->type();
273         event->setType(legacyTypeName);
274         fireEventListeners(event, d, *legacyListenersVector);
275         event->setType(unprefixedTypeName);
276     }
277
278     countLegacyEvents(legacyTypeName, listenersVector, legacyListenersVector);
279     return !event->defaultPrevented();
280 }
281
282 void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry)
283 {
284     RefPtr<EventTarget> protect = this;
285
286     // Fire all listeners registered for this event. Don't fire listeners removed
287     // during event dispatch. Also, don't fire event listeners added during event
288     // dispatch. Conveniently, all new event listeners will be added after or at
289     // index |size|, so iterating up to (but not including) |size| naturally excludes
290     // new event listeners.
291
292     if (event->type() == EventTypeNames::beforeunload) {
293         if (DOMWindow* executingWindow = this->executingWindow()) {
294             if (executingWindow->top())
295                 UseCounter::count(executingWindow->document(), UseCounter::SubFrameBeforeUnloadFired);
296             UseCounter::count(executingWindow->document(), UseCounter::DocumentBeforeUnloadFired);
297         }
298     } else if (event->type() == EventTypeNames::unload) {
299         if (DOMWindow* executingWindow = this->executingWindow())
300             UseCounter::count(executingWindow->document(), UseCounter::DocumentUnloadFired);
301     }
302
303     bool userEventWasHandled = false;
304     size_t i = 0;
305     size_t size = entry.size();
306     if (!d->firingEventIterators)
307         d->firingEventIterators = adoptPtr(new FiringEventIteratorVector);
308     d->firingEventIterators->append(FiringEventIterator(event->type(), i, size));
309     for ( ; i < size; ++i) {
310         RegisteredEventListener& registeredListener = entry[i];
311         if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
312             continue;
313         if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture)
314             continue;
315
316         // If stopImmediatePropagation has been called, we just break out immediately, without
317         // handling any more events on this target.
318         if (event->immediatePropagationStopped())
319             break;
320
321         ExecutionContext* context = executionContext();
322         if (!context)
323             break;
324
325         InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(this, event->type(), registeredListener.listener.get(), registeredListener.useCapture);
326         // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
327         // event listeners, even though that violates some versions of the DOM spec.
328         registeredListener.listener->handleEvent(context, event);
329         if (!userEventWasHandled && UserGestureIndicator::processingUserGesture())
330             userEventWasHandled = true;
331         InspectorInstrumentation::didHandleEvent(cookie);
332     }
333     d->firingEventIterators->removeLast();
334     if (userEventWasHandled) {
335         if (ExecutionContext* context = executionContext())
336             context->userEventWasHandled();
337     }
338 }
339
340 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType)
341 {
342     DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ());
343
344     EventTargetData* d = eventTargetData();
345     if (!d)
346         return emptyVector;
347
348     EventListenerVector* listenerVector = d->eventListenerMap.find(eventType);
349     if (!listenerVector)
350         return emptyVector;
351
352     return *listenerVector;
353 }
354
355 Vector<AtomicString> EventTarget::eventTypes()
356 {
357     EventTargetData* d = eventTargetData();
358     return d ? d->eventListenerMap.eventTypes() : Vector<AtomicString>();
359 }
360
361 void EventTarget::removeAllEventListeners()
362 {
363     EventTargetData* d = eventTargetData();
364     if (!d)
365         return;
366     d->eventListenerMap.clear();
367     InspectorInstrumentation::didRemoveAllEventListeners(this);
368
369     // Notify firing events planning to invoke the listener at 'index' that
370     // they have one less listener to invoke.
371     if (d->firingEventIterators) {
372         for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
373             d->firingEventIterators->at(i).iterator = 0;
374             d->firingEventIterators->at(i).end = 0;
375         }
376     }
377 }
378
379 } // namespace WebCore