• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "bindings/core/v8/ExceptionState.h"
36 #include "bindings/core/v8/V8DOMActivityLogger.h"
37 #include "core/dom/ExceptionCode.h"
38 #include "core/editing/Editor.h"
39 #include "core/events/Event.h"
40 #include "core/inspector/InspectorInstrumentation.h"
41 #include "core/frame/LocalDOMWindow.h"
42 #include "core/frame/UseCounter.h"
43 #include "platform/EventDispatchForbiddenScope.h"
44 #include "platform/RuntimeEnabledFeatures.h"
45 #include "wtf/StdLibExtras.h"
46 #include "wtf/Vector.h"
47 
48 using namespace WTF;
49 
50 namespace blink {
51 
EventTargetData()52 EventTargetData::EventTargetData()
53 {
54 }
55 
~EventTargetData()56 EventTargetData::~EventTargetData()
57 {
58 }
59 
EventTarget()60 EventTarget::EventTarget()
61 {
62 }
63 
~EventTarget()64 EventTarget::~EventTarget()
65 {
66 }
67 
toNode()68 Node* EventTarget::toNode()
69 {
70     return 0;
71 }
72 
toDOMWindow()73 LocalDOMWindow* EventTarget::toDOMWindow()
74 {
75     return 0;
76 }
77 
toMessagePort()78 MessagePort* EventTarget::toMessagePort()
79 {
80     return 0;
81 }
82 
executingWindow()83 inline LocalDOMWindow* EventTarget::executingWindow()
84 {
85     if (ExecutionContext* context = executionContext())
86         return context->executingWindow();
87     return 0;
88 }
89 
addEventListener(const AtomicString & eventType,PassRefPtr<EventListener> listener,bool useCapture)90 bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
91 {
92     // FIXME: listener null check should throw TypeError (and be done in
93     // generated bindings), but breaks legacy content. http://crbug.com/249598
94     if (!listener)
95         return false;
96 
97     V8DOMActivityLogger* activityLogger = V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld();
98     if (activityLogger) {
99         Vector<String> argv;
100         argv.append(toNode() ? toNode()->nodeName() : interfaceName());
101         argv.append(eventType);
102         activityLogger->logEvent("blinkAddEventListener", argv.size(), argv.data());
103     }
104 
105     return ensureEventTargetData().eventListenerMap.add(eventType, listener, useCapture);
106 }
107 
removeEventListener(const AtomicString & eventType,PassRefPtr<EventListener> listener,bool useCapture)108 bool EventTarget::removeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
109 {
110     // FIXME: listener null check should throw TypeError (and be done in
111     // generated bindings), but breaks legacy content. http://crbug.com/249598
112     if (!listener)
113         return false;
114 
115     EventTargetData* d = eventTargetData();
116     if (!d)
117         return false;
118 
119     size_t indexOfRemovedListener;
120 
121     if (!d->eventListenerMap.remove(eventType, listener.get(), useCapture, indexOfRemovedListener))
122         return false;
123 
124     // Notify firing events planning to invoke the listener at 'index' that
125     // they have one less listener to invoke.
126     if (!d->firingEventIterators)
127         return true;
128     for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
129         FiringEventIterator& firingIterator = d->firingEventIterators->at(i);
130         if (eventType != firingIterator.eventType)
131             continue;
132 
133         if (indexOfRemovedListener >= firingIterator.end)
134             continue;
135 
136         --firingIterator.end;
137         if (indexOfRemovedListener <= firingIterator.iterator)
138             --firingIterator.iterator;
139     }
140 
141     return true;
142 }
143 
setAttributeEventListener(const AtomicString & eventType,PassRefPtr<EventListener> listener)144 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener)
145 {
146     clearAttributeEventListener(eventType);
147     if (!listener)
148         return false;
149     return addEventListener(eventType, listener, false);
150 }
151 
getAttributeEventListener(const AtomicString & eventType)152 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType)
153 {
154     const EventListenerVector& entry = getEventListeners(eventType);
155     for (size_t i = 0; i < entry.size(); ++i) {
156         EventListener* listener = entry[i].listener.get();
157         if (listener->isAttribute() && listener->belongsToTheCurrentWorld())
158             return listener;
159     }
160     return 0;
161 }
162 
clearAttributeEventListener(const AtomicString & eventType)163 bool EventTarget::clearAttributeEventListener(const AtomicString& eventType)
164 {
165     EventListener* listener = getAttributeEventListener(eventType);
166     if (!listener)
167         return false;
168     return removeEventListener(eventType, listener, false);
169 }
170 
dispatchEvent(PassRefPtrWillBeRawPtr<Event> event,ExceptionState & exceptionState)171 bool EventTarget::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event, ExceptionState& exceptionState)
172 {
173     if (!event) {
174         exceptionState.throwDOMException(InvalidStateError, "The event provided is null.");
175         return false;
176     }
177     if (event->type().isEmpty()) {
178         exceptionState.throwDOMException(InvalidStateError, "The event provided is uninitialized.");
179         return false;
180     }
181     if (event->isBeingDispatched()) {
182         exceptionState.throwDOMException(InvalidStateError, "The event is already being dispatched.");
183         return false;
184     }
185 
186     if (!executionContext())
187         return false;
188 
189     return dispatchEvent(event);
190 }
191 
dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)192 bool EventTarget::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
193 {
194     event->setTarget(this);
195     event->setCurrentTarget(this);
196     event->setEventPhase(Event::AT_TARGET);
197     bool defaultPrevented = fireEventListeners(event.get());
198     event->setEventPhase(0);
199     return defaultPrevented;
200 }
201 
uncaughtExceptionInEventHandler()202 void EventTarget::uncaughtExceptionInEventHandler()
203 {
204 }
205 
legacyType(const Event * event)206 static const AtomicString& legacyType(const Event* event)
207 {
208     if (event->type() == EventTypeNames::transitionend)
209         return EventTypeNames::webkitTransitionEnd;
210 
211     if (event->type() == EventTypeNames::animationstart)
212         return EventTypeNames::webkitAnimationStart;
213 
214     if (event->type() == EventTypeNames::animationend)
215         return EventTypeNames::webkitAnimationEnd;
216 
217     if (event->type() == EventTypeNames::animationiteration)
218         return EventTypeNames::webkitAnimationIteration;
219 
220     if (event->type() == EventTypeNames::wheel)
221         return EventTypeNames::mousewheel;
222 
223     return emptyAtom;
224 }
225 
countLegacyEvents(const AtomicString & legacyTypeName,EventListenerVector * listenersVector,EventListenerVector * legacyListenersVector)226 void EventTarget::countLegacyEvents(const AtomicString& legacyTypeName, EventListenerVector* listenersVector, EventListenerVector* legacyListenersVector)
227 {
228     UseCounter::Feature unprefixedFeature;
229     UseCounter::Feature prefixedFeature;
230     UseCounter::Feature prefixedAndUnprefixedFeature;
231     if (legacyTypeName == EventTypeNames::webkitTransitionEnd) {
232         prefixedFeature = UseCounter::PrefixedTransitionEndEvent;
233         unprefixedFeature = UseCounter::UnprefixedTransitionEndEvent;
234         prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedTransitionEndEvent;
235     } else if (legacyTypeName == EventTypeNames::webkitAnimationEnd) {
236         prefixedFeature = UseCounter::PrefixedAnimationEndEvent;
237         unprefixedFeature = UseCounter::UnprefixedAnimationEndEvent;
238         prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimationEndEvent;
239     } else if (legacyTypeName == EventTypeNames::webkitAnimationStart) {
240         prefixedFeature = UseCounter::PrefixedAnimationStartEvent;
241         unprefixedFeature = UseCounter::UnprefixedAnimationStartEvent;
242         prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimationStartEvent;
243     } else if (legacyTypeName == EventTypeNames::webkitAnimationIteration) {
244         prefixedFeature = UseCounter::PrefixedAnimationIterationEvent;
245         unprefixedFeature = UseCounter::UnprefixedAnimationIterationEvent;
246         prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimationIterationEvent;
247     } else {
248         return;
249     }
250 
251     if (LocalDOMWindow* executingWindow = this->executingWindow()) {
252         if (legacyListenersVector) {
253             if (listenersVector)
254                 UseCounter::count(executingWindow->document(), prefixedAndUnprefixedFeature);
255             else
256                 UseCounter::count(executingWindow->document(), prefixedFeature);
257         } else if (listenersVector) {
258             UseCounter::count(executingWindow->document(), unprefixedFeature);
259         }
260     }
261 }
262 
fireEventListeners(Event * event)263 bool EventTarget::fireEventListeners(Event* event)
264 {
265     ASSERT(!EventDispatchForbiddenScope::isEventDispatchForbidden());
266     ASSERT(event && !event->type().isEmpty());
267 
268     EventTargetData* d = eventTargetData();
269     if (!d)
270         return true;
271 
272     EventListenerVector* legacyListenersVector = 0;
273     AtomicString legacyTypeName = legacyType(event);
274     if (!legacyTypeName.isEmpty())
275         legacyListenersVector = d->eventListenerMap.find(legacyTypeName);
276 
277     EventListenerVector* listenersVector = d->eventListenerMap.find(event->type());
278     if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled() && (event->type() == EventTypeNames::animationiteration || event->type() == EventTypeNames::animationend
279         || event->type() == EventTypeNames::animationstart)
280         // Some code out-there uses custom events to dispatch unprefixed animation events manually,
281         // we can safely remove all this block when cssAnimationUnprefixedEnabled is always on, this
282         // is really a special case. DO NOT ADD MORE EVENTS HERE.
283         && event->interfaceName() != EventNames::CustomEvent)
284         listenersVector = 0;
285 
286     if (listenersVector) {
287         fireEventListeners(event, d, *listenersVector);
288     } else if (legacyListenersVector) {
289         AtomicString unprefixedTypeName = event->type();
290         event->setType(legacyTypeName);
291         fireEventListeners(event, d, *legacyListenersVector);
292         event->setType(unprefixedTypeName);
293     }
294 
295     Editor::countEvent(executionContext(), event);
296     countLegacyEvents(legacyTypeName, listenersVector, legacyListenersVector);
297     return !event->defaultPrevented();
298 }
299 
fireEventListeners(Event * event,EventTargetData * d,EventListenerVector & entry)300 void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry)
301 {
302     RefPtrWillBeRawPtr<EventTarget> protect(this);
303 
304     // Fire all listeners registered for this event. Don't fire listeners removed
305     // during event dispatch. Also, don't fire event listeners added during event
306     // dispatch. Conveniently, all new event listeners will be added after or at
307     // index |size|, so iterating up to (but not including) |size| naturally excludes
308     // new event listeners.
309 
310     if (event->type() == EventTypeNames::beforeunload) {
311         if (LocalDOMWindow* executingWindow = this->executingWindow()) {
312             if (executingWindow->top())
313                 UseCounter::count(executingWindow->document(), UseCounter::SubFrameBeforeUnloadFired);
314             UseCounter::count(executingWindow->document(), UseCounter::DocumentBeforeUnloadFired);
315         }
316     } else if (event->type() == EventTypeNames::unload) {
317         if (LocalDOMWindow* executingWindow = this->executingWindow())
318             UseCounter::count(executingWindow->document(), UseCounter::DocumentUnloadFired);
319     } else if (event->type() == EventTypeNames::DOMFocusIn || event->type() == EventTypeNames::DOMFocusOut) {
320         if (LocalDOMWindow* executingWindow = this->executingWindow())
321             UseCounter::count(executingWindow->document(), UseCounter::DOMFocusInOutEvent);
322     } else if (event->type() == EventTypeNames::focusin || event->type() == EventTypeNames::focusout) {
323         if (LocalDOMWindow* executingWindow = this->executingWindow())
324             UseCounter::count(executingWindow->document(), UseCounter::FocusInOutEvent);
325     }
326 
327     size_t i = 0;
328     size_t size = entry.size();
329     if (!d->firingEventIterators)
330         d->firingEventIterators = adoptPtr(new FiringEventIteratorVector);
331     d->firingEventIterators->append(FiringEventIterator(event->type(), i, size));
332     for ( ; i < size; ++i) {
333         RegisteredEventListener& registeredListener = entry[i];
334         if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
335             continue;
336         if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture)
337             continue;
338 
339         // If stopImmediatePropagation has been called, we just break out immediately, without
340         // handling any more events on this target.
341         if (event->immediatePropagationStopped())
342             break;
343 
344         ExecutionContext* context = executionContext();
345         if (!context)
346             break;
347 
348         InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(this, event, registeredListener.listener.get(), registeredListener.useCapture);
349         // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
350         // event listeners, even though that violates some versions of the DOM spec.
351         registeredListener.listener->handleEvent(context, event);
352         InspectorInstrumentation::didHandleEvent(cookie);
353     }
354     d->firingEventIterators->removeLast();
355 }
356 
getEventListeners(const AtomicString & eventType)357 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType)
358 {
359     DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ());
360 
361     EventTargetData* d = eventTargetData();
362     if (!d)
363         return emptyVector;
364 
365     EventListenerVector* listenerVector = d->eventListenerMap.find(eventType);
366     if (!listenerVector)
367         return emptyVector;
368 
369     return *listenerVector;
370 }
371 
eventTypes()372 Vector<AtomicString> EventTarget::eventTypes()
373 {
374     EventTargetData* d = eventTargetData();
375     return d ? d->eventListenerMap.eventTypes() : Vector<AtomicString>();
376 }
377 
removeAllEventListeners()378 void EventTarget::removeAllEventListeners()
379 {
380     EventTargetData* d = eventTargetData();
381     if (!d)
382         return;
383     d->eventListenerMap.clear();
384 
385     // Notify firing events planning to invoke the listener at 'index' that
386     // they have one less listener to invoke.
387     if (d->firingEventIterators) {
388         for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
389             d->firingEventIterators->at(i).iterator = 0;
390             d->firingEventIterators->at(i).end = 0;
391         }
392     }
393 }
394 
395 } // namespace blink
396