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;
};
}