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 "EventTarget.h"
     34 
     35 #include "Event.h"
     36 #include "EventException.h"
     37 #include <wtf/StdLibExtras.h>
     38 
     39 using namespace WTF;
     40 
     41 namespace WebCore {
     42 
     43 #ifndef NDEBUG
     44 static int gEventDispatchForbidden = 0;
     45 
     46 void forbidEventDispatch()
     47 {
     48     if (!isMainThread())
     49         return;
     50     ++gEventDispatchForbidden;
     51 }
     52 
     53 void allowEventDispatch()
     54 {
     55     if (!isMainThread())
     56         return;
     57     if (gEventDispatchForbidden > 0)
     58         --gEventDispatchForbidden;
     59 }
     60 
     61 bool eventDispatchForbidden()
     62 {
     63     if (!isMainThread())
     64         return false;
     65     return gEventDispatchForbidden > 0;
     66 }
     67 #endif // NDEBUG
     68 
     69 EventTargetData::EventTargetData()
     70 {
     71 }
     72 
     73 EventTargetData::~EventTargetData()
     74 {
     75     deleteAllValues(eventListenerMap);
     76 }
     77 
     78 EventTarget::~EventTarget()
     79 {
     80 }
     81 
     82 EventSource* EventTarget::toEventSource()
     83 {
     84     return 0;
     85 }
     86 
     87 Node* EventTarget::toNode()
     88 {
     89     return 0;
     90 }
     91 
     92 DOMWindow* EventTarget::toDOMWindow()
     93 {
     94     return 0;
     95 }
     96 
     97 XMLHttpRequest* EventTarget::toXMLHttpRequest()
     98 {
     99     return 0;
    100 }
    101 
    102 XMLHttpRequestUpload* EventTarget::toXMLHttpRequestUpload()
    103 {
    104     return 0;
    105 }
    106 
    107 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
    108 DOMApplicationCache* EventTarget::toDOMApplicationCache()
    109 {
    110     return 0;
    111 }
    112 #endif
    113 
    114 #if ENABLE(SVG)
    115 SVGElementInstance* EventTarget::toSVGElementInstance()
    116 {
    117     return 0;
    118 }
    119 #endif
    120 
    121 #if ENABLE(WEB_AUDIO)
    122 AudioContext* EventTarget::toAudioContext()
    123 {
    124     return 0;
    125 }
    126 
    127 JavaScriptAudioNode* EventTarget::toJavaScriptAudioNode()
    128 {
    129     return 0;
    130 }
    131 #endif
    132 
    133 #if ENABLE(WEB_SOCKETS)
    134 WebSocket* EventTarget::toWebSocket()
    135 {
    136     return 0;
    137 }
    138 #endif
    139 
    140 MessagePort* EventTarget::toMessagePort()
    141 {
    142     return 0;
    143 }
    144 
    145 #if ENABLE(WORKERS)
    146 Worker* EventTarget::toWorker()
    147 {
    148     return 0;
    149 }
    150 
    151 DedicatedWorkerContext* EventTarget::toDedicatedWorkerContext()
    152 {
    153     return 0;
    154 }
    155 #endif
    156 
    157 #if ENABLE(SHARED_WORKERS)
    158 SharedWorker* EventTarget::toSharedWorker()
    159 {
    160     return 0;
    161 }
    162 SharedWorkerContext* EventTarget::toSharedWorkerContext()
    163 {
    164     return 0;
    165 }
    166 #endif
    167 
    168 #if ENABLE(NOTIFICATIONS)
    169 Notification* EventTarget::toNotification()
    170 {
    171     return 0;
    172 }
    173 #endif
    174 
    175 #if ENABLE(BLOB)
    176 FileReader* EventTarget::toFileReader()
    177 {
    178     return 0;
    179 }
    180 #endif
    181 #if ENABLE(FILE_SYSTEM)
    182 FileWriter* EventTarget::toFileWriter()
    183 {
    184     return 0;
    185 }
    186 #endif
    187 
    188 #if ENABLE(INDEXED_DATABASE)
    189 IDBDatabase* EventTarget::toIDBDatabase()
    190 {
    191     return 0;
    192 }
    193 IDBRequest* EventTarget::toIDBRequest()
    194 {
    195     return 0;
    196 }
    197 IDBTransaction* EventTarget::toIDBTransaction()
    198 {
    199     return 0;
    200 }
    201 IDBVersionChangeRequest* EventTarget::toIDBVersionChangeRequest()
    202 {
    203     return 0;
    204 }
    205 #endif
    206 
    207 bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
    208 {
    209     EventTargetData* d = ensureEventTargetData();
    210 
    211     pair<EventListenerMap::iterator, bool> result = d->eventListenerMap.add(eventType, 0);
    212     EventListenerVector*& entry = result.first->second;
    213     const bool isNewEntry = result.second;
    214     if (isNewEntry)
    215         entry = new EventListenerVector();
    216 
    217     RegisteredEventListener registeredListener(listener, useCapture);
    218     if (!isNewEntry) {
    219         if (entry->find(registeredListener) != notFound) // duplicate listener
    220             return false;
    221     }
    222 
    223     entry->append(registeredListener);
    224     return true;
    225 }
    226 
    227 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
    228 {
    229     EventTargetData* d = eventTargetData();
    230     if (!d)
    231         return false;
    232 
    233     EventListenerMap::iterator result = d->eventListenerMap.find(eventType);
    234     if (result == d->eventListenerMap.end())
    235         return false;
    236     EventListenerVector* entry = result->second;
    237 
    238     RegisteredEventListener registeredListener(listener, useCapture);
    239     size_t index = entry->find(registeredListener);
    240     if (index == notFound)
    241         return false;
    242 
    243     entry->remove(index);
    244     if (entry->isEmpty()) {
    245         delete entry;
    246         d->eventListenerMap.remove(result);
    247     }
    248 
    249     // Notify firing events planning to invoke the listener at 'index' that
    250     // they have one less listener to invoke.
    251     for (size_t i = 0; i < d->firingEventIterators.size(); ++i) {
    252         if (eventType != d->firingEventIterators[i].eventType)
    253             continue;
    254 
    255         if (index >= d->firingEventIterators[i].end)
    256             continue;
    257 
    258         --d->firingEventIterators[i].end;
    259         if (index <= d->firingEventIterators[i].iterator)
    260             --d->firingEventIterators[i].iterator;
    261     }
    262 
    263     return true;
    264 }
    265 
    266 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener)
    267 {
    268     clearAttributeEventListener(eventType);
    269     if (!listener)
    270         return false;
    271     return addEventListener(eventType, listener, false);
    272 }
    273 
    274 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType)
    275 {
    276     const EventListenerVector& entry = getEventListeners(eventType);
    277     for (size_t i = 0; i < entry.size(); ++i) {
    278         if (entry[i].listener->isAttribute())
    279             return entry[i].listener.get();
    280     }
    281     return 0;
    282 }
    283 
    284 bool EventTarget::clearAttributeEventListener(const AtomicString& eventType)
    285 {
    286     EventListener* listener = getAttributeEventListener(eventType);
    287     if (!listener)
    288         return false;
    289     return removeEventListener(eventType, listener, false);
    290 }
    291 
    292 bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec)
    293 {
    294     if (!event || event->type().isEmpty()) {
    295         ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
    296         return false;
    297     }
    298 
    299     if (!scriptExecutionContext())
    300         return false;
    301 
    302     return dispatchEvent(event);
    303 }
    304 
    305 bool EventTarget::dispatchEvent(PassRefPtr<Event> event)
    306 {
    307     event->setTarget(this);
    308     event->setCurrentTarget(this);
    309     event->setEventPhase(Event::AT_TARGET);
    310     return fireEventListeners(event.get());
    311 }
    312 
    313 void EventTarget::uncaughtExceptionInEventHandler()
    314 {
    315 }
    316 
    317 bool EventTarget::fireEventListeners(Event* event)
    318 {
    319     ASSERT(!eventDispatchForbidden());
    320     ASSERT(event && !event->type().isEmpty());
    321 
    322     EventTargetData* d = eventTargetData();
    323     if (!d)
    324         return true;
    325 
    326     EventListenerMap::iterator result = d->eventListenerMap.find(event->type());
    327     if (result != d->eventListenerMap.end())
    328         fireEventListeners(event, d, *result->second);
    329 
    330 #if ENABLE(TOUCH_EVENTS) && PLATFORM(ANDROID)
    331     if (event->isTouchEvent() && !event->hitTouchHandler()) {
    332         // Check for touchmove or touchend to see if we can skip
    333         // the rest of the stream (we always get touchstart, don't need to check that)
    334         if (d->eventListenerMap.contains(eventNames().touchmoveEvent)
    335                 || d->eventListenerMap.contains(eventNames().touchendEvent))
    336             event->setHitTouchHandler();
    337     }
    338 #endif
    339 
    340     return !event->defaultPrevented();
    341 }
    342 
    343 void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry)
    344 {
    345     RefPtr<EventTarget> protect = this;
    346 
    347 #if ENABLE(TOUCH_EVENTS) && PLATFORM(ANDROID)
    348     if (event->isTouchEvent())
    349         event->setHitTouchHandler();
    350 #endif
    351 
    352     // Fire all listeners registered for this event. Don't fire listeners removed
    353     // during event dispatch. Also, don't fire event listeners added during event
    354     // dispatch. Conveniently, all new event listeners will be added after 'end',
    355     // so iterating to 'end' naturally excludes new event listeners.
    356 
    357     size_t i = 0;
    358     size_t end = entry.size();
    359     d->firingEventIterators.append(FiringEventIterator(event->type(), i, end));
    360     for ( ; i < end; ++i) {
    361         RegisteredEventListener& registeredListener = entry[i];
    362         if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
    363             continue;
    364         if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture)
    365             continue;
    366 
    367         // If stopImmediatePropagation has been called, we just break out immediately, without
    368         // handling any more events on this target.
    369         if (event->immediatePropagationStopped())
    370             break;
    371 
    372         // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
    373         // event listeners, even though that violates some versions of the DOM spec.
    374         registeredListener.listener->handleEvent(scriptExecutionContext(), event);
    375     }
    376     d->firingEventIterators.removeLast();
    377 }
    378 
    379 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType)
    380 {
    381     DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ());
    382 
    383     EventTargetData* d = eventTargetData();
    384     if (!d)
    385         return emptyVector;
    386     EventListenerMap::iterator it = d->eventListenerMap.find(eventType);
    387     if (it == d->eventListenerMap.end())
    388         return emptyVector;
    389     return *it->second;
    390 }
    391 
    392 void EventTarget::removeAllEventListeners()
    393 {
    394     EventTargetData* d = eventTargetData();
    395     if (!d)
    396         return;
    397     deleteAllValues(d->eventListenerMap);
    398     d->eventListenerMap.clear();
    399 
    400     // Notify firing events planning to invoke the listener at 'index' that
    401     // they have one less listener to invoke.
    402     for (size_t i = 0; i < d->firingEventIterators.size(); ++i) {
    403         d->firingEventIterators[i].iterator = 0;
    404         d->firingEventIterators[i].end = 0;
    405     }
    406 }
    407 
    408 } // namespace WebCore
    409