Title: [98910] trunk
Revision
98910
Author
ad...@chromium.org
Date
2011-10-31 16:46:50 -0700 (Mon, 31 Oct 2011)

Log Message

[MutationObservers] Support characterDataOldValue for characterData mutations
https://bugs.webkit.org/show_bug.cgi?id=70862

Reviewed by Ojan Vafai.

Source/WebCore:

* dom/CharacterData.cpp:
(WebCore::hasOldValue):
(WebCore::isOldValueRequested):
(WebCore::CharacterData::dispatchModifiedEvent):
* dom/MutationRecord.cpp:
(WebCore::MutationRecord::createCharacterData):
* dom/MutationRecord.h:

LayoutTests:

Added oldValue test cases to existing characterData tests.

* fast/mutation/observe-characterdata-expected.txt:
* fast/mutation/observe-characterdata.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (98909 => 98910)


--- trunk/LayoutTests/ChangeLog	2011-10-31 23:43:58 UTC (rev 98909)
+++ trunk/LayoutTests/ChangeLog	2011-10-31 23:46:50 UTC (rev 98910)
@@ -1,3 +1,15 @@
+2011-10-27  Adam Klein  <ad...@chromium.org>
+
+        [MutationObservers] Support characterDataOldValue for characterData mutations
+        https://bugs.webkit.org/show_bug.cgi?id=70862
+
+        Reviewed by Ojan Vafai.
+
+        Added oldValue test cases to existing characterData tests.
+
+        * fast/mutation/observe-characterdata-expected.txt:
+        * fast/mutation/observe-characterdata.html:
+
 2011-10-31  John Gregg  <john...@google.com>
 
         Chromium rebaselines, unreviewed.

Modified: trunk/LayoutTests/fast/mutation/observe-characterdata-expected.txt (98909 => 98910)


--- trunk/LayoutTests/fast/mutation/observe-characterdata-expected.txt	2011-10-31 23:43:58 UTC (rev 98909)
+++ trunk/LayoutTests/fast/mutation/observe-characterdata-expected.txt	2011-10-31 23:46:50 UTC (rev 98910)
@@ -33,6 +33,28 @@
 PASS mutations[0].type is "characterData"
 PASS mutations[1].type is "attributes"
 
+Testing that oldValue is returned when requested.
+PASS mutations.length is 2
+PASS mutations[0].type is "characterData"
+PASS mutations[0].target is charDataNode
+PASS mutations[0].oldValue is "foo"
+PASS mutations[1].type is "characterData"
+PASS mutations[1].target is charDataNode
+PASS mutations[1].oldValue is "bar"
+
+Testing that oldValue is delivered as requested (or not).
+PASS mutationsWithOldValue.length is 1
+PASS mutationsWithOldValue[0].type is "characterData"
+PASS mutationsWithOldValue[0].oldValue is "foo"
+PASS mutations.length is 1
+PASS mutations[0].type is "characterData"
+PASS mutations[0].oldValue is null
+
+An observer with multiple observations will get characterDataOldValue if any entries request it.
+PASS mutations.length is 1
+PASS mutations[0].type is "characterData"
+PASS mutations[0].oldValue is "foo"
+
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/fast/mutation/observe-characterdata.html (98909 => 98910)


--- trunk/LayoutTests/fast/mutation/observe-characterdata.html	2011-10-31 23:43:58 UTC (rev 98909)
+++ trunk/LayoutTests/fast/mutation/observe-characterdata.html	2011-10-31 23:46:50 UTC (rev 98910)
@@ -12,6 +12,7 @@
 window.jsTestIsAsync = true;
 var mutations;
 var mutations2;
+var mutationsWithOldValue;
 var calls;
 var charDataNode;
 
@@ -191,7 +192,121 @@
     start();
 }
 
-var tests = [testBasic, testWrongType, testMultipleObservers, testOrderingWrtDOMSubtreeModified];
+function testOldValue() {
+    var div;
+    var observer;
+
+    function start() {
+        debug('Testing that oldValue is returned when requested.');
+        mutations = null;
+        div = document.createElement('div');
+        div.textContent = 'foo';
+        charDataNode = div.firstChild;
+        observer = new WebKitMutationObserver(function(mutations) {
+            window.mutations = mutations;
+        });
+        observer.observe(charDataNode, {characterData: true, characterDataOldValue: true});
+        charDataNode.textContent = 'bar';
+        charDataNode.textContent = 'baz';
+        setTimeout(finish, 0);
+    }
+
+    function finish() {
+        shouldBe('mutations.length', '2');
+        shouldBe('mutations[0].type', '"characterData"');
+        shouldBe('mutations[0].target', 'charDataNode');
+        shouldBe('mutations[0].oldValue', '"foo"');
+        shouldBe('mutations[1].type', '"characterData"');
+        shouldBe('mutations[1].target', 'charDataNode');
+        shouldBe('mutations[1].oldValue', '"bar"');
+        observer.disconnect();
+        debug('');
+        runNextTest();
+    }
+
+    start();
+}
+
+function testOldValueAsRequested() {
+    var div;
+    var observerWithOldValue;
+    var observer;
+
+    function start() {
+        debug('Testing that oldValue is delivered as requested (or not).');
+        mutations = null;
+        mutationsWithOldValue = null;
+        div = document.createElement('div');
+        div.textContent = 'foo';
+        charDataNode = div.firstChild;
+        observerWithOldValue = new WebKitMutationObserver(function(mutations) {
+            window.mutationsWithOldValue = mutations;
+        });
+        observer = new WebKitMutationObserver(function(mutations) {
+            window.mutations = mutations;
+        });
+        observerWithOldValue.observe(charDataNode, {characterData: true, characterDataOldValue: true});
+        observer.observe(charDataNode, {characterData: true});
+        charDataNode.textContent = 'bar';
+        setTimeout(finish, 0);
+    }
+
+    function finish() {
+        shouldBe('mutationsWithOldValue.length', '1');
+        shouldBe('mutationsWithOldValue[0].type', '"characterData"');
+        shouldBe('mutationsWithOldValue[0].oldValue', '"foo"');
+        shouldBe('mutations.length', '1');
+        shouldBe('mutations[0].type', '"characterData"');
+        shouldBe('mutations[0].oldValue', 'null');
+        observerWithOldValue.disconnect();
+        observer.disconnect();
+        debug('');
+        runNextTest();
+    }
+
+    start();
+}
+
+function testOldValueUnionMultipleObservations() {
+    var div;
+    var observer;
+
+    function start() {
+        debug('An observer with multiple observations will get characterDataOldValue if any entries request it.');
+        mutations = null;
+        div = document.createElement('div');
+        div.textContent = 'foo';
+        charDataNode = div.firstChild;
+        observer = new WebKitMutationObserver(function(mutations) {
+            window.mutations = mutations;
+        });
+        observer.observe(div, {characterData: true, characterDataOldValue: true, subtree: true});
+        observer.observe(charDataNode, {characterData: true});
+        charDataNode.textContent = 'bar';
+        setTimeout(finish, 0);
+    }
+
+    function finish() {
+        shouldBe('mutations.length', '1');
+        shouldBe('mutations[0].type', '"characterData"');
+        shouldBe('mutations[0].oldValue', '"foo"');
+        observer.disconnect();
+        debug('');
+        runNextTest();
+    }
+
+    start();
+}
+
+var tests = [
+    testBasic,
+    testWrongType,
+    testMultipleObservers,
+    testOrderingWrtDOMSubtreeModified,
+    testOldValue,
+    testOldValueAsRequested,
+    testOldValueUnionMultipleObservations
+];
 var testIndex = 0;
 
 function runNextTest() {

Modified: trunk/Source/WebCore/ChangeLog (98909 => 98910)


--- trunk/Source/WebCore/ChangeLog	2011-10-31 23:43:58 UTC (rev 98909)
+++ trunk/Source/WebCore/ChangeLog	2011-10-31 23:46:50 UTC (rev 98910)
@@ -1,3 +1,18 @@
+2011-10-27  Adam Klein  <ad...@chromium.org>
+
+        [MutationObservers] Support characterDataOldValue for characterData mutations
+        https://bugs.webkit.org/show_bug.cgi?id=70862
+
+        Reviewed by Ojan Vafai.
+
+        * dom/CharacterData.cpp:
+        (WebCore::hasOldValue):
+        (WebCore::isOldValueRequested):
+        (WebCore::CharacterData::dispatchModifiedEvent):
+        * dom/MutationRecord.cpp:
+        (WebCore::MutationRecord::createCharacterData):
+        * dom/MutationRecord.h:
+
 2011-10-31  Sam Weinig  <s...@webkit.org>
 
         Remove need for virtual JSObject::unwrappedObject

Modified: trunk/Source/WebCore/dom/CharacterData.cpp (98909 => 98910)


--- trunk/Source/WebCore/dom/CharacterData.cpp	2011-10-31 23:43:58 UTC (rev 98909)
+++ trunk/Source/WebCore/dom/CharacterData.cpp	2011-10-31 23:46:50 UTC (rev 98910)
@@ -190,16 +190,52 @@
         toRenderText(renderer())->setTextWithOffset(m_data, offsetOfReplacedData, lengthOfReplacedData);
 }
 
+#if ENABLE(MUTATION_OBSERVERS)
+static inline bool hasOldValue(MutationObserverOptions options)
+{
+    return options & WebKitMutationObserver::CharacterDataOldValue;
+}
+
+static bool isOldValueRequested(const HashMap<WebKitMutationObserver*, MutationObserverOptions>& observers)
+{
+    for (HashMap<WebKitMutationObserver*, MutationObserverOptions>::const_iterator iter = observers.begin(); iter != observers.end(); ++iter) {
+        if (hasOldValue(iter->second))
+            return true;
+    }
+    return false;
+}
+
+static void enqueueCharacterDataMutationRecord(Node* node, const String& oldData)
+{
+    HashMap<WebKitMutationObserver*, MutationObserverOptions> observers;
+    node->getRegisteredMutationObserversOfType(observers, WebKitMutationObserver::CharacterData);
+    if (observers.isEmpty())
+        return;
+
+    // FIXME: Factor this logic out to avoid duplication with attributeOldValue.
+    RefPtr<MutationRecord> mutation = MutationRecord::createCharacterData(node, isOldValueRequested(observers) ? oldData : String());
+    RefPtr<MutationRecord> mutationWithNullOldValue;
+    for (HashMap<WebKitMutationObserver*, MutationObserverOptions>::iterator iter = observers.begin(); iter != observers.end(); ++iter) {
+        WebKitMutationObserver* observer = iter->first;
+        if (hasOldValue(iter->second)) {
+            observer->enqueueMutationRecord(mutation);
+            continue;
+        }
+        if (!mutationWithNullOldValue) {
+            if (mutation->oldValue().isNull())
+                mutationWithNullOldValue = mutation;
+            else
+                mutationWithNullOldValue = MutationRecord::createWithNullOldValue(mutation);
+        }
+        observer->enqueueMutationRecord(mutationWithNullOldValue);
+    }
+}
+#endif // ENABLE(MUTATION_OBSERVERS)
+
 void CharacterData::dispatchModifiedEvent(StringImpl* oldData)
 {
 #if ENABLE(MUTATION_OBSERVERS)
-    HashMap<WebKitMutationObserver*, MutationObserverOptions> observers;
-    getRegisteredMutationObserversOfType(observers, WebKitMutationObserver::CharacterData);
-    if (!observers.isEmpty()) {
-        RefPtr<MutationRecord> mutation = MutationRecord::createCharacterData(this);
-        for (HashMap<WebKitMutationObserver*, MutationObserverOptions>::iterator iter = observers.begin(); iter != observers.end(); ++iter)
-                iter->first->enqueueMutationRecord(mutation);
-    }
+    enqueueCharacterDataMutationRecord(this, oldData);
 #endif
     if (parentNode())
         parentNode()->childrenChanged();

Modified: trunk/Source/WebCore/dom/Element.cpp (98909 => 98910)


--- trunk/Source/WebCore/dom/Element.cpp	2011-10-31 23:43:58 UTC (rev 98909)
+++ trunk/Source/WebCore/dom/Element.cpp	2011-10-31 23:46:50 UTC (rev 98910)
@@ -638,6 +638,7 @@
     if (observers.isEmpty())
         return;
 
+    // FIXME: Factor this logic out to avoid duplication with characterDataOldValue.
     RefPtr<MutationRecord> mutation = MutationRecord::createAttributes(element, name, isOldValueRequested(observers) ? oldValue : nullAtom);
     RefPtr<MutationRecord> mutationWithNullOldValue;
     for (HashMap<WebKitMutationObserver*, MutationObserverOptions>::iterator iter = observers.begin(); iter != observers.end(); ++iter) {

Modified: trunk/Source/WebCore/dom/MutationRecord.cpp (98909 => 98910)


--- trunk/Source/WebCore/dom/MutationRecord.cpp	2011-10-31 23:43:58 UTC (rev 98909)
+++ trunk/Source/WebCore/dom/MutationRecord.cpp	2011-10-31 23:46:50 UTC (rev 98910)
@@ -95,16 +95,19 @@
 
 class CharacterDataRecord : public MutationRecord {
 public:
-    CharacterDataRecord(PassRefPtr<Node> target)
+    CharacterDataRecord(PassRefPtr<Node> target, const String& oldValue)
         : m_target(target)
+        , m_oldValue(oldValue)
     {
     }
 
 private:
     virtual const AtomicString& type() OVERRIDE;
     virtual Node* target() OVERRIDE { return m_target.get(); }
+    virtual String oldValue() OVERRIDE { return m_oldValue; }
 
     RefPtr<Node> m_target;
+    String m_oldValue;
 };
 
 class MutationRecordWithNullOldValue : public MutationRecord {
@@ -159,9 +162,9 @@
     return adoptRef(static_cast<MutationRecord*>(new AttributesRecord(target, name, oldValue)));
 }
 
-PassRefPtr<MutationRecord> MutationRecord::createCharacterData(PassRefPtr<Node> target)
+PassRefPtr<MutationRecord> MutationRecord::createCharacterData(PassRefPtr<Node> target, const String& oldValue)
 {
-    return adoptRef(static_cast<MutationRecord*>(new CharacterDataRecord(target)));
+    return adoptRef(static_cast<MutationRecord*>(new CharacterDataRecord(target, oldValue)));
 }
 
 PassRefPtr<MutationRecord> MutationRecord::createWithNullOldValue(PassRefPtr<MutationRecord> record)

Modified: trunk/Source/WebCore/dom/MutationRecord.h (98909 => 98910)


--- trunk/Source/WebCore/dom/MutationRecord.h	2011-10-31 23:43:58 UTC (rev 98909)
+++ trunk/Source/WebCore/dom/MutationRecord.h	2011-10-31 23:46:50 UTC (rev 98910)
@@ -48,7 +48,7 @@
 public:
     static PassRefPtr<MutationRecord> createChildList(PassRefPtr<Node> target, PassRefPtr<NodeList> added, PassRefPtr<NodeList> removed, PassRefPtr<Node> previousSibling, PassRefPtr<Node> nextSibling);
     static PassRefPtr<MutationRecord> createAttributes(PassRefPtr<Node> target, const QualifiedName&, const AtomicString& oldValue);
-    static PassRefPtr<MutationRecord> createCharacterData(PassRefPtr<Node> target);
+    static PassRefPtr<MutationRecord> createCharacterData(PassRefPtr<Node> target, const String& oldValue);
 
     static PassRefPtr<MutationRecord> createWithNullOldValue(PassRefPtr<MutationRecord>);
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to