Title: [110465] trunk
Revision
110465
Author
[email protected]
Date
2012-03-12 13:11:16 -0700 (Mon, 12 Mar 2012)

Log Message

[MutationObservers] Enforce a consistent order of MutationRecord delivery
https://bugs.webkit.org/show_bug.cgi?id=80549

Reviewed by Ojan Vafai.

Source/WebCore:

Mutations should be delivered in order of creation.

Tests: fast/mutation/create-during-delivery.html
       fast/mutation/delivery-order.html
       fast/mutation/mutate-during-delivery.html

* dom/WebKitMutationObserver.cpp:
(WebCore):
(WebCore::WebKitMutationObserver::ObserverLessThan::operator()): Functor for use with std::sort.
(WebCore::WebKitMutationObserver::create):
(WebCore::WebKitMutationObserver::WebKitMutationObserver):
(WebCore::WebKitMutationObserver::deliverAllMutations): Move observers into a sorted vector before delivery.
* dom/WebKitMutationObserver.h: Add a "priority" member which monotonically increases with each construction.

LayoutTests:

* fast/mutation/create-during-delivery-expected.txt: Added.
* fast/mutation/create-during-delivery.html: Added.
* fast/mutation/delivery-order.html: Added.
* fast/mutation/mutate-during-delivery-expected.txt: Added.
* fast/mutation/mutate-during-delivery.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (110464 => 110465)


--- trunk/LayoutTests/ChangeLog	2012-03-12 20:08:20 UTC (rev 110464)
+++ trunk/LayoutTests/ChangeLog	2012-03-12 20:11:16 UTC (rev 110465)
@@ -1,3 +1,16 @@
+2012-03-12  Adam Klein  <[email protected]>
+
+        [MutationObservers] Enforce a consistent order of MutationRecord delivery
+        https://bugs.webkit.org/show_bug.cgi?id=80549
+
+        Reviewed by Ojan Vafai.
+
+        * fast/mutation/create-during-delivery-expected.txt: Added.
+        * fast/mutation/create-during-delivery.html: Added.
+        * fast/mutation/delivery-order.html: Added.
+        * fast/mutation/mutate-during-delivery-expected.txt: Added.
+        * fast/mutation/mutate-during-delivery.html: Added.
+
 2012-03-12  Mike Lawther  <[email protected]>
 
         CSS3 calc: enable mixed percent/absolute for font

Added: trunk/LayoutTests/fast/mutation/create-during-delivery-expected.txt (0 => 110465)


--- trunk/LayoutTests/fast/mutation/create-during-delivery-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/mutation/create-during-delivery-expected.txt	2012-03-12 20:11:16 UTC (rev 110465)
@@ -0,0 +1,14 @@
+Test that MutationObservers created during delivery must wait for the next loop.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS order.length is 4
+PASS order[0] is 1
+PASS order[1] is 2
+PASS order[2] is 1
+PASS order[3] is 3
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/mutation/create-during-delivery.html (0 => 110465)


--- trunk/LayoutTests/fast/mutation/create-during-delivery.html	                        (rev 0)
+++ trunk/LayoutTests/fast/mutation/create-during-delivery.html	2012-03-12 20:11:16 UTC (rev 110465)
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<script src=""
+<script>
+window.jsTestIsAsync = true;
+
+description('Test that MutationObservers created during delivery must wait for the next loop.');
+function finish() {
+    shouldBe('order.length', '4');
+    shouldBe('order[0]', '1');
+    shouldBe('order[1]', '2');
+    shouldBe('order[2]', '1');
+    shouldBe('order[3]', '3');
+    finishJSTest();
+}
+
+var order = [];
+var div = document.createElement('div');
+
+var observer3;
+var observer1 = new WebKitMutationObserver(function(mutations) {
+    order.push(1);
+    if (!observer3) {
+        observer3 = new WebKitMutationObserver(function(mutations) {
+            order.push(3);
+        });
+        observer3.observe(div, {attributes: true});
+        div.setAttribute('foo', 'baz');
+    }
+});
+var observer2 = new WebKitMutationObserver(function(mutations) {
+    order.push(2);
+});
+
+observer1.observe(div, {attributes: true});
+observer2.observe(div, {attributes: true});
+div.setAttribute('foo', 'bar');
+setTimeout(finish, 0);
+</script>
+<script src=""

Added: trunk/LayoutTests/fast/mutation/delivery-order.html (0 => 110465)


--- trunk/LayoutTests/fast/mutation/delivery-order.html	                        (rev 0)
+++ trunk/LayoutTests/fast/mutation/delivery-order.html	2012-03-12 20:11:16 UTC (rev 110465)
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<script src=""
+<script>
+window.jsTestIsAsync = true;
+
+description('Test that MutationObservers are delivered to in order of creation.');
+function finish() {
+    shouldBe('order.length', '10');
+    shouldBe('order[0]', '0');
+    shouldBe('order[1]', '1');
+    shouldBe('order[2]', '2');
+    shouldBe('order[3]', '3');
+    shouldBe('order[4]', '4');
+    shouldBe('order[5]', '5');
+    shouldBe('order[6]', '6');
+    shouldBe('order[7]', '7');
+    shouldBe('order[8]', '8');
+    shouldBe('order[9]', '9');
+    finishJSTest();
+}
+
+var order = [];
+var observers = [];
+
+function setUpOrdering(num) {
+    observers.push(new WebKitMutationObserver(function(mutations) {
+        order.push(num);
+    }));
+}
+
+for (var i = 0; i < 10; ++i) {
+    setUpOrdering(i);
+}
+
+var div = document.createElement('div');
+observers[3].observe(div, {attributes: true});
+observers[2].observe(div, {characterData: true, subtree: true});
+observers[1].observe(div, {attributes: true});
+observers[7].observe(div, {childList: true});
+observers[4].observe(div, {attributes: true});
+observers[9].observe(div, {attributes: true});
+observers[0].observe(div, {childList: true});
+observers[5].observe(div, {attributes: true});
+observers[6].observe(div, {characterData: true, subtree: true});
+observers[8].observe(div, {attributes: true});
+div.setAttribute('foo', 'bar');
+div.appendChild(document.createTextNode('hello'));
+div.firstChild.textContent = 'goodbye';
+setTimeout(finish, 0);
+</script>
+<script src=""

Added: trunk/LayoutTests/fast/mutation/mutate-during-delivery-expected.txt (0 => 110465)


--- trunk/LayoutTests/fast/mutation/mutate-during-delivery-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/mutation/mutate-during-delivery-expected.txt	2012-03-12 20:11:16 UTC (rev 110465)
@@ -0,0 +1,13 @@
+Test that mutations during delivery do not interrupt delivery order.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS order.length is 3
+PASS order[0] is 1
+PASS order[1] is 3
+PASS order[2] is 2
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/mutation/mutate-during-delivery.html (0 => 110465)


--- trunk/LayoutTests/fast/mutation/mutate-during-delivery.html	                        (rev 0)
+++ trunk/LayoutTests/fast/mutation/mutate-during-delivery.html	2012-03-12 20:11:16 UTC (rev 110465)
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<script src=""
+<script>
+window.jsTestIsAsync = true;
+
+description('Test that mutations during delivery do not interrupt delivery order.');
+function finish() {
+    shouldBe('order.length', '3');
+    shouldBe('order[0]', '1');
+    shouldBe('order[1]', '3');
+    shouldBe('order[2]', '2');
+    finishJSTest();
+}
+
+var order = [];
+var div = document.createElement('div');
+
+var observer1 = new WebKitMutationObserver(function(mutations) {
+    order.push(1);
+    div.appendChild(document.createElement('span'));
+});
+var observer2 = new WebKitMutationObserver(function(mutations) {
+    order.push(2);
+});
+var observer3 = new WebKitMutationObserver(function(mutations) {
+    order.push(3);
+});
+
+observer1.observe(div, {attributes: true});
+observer2.observe(div, {childList: true});
+observer3.observe(div, {attributes: true});
+div.setAttribute('foo', 'bar');
+setTimeout(finish, 0);
+</script>
+<script src=""

Modified: trunk/Source/WebCore/ChangeLog (110464 => 110465)


--- trunk/Source/WebCore/ChangeLog	2012-03-12 20:08:20 UTC (rev 110464)
+++ trunk/Source/WebCore/ChangeLog	2012-03-12 20:11:16 UTC (rev 110465)
@@ -1,3 +1,24 @@
+2012-03-12  Adam Klein  <[email protected]>
+
+        [MutationObservers] Enforce a consistent order of MutationRecord delivery
+        https://bugs.webkit.org/show_bug.cgi?id=80549
+
+        Reviewed by Ojan Vafai.
+
+        Mutations should be delivered in order of creation.
+
+        Tests: fast/mutation/create-during-delivery.html
+               fast/mutation/delivery-order.html
+               fast/mutation/mutate-during-delivery.html
+
+        * dom/WebKitMutationObserver.cpp:
+        (WebCore):
+        (WebCore::WebKitMutationObserver::ObserverLessThan::operator()): Functor for use with std::sort.
+        (WebCore::WebKitMutationObserver::create):
+        (WebCore::WebKitMutationObserver::WebKitMutationObserver):
+        (WebCore::WebKitMutationObserver::deliverAllMutations): Move observers into a sorted vector before delivery.
+        * dom/WebKitMutationObserver.h: Add a "priority" member which monotonically increases with each construction.
+
 2012-03-12  Nat Duca  <[email protected]>
 
         [Chromium] Force compositeAndReadback through regular scheduling flow

Modified: trunk/Source/WebCore/dom/WebKitMutationObserver.cpp (110464 => 110465)


--- trunk/Source/WebCore/dom/WebKitMutationObserver.cpp	2012-03-12 20:08:20 UTC (rev 110464)
+++ trunk/Source/WebCore/dom/WebKitMutationObserver.cpp	2012-03-12 20:11:16 UTC (rev 110465)
@@ -40,18 +40,31 @@
 #include "MutationObserverRegistration.h"
 #include "MutationRecord.h"
 #include "Node.h"
-#include <wtf/ListHashSet.h>
+#include <algorithm>
+#include <wtf/HashSet.h>
 #include <wtf/MainThread.h>
+#include <wtf/Vector.h>
 
 namespace WebCore {
 
+static unsigned s_observerPriority = 0;
+
+struct WebKitMutationObserver::ObserverLessThan {
+    bool operator()(const RefPtr<WebKitMutationObserver>& lhs, const RefPtr<WebKitMutationObserver>& rhs)
+    {
+        return lhs->m_priority < rhs->m_priority;
+    }
+};
+
 PassRefPtr<WebKitMutationObserver> WebKitMutationObserver::create(PassRefPtr<MutationCallback> callback)
 {
+    ASSERT(isMainThread());
     return adoptRef(new WebKitMutationObserver(callback));
 }
 
 WebKitMutationObserver::WebKitMutationObserver(PassRefPtr<MutationCallback> callback)
     : m_callback(callback)
+    , m_priority(s_observerPriority++)
 {
 }
 
@@ -107,7 +120,7 @@
     m_registrations.remove(registration);
 }
 
-typedef ListHashSet<RefPtr<WebKitMutationObserver> > MutationObserverSet;
+typedef HashSet<RefPtr<WebKitMutationObserver> > MutationObserverSet;
 
 static MutationObserverSet& activeMutationObservers()
 {
@@ -145,10 +158,12 @@
     deliveryInProgress = true;
 
     while (!activeMutationObservers().isEmpty()) {
-        MutationObserverSet::iterator iter = activeMutationObservers().begin();
-        RefPtr<WebKitMutationObserver> observer = *iter;
-        activeMutationObservers().remove(iter);
-        observer->deliver();
+        Vector<RefPtr<WebKitMutationObserver> > observers;
+        copyToVector(activeMutationObservers(), observers);
+        activeMutationObservers().clear();
+        std::sort(observers.begin(), observers.end(), ObserverLessThan());
+        for (size_t i = 0; i < observers.size(); ++i)
+            observers[i]->deliver();
     }
 
     deliveryInProgress = false;

Modified: trunk/Source/WebCore/dom/WebKitMutationObserver.h (110464 => 110465)


--- trunk/Source/WebCore/dom/WebKitMutationObserver.h	2012-03-12 20:08:20 UTC (rev 110464)
+++ trunk/Source/WebCore/dom/WebKitMutationObserver.h	2012-03-12 20:11:16 UTC (rev 110465)
@@ -85,6 +85,8 @@
     void enqueueMutationRecord(PassRefPtr<MutationRecord>);
 
 private:
+    struct ObserverLessThan;
+
     WebKitMutationObserver(PassRefPtr<MutationCallback>);
     void deliver();
 
@@ -93,6 +95,7 @@
     RefPtr<MutationCallback> m_callback;
     Vector<RefPtr<MutationRecord> > m_records;
     HashSet<MutationObserverRegistration*> m_registrations;
+    unsigned m_priority;
 };
 
 }
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to