1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. 6 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) 7 * (C) 2007, 2008 Nikolas Zimmermann <zimmermann@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 39using namespace WTF; 40 41namespace WebCore { 42 43#ifndef NDEBUG 44static int gEventDispatchForbidden = 0; 45 46void forbidEventDispatch() 47{ 48 if (!isMainThread()) 49 return; 50 ++gEventDispatchForbidden; 51} 52 53void allowEventDispatch() 54{ 55 if (!isMainThread()) 56 return; 57 if (gEventDispatchForbidden > 0) 58 --gEventDispatchForbidden; 59} 60 61bool eventDispatchForbidden() 62{ 63 if (!isMainThread()) 64 return false; 65 return gEventDispatchForbidden > 0; 66} 67#endif // NDEBUG 68 69EventTargetData::EventTargetData() 70{ 71} 72 73EventTargetData::~EventTargetData() 74{ 75 deleteAllValues(eventListenerMap); 76} 77 78EventTarget::~EventTarget() 79{ 80} 81 82EventSource* EventTarget::toEventSource() 83{ 84 return 0; 85} 86 87Node* EventTarget::toNode() 88{ 89 return 0; 90} 91 92DOMWindow* EventTarget::toDOMWindow() 93{ 94 return 0; 95} 96 97XMLHttpRequest* EventTarget::toXMLHttpRequest() 98{ 99 return 0; 100} 101 102XMLHttpRequestUpload* EventTarget::toXMLHttpRequestUpload() 103{ 104 return 0; 105} 106 107#if ENABLE(OFFLINE_WEB_APPLICATIONS) 108DOMApplicationCache* EventTarget::toDOMApplicationCache() 109{ 110 return 0; 111} 112#endif 113 114#if ENABLE(SVG) 115SVGElementInstance* EventTarget::toSVGElementInstance() 116{ 117 return 0; 118} 119#endif 120 121#if ENABLE(WEB_AUDIO) 122AudioContext* EventTarget::toAudioContext() 123{ 124 return 0; 125} 126 127JavaScriptAudioNode* EventTarget::toJavaScriptAudioNode() 128{ 129 return 0; 130} 131#endif 132 133#if ENABLE(WEB_SOCKETS) 134WebSocket* EventTarget::toWebSocket() 135{ 136 return 0; 137} 138#endif 139 140MessagePort* EventTarget::toMessagePort() 141{ 142 return 0; 143} 144 145#if ENABLE(WORKERS) 146Worker* EventTarget::toWorker() 147{ 148 return 0; 149} 150 151DedicatedWorkerContext* EventTarget::toDedicatedWorkerContext() 152{ 153 return 0; 154} 155#endif 156 157#if ENABLE(SHARED_WORKERS) 158SharedWorker* EventTarget::toSharedWorker() 159{ 160 return 0; 161} 162SharedWorkerContext* EventTarget::toSharedWorkerContext() 163{ 164 return 0; 165} 166#endif 167 168#if ENABLE(NOTIFICATIONS) 169Notification* EventTarget::toNotification() 170{ 171 return 0; 172} 173#endif 174 175#if ENABLE(BLOB) 176FileReader* EventTarget::toFileReader() 177{ 178 return 0; 179} 180#endif 181#if ENABLE(FILE_SYSTEM) 182FileWriter* EventTarget::toFileWriter() 183{ 184 return 0; 185} 186#endif 187 188#if ENABLE(INDEXED_DATABASE) 189IDBDatabase* EventTarget::toIDBDatabase() 190{ 191 return 0; 192} 193IDBRequest* EventTarget::toIDBRequest() 194{ 195 return 0; 196} 197IDBTransaction* EventTarget::toIDBTransaction() 198{ 199 return 0; 200} 201IDBVersionChangeRequest* EventTarget::toIDBVersionChangeRequest() 202{ 203 return 0; 204} 205#endif 206 207bool 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 227bool 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 266bool 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 274EventListener* 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 284bool 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 292bool 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 305bool 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 313void EventTarget::uncaughtExceptionInEventHandler() 314{ 315} 316 317bool 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 343void 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 379const 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 392void 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