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