Title: [139790] trunk
Revision
139790
Author
commit-qu...@webkit.org
Date
2013-01-15 14:17:06 -0800 (Tue, 15 Jan 2013)

Log Message

HTML parser should queue MutationRecords for its operations
https://bugs.webkit.org/show_bug.cgi?id=89351

Patch by Elliott Sprehn <espr...@gmail.com> on 2013-01-15
Reviewed by Eric Seidel.

Source/WebCore:

Generate mutation records inside the parser. This is done by using a
ChildListMutationScope in the ContainerNode::parser* methods and then
adding delivery before each <script> element would be processed by
the parser.

Test: fast/dom/MutationObserver/parser-mutations.html

* dom/ContainerNode.cpp:
(WebCore::ContainerNode::parserInsertBefore):
(WebCore::ContainerNode::parserRemoveChild):
(WebCore::ContainerNode::parserAppendChild):
* html/parser/HTMLScriptRunner.cpp:
(WebCore::HTMLScriptRunner::executeParsingBlockingScript):
(WebCore::HTMLScriptRunner::executePendingScriptAndDispatchEvent):
(WebCore::HTMLScriptRunner::execute):
(WebCore::HTMLScriptRunner::executeScriptsWaitingForLoad):
(WebCore::HTMLScriptRunner::executeScriptsWaitingForStylesheets):
(WebCore::HTMLScriptRunner::executeScriptsWaitingForParsing):
(WebCore::HTMLScriptRunner::runScript):

LayoutTests:

Add tests for parser generated mutations.

XXX: This needs a bunch more tests observing the adoption
agency algorithm to catch parserInsertBefore and parserRemoveChild
mutations.

* fast/dom/MutationObserver/parser-mutations-expected.txt: Added.
* fast/dom/MutationObserver/parser-mutations.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (139789 => 139790)


--- trunk/LayoutTests/ChangeLog	2013-01-15 22:15:35 UTC (rev 139789)
+++ trunk/LayoutTests/ChangeLog	2013-01-15 22:17:06 UTC (rev 139790)
@@ -1,3 +1,19 @@
+2013-01-15  Elliott Sprehn  <espr...@gmail.com>
+
+        HTML parser should queue MutationRecords for its operations
+        https://bugs.webkit.org/show_bug.cgi?id=89351
+
+        Reviewed by Eric Seidel.
+
+        Add tests for parser generated mutations.
+
+        XXX: This needs a bunch more tests observing the adoption
+        agency algorithm to catch parserInsertBefore and parserRemoveChild
+        mutations.
+
+        * fast/dom/MutationObserver/parser-mutations-expected.txt: Added.
+        * fast/dom/MutationObserver/parser-mutations.html: Added.
+
 2013-01-15  Ojan Vafai  <o...@chromium.org>
 
         Unreviewed, rolling out r139782.

Added: trunk/LayoutTests/fast/dom/MutationObserver/parser-mutations-expected.txt (0 => 139790)


--- trunk/LayoutTests/fast/dom/MutationObserver/parser-mutations-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/MutationObserver/parser-mutations-expected.txt	2013-01-15 22:17:06 UTC (rev 139790)
@@ -0,0 +1,6 @@
+PASS mutations.length is 6
+PASS mutations[1].type is "childList"
+PASS mutations[1].target.tagName is "BODY"
+PASS mutations[1].addedNodes.length is 1
+PASS mutations[1].addedNodes[0].tagName is "P"
+Mutation records should be delivered for all parser mutations after the above script.

Added: trunk/LayoutTests/fast/dom/MutationObserver/parser-mutations.html (0 => 139790)


--- trunk/LayoutTests/fast/dom/MutationObserver/parser-mutations.html	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/MutationObserver/parser-mutations.html	2013-01-15 22:17:06 UTC (rev 139790)
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+
+<body>
+<script src=""
+
+<script>
+    if (window.testRunner)
+        testRunner.dumpAsText();
+
+    var observer = new WebKitMutationObserver(function(mutations, observer) {
+        window.mutations = mutations;
+    });
+    observer.observe(document.body, {childList: true, subtree:true});
+</script>
+
+<p>
+    Mutation records should be delivered for all parser mutations after the above script.
+</p>
+
+<script>
+    shouldBe('mutations.length', '6');
+    shouldBeEqualToString('mutations[1].type', 'childList');
+    shouldBeEqualToString('mutations[1].target.tagName', 'BODY');
+    shouldBe('mutations[1].addedNodes.length', '1');
+    shouldBeEqualToString('mutations[1].addedNodes[0].tagName', 'P');
+</script>
+</body>
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (139789 => 139790)


--- trunk/Source/WebCore/ChangeLog	2013-01-15 22:15:35 UTC (rev 139789)
+++ trunk/Source/WebCore/ChangeLog	2013-01-15 22:17:06 UTC (rev 139790)
@@ -1,3 +1,30 @@
+2013-01-15  Elliott Sprehn  <espr...@gmail.com>
+
+        HTML parser should queue MutationRecords for its operations
+        https://bugs.webkit.org/show_bug.cgi?id=89351
+
+        Reviewed by Eric Seidel.
+
+        Generate mutation records inside the parser. This is done by using a
+        ChildListMutationScope in the ContainerNode::parser* methods and then
+        adding delivery before each <script> element would be processed by
+        the parser.
+
+        Test: fast/dom/MutationObserver/parser-mutations.html
+
+        * dom/ContainerNode.cpp:
+        (WebCore::ContainerNode::parserInsertBefore):
+        (WebCore::ContainerNode::parserRemoveChild):
+        (WebCore::ContainerNode::parserAppendChild):
+        * html/parser/HTMLScriptRunner.cpp:
+        (WebCore::HTMLScriptRunner::executeParsingBlockingScript):
+        (WebCore::HTMLScriptRunner::executePendingScriptAndDispatchEvent):
+        (WebCore::HTMLScriptRunner::execute):
+        (WebCore::HTMLScriptRunner::executeScriptsWaitingForLoad):
+        (WebCore::HTMLScriptRunner::executeScriptsWaitingForStylesheets):
+        (WebCore::HTMLScriptRunner::executeScriptsWaitingForParsing):
+        (WebCore::HTMLScriptRunner::runScript):
+
 2013-01-15  Ojan Vafai  <o...@chromium.org>
 
         Unreviewed, rolling out r139782.

Modified: trunk/Source/WebCore/dom/ContainerNode.cpp (139789 => 139790)


--- trunk/Source/WebCore/dom/ContainerNode.cpp	2013-01-15 22:15:35 UTC (rev 139789)
+++ trunk/Source/WebCore/dom/ContainerNode.cpp	2013-01-15 22:17:06 UTC (rev 139790)
@@ -331,6 +331,10 @@
 
     insertBeforeCommon(nextChild, newChild.get());
 
+#if ENABLE(MUTATION_OBSERVERS)
+    ChildListMutationScope(this).childAdded(newChild.get());
+#endif
+
     childrenChanged(true, newChild->previousSibling(), nextChild, 1);
     ChildNodeInsertionNotifier(this).notify(newChild.get());
 }
@@ -552,6 +556,11 @@
     Node* prev = oldChild->previousSibling();
     Node* next = oldChild->nextSibling();
 
+#if ENABLE(MUTATION_OBSERVERS)
+    ChildListMutationScope(this).willRemoveChild(oldChild);
+    oldChild->notifyMutationObserversNodeWillDetach();
+#endif
+
     removeBetween(prev, next, oldChild);
 
     childrenChanged(true, prev, next, -1);
@@ -697,6 +706,10 @@
         treeScope()->adoptIfNeeded(newChild.get());
     }
 
+#if ENABLE(MUTATION_OBSERVERS)
+    ChildListMutationScope(this).childAdded(newChild.get());
+#endif
+
     childrenChanged(true, last, 0, 1);
     ChildNodeInsertionNotifier(this).notify(newChild.get());
 }

Modified: trunk/Source/WebCore/html/parser/HTMLScriptRunner.cpp (139789 => 139790)


--- trunk/Source/WebCore/html/parser/HTMLScriptRunner.cpp	2013-01-15 22:15:35 UTC (rev 139789)
+++ trunk/Source/WebCore/html/parser/HTMLScriptRunner.cpp	2013-01-15 22:17:06 UTC (rev 139790)
@@ -36,6 +36,7 @@
 #include "HTMLNames.h"
 #include "HTMLScriptRunnerHost.h"
 #include "IgnoreDestructiveWriteCountIncrementer.h"
+#include "MutationObserver.h"
 #include "NestingLevelIncrementer.h"
 #include "NotImplemented.h"
 #include "ScriptElement.h"
@@ -110,7 +111,7 @@
 void HTMLScriptRunner::executeParsingBlockingScript()
 {
     ASSERT(m_document);
-    ASSERT(!m_scriptNestingLevel);
+    ASSERT(!isExecutingScript());
     ASSERT(m_document->haveStylesheetsLoaded());
     ASSERT(isPendingScriptReady(m_parserBlockingScript));
 
@@ -127,6 +128,11 @@
     if (pendingScript.cachedScript() && pendingScript.watchingForLoad())
         stopWatchingForLoad(pendingScript);
 
+#if ENABLE(MUTATION_OBSERVERS)
+    if (!isExecutingScript())
+        MutationObserver::deliverAllMutations();
+#endif
+
     // Clear the pending script before possible rentrancy from executeScript()
     RefPtr<Element> element = pendingScript.releaseElementAndClear();
     if (ScriptElement* scriptElement = toScriptElement(element.get())) {
@@ -140,7 +146,7 @@
             element->dispatchEvent(createScriptLoadEvent());
         }
     }
-    ASSERT(!m_scriptNestingLevel);
+    ASSERT(!isExecutingScript());
 }
 
 void HTMLScriptRunner::watchForLoad(PendingScript& pendingScript)
@@ -170,7 +176,7 @@
     runScript(scriptElement.get(), scriptStartPosition);
 
     if (hasParserBlockingScript()) {
-        if (m_scriptNestingLevel)
+        if (isExecutingScript())
             return; // Unwind to the outermost HTMLScriptRunner::execute before continuing parsing.
         // If preload scanner got created, it is missing the source after the current insertion point. Append it and scan.
         if (!hadPreloadScanner && m_host->hasPreloadScanner())
@@ -192,7 +198,7 @@
 
 void HTMLScriptRunner::executeScriptsWaitingForLoad(CachedResource* cachedScript)
 {
-    ASSERT(!m_scriptNestingLevel);
+    ASSERT(!isExecutingScript());
     ASSERT(hasParserBlockingScript());
     ASSERT_UNUSED(cachedScript, m_parserBlockingScript.cachedScript() == cachedScript);
     ASSERT(m_parserBlockingScript.cachedScript()->isLoaded());
@@ -205,7 +211,7 @@
     // Callers should check hasScriptsWaitingForStylesheets() before calling
     // to prevent parser or script re-entry during </style> parsing.
     ASSERT(hasScriptsWaitingForStylesheets());
-    ASSERT(!m_scriptNestingLevel);
+    ASSERT(!isExecutingScript());
     ASSERT(m_document->haveStylesheetsLoaded());
     executeParsingBlockingScripts();
 }
@@ -213,7 +219,7 @@
 bool HTMLScriptRunner::executeScriptsWaitingForParsing()
 {
     while (!m_scriptsToExecuteAfterParsing.isEmpty()) {
-        ASSERT(!m_scriptNestingLevel);
+        ASSERT(!isExecutingScript());
         ASSERT(!hasParserBlockingScript());
         ASSERT(m_scriptsToExecuteAfterParsing.first().cachedScript());
         if (!m_scriptsToExecuteAfterParsing.first().cachedScript()->isLoaded()) {
@@ -274,9 +280,6 @@
     ASSERT(m_document);
     ASSERT(!hasParserBlockingScript());
     {
-        InsertionPointRecord insertionPointRecord(m_host->inputStream());
-        NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
-
         ScriptElement* scriptElement = toScriptElement(script);
 
         // This contains both and ASSERTION and a null check since we should not
@@ -287,6 +290,18 @@
         if (!scriptElement)
             return;
 
+#if ENABLE(MUTATION_OBSERVERS)
+        // FIXME: This may be too agressive as we always deliver mutations at
+        // every script element, even if it's not ready to execute yet. There's
+        // unfortuantely no obvious way to tell if prepareScript is going to
+        // execute the script from out here.
+        if (!isExecutingScript())
+            MutationObserver::deliverAllMutations();
+#endif
+
+        InsertionPointRecord insertionPointRecord(m_host->inputStream());
+        NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
+
         scriptElement->prepareScript(scriptStartPosition);
 
         if (!scriptElement->willBeParserExecuted())
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to