Title: [204459] trunk/Source/WebCore
Revision
204459
Author
[email protected]
Date
2016-08-14 17:48:16 -0700 (Sun, 14 Aug 2016)

Log Message

Align the event listener firing code with the latest DOM Specification and simplify it
https://bugs.webkit.org/show_bug.cgi?id=160828

Reviewed by Darin Adler.

Align the event listener firing code with the latest DOM specification:
- https://dom.spec.whatwg.org/#concept-event-listener-invoke
- https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke
- https://dom.spec.whatwg.org/#concept-event-listener

The following changes were made:
1. RegisteredEventListener (equivalent to "event listener" in the spec)
   is now RefCounted
2. RegisteredEventListener now has a wasRemoved flag as in specification.
3. fireEventListeners() is now iterating over a copy of the event
   listeners, as in the specification. We rely on the wasRemoved removed
   flag to avoid executing event listeners that were removed while we
   iterate.

Previously, the code was modifying the event listeners vector we were
iterating on. Doing so safely lead to complicated and error prone code.
The new code is much simpler and easier to reason about.

This change seems to be perf-neutral on Speedometer.

No new tests, no web-exposed behavior change.

* CMakeLists.txt:
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSCommandLineAPIHostCustom.cpp:
(WebCore::getJSListenerFunctions):
* dom/DOMAllInOne.cpp:
* dom/EventListenerMap.cpp:
(WebCore::EventListenerMap::assertNoActiveIterators):
(WebCore::EventListenerMap::containsCapturing):
(WebCore::EventListenerMap::containsActive):
(WebCore::findListener):
(WebCore::EventListenerMap::add):
(WebCore::removeListenerFromVector):
(WebCore::EventListenerMap::remove):
(WebCore::EventListenerMap::find):
(WebCore::removeFirstListenerCreatedFromMarkup):
(WebCore::copyListenersNotCreatedFromMarkupToTarget):
(WebCore::EventListenerMap::copyEventListenersNotCreatedFromMarkupToTarget):
(WebCore::EventListenerIterator::nextListener):
(WebCore::EventListenerMap::clear): Deleted.
* dom/EventListenerMap.h:
(WebCore::EventListenerMap::contains):
(WebCore::EventListenerMap::assertNoActiveIterators):
* dom/EventTarget.cpp:
(WebCore::EventTarget::removeEventListener):
(WebCore::EventTarget::getAttributeEventListener):
(WebCore::FiringEventListenersScope::FiringEventListenersScope):
(WebCore::FiringEventListenersScope::~FiringEventListenersScope):
(WebCore::EventTarget::fireEventListeners):
(WebCore::EventTarget::setAttributeEventListener): Deleted.
(WebCore::EventTarget::hasActiveEventListeners): Deleted.
(WebCore::EventTarget::dispatchEventForBindings): Deleted.
(WebCore::EventTarget::getEventListeners): Deleted.
* dom/EventTarget.h:
(WebCore::EventTarget::isFiringEventListeners):
* dom/RegisteredEventListener.cpp: Removed.
* dom/RegisteredEventListener.h:
(WebCore::RegisteredEventListener::Options::Options):
(WebCore::RegisteredEventListener::create):
(WebCore::RegisteredEventListener::listener):
(WebCore::RegisteredEventListener::useCapture):
(WebCore::RegisteredEventListener::isPassive):
(WebCore::RegisteredEventListener::isOnce):
(WebCore::RegisteredEventListener::wasRemoved):
(WebCore::RegisteredEventListener::markAsRemoved):
(WebCore::RegisteredEventListener::RegisteredEventListener):
* inspector/InspectorDOMAgent.cpp:
(WebCore::InspectorDOMAgent::getEventListenersForNode):
(WebCore::InspectorDOMAgent::getEventListeners):
(WebCore::InspectorDOMAgent::buildObjectForEventListener):
* inspector/InspectorDOMAgent.h:
(WebCore::EventListenerInfo::EventListenerInfo):
* svg/SVGElement.cpp:
(WebCore::hasLoadListener):

Modified Paths

Removed Paths

Diff

Modified: trunk/Source/WebCore/CMakeLists.txt (204458 => 204459)


--- trunk/Source/WebCore/CMakeLists.txt	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/CMakeLists.txt	2016-08-15 00:48:16 UTC (rev 204459)
@@ -1503,7 +1503,6 @@
     dom/QualifiedName.cpp
     dom/RadioButtonGroups.cpp
     dom/Range.cpp
-    dom/RegisteredEventListener.cpp
     dom/ScopedEventQueue.cpp
     dom/ScriptElement.cpp
     dom/ScriptExecutionContext.cpp

Modified: trunk/Source/WebCore/ChangeLog (204458 => 204459)


--- trunk/Source/WebCore/ChangeLog	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/ChangeLog	2016-08-15 00:48:16 UTC (rev 204459)
@@ -1,3 +1,86 @@
+2016-08-14  Chris Dumez  <[email protected]>
+
+        Align the event listener firing code with the latest DOM Specification and simplify it
+        https://bugs.webkit.org/show_bug.cgi?id=160828
+
+        Reviewed by Darin Adler.
+
+        Align the event listener firing code with the latest DOM specification:
+        - https://dom.spec.whatwg.org/#concept-event-listener-invoke
+        - https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke
+        - https://dom.spec.whatwg.org/#concept-event-listener
+
+        The following changes were made:
+        1. RegisteredEventListener (equivalent to "event listener" in the spec)
+           is now RefCounted
+        2. RegisteredEventListener now has a wasRemoved flag as in specification.
+        3. fireEventListeners() is now iterating over a copy of the event
+           listeners, as in the specification. We rely on the wasRemoved removed
+           flag to avoid executing event listeners that were removed while we
+           iterate.
+
+        Previously, the code was modifying the event listeners vector we were
+        iterating on. Doing so safely lead to complicated and error prone code.
+        The new code is much simpler and easier to reason about.
+
+        This change seems to be perf-neutral on Speedometer.
+
+        No new tests, no web-exposed behavior change.
+
+        * CMakeLists.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSCommandLineAPIHostCustom.cpp:
+        (WebCore::getJSListenerFunctions):
+        * dom/DOMAllInOne.cpp:
+        * dom/EventListenerMap.cpp:
+        (WebCore::EventListenerMap::assertNoActiveIterators):
+        (WebCore::EventListenerMap::containsCapturing):
+        (WebCore::EventListenerMap::containsActive):
+        (WebCore::findListener):
+        (WebCore::EventListenerMap::add):
+        (WebCore::removeListenerFromVector):
+        (WebCore::EventListenerMap::remove):
+        (WebCore::EventListenerMap::find):
+        (WebCore::removeFirstListenerCreatedFromMarkup):
+        (WebCore::copyListenersNotCreatedFromMarkupToTarget):
+        (WebCore::EventListenerMap::copyEventListenersNotCreatedFromMarkupToTarget):
+        (WebCore::EventListenerIterator::nextListener):
+        (WebCore::EventListenerMap::clear): Deleted.
+        * dom/EventListenerMap.h:
+        (WebCore::EventListenerMap::contains):
+        (WebCore::EventListenerMap::assertNoActiveIterators):
+        * dom/EventTarget.cpp:
+        (WebCore::EventTarget::removeEventListener):
+        (WebCore::EventTarget::getAttributeEventListener):
+        (WebCore::FiringEventListenersScope::FiringEventListenersScope):
+        (WebCore::FiringEventListenersScope::~FiringEventListenersScope):
+        (WebCore::EventTarget::fireEventListeners):
+        (WebCore::EventTarget::setAttributeEventListener): Deleted.
+        (WebCore::EventTarget::hasActiveEventListeners): Deleted.
+        (WebCore::EventTarget::dispatchEventForBindings): Deleted.
+        (WebCore::EventTarget::getEventListeners): Deleted.
+        * dom/EventTarget.h:
+        (WebCore::EventTarget::isFiringEventListeners):
+        * dom/RegisteredEventListener.cpp: Removed.
+        * dom/RegisteredEventListener.h:
+        (WebCore::RegisteredEventListener::Options::Options):
+        (WebCore::RegisteredEventListener::create):
+        (WebCore::RegisteredEventListener::listener):
+        (WebCore::RegisteredEventListener::useCapture):
+        (WebCore::RegisteredEventListener::isPassive):
+        (WebCore::RegisteredEventListener::isOnce):
+        (WebCore::RegisteredEventListener::wasRemoved):
+        (WebCore::RegisteredEventListener::markAsRemoved):
+        (WebCore::RegisteredEventListener::RegisteredEventListener):
+        * inspector/InspectorDOMAgent.cpp:
+        (WebCore::InspectorDOMAgent::getEventListenersForNode):
+        (WebCore::InspectorDOMAgent::getEventListeners):
+        (WebCore::InspectorDOMAgent::buildObjectForEventListener):
+        * inspector/InspectorDOMAgent.h:
+        (WebCore::EventListenerInfo::EventListenerInfo):
+        * svg/SVGElement.cpp:
+        (WebCore::hasLoadListener):
+
 2016-08-14  Daniel Bates  <[email protected]>
 
         Fix compiler errors when building iOS WebKit using the iOS 10 beta SDK

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (204458 => 204459)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2016-08-15 00:48:16 UTC (rev 204459)
@@ -3066,7 +3066,6 @@
 		85031B480A44EFC700F992E0 /* MouseRelatedEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 85031B320A44EFC700F992E0 /* MouseRelatedEvent.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		85031B490A44EFC700F992E0 /* MutationEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 85031B330A44EFC700F992E0 /* MutationEvent.cpp */; };
 		85031B4A0A44EFC700F992E0 /* MutationEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 85031B340A44EFC700F992E0 /* MutationEvent.h */; };
-		85031B4B0A44EFC700F992E0 /* RegisteredEventListener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 85031B350A44EFC700F992E0 /* RegisteredEventListener.cpp */; };
 		85031B4C0A44EFC700F992E0 /* RegisteredEventListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 85031B360A44EFC700F992E0 /* RegisteredEventListener.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		85031B4D0A44EFC700F992E0 /* UIEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 85031B370A44EFC700F992E0 /* UIEvent.cpp */; };
 		85031B4E0A44EFC700F992E0 /* UIEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 85031B380A44EFC700F992E0 /* UIEvent.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -10507,7 +10506,6 @@
 		85031B320A44EFC700F992E0 /* MouseRelatedEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MouseRelatedEvent.h; sourceTree = "<group>"; };
 		85031B330A44EFC700F992E0 /* MutationEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MutationEvent.cpp; sourceTree = "<group>"; };
 		85031B340A44EFC700F992E0 /* MutationEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MutationEvent.h; sourceTree = "<group>"; };
-		85031B350A44EFC700F992E0 /* RegisteredEventListener.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RegisteredEventListener.cpp; sourceTree = "<group>"; };
 		85031B360A44EFC700F992E0 /* RegisteredEventListener.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RegisteredEventListener.h; sourceTree = "<group>"; };
 		85031B370A44EFC700F992E0 /* UIEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = UIEvent.cpp; sourceTree = "<group>"; };
 		85031B380A44EFC700F992E0 /* UIEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = UIEvent.h; sourceTree = "<group>"; };
@@ -24195,7 +24193,6 @@
 				936DD03A09CEAC270056AE8C /* Range.idl */,
 				93D9D53B0DA27E180077216C /* RangeBoundaryPoint.h */,
 				A84D827B11D333ED00972990 /* RawDataDocumentParser.h */,
-				85031B350A44EFC700F992E0 /* RegisteredEventListener.cpp */,
 				85031B360A44EFC700F992E0 /* RegisteredEventListener.h */,
 				A76E5F7E135E0DCF00A69837 /* RenderedDocumentMarker.h */,
 				4998AEC413F9D0EA0090B1AA /* RequestAnimationFrameCallback.h */,
@@ -30879,7 +30876,6 @@
 				2EC41DE41C0410A300D294FE /* RealtimeMediaSourceSupportedConstraints.cpp in Sources */,
 				FD45A95A175D417100C21EC8 /* RectangleShape.cpp in Sources */,
 				BCAB418113E356E800D8AAF3 /* Region.cpp in Sources */,
-				85031B4B0A44EFC700F992E0 /* RegisteredEventListener.cpp in Sources */,
 				CDFC360518CA61C20026E56F /* RemoteCommandListener.cpp in Sources */,
 				CDFC360718CA696C0026E56F /* RemoteCommandListenerIOS.mm in Sources */,
 				CD8ACA881D237AA200ECC59E /* RemoteCommandListenerMac.mm in Sources */,

Modified: trunk/Source/WebCore/bindings/js/JSCommandLineAPIHostCustom.cpp (204458 => 204459)


--- trunk/Source/WebCore/bindings/js/JSCommandLineAPIHostCustom.cpp	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/bindings/js/JSCommandLineAPIHostCustom.cpp	2016-08-15 00:48:16 UTC (rev 204459)
@@ -73,7 +73,7 @@
         return nullptr;
     size_t handlersCount = listenerInfo.eventListenerVector.size();
     for (size_t i = 0, outputIndex = 0; i < handlersCount; ++i) {
-        const JSEventListener* jsListener = JSEventListener::cast(listenerInfo.eventListenerVector[i].listener.get());
+        const JSEventListener* jsListener = JSEventListener::cast(&listenerInfo.eventListenerVector[i]->listener());
         if (!jsListener) {
             ASSERT_NOT_REACHED();
             continue;
@@ -89,7 +89,7 @@
 
         JSObject* listenerEntry = constructEmptyObject(&state);
         listenerEntry->putDirect(vm, Identifier::fromString(&state, "listener"), function);
-        listenerEntry->putDirect(vm, Identifier::fromString(&state, "useCapture"), jsBoolean(listenerInfo.eventListenerVector[i].useCapture));
+        listenerEntry->putDirect(vm, Identifier::fromString(&state, "useCapture"), jsBoolean(listenerInfo.eventListenerVector[i]->useCapture()));
         result->putDirectIndex(&state, outputIndex++, JSValue(listenerEntry));
     }
     return result;

Modified: trunk/Source/WebCore/dom/DOMAllInOne.cpp (204458 => 204459)


--- trunk/Source/WebCore/dom/DOMAllInOne.cpp	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/dom/DOMAllInOne.cpp	2016-08-15 00:48:16 UTC (rev 204459)
@@ -128,7 +128,6 @@
 // #include "QualifiedName.cpp"
 #include "RadioButtonGroups.cpp"
 #include "Range.cpp"
-#include "RegisteredEventListener.cpp"
 #include "ScopedEventQueue.cpp"
 #include "ScriptElement.cpp"
 #include "ScriptExecutionContext.cpp"

Modified: trunk/Source/WebCore/dom/EventListenerMap.cpp (204458 => 204459)


--- trunk/Source/WebCore/dom/EventListenerMap.cpp	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/dom/EventListenerMap.cpp	2016-08-15 00:48:16 UTC (rev 204459)
@@ -45,7 +45,7 @@
 namespace WebCore {
 
 #ifndef NDEBUG
-void EventListenerMap::assertNoActiveIterators()
+void EventListenerMap::assertNoActiveIterators() const
 {
     ASSERT(!m_activeIteratorCount);
 }
@@ -55,37 +55,28 @@
 {
 }
 
-bool EventListenerMap::contains(const AtomicString& eventType) const
+bool EventListenerMap::containsCapturing(const AtomicString& eventType) const
 {
-    for (auto& entry : m_entries) {
-        if (entry.first == eventType)
+    auto* listeners = find(eventType);
+    if (!listeners)
+        return false;
+
+    for (auto& eventListener : *listeners) {
+        if (eventListener->useCapture())
             return true;
     }
     return false;
 }
 
-bool EventListenerMap::containsCapturing(const AtomicString& eventType) const
+bool EventListenerMap::containsActive(const AtomicString& eventType) const
 {
-    for (auto& entry : m_entries) {
-        if (entry.first == eventType) {
-            for (auto& eventListener : *entry.second) {
-                if (eventListener.useCapture)
-                    return true;
-            }
-        }
-    }
-    return false;
-}
+    auto* listeners = find(eventType);
+    if (!listeners)
+        return false;
 
-bool EventListenerMap::containsActive(const AtomicString& eventType) const
-{
-    for (auto& entry : m_entries) {
-        if (entry.first == eventType) {
-            for (auto& eventListener : *entry.second) {
-                if (!eventListener.isPassive)
-                    return true;
-            }
-        }
+    for (auto& eventListener : *listeners) {
+        if (!eventListener->isPassive())
+            return true;
     }
     return false;
 }
@@ -108,15 +99,14 @@
     return types;
 }
 
-static bool addListenerToVector(EventListenerVector* vector, Ref<EventListener>&& listener, const RegisteredEventListener::Options& options)
+static inline size_t findListener(const EventListenerVector& listeners, EventListener& listener, bool useCapture)
 {
-    RegisteredEventListener registeredListener(WTFMove(listener), options);
-
-    if (vector->find(registeredListener) != notFound)
-        return false; // Duplicate listener.
-
-    vector->append(registeredListener);
-    return true;
+    for (size_t i = 0; i < listeners.size(); ++i) {
+        auto& registeredListener = listeners[i];
+        if (registeredListener->listener() == listener && registeredListener->useCapture() == useCapture)
+            return i;
+    }
+    return notFound;
 }
 
 bool EventListenerMap::add(const AtomicString& eventType, Ref<EventListener>&& listener, const RegisteredEventListener::Options& options)
@@ -123,32 +113,37 @@
 {
     assertNoActiveIterators();
 
-    for (auto& entry : m_entries) {
-        if (entry.first == eventType)
-            return addListenerToVector(entry.second.get(), WTFMove(listener), options);
+    if (auto* listeners = find(eventType)) {
+        if (findListener(*listeners, listener, options.capture) != notFound)
+            return false; // Duplicate listener.
+        listeners->append(RegisteredEventListener::create(WTFMove(listener), options));
+        return true;
     }
 
-    m_entries.append(std::make_pair(eventType, std::make_unique<EventListenerVector>()));
-    return addListenerToVector(m_entries.last().second.get(), WTFMove(listener), options);
+    auto listeners = std::make_unique<EventListenerVector>();
+    listeners->uncheckedAppend(RegisteredEventListener::create(WTFMove(listener), options));
+    m_entries.append({ eventType, WTFMove(listeners) });
+    return true;
 }
 
-static bool removeListenerFromVector(EventListenerVector* listenerVector, EventListener& listener, bool useCapture, size_t& indexOfRemovedListener)
+static bool removeListenerFromVector(EventListenerVector& listeners, EventListener& listener, bool useCapture)
 {
-    RegisteredEventListener registeredListener(listener, useCapture);
-    indexOfRemovedListener = listenerVector->find(registeredListener);
-    if (indexOfRemovedListener == notFound)
+    size_t indexOfRemovedListener = findListener(listeners, listener, useCapture);
+    if (UNLIKELY(indexOfRemovedListener == notFound))
         return false;
-    listenerVector->remove(indexOfRemovedListener);
+
+    listeners[indexOfRemovedListener]->markAsRemoved();
+    listeners.remove(indexOfRemovedListener);
     return true;
 }
 
-bool EventListenerMap::remove(const AtomicString& eventType, EventListener& listener, bool useCapture, size_t& indexOfRemovedListener)
+bool EventListenerMap::remove(const AtomicString& eventType, EventListener& listener, bool useCapture)
 {
     assertNoActiveIterators();
 
     for (unsigned i = 0; i < m_entries.size(); ++i) {
         if (m_entries[i].first == eventType) {
-            bool wasRemoved = removeListenerFromVector(m_entries[i].second.get(), listener, useCapture, indexOfRemovedListener);
+            bool wasRemoved = removeListenerFromVector(*m_entries[i].second, listener, useCapture);
             if (m_entries[i].second->isEmpty())
                 m_entries.remove(i);
             return wasRemoved;
@@ -158,7 +153,7 @@
     return false;
 }
 
-EventListenerVector* EventListenerMap::find(const AtomicString& eventType)
+EventListenerVector* EventListenerMap::find(const AtomicString& eventType) const
 {
     assertNoActiveIterators();
 
@@ -172,8 +167,12 @@
 
 static void removeFirstListenerCreatedFromMarkup(EventListenerVector& listenerVector)
 {
-    bool foundListener = listenerVector.removeFirstMatching([] (const RegisteredEventListener& listener) {
-        return listener.listener->wasCreatedFromMarkup();
+    bool foundListener = listenerVector.removeFirstMatching([] (const auto& registeredListener) {
+        if (registeredListener->listener().wasCreatedFromMarkup()) {
+            registeredListener->markAsRemoved();
+            return true;
+        }
+        return false;
     });
     ASSERT_UNUSED(foundListener, foundListener);
 }
@@ -192,13 +191,13 @@
     }
 }
 
-static void copyListenersNotCreatedFromMarkupToTarget(const AtomicString& eventType, EventListenerVector* listenerVector, EventTarget* target)
+static void copyListenersNotCreatedFromMarkupToTarget(const AtomicString& eventType, EventListenerVector& listenerVector, EventTarget* target)
 {
-    for (auto& listener : *listenerVector) {
+    for (auto& registeredListener : listenerVector) {
         // Event listeners created from markup have already been transfered to the shadow tree during cloning.
-        if (listener.listener->wasCreatedFromMarkup())
+        if (registeredListener->listener().wasCreatedFromMarkup())
             continue;
-        target->addEventListener(eventType, *listener.listener, listener.useCapture);
+        target->addEventListener(eventType, registeredListener->listener(), registeredListener->useCapture());
     }
 }
 
@@ -207,7 +206,7 @@
     assertNoActiveIterators();
 
     for (auto& entry : m_entries)
-        copyListenersNotCreatedFromMarkupToTarget(entry.first, entry.second.get(), target);
+        copyListenersNotCreatedFromMarkupToTarget(entry.first, *entry.second, target);
 }
 
 EventListenerIterator::EventListenerIterator(EventTarget* target)
@@ -236,16 +235,16 @@
 EventListener* EventListenerIterator::nextListener()
 {
     if (!m_map)
-        return 0;
+        return nullptr;
 
     for (; m_entryIndex < m_map->m_entries.size(); ++m_entryIndex) {
         EventListenerVector& listeners = *m_map->m_entries[m_entryIndex].second;
         if (m_index < listeners.size())
-            return listeners[m_index++].listener.get();
+            return &listeners[m_index++]->listener();
         m_index = 0;
     }
 
-    return 0;
+    return nullptr;
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/EventListenerMap.h (204458 => 204459)


--- trunk/Source/WebCore/dom/EventListenerMap.h	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/dom/EventListenerMap.h	2016-08-15 00:48:16 UTC (rev 204459)
@@ -30,8 +30,7 @@
  *
  */
 
-#ifndef EventListenerMap_h
-#define EventListenerMap_h
+#pragma once
 
 #include "RegisteredEventListener.h"
 #include <atomic>
@@ -43,7 +42,7 @@
 
 class EventTarget;
 
-typedef Vector<RegisteredEventListener, 1> EventListenerVector;
+using EventListenerVector = Vector<RefPtr<RegisteredEventListener>, 1>;
 
 class EventListenerMap {
 public:
@@ -50,7 +49,7 @@
     EventListenerMap();
 
     bool isEmpty() const { return m_entries.isEmpty(); }
-    WEBCORE_EXPORT bool contains(const AtomicString& eventType) const;
+    bool contains(const AtomicString& eventType) const { return find(eventType); }
     bool containsCapturing(const AtomicString& eventType) const;
     bool containsActive(const AtomicString& eventType) const;
 
@@ -57,8 +56,8 @@
     void clear();
 
     bool add(const AtomicString& eventType, Ref<EventListener>&&, const RegisteredEventListener::Options&);
-    bool remove(const AtomicString& eventType, EventListener&, bool useCapture, size_t& indexOfRemovedListener);
-    EventListenerVector* find(const AtomicString& eventType);
+    bool remove(const AtomicString& eventType, EventListener&, bool useCapture);
+    WEBCORE_EXPORT EventListenerVector* find(const AtomicString& eventType) const;
     Vector<AtomicString> eventTypes() const;
 
     void removeFirstEventListenerCreatedFromMarkup(const AtomicString& eventType);
@@ -67,7 +66,7 @@
 private:
     friend class EventListenerIterator;
 
-    void assertNoActiveIterators();
+    void assertNoActiveIterators() const;
 
     Vector<std::pair<AtomicString, std::unique_ptr<EventListenerVector>>, 2> m_entries;
 
@@ -79,7 +78,6 @@
 class EventListenerIterator {
     WTF_MAKE_NONCOPYABLE(EventListenerIterator);
 public:
-    EventListenerIterator();
     explicit EventListenerIterator(EventTarget*);
 #ifndef NDEBUG
     ~EventListenerIterator();
@@ -94,9 +92,7 @@
 };
 
 #ifdef NDEBUG
-inline void EventListenerMap::assertNoActiveIterators() { }
+inline void EventListenerMap::assertNoActiveIterators() const { }
 #endif
 
 } // namespace WebCore
-
-#endif // EventListenerMap_h

Modified: trunk/Source/WebCore/dom/EventTarget.cpp (204458 => 204459)


--- trunk/Source/WebCore/dom/EventTarget.cpp	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/dom/EventTarget.cpp	2016-08-15 00:48:16 UTC (rev 204459)
@@ -43,6 +43,7 @@
 #include <wtf/NeverDestroyed.h>
 #include <wtf/Ref.h>
 #include <wtf/StdLibExtras.h>
+#include <wtf/TemporaryChange.h>
 #include <wtf/Vector.h>
 
 using namespace WTF;
@@ -101,28 +102,7 @@
     if (!d)
         return false;
 
-    size_t indexOfRemovedListener;
-
-    if (!d->eventListenerMap.remove(eventType, listener, options.capture, indexOfRemovedListener))
-        return false;
-
-    // Notify firing events planning to invoke the listener at 'index' that
-    // they have one less listener to invoke.
-    if (!d->firingEventIterators)
-        return true;
-    for (auto& firingIterator : *d->firingEventIterators) {
-        if (eventType != firingIterator.eventType)
-            continue;
-
-        if (indexOfRemovedListener >= firingIterator.size)
-            continue;
-
-        --firingIterator.size;
-        if (indexOfRemovedListener <= firingIterator.iterator)
-            --firingIterator.iterator;
-    }
-
-    return true;
+    return d->eventListenerMap.remove(eventType, listener, options.capture);
 }
 
 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, RefPtr<EventListener>&& listener)
@@ -136,10 +116,10 @@
 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType)
 {
     for (auto& eventListener : getEventListeners(eventType)) {
-        if (eventListener.listener->isAttribute())
-            return eventListener.listener.get();
+        if (eventListener->listener().isAttribute())
+            return &eventListener->listener();
     }
-    return 0;
+    return nullptr;
 }
 
 bool EventTarget::hasActiveEventListeners(const AtomicString& eventType) const
@@ -215,57 +195,51 @@
     ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
     ASSERT(event.isInitialized());
 
-    EventTargetData* d = eventTargetData();
-    if (!d)
+    EventTargetData* data = ""
+    if (!data)
         return true;
 
-    EventListenerVector* legacyListenersVector = nullptr;
-    const AtomicString& legacyTypeName = legacyType(event);
-    if (!legacyTypeName.isEmpty())
-        legacyListenersVector = d->eventListenerMap.find(legacyTypeName);
+    TemporaryChange<bool> firingEventListenersScope(data->isFiringEventListeners, true);
 
-    EventListenerVector* listenersVector = d->eventListenerMap.find(event.type());
+    if (auto* listenersVector = data->eventListenerMap.find(event.type())) {
+        fireEventListeners(event, *listenersVector);
+        return !event.defaultPrevented();
+    }
 
-    if (listenersVector)
-        fireEventListeners(event, d, *listenersVector);
-    else if (legacyListenersVector) {
-        AtomicString typeName = event.type();
-        event.setType(legacyTypeName);
-        fireEventListeners(event, d, *legacyListenersVector);
-        event.setType(typeName);
+    const AtomicString& legacyTypeName = legacyType(event);
+    if (!legacyTypeName.isEmpty()) {
+        if (auto* legacyListenersVector = data->eventListenerMap.find(legacyTypeName)) {
+            AtomicString typeName = event.type();
+            event.setType(legacyTypeName);
+            fireEventListeners(event, *legacyListenersVector);
+            event.setType(typeName);
+        }
     }
-
     return !event.defaultPrevented();
 }
 
-void EventTarget::fireEventListeners(Event& event, EventTargetData* d, EventListenerVector& entry)
+// Intentionally creates a copy of the listeners vector to avoid event listeners added after this point from being run.
+// Note that removal still has an effect due to the removed field in RegisteredEventListener.
+void EventTarget::fireEventListeners(Event& event, EventListenerVector listeners)
 {
     Ref<EventTarget> protectedThis(*this);
+    ASSERT(!listeners.isEmpty());
 
-    // 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 or at index |size|, so iterating up to (but not including) |size| naturally excludes new event listeners.
-
-    size_t i = 0;
-    size_t size = entry.size();
-    if (!d->firingEventIterators)
-        d->firingEventIterators = std::make_unique<FiringEventIteratorVector>();
-    d->firingEventIterators->append(FiringEventIterator(event.type(), i, size));
-
     ScriptExecutionContext* context = scriptExecutionContext();
     Document* document = nullptr;
     InspectorInstrumentationCookie willDispatchEventCookie;
     if (is<Document>(context)) {
         document = downcast<Document>(context);
-        willDispatchEventCookie = InspectorInstrumentation::willDispatchEvent(*document, event, size > 0);
+        willDispatchEventCookie = InspectorInstrumentation::willDispatchEvent(*document, event, true);
     }
 
-    for (; i < size; ++i) {
-        RegisteredEventListener registeredListener = entry[i];
+    for (auto& registeredListener : listeners) {
+        if (UNLIKELY(registeredListener->wasRemoved()))
+            continue;
 
-        if (event.eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
+        if (event.eventPhase() == Event::CAPTURING_PHASE && !registeredListener->useCapture())
             continue;
-        if (event.eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture)
+        if (event.eventPhase() == Event::BUBBLING_PHASE && registeredListener->useCapture())
             continue;
 
         // If stopImmediatePropagation has been called, we just break out immediately, without
@@ -274,24 +248,22 @@
             break;
 
         // Do this before invocation to avoid reentrancy issues.
-        if (registeredListener.isOnce)
-            removeEventListener(event.type(), *registeredListener.listener, ListenerOptions(registeredListener.useCapture));
+        if (registeredListener->isOnce())
+            removeEventListener(event.type(), registeredListener->listener(), ListenerOptions(registeredListener->useCapture()));
 
-        if (registeredListener.isPassive)
+        if (registeredListener->isPassive())
             event.setInPassiveListener(true);
 
         InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, event);
         // 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(context, &event);
+        registeredListener->listener().handleEvent(context, &event);
         InspectorInstrumentation::didHandleEvent(cookie);
 
-        if (registeredListener.isPassive)
+        if (registeredListener->isPassive())
             event.setInPassiveListener(false);
     }
 
-    d->firingEventIterators->removeLast();
-
     if (document)
         InspectorInstrumentation::didDispatchEvent(willDispatchEventCookie);
 }
@@ -310,15 +282,6 @@
     if (!d)
         return;
     d->eventListenerMap.clear();
-
-    // Notify firing events planning to invoke the listener at 'index' that
-    // they have one less listener to invoke.
-    if (d->firingEventIterators) {
-        for (auto& firingEventIterator : *d->firingEventIterators) {
-            firingEventIterator.iterator = 0;
-            firingEventIterator.size = 0;
-        }
-    }
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/EventTarget.h (204458 => 204459)


--- trunk/Source/WebCore/dom/EventTarget.h	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/dom/EventTarget.h	2016-08-15 00:48:16 UTC (rev 204459)
@@ -97,7 +97,7 @@
     ~EventTargetData();
 
     EventListenerMap eventListenerMap;
-    std::unique_ptr<FiringEventIteratorVector> firingEventIterators;
+    bool isFiringEventListeners { false };
 };
 
 enum EventTargetInterface {
@@ -182,7 +182,7 @@
     virtual void refEventTarget() = 0;
     virtual void derefEventTarget() = 0;
     
-    void fireEventListeners(Event&, EventTargetData*, EventListenerVector&);
+    void fireEventListeners(Event&, EventListenerVector);
 
     friend class EventListenerIterator;
 };
@@ -207,7 +207,7 @@
     EventTargetData* d = eventTargetData();
     if (!d)
         return false;
-    return d->firingEventIterators && !d->firingEventIterators->isEmpty();
+    return d->isFiringEventListeners;
 }
 
 inline bool EventTarget::hasEventListeners() const

Deleted: trunk/Source/WebCore/dom/RegisteredEventListener.cpp (204458 => 204459)


--- trunk/Source/WebCore/dom/RegisteredEventListener.cpp	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/dom/RegisteredEventListener.cpp	2016-08-15 00:48:16 UTC (rev 204459)
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2001 Peter Kelly ([email protected])
- * Copyright (C) 2001 Tobias Anton ([email protected])
- * Copyright (C) 2006 Samuel Weinig ([email protected])
- * Copyright (C) 2003, 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB.  If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "RegisteredEventListener.h"
-
-
-namespace WebCore {
-
-} // namespace WebCore

Modified: trunk/Source/WebCore/dom/RegisteredEventListener.h (204458 => 204459)


--- trunk/Source/WebCore/dom/RegisteredEventListener.h	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/dom/RegisteredEventListener.h	2016-08-15 00:48:16 UTC (rev 204459)
@@ -29,47 +29,50 @@
 
 namespace WebCore {
 
-    class RegisteredEventListener {
-    public:
-        struct Options {
-            Options(bool capture = false, bool passive = false, bool _once_ = false)
-                : capture(capture)
-                , passive(passive)
-                , once(once)
-            { }
+// https://dom.spec.whatwg.org/#concept-event-listener
+class RegisteredEventListener : public RefCounted<RegisteredEventListener> {
+public:
+    struct Options {
+        Options(bool capture = false, bool passive = false, bool _once_ = false)
+            : capture(capture)
+            , passive(passive)
+            , once(once)
+        { }
 
-            bool capture;
-            bool passive;
-            bool once;
-        };
+        bool capture;
+        bool passive;
+        bool once;
+    };
 
-        RegisteredEventListener(Ref<EventListener>&& listener, const Options& options)
-            : listener(WTFMove(listener))
-            , useCapture(options.capture)
-            , isPassive(options.passive)
-            , isOnce(options.once)
-        {
-        }
+    static Ref<RegisteredEventListener> create(Ref<EventListener>&& listener, const Options& options)
+    {
+        return adoptRef(*new RegisteredEventListener(WTFMove(listener), options));
+    }
 
-        RegisteredEventListener(Ref<EventListener>&& listener, bool useCapture)
-            : listener(WTFMove(listener))
-            , useCapture(useCapture)
-        {
-        }
+    EventListener& listener() const { return const_cast<EventListener&>(m_listener.get()); }
+    bool useCapture() const { return m_useCapture; }
+    bool isPassive() const { return m_isPassive; }
+    bool isOnce() const { return m_isOnce; }
+    bool wasRemoved() const { return m_wasRemoved; }
 
-        RefPtr<EventListener> listener;
-        bool useCapture { false };
-        bool isPassive { false };
-        bool isOnce { false };
-    };
-    
-    inline bool operator==(const RegisteredEventListener& a, const RegisteredEventListener& b)
+    void markAsRemoved() { m_wasRemoved = true; }
+
+private:
+    RegisteredEventListener(Ref<EventListener>&& listener, const Options& options)
+        : m_listener(WTFMove(listener))
+        , m_useCapture(options.capture)
+        , m_isPassive(options.passive)
+        , m_isOnce(options.once)
     {
-        // Other data members are purposefully not checked. The DOM specification says that upon adding / removing
-        // EventListeners, we should only check the type and the capture flag.
-        return *a.listener == *b.listener && a.useCapture == b.useCapture;
     }
 
+    Ref<EventListener> m_listener;
+    bool m_useCapture { false };
+    bool m_isPassive { false };
+    bool m_isOnce { false };
+    bool m_wasRemoved { false };
+};
+
 } // namespace WebCore
 
 #endif // RegisteredEventListener_h

Modified: trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp (204458 => 204459)


--- trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp	2016-08-15 00:48:16 UTC (rev 204459)
@@ -822,8 +822,8 @@
     size_t eventInformationLength = eventInformation.size();
     for (auto& info : eventInformation) {
         for (auto& listener : info.eventListenerVector) {
-            if (listener.useCapture)
-                listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node, objectGroup));
+            if (listener->useCapture())
+                listenersArray->addItem(buildObjectForEventListener(*listener, info.eventType, info.node, objectGroup));
         }
     }
 
@@ -831,8 +831,8 @@
     for (size_t i = eventInformationLength; i; --i) {
         const EventListenerInfo& info = eventInformation[i - 1];
         for (auto& listener : info.eventListenerVector) {
-            if (!listener.useCapture)
-                listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node, objectGroup));
+            if (!listener->useCapture())
+                listenersArray->addItem(buildObjectForEventListener(*listener, info.eventType, info.node, objectGroup));
         }
     }
 }
@@ -858,13 +858,13 @@
         for (auto& type : d->eventListenerMap.eventTypes()) {
             const EventListenerVector& listeners = ancestor->getEventListeners(type);
             EventListenerVector filteredListeners;
-            filteredListeners.reserveCapacity(listeners.size());
+            filteredListeners.reserveInitialCapacity(listeners.size());
             for (auto& listener : listeners) {
-                if (listener.listener->type() == EventListener::JSEventListenerType)
-                    filteredListeners.append(listener);
+                if (listener->listener().type() == EventListener::JSEventListenerType)
+                    filteredListeners.uncheckedAppend(listener);
             }
             if (!filteredListeners.isEmpty())
-                eventInformation.append(EventListenerInfo(ancestor, type, filteredListeners));
+                eventInformation.append(EventListenerInfo(ancestor, type, WTFMove(filteredListeners)));
         }
     }
 }
@@ -1477,7 +1477,7 @@
 
 Ref<Inspector::Protocol::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node, const String* objectGroupId)
 {
-    RefPtr<EventListener> eventListener = registeredEventListener.listener;
+    Ref<EventListener> eventListener = registeredEventListener.listener();
 
     JSC::ExecState* state = nullptr;
     JSC::JSObject* handler = nullptr;
@@ -1486,7 +1486,7 @@
     int columnNumber = 0;
     String scriptID;
     String sourceName;
-    if (auto scriptListener = JSEventListener::cast(eventListener.get())) {
+    if (auto scriptListener = JSEventListener::cast(eventListener.ptr())) {
         JSC::JSLockHolder lock(scriptListener->isolatedWorld().vm());
         state = execStateFromNode(scriptListener->isolatedWorld(), &node->document());
         handler = scriptListener->jsFunction(&node->document());
@@ -1507,7 +1507,7 @@
 
     auto value = Inspector::Protocol::DOM::EventListener::create()
         .setType(eventType)
-        .setUseCapture(registeredEventListener.useCapture)
+        .setUseCapture(registeredEventListener.useCapture())
         .setIsAttribute(eventListener->isAttribute())
         .setNodeId(pushNodePathToFrontend(node))
         .setHandlerBody(body)

Modified: trunk/Source/WebCore/inspector/InspectorDOMAgent.h (204458 => 204459)


--- trunk/Source/WebCore/inspector/InspectorDOMAgent.h	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/inspector/InspectorDOMAgent.h	2016-08-15 00:48:16 UTC (rev 204459)
@@ -80,10 +80,10 @@
 typedef int BackendNodeId;
 
 struct EventListenerInfo {
-    EventListenerInfo(Node* node, const AtomicString& eventType, const EventListenerVector& eventListenerVector)
+    EventListenerInfo(Node* node, const AtomicString& eventType, EventListenerVector&& eventListenerVector)
         : node(node)
         , eventType(eventType)
-        , eventListenerVector(eventListenerVector)
+        , eventListenerVector(WTFMove(eventListenerVector))
     {
     }
 

Modified: trunk/Source/WebCore/svg/SVGElement.cpp (204458 => 204459)


--- trunk/Source/WebCore/svg/SVGElement.cpp	2016-08-15 00:02:31 UTC (rev 204458)
+++ trunk/Source/WebCore/svg/SVGElement.cpp	2016-08-15 00:48:16 UTC (rev 204459)
@@ -584,11 +584,8 @@
         return true;
 
     for (element = element->parentOrShadowHostElement(); element; element = element->parentOrShadowHostElement()) {
-        const EventListenerVector& entry = element->getEventListeners(eventNames().loadEvent);
-        for (auto& listener : entry) {
-            if (listener.useCapture)
-                return true;
-        }
+        if (element->hasCapturingEventListeners(eventNames().loadEvent))
+            return true;
     }
 
     return false;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to