- Revision
- 115897
- Author
- ad...@chromium.org
- Date
- 2012-05-02 15:04:15 -0700 (Wed, 02 May 2012)
Log Message
Childlist mutations in shadow DOM should be observable with MutationObservers
https://bugs.webkit.org/show_bug.cgi?id=85402
Reviewed by Ojan Vafai.
Source/WebCore:
Though Mutation Events are not supported in Shadow DOM,
MutationObservers are supposed to be. Due to a misplacement of the
ChildListMutationScope, they were erroneously getting skipped.
This patch moves code around to properly notify when childlist are
mutated in shadow DOM and covers that change with a new test.
Test: fast/mutation/shadow-dom.html
* dom/ContainerNode.cpp:
(WebCore::willRemoveChild): Handle notification of removal directly.
(WebCore::willRemoveChildren): ditto.
(WebCore::dispatchChildInsertionEvents): Remove notification of insertion.
(WebCore::dispatchChildRemovalEvents): Remove notification of removal.
(WebCore::updateTreeAfterInsertion): Handle notification of insertion directly.
LayoutTests:
Added test covering childList mutations as well as attribute and
characterData mutations (these were already working).
* fast/mutation/shadow-dom-expected.txt: Added.
* fast/mutation/shadow-dom.html: Added.
Modified Paths
Added Paths
Diff
Modified: trunk/LayoutTests/ChangeLog (115896 => 115897)
--- trunk/LayoutTests/ChangeLog 2012-05-02 22:01:37 UTC (rev 115896)
+++ trunk/LayoutTests/ChangeLog 2012-05-02 22:04:15 UTC (rev 115897)
@@ -1,3 +1,16 @@
+2012-05-02 Adam Klein <ad...@chromium.org>
+
+ Childlist mutations in shadow DOM should be observable with MutationObservers
+ https://bugs.webkit.org/show_bug.cgi?id=85402
+
+ Reviewed by Ojan Vafai.
+
+ Added test covering childList mutations as well as attribute and
+ characterData mutations (these were already working).
+
+ * fast/mutation/shadow-dom-expected.txt: Added.
+ * fast/mutation/shadow-dom.html: Added.
+
2012-05-02 Eric Carlson <eric.carl...@apple.com>
Crash in WebCore::TextTrackList::remove
Added: trunk/LayoutTests/fast/mutation/shadow-dom-expected.txt (0 => 115897)
--- trunk/LayoutTests/fast/mutation/shadow-dom-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/mutation/shadow-dom-expected.txt 2012-05-02 22:04:15 UTC (rev 115897)
@@ -0,0 +1,18 @@
+Test that MutationObservers operate in Shadow DOM
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Mutations in shadow DOM should have been observed:
+PASS mutations.length is 4
+PASS mutations[0].type is "attributes"
+PASS mutations[1].type is "childList"
+PASS mutations[2].type is "characterData"
+PASS mutations[3].type is "childList"
+
+Observing from outside shadow DOM should not see mutations in the shadow:
+PASS mutations is null
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/mutation/shadow-dom.html (0 => 115897)
--- trunk/LayoutTests/fast/mutation/shadow-dom.html (rev 0)
+++ trunk/LayoutTests/fast/mutation/shadow-dom.html 2012-05-02 22:04:15 UTC (rev 115897)
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<body>
+<input type="range">
+<script src=""
+<script>
+description('Test that MutationObservers operate in Shadow DOM');
+
+function doTest() {
+ function mutate(elt) {
+ elt.setAttribute('data-foo', 'bar');
+ elt.insertBefore(document.createTextNode('hello'), elt.firstChild);
+ elt.firstChild.textContent = 'goodbye';
+ elt.removeChild(elt.firstChild);
+ }
+
+ var shadowRoot = internals.shadowRoot(document.querySelector('input'));
+ var observer = new WebKitMutationObserver(function(mutations) {
+ window.mutations = mutations;
+ });
+
+ observer.observe(shadowRoot.firstChild, {attributes: true, childList: true, characterData: true, subtree: true});
+ mutate(shadowRoot.firstChild);
+
+ setTimeout(function() {
+ debug('Mutations in shadow DOM should have been observed:');
+ shouldBe('mutations.length', '4');
+ shouldBe('mutations[0].type', '"attributes"');
+ shouldBe('mutations[1].type', '"childList"');
+ shouldBe('mutations[2].type', '"characterData"');
+ shouldBe('mutations[3].type', '"childList"');
+ observer.disconnect();
+
+ window.mutations = null;
+ observer.observe(document, {attributes: true, childList: true, characterData: true, subtree: true});
+ mutate(shadowRoot.firstChild);
+ setTimeout(function() {
+ debug('\nObserving from outside shadow DOM should not see mutations in the shadow:');
+ shouldBeNull('mutations');
+ finishJSTest();
+ }, 0);
+ }, 0);
+}
+
+if (window.internals) {
+ doTest();
+ window.jsTestIsAsync = true;
+} else
+ testFailed('This test only runs in DRT');
+</script>
+<script src=""
+</body>
Modified: trunk/Source/WebCore/ChangeLog (115896 => 115897)
--- trunk/Source/WebCore/ChangeLog 2012-05-02 22:01:37 UTC (rev 115896)
+++ trunk/Source/WebCore/ChangeLog 2012-05-02 22:04:15 UTC (rev 115897)
@@ -1,3 +1,26 @@
+2012-05-02 Adam Klein <ad...@chromium.org>
+
+ Childlist mutations in shadow DOM should be observable with MutationObservers
+ https://bugs.webkit.org/show_bug.cgi?id=85402
+
+ Reviewed by Ojan Vafai.
+
+ Though Mutation Events are not supported in Shadow DOM,
+ MutationObservers are supposed to be. Due to a misplacement of the
+ ChildListMutationScope, they were erroneously getting skipped.
+
+ This patch moves code around to properly notify when childlist are
+ mutated in shadow DOM and covers that change with a new test.
+
+ Test: fast/mutation/shadow-dom.html
+
+ * dom/ContainerNode.cpp:
+ (WebCore::willRemoveChild): Handle notification of removal directly.
+ (WebCore::willRemoveChildren): ditto.
+ (WebCore::dispatchChildInsertionEvents): Remove notification of insertion.
+ (WebCore::dispatchChildRemovalEvents): Remove notification of removal.
+ (WebCore::updateTreeAfterInsertion): Handle notification of insertion directly.
+
2012-05-02 Eric Carlson <eric.carl...@apple.com>
Crash in WebCore::TextTrackList::remove
Modified: trunk/Source/WebCore/dom/ContainerNode.cpp (115896 => 115897)
--- trunk/Source/WebCore/dom/ContainerNode.cpp 2012-05-02 22:01:37 UTC (rev 115896)
+++ trunk/Source/WebCore/dom/ContainerNode.cpp 2012-05-02 22:04:15 UTC (rev 115897)
@@ -328,6 +328,12 @@
static void willRemoveChild(Node* child)
{
+#if ENABLE(MUTATION_OBSERVERS)
+ ASSERT(child->parentNode());
+ ChildListMutationScope(child->parentNode()).willRemoveChild(child);
+ child->notifyMutationObserversNodeWillDetach();
+#endif
+
dispatchChildRemovalEvents(child);
child->document()->nodeWillBeRemoved(child); // e.g. mutation event listener can create a new range.
child->willRemove();
@@ -346,6 +352,12 @@
for (NodeVector::const_iterator it = children.begin(); it != children.end(); it++) {
Node* child = it->get();
+
+#if ENABLE(MUTATION_OBSERVERS)
+ mutation.willRemoveChild(child);
+ child->notifyMutationObserversNodeWillDetach();
+#endif
+
// fire removed from document mutation events.
dispatchChildRemovalEvents(child);
child->willRemove();
@@ -936,13 +948,6 @@
RefPtr<Node> c = child;
RefPtr<Document> document = child->document();
-#if ENABLE(MUTATION_OBSERVERS)
- if (c->parentNode()) {
- ChildListMutationScope mutation(c->parentNode());
- mutation.childAdded(c.get());
- }
-#endif
-
if (c->parentNode() && document->hasListenerType(Document::DOMNODEINSERTED_LISTENER))
c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode()));
@@ -967,14 +972,6 @@
RefPtr<Node> c = child;
RefPtr<Document> document = child->document();
-#if ENABLE(MUTATION_OBSERVERS)
- if (c->parentNode()) {
- ChildListMutationScope mutation(c->parentNode());
- mutation.willRemoveChild(c.get());
- c->notifyMutationObserversNodeWillDetach();
- }
-#endif
-
// dispatch pre-removal mutation events
if (c->parentNode() && document->hasListenerType(Document::DOMNODEREMOVED_LISTENER))
c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, c->parentNode()));
@@ -991,6 +988,10 @@
ASSERT(parent->refCount());
ASSERT(child->refCount());
+#if ENABLE(MUTATION_OBSERVERS)
+ ChildListMutationScope(parent).childAdded(child);
+#endif
+
parent->childrenChanged(false, child->previousSibling(), child->nextSibling(), 1);
ChildNodeInsertionNotifier(parent).notify(child);