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/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 
     52 EventTargetData::EventTargetData()
     53 {
     54 }
     55 
     56 EventTargetData::~EventTargetData()
     57 {
     58 }
     59 
     60 EventTarget::EventTarget()
     61 {
     62 }
     63 
     64 EventTarget::~EventTarget()
     65 {
     66 }
     67 
     68 Node* EventTarget::toNode()
     69 {
     70     return 0;
     71 }
     72 
     73 LocalDOMWindow* EventTarget::toDOMWindow()
     74 {
     75     return 0;
     76 }
     77 
     78 MessagePort* EventTarget::toMessagePort()
     79 {
     80     return 0;
     81 }
     82 
     83 inline LocalDOMWindow* EventTarget::executingWindow()
     84 {
     85     if (ExecutionContext* context = executionContext())
     86         return context->executingWindow();
     87     return 0;
     88 }
     89 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    202 void EventTarget::uncaughtExceptionInEventHandler()
    203 {
    204 }
    205 
    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 
    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 
    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 
    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 
    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 
    372 Vector<AtomicString> EventTarget::eventTypes()
    373 {
    374     EventTargetData* d = eventTargetData();
    375     return d ? d->eventListenerMap.eventTypes() : Vector<AtomicString>();
    376 }
    377 
    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