Home | History | Annotate | Download | only in dom
      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/dom/EventTarget.h"
     34 
     35 #include "bindings/v8/DOMWrapperWorld.h"
     36 #include "bindings/v8/ExceptionState.h"
     37 #include "bindings/v8/ScriptController.h"
     38 #include "core/dom/Event.h"
     39 #include "core/dom/ExceptionCode.h"
     40 #include "core/inspector/InspectorInstrumentation.h"
     41 #include "core/page/DOMWindow.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 inline DOMWindow* EventTarget::executingWindow()
     72 {
     73     if (ScriptExecutionContext* context = scriptExecutionContext())
     74         return context->executingWindow();
     75     return 0;
     76 }
     77 
     78 bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
     79 {
     80     EventTargetData* d = ensureEventTargetData();
     81     return d->eventListenerMap.add(eventType, listener, useCapture);
     82 }
     83 
     84 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
     85 {
     86     EventTargetData* d = eventTargetData();
     87     if (!d)
     88         return false;
     89 
     90     size_t indexOfRemovedListener;
     91 
     92     if (!d->eventListenerMap.remove(eventType, listener, useCapture, indexOfRemovedListener))
     93         return false;
     94 
     95     // Notify firing events planning to invoke the listener at 'index' that
     96     // they have one less listener to invoke.
     97     if (!d->firingEventIterators)
     98         return true;
     99     for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
    100         FiringEventIterator& firingIterator = d->firingEventIterators->at(i);
    101         if (eventType != firingIterator.eventType)
    102             continue;
    103 
    104         if (indexOfRemovedListener >= firingIterator.end)
    105             continue;
    106 
    107         --firingIterator.end;
    108         if (indexOfRemovedListener <= firingIterator.iterator)
    109             --firingIterator.iterator;
    110     }
    111 
    112     return true;
    113 }
    114 
    115 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, DOMWrapperWorld* isolatedWorld)
    116 {
    117     clearAttributeEventListener(eventType, isolatedWorld);
    118     if (!listener)
    119         return false;
    120     return addEventListener(eventType, listener, false);
    121 }
    122 
    123 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType, DOMWrapperWorld* isolatedWorld)
    124 {
    125     const EventListenerVector& entry = getEventListeners(eventType);
    126     for (size_t i = 0; i < entry.size(); ++i) {
    127         EventListener* listener = entry[i].listener.get();
    128         if (listener->isAttribute()) {
    129             DOMWrapperWorld* listenerWorld = listener->world();
    130             // Worker listener
    131             if (!listenerWorld) {
    132                 ASSERT(!isolatedWorld);
    133                 return listener;
    134             }
    135             if (listenerWorld->isMainWorld() && !isolatedWorld)
    136                 return listener;
    137             if (listenerWorld == isolatedWorld)
    138                 return listener;
    139         }
    140     }
    141     return 0;
    142 }
    143 
    144 bool EventTarget::clearAttributeEventListener(const AtomicString& eventType, DOMWrapperWorld* isolatedWorld)
    145 {
    146     EventListener* listener = getAttributeEventListener(eventType, isolatedWorld);
    147     if (!listener)
    148         return false;
    149     return removeEventListener(eventType, listener, false);
    150 }
    151 
    152 bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionState& es)
    153 {
    154     if (!event || event->type().isEmpty() || event->isBeingDispatched()) {
    155         es.throwDOMException(InvalidStateError);
    156         return false;
    157     }
    158 
    159     if (!scriptExecutionContext())
    160         return false;
    161 
    162     return dispatchEvent(event);
    163 }
    164 
    165 bool EventTarget::dispatchEvent(PassRefPtr<Event> event)
    166 {
    167     event->setTarget(this);
    168     event->setCurrentTarget(this);
    169     event->setEventPhase(Event::AT_TARGET);
    170     bool defaultPrevented = fireEventListeners(event.get());
    171     event->setEventPhase(0);
    172     return defaultPrevented;
    173 }
    174 
    175 void EventTarget::uncaughtExceptionInEventHandler()
    176 {
    177 }
    178 
    179 static AtomicString prefixedType(const Event* event)
    180 {
    181     if (event->type() == eventNames().transitionendEvent)
    182         return eventNames().webkitTransitionEndEvent;
    183 
    184     return emptyString();
    185 }
    186 
    187 bool EventTarget::fireEventListeners(Event* event)
    188 {
    189     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
    190     ASSERT(event && !event->type().isEmpty());
    191 
    192     EventTargetData* d = eventTargetData();
    193     if (!d)
    194         return true;
    195 
    196     EventListenerVector* listenerPrefixedVector = 0;
    197     AtomicString prefixedTypeName = prefixedType(event);
    198     if (!prefixedTypeName.isEmpty())
    199         listenerPrefixedVector = d->eventListenerMap.find(prefixedTypeName);
    200 
    201     EventListenerVector* listenerUnprefixedVector = d->eventListenerMap.find(event->type());
    202 
    203     if (listenerUnprefixedVector)
    204         fireEventListeners(event, d, *listenerUnprefixedVector);
    205     else if (listenerPrefixedVector) {
    206         AtomicString unprefixedTypeName = event->type();
    207         event->setType(prefixedTypeName);
    208         fireEventListeners(event, d, *listenerPrefixedVector);
    209         event->setType(unprefixedTypeName);
    210     }
    211 
    212     if (!prefixedTypeName.isEmpty()) {
    213         if (DOMWindow* executingWindow = this->executingWindow()) {
    214             if (listenerPrefixedVector) {
    215                 if (listenerUnprefixedVector)
    216                     UseCounter::count(executingWindow, UseCounter::PrefixedAndUnprefixedTransitionEndEvent);
    217                 else
    218                     UseCounter::count(executingWindow, UseCounter::PrefixedTransitionEndEvent);
    219             } else if (listenerUnprefixedVector) {
    220                 UseCounter::count(executingWindow, UseCounter::UnprefixedTransitionEndEvent);
    221             }
    222         }
    223     }
    224 
    225     return !event->defaultPrevented();
    226 }
    227 
    228 void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry)
    229 {
    230     RefPtr<EventTarget> protect = this;
    231 
    232     // Fire all listeners registered for this event. Don't fire listeners removed
    233     // during event dispatch. Also, don't fire event listeners added during event
    234     // dispatch. Conveniently, all new event listeners will be added after or at
    235     // index |size|, so iterating up to (but not including) |size| naturally excludes
    236     // new event listeners.
    237 
    238     if (event->type() == eventNames().beforeunloadEvent) {
    239         if (DOMWindow* executingWindow = this->executingWindow()) {
    240             if (executingWindow->top())
    241                 UseCounter::count(executingWindow, UseCounter::SubFrameBeforeUnloadFired);
    242         }
    243     }
    244 
    245     bool userEventWasHandled = false;
    246     size_t i = 0;
    247     size_t size = entry.size();
    248     if (!d->firingEventIterators)
    249         d->firingEventIterators = adoptPtr(new FiringEventIteratorVector);
    250     d->firingEventIterators->append(FiringEventIterator(event->type(), i, size));
    251     for ( ; i < size; ++i) {
    252         RegisteredEventListener& registeredListener = entry[i];
    253         if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
    254             continue;
    255         if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture)
    256             continue;
    257 
    258         // If stopImmediatePropagation has been called, we just break out immediately, without
    259         // handling any more events on this target.
    260         if (event->immediatePropagationStopped())
    261             break;
    262 
    263         ScriptExecutionContext* context = scriptExecutionContext();
    264         InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, event);
    265         // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
    266         // event listeners, even though that violates some versions of the DOM spec.
    267         registeredListener.listener->handleEvent(context, event);
    268         if (!userEventWasHandled && ScriptController::processingUserGesture())
    269             userEventWasHandled = true;
    270         InspectorInstrumentation::didHandleEvent(cookie);
    271     }
    272     d->firingEventIterators->removeLast();
    273     if (userEventWasHandled) {
    274         if (ScriptExecutionContext* context = scriptExecutionContext())
    275             context->userEventWasHandled();
    276     }
    277 }
    278 
    279 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType)
    280 {
    281     DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ());
    282 
    283     EventTargetData* d = eventTargetData();
    284     if (!d)
    285         return emptyVector;
    286 
    287     EventListenerVector* listenerVector = d->eventListenerMap.find(eventType);
    288     if (!listenerVector)
    289         return emptyVector;
    290 
    291     return *listenerVector;
    292 }
    293 
    294 void EventTarget::removeAllEventListeners()
    295 {
    296     EventTargetData* d = eventTargetData();
    297     if (!d)
    298         return;
    299     d->eventListenerMap.clear();
    300 
    301     // Notify firing events planning to invoke the listener at 'index' that
    302     // they have one less listener to invoke.
    303     if (d->firingEventIterators) {
    304         for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
    305             d->firingEventIterators->at(i).iterator = 0;
    306             d->firingEventIterators->at(i).end = 0;
    307         }
    308     }
    309 }
    310 
    311 } // namespace WebCore
    312