- 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())