Title: [95372] trunk/Source/WebCore
Revision
95372
Author
commit-qu...@webkit.org
Date
2011-09-16 23:34:05 -0700 (Fri, 16 Sep 2011)

Log Message

Reduce EventTarget memory usage by deferring hash map allocation
until there are listeners for more than 1 event type.

http://webkit.org/b/68105

Patch by Andreas Kling <kl...@webkit.org> on 2011-09-16
Reviewed by Darin Adler.

Introduce an EventListenerMap class which manages a map of event types that have
one or more listeners connected.

When there is only one event type, it's stored directly on the EventListenerMap
internally, and when more are added it moves to a hash map. It only goes back
from the hash map if all the listeners are removed at once (i.e clear() is called.)

* CMakeLists.txt:
* GNUmakefile.list.am:
* WebCore.gypi:
* WebCore.pro:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:

    Adding files.

* WebCore.exp.in:

    Export EventListenerMap::contains() for WebKit/mac.

* dom/EventListenerMap.cpp: Added.
(WebCore::EventListenerMap::EventListenerMap):
(WebCore::EventListenerMap::~EventListenerMap):
(WebCore::EventListenerMap::isEmpty):
(WebCore::EventListenerMap::contains):
(WebCore::EventListenerMap::clear):
(WebCore::EventListenerMap::eventTypes):
(WebCore::addListenerToVector):
(WebCore::EventListenerMap::add):
(WebCore::removeListenerFromVector):
(WebCore::EventListenerMap::remove):
(WebCore::EventListenerMap::find):
(WebCore::removeFirstListenerCreatedFromMarkup):
(WebCore::EventListenerMap::removeFirstEventListenerCreatedFromMarkup):
(WebCore::copyListenersNotCreatedFromMarkupToTarget):
(WebCore::EventListenerMap::copyEventListenersNotCreatedFromMarkupToTarget):
(WebCore::EventListenerIterator::EventListenerIterator):
(WebCore::EventListenerIterator::nextListener):
* dom/EventListenerMap.h: Added.

* dom/EventTarget.cpp:
(WebCore::EventTargetData::~EventTargetData):
(WebCore::EventTarget::addEventListener):
(WebCore::EventTarget::removeEventListener):
(WebCore::EventTarget::fireEventListeners):
(WebCore::EventTarget::getEventListeners):
(WebCore::EventTarget::removeAllEventListeners):

* dom/EventTarget.h:
(WebCore::EventTarget::visitJSEventListeners):

    Use EventListenerIterator to visit listeners. (JSC specific.)

* inspector/InspectorDOMAgent.cpp:
(WebCore::InspectorDOMAgent::getEventListenersForNode):

    Call EventListenerMap::eventTypes() go get the list of event types
    currently listened for.

* dom/Node.cpp:
(WebCore::Node::removeEventListener):
* svg/SVGUseElement.cpp:
(WebCore::SVGUseElement::transferEventListenersToShadowTree):

    Move implementations of SVG-specific hacks into EventListenerMap and
    call them from here.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/CMakeLists.txt (95371 => 95372)


--- trunk/Source/WebCore/CMakeLists.txt	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/CMakeLists.txt	2011-09-17 06:34:05 UTC (rev 95372)
@@ -529,6 +529,7 @@
     dom/EventContext.cpp
     dom/EventDispatchMediator.cpp
     dom/EventDispatcher.cpp
+    dom/EventListenerMap.cpp
     dom/EventNames.cpp
     dom/EventTarget.cpp
     dom/EventQueue.cpp

Modified: trunk/Source/WebCore/ChangeLog (95371 => 95372)


--- trunk/Source/WebCore/ChangeLog	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/ChangeLog	2011-09-17 06:34:05 UTC (rev 95372)
@@ -1,3 +1,79 @@
+2011-09-16  Andreas Kling  <kl...@webkit.org>
+
+        Reduce EventTarget memory usage by deferring hash map allocation
+        until there are listeners for more than 1 event type.
+
+        http://webkit.org/b/68105
+
+        Reviewed by Darin Adler.
+
+        Introduce an EventListenerMap class which manages a map of event types that have
+        one or more listeners connected.
+
+        When there is only one event type, it's stored directly on the EventListenerMap
+        internally, and when more are added it moves to a hash map. It only goes back
+        from the hash map if all the listeners are removed at once (i.e clear() is called.)
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * WebCore.gypi:
+        * WebCore.pro:
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+
+            Adding files.
+
+        * WebCore.exp.in:
+
+            Export EventListenerMap::contains() for WebKit/mac.
+
+        * dom/EventListenerMap.cpp: Added.
+        (WebCore::EventListenerMap::EventListenerMap):
+        (WebCore::EventListenerMap::~EventListenerMap):
+        (WebCore::EventListenerMap::isEmpty):
+        (WebCore::EventListenerMap::contains):
+        (WebCore::EventListenerMap::clear):
+        (WebCore::EventListenerMap::eventTypes):
+        (WebCore::addListenerToVector):
+        (WebCore::EventListenerMap::add):
+        (WebCore::removeListenerFromVector):
+        (WebCore::EventListenerMap::remove):
+        (WebCore::EventListenerMap::find):
+        (WebCore::removeFirstListenerCreatedFromMarkup):
+        (WebCore::EventListenerMap::removeFirstEventListenerCreatedFromMarkup):
+        (WebCore::copyListenersNotCreatedFromMarkupToTarget):
+        (WebCore::EventListenerMap::copyEventListenersNotCreatedFromMarkupToTarget):
+        (WebCore::EventListenerIterator::EventListenerIterator):
+        (WebCore::EventListenerIterator::nextListener):
+        * dom/EventListenerMap.h: Added.
+
+        * dom/EventTarget.cpp:
+        (WebCore::EventTargetData::~EventTargetData):
+        (WebCore::EventTarget::addEventListener):
+        (WebCore::EventTarget::removeEventListener):
+        (WebCore::EventTarget::fireEventListeners):
+        (WebCore::EventTarget::getEventListeners):
+        (WebCore::EventTarget::removeAllEventListeners):
+
+        * dom/EventTarget.h:
+        (WebCore::EventTarget::visitJSEventListeners):
+
+            Use EventListenerIterator to visit listeners. (JSC specific.)
+
+        * inspector/InspectorDOMAgent.cpp:
+        (WebCore::InspectorDOMAgent::getEventListenersForNode):
+
+            Call EventListenerMap::eventTypes() go get the list of event types
+            currently listened for.
+
+        * dom/Node.cpp:
+        (WebCore::Node::removeEventListener):
+        * svg/SVGUseElement.cpp:
+        (WebCore::SVGUseElement::transferEventListenersToShadowTree):
+
+            Move implementations of SVG-specific hacks into EventListenerMap and
+            call them from here.
+
 2011-09-16  Jeremy Apthorp <jere...@chromium.org> and James Kozianski  <k...@chromium.org>
 
         Don't detach elements from the render tree when entering fullscreen mode

Modified: trunk/Source/WebCore/GNUmakefile.list.am (95371 => 95372)


--- trunk/Source/WebCore/GNUmakefile.list.am	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/GNUmakefile.list.am	2011-09-17 06:34:05 UTC (rev 95372)
@@ -1177,6 +1177,8 @@
 	Source/WebCore/dom/EventDispatcher.h \
 	Source/WebCore/dom/EventException.h \
 	Source/WebCore/dom/EventListener.h \
+	Source/WebCore/dom/EventListenerMap.cpp \
+	Source/WebCore/dom/EventListenerMap.h \
 	Source/WebCore/dom/EventNames.cpp \
 	Source/WebCore/dom/EventNames.h \
 	Source/WebCore/dom/EventTarget.cpp \

Modified: trunk/Source/WebCore/WebCore.exp.in (95371 => 95372)


--- trunk/Source/WebCore/WebCore.exp.in	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/WebCore.exp.in	2011-09-17 06:34:05 UTC (rev 95372)
@@ -1184,6 +1184,7 @@
 __ZNK7WebCore15VisiblePosition19absoluteCaretBoundsEv
 __ZNK7WebCore15VisiblePosition4nextENS_27EditingBoundaryCrossingRuleE
 __ZNK7WebCore15VisiblePosition8previousENS_27EditingBoundaryCrossingRuleE
+__ZNK7WebCore16EventListenerMap8containsERKN3WTF12AtomicStringE
 __ZNK7WebCore16FontFallbackList10fontDataAtEPKNS_4FontEj
 __ZNK7WebCore16HTMLInputElement11isTextFieldEv
 __ZNK7WebCore16HTMLInputElement14suggestedValueEv

Modified: trunk/Source/WebCore/WebCore.gypi (95371 => 95372)


--- trunk/Source/WebCore/WebCore.gypi	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/WebCore.gypi	2011-09-17 06:34:05 UTC (rev 95372)
@@ -994,6 +994,7 @@
             'dom/Element.h',
             'dom/Event.h',
             'dom/EventListener.h',
+            'dom/EventListenerMap.h',
             'dom/EventNames.h',
             'dom/EventTarget.h',
             'dom/ExceptionCode.h',
@@ -5276,6 +5277,7 @@
             'dom/EventDispatcher.cpp',
             'dom/EventDispatcher.h',
             'dom/EventException.h',
+            'dom/EventListenerMap.cpp',
             'dom/EventNames.cpp',
             'dom/EventQueue.cpp',
             'dom/EventQueue.h',

Modified: trunk/Source/WebCore/WebCore.pro (95371 => 95372)


--- trunk/Source/WebCore/WebCore.pro	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/WebCore.pro	2011-09-17 06:34:05 UTC (rev 95372)
@@ -499,6 +499,7 @@
     dom/EventContext.cpp \
     dom/EventDispatchMediator.cpp \
     dom/EventDispatcher.cpp \
+    dom/EventListenerMap.cpp \
     dom/EventNames.cpp \
     dom/EventTarget.cpp \
     dom/EventQueue.cpp \
@@ -1506,6 +1507,7 @@
     dom/EntityReference.h \
     dom/Event.h \
     dom/EventDispatchMediator.h \
+    dom/EventListenerMap.h \
     dom/EventNames.h \
     dom/EventTarget.h \
     dom/ExceptionBase.h \

Modified: trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj (95371 => 95372)


--- trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj	2011-09-17 06:34:05 UTC (rev 95372)
@@ -45754,6 +45754,86 @@
 				>
 			</File>
 			<File
+				RelativePath="..\dom\EventListenerMap.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Cairo_CFLite|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release_Cairo_CFLite|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_All|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Production|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Internal|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Cairo|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release_Cairo|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\dom\EventListenerMap.h"
+				>
+			</File>
+			<File
 				RelativePath="..\dom\EventListener.h"
 				>
 			</File>

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (95371 => 95372)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2011-09-17 06:34:05 UTC (rev 95372)
@@ -4093,6 +4093,8 @@
 		ABC128770B33AA6D00C693D5 /* PopupMenuClient.h in Headers */ = {isa = PBXBuildFile; fileRef = ABC128760B33AA6D00C693D5 /* PopupMenuClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		ABDDFE790A5C6E7000A3E11D /* RenderMenuList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABDDFE730A5C6E6F00A3E11D /* RenderMenuList.cpp */; };
 		ABDDFE7A0A5C6E7000A3E11D /* RenderMenuList.h in Headers */ = {isa = PBXBuildFile; fileRef = ABDDFE740A5C6E7000A3E11D /* RenderMenuList.h */; };
+		AD4495F3141FC08900541EDF /* EventListenerMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD4495F1141FC08900541EDF /* EventListenerMap.cpp */; };
+		AD4495F4141FC08900541EDF /* EventListenerMap.h in Headers */ = {isa = PBXBuildFile; fileRef = AD4495F2141FC08900541EDF /* EventListenerMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		ADDF1AD71257CD9A0003A759 /* RenderSVGPath.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF1AD51257CD9A0003A759 /* RenderSVGPath.h */; };
 		B10B6980140C174000BC1C26 /* WebVTTToken.h in Headers */ = {isa = PBXBuildFile; fileRef = B10B697D140C174000BC1C26 /* WebVTTToken.h */; };
 		B10B6981140C174000BC1C26 /* WebVTTTokenizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B10B697E140C174000BC1C26 /* WebVTTTokenizer.cpp */; };
@@ -10651,6 +10653,8 @@
 		ABC128760B33AA6D00C693D5 /* PopupMenuClient.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PopupMenuClient.h; sourceTree = "<group>"; };
 		ABDDFE730A5C6E6F00A3E11D /* RenderMenuList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderMenuList.cpp; sourceTree = "<group>"; };
 		ABDDFE740A5C6E7000A3E11D /* RenderMenuList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenderMenuList.h; sourceTree = "<group>"; };
+		AD4495F1141FC08900541EDF /* EventListenerMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventListenerMap.cpp; sourceTree = "<group>"; };
+		AD4495F2141FC08900541EDF /* EventListenerMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventListenerMap.h; sourceTree = "<group>"; };
 		ADDF1AD41257CD9A0003A759 /* RenderSVGPath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderSVGPath.cpp; sourceTree = "<group>"; };
 		ADDF1AD51257CD9A0003A759 /* RenderSVGPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderSVGPath.h; sourceTree = "<group>"; };
 		B10B697D140C174000BC1C26 /* WebVTTToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebVTTToken.h; sourceTree = "<group>"; };
@@ -19958,6 +19962,8 @@
 				BC60D90A0D2A17CE00B9918F /* EventException.idl */,
 				935FBC4409BA00B900E230B1 /* EventListener.h */,
 				85AFA7410AAF298400E84305 /* EventListener.idl */,
+				AD4495F1141FC08900541EDF /* EventListenerMap.cpp */,
+				AD4495F2141FC08900541EDF /* EventListenerMap.h */,
 				939885C108B7E3D100E707C4 /* EventNames.cpp */,
 				939885C208B7E3D100E707C4 /* EventNames.h */,
 				8F67561A1288B17B0047ACA3 /* EventQueue.cpp */,
@@ -20467,6 +20473,7 @@
 				29A8122C0FBB9C1D00510293 /* AccessibilityList.h in Headers */,
 				29A812430FBB9C1D00510293 /* AccessibilityListBox.h in Headers */,
 				29A812420FBB9C1D00510293 /* AccessibilityListBoxOption.h in Headers */,
+				AD4495F4141FC08900541EDF /* EventListenerMap.h in Headers */,
 				07B0113F1032242200FBDC33 /* AccessibilityMediaControls.h in Headers */,
 				76CDD2F31103DA6600680521 /* AccessibilityMenuList.h in Headers */,
 				76CDD2F71103DA6600680521 /* AccessibilityMenuListOption.h in Headers */,
@@ -24451,6 +24458,7 @@
 				418A06D1133C04D500CD379C /* EventDispatcher.cpp in Sources */,
 				93C09A810B064F00005ABD4D /* EventHandler.cpp in Sources */,
 				93C09A7F0B064EEF005ABD4D /* EventHandlerMac.mm in Sources */,
+				AD4495F3141FC08900541EDF /* EventListenerMap.cpp in Sources */,
 				1CA19E050DC255950065A994 /* EventLoopMac.mm in Sources */,
 				939885C308B7E3D100E707C4 /* EventNames.cpp in Sources */,
 				8F67561C1288B17B0047ACA3 /* EventQueue.cpp in Sources */,

Added: trunk/Source/WebCore/dom/EventListenerMap.cpp (0 => 95372)


--- trunk/Source/WebCore/dom/EventListenerMap.cpp	                        (rev 0)
+++ trunk/Source/WebCore/dom/EventListenerMap.cpp	2011-09-17 06:34:05 UTC (rev 95372)
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (kn...@kde.org)
+ *           (C) 1999 Antti Koivisto (koivi...@kde.org)
+ *           (C) 2001 Dirk Mueller (muel...@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (a...@webkit.org)
+ *           (C) 2007, 2008 Nikolas Zimmermann <zimmerm...@kde.org>
+ * Copyright (C) 2011 Andreas Kling (kl...@webkit.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 "EventListenerMap.h"
+
+#include "Event.h"
+#include "EventException.h"
+#include <wtf/MainThread.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+EventListenerMap::EventListenerMap()
+{
+}
+
+EventListenerMap::~EventListenerMap()
+{
+    clear();
+}
+
+bool EventListenerMap::isEmpty() const
+{
+    if (m_hashMap)
+        return m_hashMap->isEmpty();
+    return !m_singleEventListenerVector;
+}
+
+bool EventListenerMap::contains(const AtomicString& eventType) const
+{
+    if (m_hashMap)
+        return m_hashMap->contains(eventType);
+    return m_singleEventListenerType == eventType;
+}
+
+void EventListenerMap::clear()
+{
+    if (m_hashMap) {
+        deleteAllValues(*m_hashMap);
+        m_hashMap.clear();
+    } else {
+        m_singleEventListenerType = nullAtom;
+        m_singleEventListenerVector.clear();
+    }
+}
+
+Vector<AtomicString> EventListenerMap::eventTypes() const
+{
+    Vector<AtomicString> types;
+
+    if (m_hashMap) {
+        EventListenerHashMap::iterator it = m_hashMap->begin();
+        EventListenerHashMap::iterator end = m_hashMap->end();
+        for (; it != end; ++it)
+            types.append(it->first);
+    } else if (m_singleEventListenerVector)
+        types.append(m_singleEventListenerType);
+
+    return types;
+}
+
+static bool addListenerToVector(EventListenerVector* vector, PassRefPtr<EventListener> listener, bool useCapture)
+{
+    RegisteredEventListener registeredListener(listener, useCapture);
+
+    if (vector->find(registeredListener) != notFound)
+        return false; // Duplicate listener.
+
+    vector->append(registeredListener);
+    return true;
+}
+
+bool EventListenerMap::add(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
+{
+    if (m_singleEventListenerVector && m_singleEventListenerType != eventType) {
+        // We already have a single (first) listener vector, and this event is not
+        // of that type, so create the hash map and move the first listener vector there.
+        ASSERT(!m_hashMap);
+        m_hashMap = adoptPtr(new EventListenerHashMap);
+        m_hashMap->add(m_singleEventListenerType, m_singleEventListenerVector.leakPtr());
+        m_singleEventListenerType = nullAtom;
+    }
+
+    if (m_hashMap) {
+        pair<EventListenerHashMap::iterator, bool> result = m_hashMap->add(eventType, 0);
+        if (result.second)
+            result.first->second = new EventListenerVector;
+
+        return addListenerToVector(result.first->second, listener, useCapture);
+    }
+
+    if (!m_singleEventListenerVector) {
+        m_singleEventListenerType = eventType;
+        m_singleEventListenerVector = adoptPtr(new EventListenerVector);
+    }
+
+    ASSERT(m_singleEventListenerType == eventType);
+    return addListenerToVector(m_singleEventListenerVector.get(), listener, useCapture);
+}
+
+static bool removeListenerFromVector(EventListenerVector* listenerVector, EventListener* listener, bool useCapture, size_t& indexOfRemovedListener)
+{
+    RegisteredEventListener registeredListener(listener, useCapture);
+    indexOfRemovedListener = listenerVector->find(registeredListener);
+    if (indexOfRemovedListener == notFound)
+        return false;
+    listenerVector->remove(indexOfRemovedListener);
+    return true;
+}
+
+bool EventListenerMap::remove(const AtomicString& eventType, EventListener* listener, bool useCapture, size_t& indexOfRemovedListener)
+{
+    if (!m_hashMap) {
+        if (m_singleEventListenerType != eventType)
+            return false;
+        bool wasRemoved = removeListenerFromVector(m_singleEventListenerVector.get(), listener, useCapture, indexOfRemovedListener);
+        if (m_singleEventListenerVector->isEmpty()) {
+            m_singleEventListenerVector.clear();
+            m_singleEventListenerType = nullAtom;
+        }
+        return wasRemoved;
+    }
+
+    EventListenerHashMap::iterator it = m_hashMap->find(eventType);
+    if (it == m_hashMap->end())
+        return false;
+
+    bool wasRemoved = removeListenerFromVector(it->second, listener, useCapture, indexOfRemovedListener);
+    if (it->second->isEmpty()) {
+        delete it->second;
+        m_hashMap->remove(it);
+    }
+    return wasRemoved;
+}
+
+EventListenerVector* EventListenerMap::find(const AtomicString& eventType)
+{
+    if (m_hashMap) {
+        EventListenerHashMap::iterator it = m_hashMap->find(eventType);
+        if (it == m_hashMap->end())
+            return 0;
+        return it->second;
+    }
+
+    if (m_singleEventListenerType == eventType)
+        return m_singleEventListenerVector.get();
+
+    return 0;
+}
+
+#if ENABLE(SVG)
+
+static void removeFirstListenerCreatedFromMarkup(EventListenerVector* listenerVector)
+{
+    bool foundListener = false;
+
+    for (size_t i = 0; i < listenerVector->size(); ++i) {
+        if (!listenerVector->at(i).listener->wasCreatedFromMarkup())
+            continue;
+        foundListener = true;
+        listenerVector->remove(i);
+        break;
+    }
+
+    ASSERT_UNUSED(foundListener, foundListener);
+}
+
+void EventListenerMap::removeFirstEventListenerCreatedFromMarkup(const AtomicString& eventType)
+{
+    if (m_hashMap) {
+        EventListenerHashMap::iterator result = m_hashMap->find(eventType);
+        ASSERT(result != m_hashMap->end());
+
+        EventListenerVector* listenerVector = result->second;
+        ASSERT(listenerVector);
+
+        removeFirstListenerCreatedFromMarkup(listenerVector);
+
+        if (listenerVector->isEmpty()) {
+            delete listenerVector;
+            m_hashMap->remove(result);
+        }
+
+        return;
+    }
+
+    ASSERT(m_singleEventListenerVector);
+    ASSERT(m_singleEventListenerType == eventType);
+
+    removeFirstListenerCreatedFromMarkup(m_singleEventListenerVector.get());
+    if (m_singleEventListenerVector->isEmpty()) {
+        m_singleEventListenerVector.clear();
+        m_singleEventListenerType = nullAtom;
+    }
+}
+
+static void copyListenersNotCreatedFromMarkupToTarget(const AtomicString& eventType, EventListenerVector* listenerVector, EventTarget* target)
+{
+    for (size_t i = 0; i < listenerVector->size(); ++i) {
+        // Event listeners created from markup have already been transfered to the shadow tree during cloning.
+        if ((*listenerVector)[i].listener->wasCreatedFromMarkup())
+            continue;
+        target->addEventListener(eventType, (*listenerVector)[i].listener, (*listenerVector)[i].useCapture);
+    }
+}
+
+void EventListenerMap::copyEventListenersNotCreatedFromMarkupToTarget(EventTarget* target)
+{
+    if (m_hashMap) {
+        EventListenerHashMap::iterator end = m_hashMap->end();
+        for (EventListenerHashMap::iterator it = m_hashMap->begin(); it != end; ++it)
+            copyListenersNotCreatedFromMarkupToTarget(it->first, it->second, target);
+        return;
+    }
+
+    if (!m_singleEventListenerVector)
+        return;
+
+    copyListenersNotCreatedFromMarkupToTarget(m_singleEventListenerType, m_singleEventListenerVector.get(), target);
+}
+
+#endif // ENABLE(SVG)
+
+EventListenerIterator::EventListenerIterator()
+    : m_map(0)
+    , m_index(0)
+{
+}
+
+EventListenerIterator::EventListenerIterator(EventTarget* target)
+    : m_map(0)
+    , m_index(0)
+{
+    ASSERT(target);
+    EventTargetData* data = ""
+
+    if (!data)
+        return;
+
+    m_map = &data->eventListenerMap;
+
+    if (m_map->m_hashMap) {
+        m_mapIterator = m_map->m_hashMap->begin();
+        m_mapEnd = m_map->m_hashMap->end();
+    }
+}
+
+EventListener* EventListenerIterator::nextListener()
+{
+    if (!m_map)
+        return 0;
+
+    if (m_map->m_hashMap) {
+        for (; m_mapIterator != m_mapEnd; ++m_mapIterator) {
+            EventListenerVector& listeners = *m_mapIterator->second;
+            if (m_index < listeners.size())
+                return listeners[m_index++].listener.get();
+            m_index = 0;
+        }
+        return 0;
+    }
+
+    if (!m_map->m_singleEventListenerVector)
+        return 0;
+    EventListenerVector& listeners = *m_map->m_singleEventListenerVector;
+    if (m_index < listeners.size())
+        return listeners[m_index++].listener.get();
+    return 0;
+}
+
+} // namespace WebCore

Added: trunk/Source/WebCore/dom/EventListenerMap.h (0 => 95372)


--- trunk/Source/WebCore/dom/EventListenerMap.h	                        (rev 0)
+++ trunk/Source/WebCore/dom/EventListenerMap.h	2011-09-17 06:34:05 UTC (rev 95372)
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (kn...@kde.org)
+ *           (C) 1999 Antti Koivisto (koivi...@kde.org)
+ *           (C) 2001 Dirk Mueller (muel...@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (a...@webkit.org)
+ *           (C) 2007, 2008 Nikolas Zimmermann <zimmerm...@kde.org>
+ * Copyright (C) 2011 Andreas Kling (kl...@webkit.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.
+ *
+ */
+
+#ifndef EventListenerMap_h
+#define EventListenerMap_h
+
+#include "RegisteredEventListener.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/text/AtomicStringHash.h>
+
+namespace WebCore {
+
+class EventTarget;
+
+typedef Vector<RegisteredEventListener, 1> EventListenerVector;
+
+class EventListenerMap {
+public:
+    EventListenerMap();
+    ~EventListenerMap();
+
+    bool isEmpty() const;
+    bool contains(const AtomicString& eventType) const;
+
+    void clear();
+    bool add(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
+    bool remove(const AtomicString& eventType, EventListener*, bool useCapture, size_t& indexOfRemovedListener);
+    EventListenerVector* find(const AtomicString& eventType);
+    Vector<AtomicString> eventTypes() const;
+
+#if ENABLE(SVG)
+    void removeFirstEventListenerCreatedFromMarkup(const AtomicString& eventType);
+    void copyEventListenersNotCreatedFromMarkupToTarget(EventTarget*);
+#endif
+
+private:
+    friend class EventListenerIterator;
+
+    struct EventListenerHashMapTraits : HashTraits<WTF::AtomicString> {
+        static const int minimumTableSize = 32;
+    };
+    typedef HashMap<AtomicString, EventListenerVector*, AtomicStringHash, EventListenerHashMapTraits> EventListenerHashMap;
+
+    OwnPtr<EventListenerHashMap> m_hashMap;
+
+    AtomicString m_singleEventListenerType;
+    OwnPtr<EventListenerVector> m_singleEventListenerVector;
+};
+
+class EventListenerIterator {
+    WTF_MAKE_NONCOPYABLE(EventListenerIterator);
+public:
+    EventListenerIterator();
+
+    // EventTarget must not be modified while an iterator is active.
+    EventListenerIterator(EventTarget*);
+
+    EventListener* nextListener();
+
+private:
+    EventListenerMap* m_map;
+    EventListenerMap::EventListenerHashMap::iterator m_mapIterator;
+    EventListenerMap::EventListenerHashMap::iterator m_mapEnd;
+    unsigned m_index;
+};
+
+} // namespace WebCore
+
+#endif // EventListenerMap_h

Modified: trunk/Source/WebCore/dom/EventTarget.cpp (95371 => 95372)


--- trunk/Source/WebCore/dom/EventTarget.cpp	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/dom/EventTarget.cpp	2011-09-17 06:34:05 UTC (rev 95372)
@@ -74,7 +74,6 @@
 
 EventTargetData::~EventTargetData()
 {
-    deleteAllValues(eventListenerMap);
 }
 
 EventTarget::~EventTarget()
@@ -226,21 +225,7 @@
 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;
+    return d->eventListenerMap.add(eventType, listener, useCapture);
 }
 
 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
@@ -249,33 +234,22 @@
     if (!d)
         return false;
 
-    EventListenerMap::iterator result = d->eventListenerMap.find(eventType);
-    if (result == d->eventListenerMap.end())
-        return false;
-    EventListenerVector* entry = result->second;
+    size_t indexOfRemovedListener;
 
-    RegisteredEventListener registeredListener(listener, useCapture);
-    size_t index = entry->find(registeredListener);
-    if (index == notFound)
+    if (!d->eventListenerMap.remove(eventType, listener, useCapture, indexOfRemovedListener))
         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)
+        if (indexOfRemovedListener >= d->firingEventIterators[i].end)
             continue;
 
         --d->firingEventIterators[i].end;
-        if (index <= d->firingEventIterators[i].iterator)
+        if (indexOfRemovedListener <= d->firingEventIterators[i].iterator)
             --d->firingEventIterators[i].iterator;
     }
 
@@ -349,9 +323,10 @@
     if (!d)
         return true;
 
-    EventListenerMap::iterator result = d->eventListenerMap.find(event->type());
-    if (result != d->eventListenerMap.end())
-        fireEventListeners(event, d, *result->second);
+    EventListenerVector* listenerVector = d->eventListenerMap.find(event->type());
+
+    if (listenerVector)
+        fireEventListeners(event, d, *listenerVector);
     
     return !event->defaultPrevented();
 }
@@ -394,10 +369,12 @@
     EventTargetData* d = eventTargetData();
     if (!d)
         return emptyVector;
-    EventListenerMap::iterator it = d->eventListenerMap.find(eventType);
-    if (it == d->eventListenerMap.end())
+
+    EventListenerVector* listenerVector = d->eventListenerMap.find(eventType);
+    if (!listenerVector)
         return emptyVector;
-    return *it->second;
+
+    return *listenerVector;
 }
 
 void EventTarget::removeAllEventListeners()
@@ -405,7 +382,6 @@
     EventTargetData* d = eventTargetData();
     if (!d)
         return;
-    deleteAllValues(d->eventListenerMap);
     d->eventListenerMap.clear();
 
     // Notify firing events planning to invoke the listener at 'index' that
@@ -416,30 +392,4 @@
     }
 }
 
-EventListenerIterator::EventListenerIterator()
-    : m_index(0)
-{
-}
-
-EventListenerIterator::EventListenerIterator(EventTarget* target)
-    : m_index(0)
-{
-    EventTargetData* data = ""
-    if (!data)
-        return;
-    m_mapIterator = data->eventListenerMap.begin();
-    m_mapEnd = data->eventListenerMap.end();
-}
-
-EventListener* EventListenerIterator::nextListener()
-{
-    for (; m_mapIterator != m_mapEnd; ++m_mapIterator) {
-        EventListenerVector& listeners = *m_mapIterator->second;
-        if (m_index < listeners.size())
-            return listeners[m_index++].listener.get();
-        m_index = 0;
-    }
-    return 0;
-}
-
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/EventTarget.h (95371 => 95372)


--- trunk/Source/WebCore/dom/EventTarget.h	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/dom/EventTarget.h	2011-09-17 06:34:05 UTC (rev 95372)
@@ -32,8 +32,8 @@
 #ifndef EventTarget_h
 #define EventTarget_h
 
+#include "EventListenerMap.h"
 #include "EventNames.h"
-#include "RegisteredEventListener.h"
 #include <wtf/Forward.h>
 #include <wtf/HashMap.h>
 #include <wtf/text/AtomicStringHash.h>
@@ -85,14 +85,6 @@
     };
     typedef Vector<FiringEventIterator, 1> FiringEventIteratorVector;
 
-    typedef Vector<RegisteredEventListener, 1> EventListenerVector;
-
-    struct EventListenerMapHashTraits : HashTraits<WTF::AtomicString> {
-        static const int minimumTableSize = 32;
-    };
-
-    typedef HashMap<AtomicString, EventListenerVector*, AtomicStringHash, EventListenerMapHashTraits> EventListenerMap;
-
     struct EventTargetData {
         WTF_MAKE_NONCOPYABLE(EventTargetData); WTF_MAKE_FAST_ALLOCATED;
     public:
@@ -202,21 +194,6 @@
         friend class EventListenerIterator;
     };
 
-    class EventListenerIterator {
-    public:
-        EventListenerIterator();
-
-        // EventTarget must not be modified while an iterator is active.
-        EventListenerIterator(EventTarget*);
-
-        EventListener* nextListener();
-
-    private:
-        EventListenerMap::iterator m_mapIterator;
-        EventListenerMap::iterator m_mapEnd;
-        unsigned m_index;
-    };
-
     // FIXME: These macros should be split into separate DEFINE and DECLARE
     // macros to avoid causing so many header includes.
     #define DEFINE_ATTRIBUTE_EVENT_LISTENER(attribute) \
@@ -255,16 +232,9 @@
 #if USE(JSC)
     inline void EventTarget::visitJSEventListeners(JSC::SlotVisitor& visitor)
     {
-        EventTargetData* d = eventTargetData();
-        if (!d)
-            return;
-
-        EventListenerMap::iterator end = d->eventListenerMap.end();
-        for (EventListenerMap::iterator it = d->eventListenerMap.begin(); it != end; ++it) {
-            EventListenerVector& entry = *it->second;
-            for (size_t i = 0; i < entry.size(); ++i)
-                entry[i].listener->visitJSFunction(visitor);
-        }
+        EventListenerIterator iterator(this);
+        while (EventListener* listener = iterator.nextListener())
+            listener->visitJSFunction(visitor);
     }
 #endif
 

Modified: trunk/Source/WebCore/dom/Node.cpp (95371 => 95372)


--- trunk/Source/WebCore/dom/Node.cpp	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/dom/Node.cpp	2011-09-17 06:34:05 UTC (rev 95372)
@@ -2620,33 +2620,7 @@
         EventTargetData* data = ""
         ASSERT(data);
 
-        EventListenerMap::iterator result = data->eventListenerMap.find(eventType);
-        ASSERT(result != data->eventListenerMap.end());
-
-        EventListenerVector* entry = result->second;
-        ASSERT(entry);
-
-        unsigned int index = 0;
-        bool foundListener = false;
-
-        EventListenerVector::iterator end = entry->end();
-        for (EventListenerVector::iterator it = entry->begin(); it != end; ++it) {
-            if (!(*it).listener->wasCreatedFromMarkup()) {
-                ++index;
-                continue;
-            }
-
-            foundListener = true;
-            entry->remove(index);
-            break;
-        }
-
-        ASSERT_UNUSED(foundListener, foundListener);
-
-        if (entry->isEmpty()) {                
-            delete entry;
-            data->eventListenerMap.remove(result);
-        }
+        data->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType);
     }
 
     return true;

Modified: trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp (95371 => 95372)


--- trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp	2011-09-17 06:34:05 UTC (rev 95372)
@@ -815,11 +815,7 @@
         return;
 
     // Get the list of event types this Node is concerned with
-    Vector<AtomicString> eventTypes;
-    const EventListenerMap& listenerMap = d->eventListenerMap;
-    EventListenerMap::const_iterator end = listenerMap.end();
-    for (EventListenerMap::const_iterator iter = listenerMap.begin(); iter != end; ++iter)
-        eventTypes.append(iter->first);
+    Vector<AtomicString> eventTypes = d->eventListenerMap.eventTypes();
 
     // Quick break if no useful listeners
     size_t eventTypesLength = eventTypes.size();

Modified: trunk/Source/WebCore/svg/SVGUseElement.cpp (95371 => 95372)


--- trunk/Source/WebCore/svg/SVGUseElement.cpp	2011-09-17 06:07:42 UTC (rev 95371)
+++ trunk/Source/WebCore/svg/SVGUseElement.cpp	2011-09-17 06:34:05 UTC (rev 95372)
@@ -939,19 +939,8 @@
     ASSERT(originalElement);
 
     if (SVGElement* shadowTreeElement = target->shadowTreeElement()) {
-        if (EventTargetData* d = originalElement->eventTargetData()) {
-            EventListenerMap& map = d->eventListenerMap;
-            EventListenerMap::iterator end = map.end();
-            for (EventListenerMap::iterator it = map.begin(); it != end; ++it) {
-                EventListenerVector& entry = *it->second;
-                for (size_t i = 0; i < entry.size(); ++i) {
-                    // Event listeners created from markup have already been transfered to the shadow tree during cloning.
-                    if (entry[i].listener->wasCreatedFromMarkup())
-                        continue;
-                    shadowTreeElement->addEventListener(it->first, entry[i].listener, entry[i].useCapture);
-                }
-            }
-        }
+        if (EventTargetData* data = ""
+            data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(shadowTreeElement);
     }
 
     for (SVGElementInstance* instance = target->firstChild(); instance; instance = instance->nextSibling())
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to