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