[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-10851-g50815da

rniwa at webkit.org rniwa at webkit.org
Wed Dec 22 18:21:51 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit b69181d8bdd7d676b11fe3984dc51be0533fbbf1
Author: rniwa at webkit.org <rniwa at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Fri Dec 10 07:48:03 2010 +0000

    2010-12-09  Ryosuke Niwa  <rniwa at webkit.org>
    
            Reviewed by Ojan Vafai.
    
            Make DOM Mutation Events Asynchronous
            https://bugs.webkit.org/show_bug.cgi?id=46936
    
            Implemented DOM mutations events as scoped events. A scoped event is an event whose
            dispatch is done via ScopedEventQueue. The behavior of the queue is controlled by
            EventQueueScope objects (RAII idiom), which increments and decrements the scoping level
            on its constructor and destructor respectively.
    
            When the scoping level is 0 (initial level), scoped events are dispatched as soon as
            they are enqueued and act like synchronous events. When the scoping level is greater than 0,
            however, events are queued in ScopedEventQueue and their dispatches are delayed until
            the scoping level goes back to 0 (by the destruction of EventQueueScope).
    
            DOMSubtreeModified, DOMNodeInserted, DOMNodeRemoved, DOMNodeRemovedFromDocument,
            DOMNodeInsertedIntoDocument, DOMFocusIn, DOMFocusOut, focusin, and focusout are treated as
            scoped events, and a scope object is instantiated in EditCommand::apply to delay dispatches
            of the events until the completion of each call of EditCommand::doApply.
    
            Test: fast/events/mutation/execCommands.html
    
            * Android.mk: Added ScopedEventQueue.cpp.
            * CMakeLists.txt: Ditto.
            * WebCore.pro: Ditto.
            * GNUmakefile.am: Added ScopedEventQueue.cpp and ScopedEventQueue.h.
            * WebCore.gypi:  Ditto.
            * WebCore.vcproj/project.vcproj: Ditto.
            * WebCore.xcodeproj/project.pbxproj: Ditto.
            * dom/ContainerNode.cpp:
            (WebCore::dispatchChildInsertionEvents): Calls dispatchScopedEvent.
            (WebCore::dispatchChildRemovalEvents): Ditto.
            * dom/DOMAllInOne.cpp: Added ScopedEventQueue.cpp.
            * dom/Element.cpp:
            (WebCore::Element::dispatchAttrRemovalEvent): Ditto.
            (WebCore::Element::dispatchAttrAdditionEvent): Ditto.
            * dom/Node.cpp:
            (WebCore::Node::dispatchScopedEvent): Added.
            (WebCore::Node::dispatchSubtreeModifiedEvent): Calls dispatchScopedEvent.
            * dom/Node.h:
            * dom/ScopedEventQueue.cpp: Added.
            (WebCore::ScopedEventQueue::initialize): Added.
            (WebCore::ScopedEventQueue::enqueueEvent): Added.
            (WebCore::ScopedEventQueue::dispatchAllEvents): Added.
            (WebCore::ScopedEventQueue::dispatchEvent): Added.
            (WebCore::ScopedEventQueue::instance): Added.
            (WebCore::ScopedEventQueue::incrementScopingLevel): Added.
            (WebCore::ScopedEventQueue::decrementScopingLevel): Added.
            * dom/ScopedEventQueue.h: Added.
            (WebCore::ScopedEventQueue::~ScopedEventQueue): Added.
            (WebCore::ScopedEventQueue::ScopedEventQueue): Added.
            (WebCore::EventQueueScope::EventQueueScope): Added.
            (WebCore::EventQueueScope::~EventQueueScope): Added.
            * editing/EditCommand.cpp:
            (WebCore::EditCommand::apply): Instantiates EventQueueScope.
    2010-12-09  Ryosuke Niwa  <rniwa at webkit.org>
    
            Reviewed by Ojan Vafai.
    
            Make DOM Mutation Events Asynchronous
            https://bugs.webkit.org/show_bug.cgi?id=46936
    
            Added a test to ensure no DOM mutation events are fired while execCommand is in progress.
    
            * fast/events/crash-on-mutate-during-drop.html: DOMNodeInserted is fired after BR is detached
            from the document, and can't be observed. Modify the DOM when text node is inserted.
            * fast/events/scoped: Added.
            * fast/events/scoped/editing-commands-expected.txt: Added.
            * fast/events/scoped/editing-commands.html: Added.
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@73690 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index c03fb52..6a273d5 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,18 @@
+2010-12-09  Ryosuke Niwa  <rniwa at webkit.org>
+
+        Reviewed by Ojan Vafai.
+
+        Make DOM Mutation Events Asynchronous
+        https://bugs.webkit.org/show_bug.cgi?id=46936
+
+        Added a test to ensure no DOM mutation events are fired while execCommand is in progress.
+
+        * fast/events/crash-on-mutate-during-drop.html: DOMNodeInserted is fired after BR is detached
+        from the document, and can't be observed. Modify the DOM when text node is inserted.
+        * fast/events/scoped: Added.
+        * fast/events/scoped/editing-commands-expected.txt: Added.
+        * fast/events/scoped/editing-commands.html: Added.
+
 2010-12-09  Sheriff Bot  <webkit.review.bot at gmail.com>
 
         Unreviewed, rolling out r73684.
diff --git a/LayoutTests/fast/events/crash-on-mutate-during-drop.html b/LayoutTests/fast/events/crash-on-mutate-during-drop.html
index 908e53e..1b85004 100644
--- a/LayoutTests/fast/events/crash-on-mutate-during-drop.html
+++ b/LayoutTests/fast/events/crash-on-mutate-during-drop.html
@@ -2,7 +2,7 @@
 <head>
 <script>
 function foo() {
-    if (event.type == "DOMNodeInserted" && event.target.nodeName == "BR")
+    if (event.type == "DOMNodeInserted" && event.target.nodeType == 3)
         document.body.innerHTML = "PASSED";
 }
 
@@ -12,7 +12,7 @@ function runTest() {
 
     window.layoutTestController.dumpAsText();
 
-    document.body.addEventListener("DOMNodeInserted", function() { foo() }, true);
+    document.addEventListener("DOMNodeInserted", function() { foo() }, true);
 
     // Select the element 'dragSource'.
     var selection = window.getSelection();
diff --git a/LayoutTests/fast/events/scoped/editing-commands-expected.txt b/LayoutTests/fast/events/scoped/editing-commands-expected.txt
new file mode 100644
index 0000000..8de3126
--- /dev/null
+++ b/LayoutTests/fast/events/scoped/editing-commands-expected.txt
@@ -0,0 +1,40 @@
+This test ensures WebKit does not fire DOM mutation events while execCommand is in progress.
+
+PASS: execCommand('BackColor', false, 'blue')
+PASS: execCommand('CreateLink', false, 'about:blank')
+PASS: execCommand('Delete', false, null)
+PASS: execCommand('FontName', false, 'Arial')
+PASS: execCommand('FontSize', false, '5')
+PASS: execCommand('FontSizeDelta', false, '5')
+PASS: execCommand('ForeColor', false, 'blue')
+PASS: execCommand('FormatBlock', false, 'pre')
+PASS: execCommand('ForwardDelete', false, null)
+PASS: execCommand('HiliteColor', false, 'red')
+PASS: execCommand('Indent', false, null)
+PASS: execCommand('InsertHTML', false, '<i>hello')
+PASS: execCommand('InsertHorizontalRule', false, null)
+PASS: execCommand('InsertImage', false, '../resources/abe.png')
+PASS: execCommand('InsertLineBreak', false, null)
+PASS: execCommand('InsertNewlineInQuotedContent', false, null)
+PASS: execCommand('InsertOrderedList', false, null)
+PASS: execCommand('InsertParagraph', false, null)
+PASS: execCommand('InsertText', false, 'webkit')
+PASS: execCommand('InsertUnorderedList', false, null)
+PASS: execCommand('Italic', false, null)
+PASS: execCommand('JustifyCenter', false, null)
+PASS: execCommand('JustifyFull', false, null)
+PASS: execCommand('JustifyLeft', false, null)
+PASS: execCommand('JustifyNone', false, null)
+PASS: execCommand('JustifyRight', false, null)
+PASS: execCommand('Outdent', false, null)
+PASS: execCommand('RemoveFormat', false, null)
+PASS: execCommand('Strikethrough', false, null)
+PASS: execCommand('Subscript', false, null)
+PASS: execCommand('Superscript', false, null)
+PASS: execCommand('Transpose', false, null)
+PASS: execCommand('Underline', false, null)
+PASS: execCommand('Unlink', false, null)
+
+
+DONE
+
diff --git a/LayoutTests/fast/events/scoped/editing-commands.html b/LayoutTests/fast/events/scoped/editing-commands.html
new file mode 100644
index 0000000..33b3dae
--- /dev/null
+++ b/LayoutTests/fast/events/scoped/editing-commands.html
@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>This test ensures WebKit does not fire DOM mutation events while execCommand is in progress.</p>
+<div id="test" contenteditable></div>
+<pre>
+<script>
+
+if (window.layoutTestController)
+    layoutTestController.dumpAsText();
+
+var commands = [
+    {name: 'BackColor', value: 'blue'},
+    {name: 'CreateLink', value: 'about:blank'},
+    {name: 'Delete', value: null},
+    {name: 'FontName', value: 'Arial'},
+    {name: 'FontSize', value: '5'},
+    {name: 'FontSizeDelta', value: '5'},
+    {name: 'ForeColor', value: 'blue'},
+    {name: 'FormatBlock', value: 'pre'},
+    {name: 'ForwardDelete', value: null},
+    {name: 'HiliteColor', value: 'red'},
+    {name: 'Indent', value: null},
+    {name: 'InsertHTML', value: "<i>hello</i>"},
+    {name: 'InsertHorizontalRule', value: null},
+    {name: 'InsertImage', value: '../resources/abe.png'},
+    {name: 'InsertLineBreak', value: null},
+    {name: 'InsertNewlineInQuotedContent', value: null},
+    {name: 'InsertOrderedList', value: null},
+    {name: 'InsertParagraph', value: null},
+    {name: 'InsertText', value: 'webkit'},
+    {name: 'InsertUnorderedList', value: null},
+    {name: 'Italic', value: null},
+    {name: 'JustifyCenter', value: null},
+    {name: 'JustifyFull', value: null},
+    {name: 'JustifyLeft', value: null},
+    {name: 'JustifyNone', value: null},
+    {name: 'JustifyRight', value: null},
+    {name: 'Outdent', value: null},
+    {name: 'RemoveFormat', value: null},
+    {name: 'Strikethrough', value: null},
+    {name: 'Subscript', value: null},
+    {name: 'Superscript', value: null},
+    {name: 'Transpose', value: null, selector: function (test) { window.getSelection().setPosition(test.firstChild, 1); }},
+    {name: 'Underline', value: null},
+    {name: 'Unlink', value: null},
+];
+
+var events = {
+    'DOMSubtreeModified': false,
+    'DOMNodeInserted': false,
+    'DOMNodeRemoved': false,
+    'DOMNodeRemovedFromDocument': false,
+    'DOMNodeInsertedIntoDocument': true, // this event can never be observed.
+    'DOMFocusIn': false,
+    'DOMFocusOut': false,
+    'focusin': false,
+    'focusout': false,
+};
+
+var log = [];
+var test = document.getElementById('test');
+
+function addEventListeners(node) {
+    for (var e in events) {
+        node.addEventListener(e, function (event) {
+            log.push(test.innerHTML);
+            events[event.type] = true;
+        }, false);
+    }
+}
+
+function isLogConsistent() {
+    for (var i= 1; i < log.length; i++) {
+        if (log[0] != log[i]) {
+            console.log(log);
+            return false;
+        }
+    }
+    return true;
+}
+
+addEventListeners(test);
+
+var initial = 'hello, <input type="text"><blockquote align="right"><u><a href="about:blank">world</a></u></blockquote>';
+for (var i = 0; i < commands.length; i++) {
+    test.innerHTML = initial;
+    if (i)
+        document.write("\n");
+
+    if (test.innerHTML != initial) {
+        document.write("FAIL: initial innerHTML didn't match");
+        continue;
+    }
+
+    if (commands[i].selector)
+        commands[i].selector(test);
+    else {    
+        document.getElementsByTagName('input')[0].focus();
+        window.getSelection().selectAllChildren(test);
+    }
+    addEventListeners(test.childNodes[2]);
+    log = []; // clear log
+    document.execCommand(commands[i].name, false, commands[i].value);
+
+    var quotedValue = commands[i].value ? "'" + commands[i].value.replace('<', '&lt;') + "'" : null;
+    var action = "execCommand('" + commands[i].name + "', false, " + quotedValue + ")";
+
+    if (test.innerHTML == initial || log.length <= 0)
+        document.write('FAIL: ' + action + ' made no change to the DOM.');
+    else if (!isLogConsistent())
+        document.write('FAIL: ' + action + ' dispatched events before finalizing the DOM tree.');
+    else
+        document.write('PASS: ' + action);
+}
+test.style.display = 'none';
+
+document.write('\n');
+for (var e in events) {
+    if (!events[e])
+        document.write('\nWARNING: ' + e + ' was never observed.');
+}
+
+document.write('\n\nDONE');
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/WebCore/Android.mk b/WebCore/Android.mk
index ce67406..04bea8f 100644
--- a/WebCore/Android.mk
+++ b/WebCore/Android.mk
@@ -165,6 +165,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
 	dom/QualifiedName.cpp \
 	dom/Range.cpp \
 	dom/RegisteredEventListener.cpp \
+	dom/ScopedEventQueue.cpp \
 	dom/ScriptableDocumentParser.cpp \
 	dom/ScriptElement.cpp \
 	dom/ScriptExecutionContext.cpp \
diff --git a/WebCore/CMakeLists.txt b/WebCore/CMakeLists.txt
index fc8f984..47b83cf 100644
--- a/WebCore/CMakeLists.txt
+++ b/WebCore/CMakeLists.txt
@@ -881,6 +881,7 @@ SET(WebCore_SOURCES
     dom/QualifiedName.cpp
     dom/Range.cpp
     dom/RegisteredEventListener.cpp
+    dom/ScopedEventQueue.cpp
     dom/ScriptableDocumentParser.cpp
     dom/ScriptElement.cpp
     dom/ScriptExecutionContext.cpp
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 19489a8..bbc485b 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,61 @@
+2010-12-09  Ryosuke Niwa  <rniwa at webkit.org>
+
+        Reviewed by Ojan Vafai.
+
+        Make DOM Mutation Events Asynchronous
+        https://bugs.webkit.org/show_bug.cgi?id=46936
+
+        Implemented DOM mutations events as scoped events. A scoped event is an event whose
+        dispatch is done via ScopedEventQueue. The behavior of the queue is controlled by
+        EventQueueScope objects (RAII idiom), which increments and decrements the scoping level
+        on its constructor and destructor respectively.
+
+        When the scoping level is 0 (initial level), scoped events are dispatched as soon as
+        they are enqueued and act like synchronous events. When the scoping level is greater than 0,
+        however, events are queued in ScopedEventQueue and their dispatches are delayed until
+        the scoping level goes back to 0 (by the destruction of EventQueueScope).
+
+        DOMSubtreeModified, DOMNodeInserted, DOMNodeRemoved, DOMNodeRemovedFromDocument,
+        DOMNodeInsertedIntoDocument, DOMFocusIn, DOMFocusOut, focusin, and focusout are treated as
+        scoped events, and a scope object is instantiated in EditCommand::apply to delay dispatches
+        of the events until the completion of each call of EditCommand::doApply.
+
+        Test: fast/events/mutation/execCommands.html
+
+        * Android.mk: Added ScopedEventQueue.cpp.
+        * CMakeLists.txt: Ditto.
+        * WebCore.pro: Ditto.
+        * GNUmakefile.am: Added ScopedEventQueue.cpp and ScopedEventQueue.h.
+        * WebCore.gypi:  Ditto.
+        * WebCore.vcproj/project.vcproj: Ditto.
+        * WebCore.xcodeproj/project.pbxproj: Ditto.
+        * dom/ContainerNode.cpp:
+        (WebCore::dispatchChildInsertionEvents): Calls dispatchScopedEvent.
+        (WebCore::dispatchChildRemovalEvents): Ditto.
+        * dom/DOMAllInOne.cpp: Added ScopedEventQueue.cpp.
+        * dom/Element.cpp:
+        (WebCore::Element::dispatchAttrRemovalEvent): Ditto. 
+        (WebCore::Element::dispatchAttrAdditionEvent): Ditto.
+        * dom/Node.cpp:
+        (WebCore::Node::dispatchScopedEvent): Added.
+        (WebCore::Node::dispatchSubtreeModifiedEvent): Calls dispatchScopedEvent.
+        * dom/Node.h:
+        * dom/ScopedEventQueue.cpp: Added.
+        (WebCore::ScopedEventQueue::initialize): Added.
+        (WebCore::ScopedEventQueue::enqueueEvent): Added.
+        (WebCore::ScopedEventQueue::dispatchAllEvents): Added.
+        (WebCore::ScopedEventQueue::dispatchEvent): Added.
+        (WebCore::ScopedEventQueue::instance): Added.
+        (WebCore::ScopedEventQueue::incrementScopingLevel): Added.
+        (WebCore::ScopedEventQueue::decrementScopingLevel): Added.
+        * dom/ScopedEventQueue.h: Added.
+        (WebCore::ScopedEventQueue::~ScopedEventQueue): Added.
+        (WebCore::ScopedEventQueue::ScopedEventQueue): Added.
+        (WebCore::EventQueueScope::EventQueueScope): Added.
+        (WebCore::EventQueueScope::~EventQueueScope): Added.
+        * editing/EditCommand.cpp:
+        (WebCore::EditCommand::apply): Instantiates EventQueueScope.
+
 2010-12-09  Sheriff Bot  <webkit.review.bot at gmail.com>
 
         Unreviewed, rolling out r73684.
diff --git a/WebCore/GNUmakefile.am b/WebCore/GNUmakefile.am
index 79754a5..25c24e9 100644
--- a/WebCore/GNUmakefile.am
+++ b/WebCore/GNUmakefile.am
@@ -1268,6 +1268,8 @@ webcore_sources += \
 	WebCore/dom/RawDataDocumentParser.h \
 	WebCore/dom/RegisteredEventListener.cpp \
 	WebCore/dom/RegisteredEventListener.h \
+	WebCore/dom/ScopedEventQueue.cpp \
+	WebCore/dom/ScopedEventQueue.h \
 	WebCore/dom/ScriptableDocumentParser.cpp \
 	WebCore/dom/ScriptableDocumentParser.h \
 	WebCore/dom/ScriptElement.cpp \
diff --git a/WebCore/WebCore.gypi b/WebCore/WebCore.gypi
index 48aa06e..327c623 100644
--- a/WebCore/WebCore.gypi
+++ b/WebCore/WebCore.gypi
@@ -1318,6 +1318,8 @@
             'dom/RawDataDocumentParser.h',
             'dom/RegisteredEventListener.cpp',
             'dom/RegisteredEventListener.h',
+            'dom/ScopedEventQueue.cpp',
+            'dom/ScopedEventQueue.h',
             'dom/ScriptableDocumentParser.cpp',
             'dom/ScriptableDocumentParser.h',
             'dom/ScriptElement.cpp',
diff --git a/WebCore/WebCore.pro b/WebCore/WebCore.pro
index 0eaff5a..5f394ed 100644
--- a/WebCore/WebCore.pro
+++ b/WebCore/WebCore.pro
@@ -762,6 +762,7 @@ SOURCES += \
     dom/Range.cpp \
     dom/RawDataDocumentParser.h \
     dom/RegisteredEventListener.cpp \
+    dom/ScopedEventQueue.cpp \
     dom/ScriptableDocumentParser.cpp \
     dom/ScriptElement.cpp \
     dom/ScriptExecutionContext.cpp \
diff --git a/WebCore/WebCore.vcproj/WebCore.vcproj b/WebCore/WebCore.vcproj/WebCore.vcproj
index 30051de..4a1e084 100755
--- a/WebCore/WebCore.vcproj/WebCore.vcproj
+++ b/WebCore/WebCore.vcproj/WebCore.vcproj
@@ -45314,6 +45314,62 @@
 				>
 			</File>
 			<File
+				RelativePath="..\dom\ScopedEventQueue.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="Release_LTCG|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\dom\ScopedEventQueue.h"
+				>
+			</File>
+			<File
 				RelativePath="..\dom\ScriptableDocumentParser.cpp"
 				>
 				<FileConfiguration
diff --git a/WebCore/WebCore.xcodeproj/project.pbxproj b/WebCore/WebCore.xcodeproj/project.pbxproj
index 7a1b190..f36a2a6 100644
--- a/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -3029,6 +3029,8 @@
 		9B417065125662B3006B28FC /* ApplyBlockElementCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9B417063125662B3006B28FC /* ApplyBlockElementCommand.cpp */; };
 		9BAB6C6C12550631001626D4 /* EditingStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BAB6C6A12550631001626D4 /* EditingStyle.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9BAB6C6D12550631001626D4 /* EditingStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9BAB6C6B12550631001626D4 /* EditingStyle.cpp */; };
+		9BD0BF9312A42BF50072FD43 /* ScopedEventQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BD0BF9112A42BF50072FD43 /* ScopedEventQueue.h */; };
+		9BD0BF9412A42BF50072FD43 /* ScopedEventQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9BD0BF9212A42BF50072FD43 /* ScopedEventQueue.cpp */; };
 		9F0D6B2E121BFEBA006C0288 /* InspectorProfilerAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9F0D6B2C121BFEBA006C0288 /* InspectorProfilerAgent.cpp */; };
 		9F0D6B2F121BFEBA006C0288 /* InspectorProfilerAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F0D6B2D121BFEBA006C0288 /* InspectorProfilerAgent.h */; };
 		9F3B947E12241758005304E7 /* ScriptHeapSnapshot.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F3B947D12241758005304E7 /* ScriptHeapSnapshot.h */; };
@@ -9341,6 +9343,8 @@
 		9B417063125662B3006B28FC /* ApplyBlockElementCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ApplyBlockElementCommand.cpp; sourceTree = "<group>"; };
 		9BAB6C6A12550631001626D4 /* EditingStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditingStyle.h; sourceTree = "<group>"; };
 		9BAB6C6B12550631001626D4 /* EditingStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditingStyle.cpp; sourceTree = "<group>"; };
+		9BD0BF9112A42BF50072FD43 /* ScopedEventQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScopedEventQueue.h; sourceTree = "<group>"; };
+		9BD0BF9212A42BF50072FD43 /* ScopedEventQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScopedEventQueue.cpp; sourceTree = "<group>"; };
 		9F0D6B2C121BFEBA006C0288 /* InspectorProfilerAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorProfilerAgent.cpp; sourceTree = "<group>"; };
 		9F0D6B2D121BFEBA006C0288 /* InspectorProfilerAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorProfilerAgent.h; sourceTree = "<group>"; };
 		9F3B947D12241758005304E7 /* ScriptHeapSnapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptHeapSnapshot.h; sourceTree = "<group>"; };
@@ -18860,6 +18864,8 @@
 				A84D827B11D333ED00972990 /* RawDataDocumentParser.h */,
 				85031B350A44EFC700F992E0 /* RegisteredEventListener.cpp */,
 				85031B360A44EFC700F992E0 /* RegisteredEventListener.h */,
+				9BD0BF9212A42BF50072FD43 /* ScopedEventQueue.cpp */,
+				9BD0BF9112A42BF50072FD43 /* ScopedEventQueue.h */,
 				A84D82C011D3474800972990 /* ScriptableDocumentParser.cpp */,
 				A84D82BF11D3474800972990 /* ScriptableDocumentParser.h */,
 				08A484750E5272C500C3FE76 /* ScriptElement.cpp */,
@@ -21469,6 +21475,7 @@
 				5DFE8F570D16477C0076E937 /* ScheduledAction.h in Headers */,
 				1CEFC9B90D78DC8C007D2579 /* SchedulePair.h in Headers */,
 				5162C7F511F77EFB00612EFE /* SchemeRegistry.h in Headers */,
+				9BD0BF9312A42BF50072FD43 /* ScopedEventQueue.h in Headers */,
 				BCEC01BE0C274DAC009F4EC9 /* Screen.h in Headers */,
 				A84D82C111D3474800972990 /* ScriptableDocumentParser.h in Headers */,
 				F39BE95C12673BF400E0A674 /* ScriptArguments.h in Headers */,
@@ -24239,6 +24246,7 @@
 				1CEFC9BA0D78DC8C007D2579 /* SchedulePair.cpp in Sources */,
 				1CE24F970D7CAF0E007E04C2 /* SchedulePairMac.mm in Sources */,
 				5162C7F411F77EFB00612EFE /* SchemeRegistry.cpp in Sources */,
+				9BD0BF9412A42BF50072FD43 /* ScopedEventQueue.cpp in Sources */,
 				BCEC01BD0C274DAC009F4EC9 /* Screen.cpp in Sources */,
 				A84D82C211D3474800972990 /* ScriptableDocumentParser.cpp in Sources */,
 				F39BE95B12673BF400E0A674 /* ScriptArguments.cpp in Sources */,
diff --git a/WebCore/dom/ContainerNode.cpp b/WebCore/dom/ContainerNode.cpp
index e158828..645768d 100644
--- a/WebCore/dom/ContainerNode.cpp
+++ b/WebCore/dom/ContainerNode.cpp
@@ -1027,12 +1027,12 @@ static void dispatchChildInsertionEvents(Node* child)
     RefPtr<Document> document = child->document();
 
     if (c->parentNode() && document->hasListenerType(Document::DOMNODEINSERTED_LISTENER))
-        c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode()));
+        c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode()));
 
     // dispatch the DOMNodeInsertedIntoDocument event to all descendants
     if (c->inDocument() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) {
         for (; c; c = c->traverseNextNode(child))
-            c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false));
+            c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false));
     }
 }
 
@@ -1049,12 +1049,12 @@ static void dispatchChildRemovalEvents(Node* child)
 
     // dispatch pre-removal mutation events
     if (c->parentNode() && document->hasListenerType(Document::DOMNODEREMOVED_LISTENER))
-        c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, c->parentNode()));
+        c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, c->parentNode()));
 
     // dispatch the DOMNodeRemovedFromDocument event to all descendants
     if (c->inDocument() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) {
         for (; c; c = c->traverseNextNode(child))
-            c->dispatchEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false));
+            c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false));
     }
 }
 
diff --git a/WebCore/dom/DOMAllInOne.cpp b/WebCore/dom/DOMAllInOne.cpp
index 2f3510d..dc4e39b 100644
--- a/WebCore/dom/DOMAllInOne.cpp
+++ b/WebCore/dom/DOMAllInOne.cpp
@@ -100,6 +100,7 @@
 #include "ProgressEvent.cpp"
 #include "Range.cpp"
 #include "RegisteredEventListener.cpp"
+#include "ScopedEventQueue.cpp"
 #include "ScriptElement.cpp"
 #include "ScriptExecutionContext.cpp"
 #include "ScriptableDocumentParser.cpp"
diff --git a/WebCore/dom/Element.cpp b/WebCore/dom/Element.cpp
index 30d239b..8e633aa 100644
--- a/WebCore/dom/Element.cpp
+++ b/WebCore/dom/Element.cpp
@@ -1218,7 +1218,7 @@ void Element::dispatchAttrRemovalEvent(Attribute*)
     if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER))
         return;
     ExceptionCode ec = 0;
-    dispatchEvent(MutationEvent::create(DOMAttrModifiedEvent, true, attr, attr->value(),
+    dispatchScopedEvent(MutationEvent::create(DOMAttrModifiedEvent, true, attr, attr->value(),
         attr->value(), document()->attrName(attr->id()), MutationEvent::REMOVAL), ec);
 #endif
 }
@@ -1231,7 +1231,7 @@ void Element::dispatchAttrAdditionEvent(Attribute*)
     if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER))
         return;
     ExceptionCode ec = 0;
-    dispatchEvent(MutationEvent::create(DOMAttrModifiedEvent, true, attr, attr->value(),
+    dispatchScopedEvent(MutationEvent::create(DOMAttrModifiedEvent, true, attr, attr->value(),
         attr->value(), document()->attrName(attr->id()), MutationEvent::ADDITION), ec);
 #endif
 }
diff --git a/WebCore/dom/Node.cpp b/WebCore/dom/Node.cpp
index 564be32..81a642b 100644
--- a/WebCore/dom/Node.cpp
+++ b/WebCore/dom/Node.cpp
@@ -70,6 +70,7 @@
 #include "ProgressEvent.h"
 #include "RegisteredEventListener.h"
 #include "RenderBox.h"
+#include "ScopedEventQueue.h"
 #include "ScriptController.h"
 #include "SelectorNodeList.h"
 #include "StaticNodeList.h"
@@ -2579,6 +2580,14 @@ bool Node::dispatchEvent(PassRefPtr<Event> prpEvent)
     return dispatchGenericEvent(event.release());
 }
 
+void Node::dispatchScopedEvent(PassRefPtr<Event> event)
+{
+    // We need to set the target here because it can go away by the time we actually fire the event.
+    event->setTarget(eventTargetRespectingSVGTargetRules(this));
+
+    ScopedEventQueue::instance()->enqueueEvent(event);
+}
+
 static const EventContext* topEventContext(const Vector<EventContext>& ancestors)
 {
     return ancestors.isEmpty() ? 0 : &ancestors.last();
@@ -2693,7 +2702,7 @@ void Node::dispatchSubtreeModifiedEvent()
     if (!document()->hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER))
         return;
 
-    dispatchEvent(MutationEvent::create(eventNames().DOMSubtreeModifiedEvent, true));
+    dispatchScopedEvent(MutationEvent::create(eventNames().DOMSubtreeModifiedEvent, true));
 }
 
 void Node::dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr<Event> underlyingEvent)
@@ -2703,10 +2712,10 @@ void Node::dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr
            eventType == eventNames().DOMFocusInEvent || eventType == eventNames().DOMFocusOutEvent || eventType == eventNames().DOMActivateEvent);
     
     bool cancelable = eventType == eventNames().DOMActivateEvent;
-    
+
     RefPtr<UIEvent> event = UIEvent::create(eventType, true, cancelable, document()->defaultView(), detail);
     event->setUnderlyingEvent(underlyingEvent);
-    dispatchEvent(event.release());
+    dispatchScopedEvent(event.release());
 }
 
 bool Node::dispatchKeyEvent(const PlatformKeyboardEvent& key)
diff --git a/WebCore/dom/Node.h b/WebCore/dom/Node.h
index 1c5c5c4..0881f08 100644
--- a/WebCore/dom/Node.h
+++ b/WebCore/dom/Node.h
@@ -520,7 +520,8 @@ public:
     virtual void postDispatchEventHandler(Event*, void* /*dataFromPreDispatch*/) { }
 
     using EventTarget::dispatchEvent;
-    virtual bool dispatchEvent(PassRefPtr<Event>);
+    bool dispatchEvent(PassRefPtr<Event>);
+    void dispatchScopedEvent(PassRefPtr<Event>);
 
     bool dispatchGenericEvent(PassRefPtr<Event>);
     virtual void handleLocalEvents(Event*);
diff --git a/WebCore/dom/ScopedEventQueue.cpp b/WebCore/dom/ScopedEventQueue.cpp
new file mode 100644
index 0000000..680d82d
--- /dev/null
+++ b/WebCore/dom/ScopedEventQueue.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 "ScopedEventQueue.h"
+
+#include "Event.h"
+#include "EventTarget.h"
+
+namespace WebCore {
+
+ScopedEventQueue* ScopedEventQueue::s_instance = 0;
+
+ScopedEventQueue::ScopedEventQueue()
+    : m_scopingLevel(0)
+{
+}
+
+ScopedEventQueue::~ScopedEventQueue()
+{
+    ASSERT(!m_scopingLevel);
+    ASSERT(!m_queuedEvents.size());
+}
+
+void ScopedEventQueue::initialize()
+{
+    ASSERT(!s_instance);
+    OwnPtr<ScopedEventQueue> instance = adoptPtr(new ScopedEventQueue);
+    s_instance = instance.leakPtr();
+}
+
+void ScopedEventQueue::enqueueEvent(PassRefPtr<Event> event)
+{
+    if (m_scopingLevel)
+        m_queuedEvents.append(event);
+    else
+        dispatchEvent(event);
+}
+
+void ScopedEventQueue::dispatchAllEvents()
+{
+    Vector<RefPtr<Event> > queuedEvents;
+    queuedEvents.swap(m_queuedEvents);
+
+    for (size_t i = 0; i < queuedEvents.size(); i++)
+        dispatchEvent(queuedEvents[i].release());
+}
+
+void ScopedEventQueue::dispatchEvent(PassRefPtr<Event> event) const
+{
+    RefPtr<EventTarget> eventTarget = event->target();
+    eventTarget->dispatchEvent(event);
+}
+
+ScopedEventQueue* ScopedEventQueue::instance()
+{
+    if (!s_instance)
+        initialize();
+
+    return s_instance;
+}
+
+void ScopedEventQueue::incrementScopingLevel()
+{
+    m_scopingLevel++;
+}
+
+void ScopedEventQueue::decrementScopingLevel()
+{
+    ASSERT(m_scopingLevel);
+    m_scopingLevel--;
+    if (!m_scopingLevel)
+        dispatchAllEvents();
+}
+
+}
diff --git a/WebCore/dom/ScopedEventQueue.h b/WebCore/dom/ScopedEventQueue.h
new file mode 100644
index 0000000..52415d4
--- /dev/null
+++ b/WebCore/dom/ScopedEventQueue.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 ScopedEventQueue_h
+#define ScopedEventQueue_h
+
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Event;
+
+class ScopedEventQueue {
+    WTF_MAKE_NONCOPYABLE(ScopedEventQueue);
+
+public:
+    ~ScopedEventQueue();
+
+    void enqueueEvent(PassRefPtr<Event>);
+    void dispatchAllEvents();
+    static ScopedEventQueue* instance();
+
+    void incrementScopingLevel();
+    void decrementScopingLevel();
+
+private:
+    ScopedEventQueue();
+    static void initialize();
+    void dispatchEvent(PassRefPtr<Event>) const;
+
+    Vector<RefPtr<Event> > m_queuedEvents;
+    unsigned m_scopingLevel;
+
+    static ScopedEventQueue* s_instance;
+};
+
+class EventQueueScope {
+    WTF_MAKE_NONCOPYABLE(EventQueueScope);
+
+public:
+    EventQueueScope() { ScopedEventQueue::instance()->incrementScopingLevel(); }
+    ~EventQueueScope() { ScopedEventQueue::instance()->decrementScopingLevel(); }
+};
+
+}
+
+#endif // ScopedEventQueue_h
diff --git a/WebCore/editing/EditCommand.cpp b/WebCore/editing/EditCommand.cpp
index 5f0cfd4..1b4451d 100644
--- a/WebCore/editing/EditCommand.cpp
+++ b/WebCore/editing/EditCommand.cpp
@@ -33,6 +33,7 @@
 #include "Element.h"
 #include "EventNames.h"
 #include "Frame.h"
+#include "ScopedEventQueue.h"
 #include "SelectionController.h"
 #include "VisiblePosition.h"
 #include "htmlediting.h"
@@ -84,10 +85,13 @@ void EditCommand::apply()
     if (isTopLevelCommand())
         updateLayout();
 
-    DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController();
-    deleteButtonController->disable();
-    doApply();
-    deleteButtonController->enable();
+    {
+        EventQueueScope scope;
+        DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController();
+        deleteButtonController->disable();
+        doApply();
+        deleteButtonController->enable();
+    }
 
     if (isTopLevelCommand()) {
         // Only need to call appliedEditing for top-level commands, and TypingCommands do it on their

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list