--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WebCore/dom/EventTarget.cpp Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "EventTarget.h"
+
+#include "Event.h"
+#include "EventException.h"
+#include <wtf/StdLibExtras.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+#ifndef NDEBUG
+static int gEventDispatchForbidden = 0;
+
+void forbidEventDispatch()
+{
+ if (!isMainThread())
+ return;
+ ++gEventDispatchForbidden;
+}
+
+void allowEventDispatch()
+{
+ if (!isMainThread())
+ return;
+ if (gEventDispatchForbidden > 0)
+ --gEventDispatchForbidden;
+}
+
+bool eventDispatchForbidden()
+{
+ if (!isMainThread())
+ return false;
+ return gEventDispatchForbidden > 0;
+}
+#endif // NDEBUG
+
+EventTargetData::~EventTargetData()
+{
+ deleteAllValues(eventListenerMap);
+}
+
+EventTarget::~EventTarget()
+{
+}
+
+EventSource* EventTarget::toEventSource()
+{
+ return 0;
+}
+
+Node* EventTarget::toNode()
+{
+ return 0;
+}
+
+DOMWindow* EventTarget::toDOMWindow()
+{
+ return 0;
+}
+
+XMLHttpRequest* EventTarget::toXMLHttpRequest()
+{
+ return 0;
+}
+
+XMLHttpRequestUpload* EventTarget::toXMLHttpRequestUpload()
+{
+ return 0;
+}
+
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+DOMApplicationCache* EventTarget::toDOMApplicationCache()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(SVG)
+SVGElementInstance* EventTarget::toSVGElementInstance()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(WEB_SOCKETS)
+WebSocket* EventTarget::toWebSocket()
+{
+ return 0;
+}
+#endif
+
+MessagePort* EventTarget::toMessagePort()
+{
+ return 0;
+}
+
+#if ENABLE(WORKERS)
+Worker* EventTarget::toWorker()
+{
+ return 0;
+}
+
+DedicatedWorkerContext* EventTarget::toDedicatedWorkerContext()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(SHARED_WORKERS)
+SharedWorker* EventTarget::toSharedWorker()
+{
+ return 0;
+}
+SharedWorkerContext* EventTarget::toSharedWorkerContext()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(NOTIFICATIONS)
+Notification* EventTarget::toNotification()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(FILE_READER)
+FileReader* EventTarget::toFileReader()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(INDEXED_DATABASE)
+IDBRequest* EventTarget::toIDBRequest()
+{
+ return 0;
+}
+#endif
+
+bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
+{
+ EventTargetData* d = ensureEventTargetData();
+
+ pair<EventListenerMap::iterator, bool> result = d->eventListenerMap.add(eventType, 0);
+ EventListenerVector*& entry = result.first->second;
+ const bool isNewEntry = result.second;
+ if (isNewEntry)
+ entry = new EventListenerVector();
+
+ RegisteredEventListener registeredListener(listener, useCapture);
+ if (!isNewEntry) {
+ if (entry->find(registeredListener) != notFound) // duplicate listener
+ return false;
+ }
+
+ entry->append(registeredListener);
+ return true;
+}
+
+bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
+{
+ EventTargetData* d = eventTargetData();
+ if (!d)
+ return false;
+
+ EventListenerMap::iterator result = d->eventListenerMap.find(eventType);
+ if (result == d->eventListenerMap.end())
+ return false;
+ EventListenerVector* entry = result->second;
+
+ RegisteredEventListener registeredListener(listener, useCapture);
+ size_t index = entry->find(registeredListener);
+ if (index == notFound)
+ return false;
+
+ entry->remove(index);
+ if (entry->isEmpty()) {
+ delete entry;
+ d->eventListenerMap.remove(result);
+ }
+
+ // Notify firing events planning to invoke the listener at 'index' that
+ // they have one less listener to invoke.
+ for (size_t i = 0; i < d->firingEventIterators.size(); ++i) {
+ if (eventType != d->firingEventIterators[i].eventType)
+ continue;
+
+ if (index >= d->firingEventIterators[i].end)
+ continue;
+
+ --d->firingEventIterators[i].end;
+ if (index <= d->firingEventIterators[i].iterator)
+ --d->firingEventIterators[i].iterator;
+ }
+
+ return true;
+}
+
+bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener)
+{
+ clearAttributeEventListener(eventType);
+ if (!listener)
+ return false;
+ return addEventListener(eventType, listener, false);
+}
+
+EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType)
+{
+ const EventListenerVector& entry = getEventListeners(eventType);
+ for (size_t i = 0; i < entry.size(); ++i) {
+ if (entry[i].listener->isAttribute())
+ return entry[i].listener.get();
+ }
+ return 0;
+}
+
+bool EventTarget::clearAttributeEventListener(const AtomicString& eventType)
+{
+ EventListener* listener = getAttributeEventListener(eventType);
+ if (!listener)
+ return false;
+ return removeEventListener(eventType, listener, false);
+}
+
+bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec)
+{
+ if (!event || event->type().isEmpty()) {
+ ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
+ return false;
+ }
+
+ if (!scriptExecutionContext())
+ return false;
+
+ return dispatchEvent(event);
+}
+
+bool EventTarget::dispatchEvent(PassRefPtr<Event> event)
+{
+ event->setTarget(this);
+ event->setCurrentTarget(this);
+ event->setEventPhase(Event::AT_TARGET);
+ return fireEventListeners(event.get());
+}
+
+bool EventTarget::fireEventListeners(Event* event)
+{
+ ASSERT(!eventDispatchForbidden());
+ ASSERT(event && !event->type().isEmpty());
+
+ EventTargetData* d = eventTargetData();
+ if (!d)
+ return true;
+
+ EventListenerMap::iterator result = d->eventListenerMap.find(event->type());
+ if (result != d->eventListenerMap.end())
+ fireEventListeners(event, d, *result->second);
+
+ // Alias DOMFocusIn/DOMFocusOut to focusin/focusout (and vice versa). Just consider them to be the
+ // same event (triggering one another's handlers). This mechanism allows us to deprecate or change event
+ // names in the future and still make them be interoperable.
+ if (event->hasAliasedType() && !event->immediatePropagationStopped()) {
+ EventListenerMap::iterator result = d->eventListenerMap.find(event->aliasedType());
+ if (result != d->eventListenerMap.end())
+ fireEventListeners(event, d, *result->second);
+ }
+ return !event->defaultPrevented();
+}
+
+void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry)
+{
+ RefPtr<EventTarget> protect = this;
+
+ // Fire all listeners registered for this event. Don't fire listeners removed
+ // during event dispatch. Also, don't fire event listeners added during event
+ // dispatch. Conveniently, all new event listeners will be added after 'end',
+ // so iterating to 'end' naturally excludes new event listeners.
+
+ size_t i = 0;
+ size_t end = entry.size();
+ d->firingEventIterators.append(FiringEventIterator(event->type(), i, end));
+ for ( ; i < end; ++i) {
+ RegisteredEventListener& registeredListener = entry[i];
+ if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
+ continue;
+ if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture)
+ continue;
+
+ // If stopImmediatePropagation has been called, we just break out immediately, without
+ // handling any more events on this target.
+ if (event->immediatePropagationStopped())
+ break;
+
+ // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
+ // event listeners, even though that violates some versions of the DOM spec.
+ registeredListener.listener->handleEvent(scriptExecutionContext(), event);
+ }
+ d->firingEventIterators.removeLast();
+}
+
+const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType)
+{
+ DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ());
+
+ EventTargetData* d = eventTargetData();
+ if (!d)
+ return emptyVector;
+ EventListenerMap::iterator it = d->eventListenerMap.find(eventType);
+ if (it == d->eventListenerMap.end())
+ return emptyVector;
+ return *it->second;
+}
+
+void EventTarget::removeAllEventListeners()
+{
+ EventTargetData* d = eventTargetData();
+ if (!d)
+ return;
+ deleteAllValues(d->eventListenerMap);
+ d->eventListenerMap.clear();
+
+ // Notify firing events planning to invoke the listener at 'index' that
+ // they have one less listener to invoke.
+ for (size_t i = 0; i < d->firingEventIterators.size(); ++i) {
+ d->firingEventIterators[i].iterator = 0;
+ d->firingEventIterators[i].end = 0;
+ }
+}
+
+} // namespace WebCore