Modified: trunk/LayoutTests/ChangeLog (97804 => 97805)
--- trunk/LayoutTests/ChangeLog 2011-10-18 23:06:31 UTC (rev 97804)
+++ trunk/LayoutTests/ChangeLog 2011-10-18 23:06:48 UTC (rev 97805)
@@ -1,3 +1,13 @@
+2011-10-18 Adam Klein <[email protected]>
+
+ [MutationObservers] Implement WebKitMutationObserver.observe for characterData changes
+ https://bugs.webkit.org/show_bug.cgi?id=68957
+
+ Reviewed by Ryosuke Niwa.
+
+ * fast/mutation/observe-characterdata-expected.txt: Added.
+ * fast/mutation/observe-characterdata.html: Added.
+
2011-10-18 Dirk Pranke <[email protected]>
Remove expectations for tests that are no longer failing.
Added: trunk/LayoutTests/fast/mutation/observe-characterdata-expected.txt (0 => 97805)
--- trunk/LayoutTests/fast/mutation/observe-characterdata-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/mutation/observe-characterdata-expected.txt 2011-10-18 23:06:48 UTC (rev 97805)
@@ -0,0 +1,39 @@
+Test WebKitMutationObserver.observe on CharacterData nodes
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Testing basic aspects of characterData observation.
+...can characterData changes be observed at all
+PASS mutations.length is 1
+PASS mutations[0].type is "characterData"
+PASS mutations[0].target is charDataNode
+...observer.disconnect() should prevent further delivery of mutations.
+PASS mutations is null
+...re-observing after disconnect works with the same observer.
+PASS mutations.length is 2
+PASS mutations[0].type is "characterData"
+PASS mutations[0].target is charDataNode
+PASS mutations[1].type is "characterData"
+PASS mutations[1].target is charDataNode
+
+Testing that observing without specifying "characterData" does not result in hearing about characterData changes.
+PASS mutations is null
+
+Testing that multiple observers can be registered to a given node and both receive mutations.
+PASS mutations.length is 1
+PASS mutations[0].type is "characterData"
+PASS mutations[0].target is charDataNode
+PASS mutations2.length is 1
+PASS mutations2[0].type is "characterData"
+PASS mutations2[0].target is charDataNode
+
+Testing mutation records are enqueued for characterData before DOMSubtreeModified is dispatched.
+PASS mutations.length is 2
+PASS mutations[0].type is "characterData"
+PASS mutations[1].type is "attributes"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/mutation/observe-characterdata.html (0 => 97805)
--- trunk/LayoutTests/fast/mutation/observe-characterdata.html (rev 0)
+++ trunk/LayoutTests/fast/mutation/observe-characterdata.html 2011-10-18 23:06:48 UTC (rev 97805)
@@ -0,0 +1,218 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href=""
+<script src=""
+<title></title>
+</head>
+<body>
+<p id=description></p>
+<div id="console"></div>
+<script>
+
+window.jsTestIsAsync = true;
+var mutations;
+var mutations2;
+var calls;
+var charDataNode;
+
+function testBasic() {
+ var div;
+ var observer;
+
+ function start() {
+ debug('Testing basic aspects of characterData observation.');
+
+ mutations = null;
+ div = document.createElement('div');
+ div.textContent = 'foo';
+ charDataNode = div.firstChild;
+ observer = new WebKitMutationObserver(function(m) {
+ mutations = m;
+ });
+
+ observer.observe(charDataNode, {characterData: true});
+ charDataNode.textContent = 'bar';
+ setTimeout(checkDisconnectAndMutate, 0);
+ }
+
+ function checkDisconnectAndMutate() {
+ debug('...can characterData changes be observed at all');
+
+ shouldBe('mutations.length', '1');
+ shouldBe('mutations[0].type', '"characterData"');
+ shouldBe('mutations[0].target', 'charDataNode');
+
+ mutations = null;
+ observer.disconnect();
+ charDataNode.textContent = 'baz';
+ setTimeout(checkNotDeliveredAndMutateMultiple, 0);
+ }
+
+ function checkNotDeliveredAndMutateMultiple() {
+ debug('...observer.disconnect() should prevent further delivery of mutations.');
+
+ shouldBe('mutations', 'null');
+ charDataNode = document.createComment();
+ observer.observe(charDataNode, { characterData: true });
+ charDataNode.textContent = 'foo';
+ charDataNode.textContent = 'bar';
+ setTimeout(finish);
+ }
+
+ function finish() {
+ debug('...re-observing after disconnect works with the same observer.');
+
+ shouldBe('mutations.length', '2');
+ shouldBe('mutations[0].type', '"characterData"');
+ shouldBe('mutations[0].target', 'charDataNode');
+ shouldBe('mutations[1].type', '"characterData"');
+ shouldBe('mutations[1].target', 'charDataNode');
+ observer.disconnect();
+ debug('');
+ runNextTest();
+ }
+
+ start();
+}
+
+function testWrongType() {
+ var div;
+ var observer;
+
+ function start() {
+ debug('Testing that observing without specifying "characterData" does not result in hearing about characterData changes.');
+
+ mutations = null;
+ div = document.createElement('div');
+ div.textContent = 'hello';
+ charDataNode = div.firstChild;
+ observer = new WebKitMutationObserver(function(m) {
+ mutations = m;
+ });
+
+ observer.observe(charDataNode, {childList: true, attributes: true});
+ charDataNode = 'goodbye';
+ setTimeout(finish, 0);
+ }
+
+ function finish() {
+ shouldBe('mutations', 'null');
+ observer.disconnect();
+ debug('');
+ runNextTest();
+ }
+
+ start();
+}
+
+function testMultipleObservers() {
+ var div;
+ var observer;
+ var observer2;
+
+ function start() {
+ debug('Testing that multiple observers can be registered to a given node and both receive mutations.');
+ mutations = null;
+ div = document.createElement('div');
+ div.textContent = 'foo';
+ charDataNode = div.firstChild;
+ observer = new WebKitMutationObserver(function(m) {
+ mutations = m;
+ });
+ observer2 = new WebKitMutationObserver(function(m) {
+ mutations2 = m;
+ });
+ observer.observe(charDataNode, {characterData: true});
+ observer2.observe(charDataNode, {characterData: true});
+ charDataNode.textContent = 'bar';
+ setTimeout(finish, 0);
+ }
+
+ function finish() {
+ shouldBe('mutations.length', '1');
+ shouldBe('mutations[0].type', '"characterData"');
+ shouldBe('mutations[0].target', 'charDataNode');
+ shouldBe('mutations2.length', '1');
+ shouldBe('mutations2[0].type', '"characterData"');
+ shouldBe('mutations2[0].target', 'charDataNode');
+ observer.disconnect();
+ observer2.disconnect();
+ debug('');
+ runNextTest();
+ }
+
+ start();
+}
+
+function testOrderingWrtDOMSubtreeModified() {
+ var div, div2, subDiv;
+ var observer;
+ var listener;
+
+ function start() {
+ debug('Testing mutation records are enqueued for characterData before DOMSubtreeModified is dispatched.');
+
+ mutations = null;
+ div = document.body.appendChild(document.createElement('div'));
+ div2 = document.body.appendChild(document.createElement('div'));
+
+ subDiv = div.appendChild(document.createElement('div'));
+ subDiv.textContent = 'foo';
+ charDataNode = subDiv.firstChild;
+
+ observer = new WebKitMutationObserver(function(m) {
+ mutations = m;
+ });
+
+ listener = function(e) {
+ div2.setAttribute('baz', 'bat');
+ }
+
+ div.addEventListener('DOMSubtreeModified', listener);
+ observer.observe(charDataNode, {characterData: true});
+ observer.observe(div2, {attributes: true});
+
+ charDataNode.textContent = 'bar';
+
+ setTimeout(finish, 0);
+ }
+
+ function finish() {
+ shouldBe('mutations.length', '2');
+ shouldBe('mutations[0].type', '"characterData"');
+ shouldBe('mutations[1].type', '"attributes"');
+ div.removeEventListener(listener);
+ document.body.removeChild(div);
+ observer.disconnect();
+ debug('');
+ runNextTest();
+ }
+
+ start();
+}
+
+var tests = [testBasic, testWrongType, testMultipleObservers, testOrderingWrtDOMSubtreeModified];
+var testIndex = 0;
+
+function runNextTest() {
+ if (testIndex < tests.length)
+ tests[testIndex++]();
+ else
+ finishJSTest();
+}
+
+description('Test WebKitMutationObserver.observe on CharacterData nodes');
+
+if (!window.WebKitMutationObserver)
+ testFailed('This test requires ENABLE(MUTATION_OBSERVERS)');
+else
+ runNextTest();
+
+var successfullyParsed = true;
+
+</script>
+<script src=""
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (97804 => 97805)
--- trunk/Source/WebCore/ChangeLog 2011-10-18 23:06:31 UTC (rev 97804)
+++ trunk/Source/WebCore/ChangeLog 2011-10-18 23:06:48 UTC (rev 97805)
@@ -1,3 +1,15 @@
+2011-10-18 Adam Klein <[email protected]>
+
+ [MutationObservers] Implement WebKitMutationObserver.observe for characterData changes
+ https://bugs.webkit.org/show_bug.cgi?id=68957
+
+ Reviewed by Ryosuke Niwa.
+
+ Test: fast/mutation/observe-characterdata.html
+
+ * dom/CharacterData.cpp:
+ (WebCore::CharacterData::dispatchModifiedEvent):
+
2011-10-18 Scott Byer <[email protected]>
Scroll animator tracing
Modified: trunk/Source/WebCore/dom/CharacterData.cpp (97804 => 97805)
--- trunk/Source/WebCore/dom/CharacterData.cpp 2011-10-18 23:06:31 UTC (rev 97804)
+++ trunk/Source/WebCore/dom/CharacterData.cpp 2011-10-18 23:06:48 UTC (rev 97805)
@@ -27,9 +27,11 @@
#include "ExceptionCode.h"
#include "InspectorInstrumentation.h"
#include "MutationEvent.h"
+#include "MutationRecord.h"
#include "NodeRenderingContext.h"
#include "RenderText.h"
#include "TextBreakIterator.h"
+#include "WebKitMutationObserver.h"
using namespace std;
@@ -190,6 +192,15 @@
void CharacterData::dispatchModifiedEvent(StringImpl* oldData)
{
+#if ENABLE(MUTATION_OBSERVERS)
+ Vector<WebKitMutationObserver*> observers;
+ registeredMutationObserversOfType(observers, WebKitMutationObserver::CharacterData);
+ if (!observers.isEmpty()) {
+ RefPtr<MutationRecord> mutation = MutationRecord::createCharacterData(this);
+ for (size_t i = 0; i < observers.size(); ++i)
+ observers[i]->enqueueMutationRecord(mutation);
+ }
+#endif
if (parentNode())
parentNode()->childrenChanged();
if (document()->hasListenerType(Document::DOMCHARACTERDATAMODIFIED_LISTENER))