Changeset 142204 in webkit


Ignore:
Timestamp:
Feb 7, 2013 4:35:17 PM (11 years ago)
Author:
esprehn@chromium.org
Message:

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

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::takeAllChildrenFrom):
(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 new test mutation records in the parser and fix shadow-dom.html
test since it used setTimeout and sometimes could observe parser
mutations.

  • fast/dom/MutationObserver/parser-mutations-expected.txt: Added.
  • fast/dom/MutationObserver/parser-mutations.html: Added.
  • fast/dom/MutationObserver/shadow-dom-expected.txt:
  • fast/dom/MutationObserver/shadow-dom.html:
Location:
trunk
Files:
2 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r142200 r142204  
     12013-02-07  Elliott Sprehn  <esprehn@chromium.org>
     2
     3        HTML parser should queue MutationRecords for its operations
     4        https://bugs.webkit.org/show_bug.cgi?id=89351
     5
     6        Reviewed by Eric Seidel.
     7
     8        Add new test mutation records in the parser and fix shadow-dom.html
     9        test since it used setTimeout and sometimes could observe parser
     10        mutations.
     11
     12        * fast/dom/MutationObserver/parser-mutations-expected.txt: Added.
     13        * fast/dom/MutationObserver/parser-mutations.html: Added.
     14        * fast/dom/MutationObserver/shadow-dom-expected.txt:
     15        * fast/dom/MutationObserver/shadow-dom.html:
     16
    1172013-02-07  Adam Barth  <abarth@webkit.org>
    218
  • trunk/LayoutTests/fast/dom/MutationObserver/shadow-dom-expected.txt

    r137662 r142204  
    1212
    1313Observing from outside shadow DOM should not see mutations in the shadow:
    14 PASS mutations is null
     14PASS mutations.length is 0
    1515PASS successfullyParsed is true
    1616
  • trunk/LayoutTests/fast/dom/MutationObserver/shadow-dom.html

    r137662 r142204  
    66description('Test that MutationObservers operate in Shadow DOM');
    77
    8 function doTest() {
    9     function mutate(elt) {
     8function doTest()
     9{
     10    function mutate(elt)
     11    {
    1012        elt.setAttribute('data-foo', 'bar');
    1113        elt.insertBefore(document.createTextNode('hello'), elt.firstChild);
     
    1517
    1618    var shadowRoot = internals.shadowRoot(document.querySelector('input'));
    17     var observer = new WebKitMutationObserver(function(mutations) {
    18         window.mutations = mutations;
    19     });
     19    var observer = new WebKitMutationObserver(function() { });
    2020
    2121    observer.observe(shadowRoot.firstChild, {attributes: true, childList: true, characterData: true, subtree: true});
    2222    mutate(shadowRoot.firstChild);
    2323
    24     setTimeout(function() {
    25         debug('Mutations in shadow DOM should have been observed:');
    26         shouldBe('mutations.length', '4');
    27         shouldBe('mutations[0].type', '"attributes"');
    28         shouldBe('mutations[1].type', '"childList"');
    29         shouldBe('mutations[2].type', '"characterData"');
    30         shouldBe('mutations[3].type', '"childList"');
    31         observer.disconnect();
     24    window.mutations = observer.takeRecords();
     25    debug('Mutations in shadow DOM should have been observed:');
     26    shouldBe('mutations.length', '4');
     27    shouldBe('mutations[0].type', '"attributes"');
     28    shouldBe('mutations[1].type', '"childList"');
     29    shouldBe('mutations[2].type', '"characterData"');
     30    shouldBe('mutations[3].type', '"childList"');
     31    observer.disconnect();
    3232
    33         window.mutations = null;
    34         observer.observe(document, {attributes: true, childList: true, characterData: true, subtree: true});
    35         mutate(shadowRoot.firstChild);
    36         setTimeout(function() {
    37             debug('\nObserving from outside shadow DOM should not see mutations in the shadow:');
    38             shouldBeNull('mutations');
    39             finishJSTest();
    40         }, 0);
    41     }, 0);
     33    window.mutations = observer.takeRecords();
     34    observer.observe(document, {attributes: true, childList: true, characterData: true, subtree: true});
     35    mutate(shadowRoot.firstChild);   
     36    debug('\nObserving from outside shadow DOM should not see mutations in the shadow:');
     37    shouldBe('mutations.length', '0');
    4238}
    4339
    44 if (window.internals) {
     40if (window.internals)
    4541    doTest();
    46     window.jsTestIsAsync = true;
    47 } else
     42else
    4843    testFailed('This test only runs in DRT');
    4944</script>
  • trunk/Source/WebCore/ChangeLog

    r142202 r142204  
     12013-02-07  Elliott Sprehn  <esprehn@chromium.org>
     2
     3        HTML parser should queue MutationRecords for its operations
     4        https://bugs.webkit.org/show_bug.cgi?id=89351
     5
     6        Reviewed by Eric Seidel.
     7
     8        Generate mutation records inside the parser. This is done by using a
     9        ChildListMutationScope in the ContainerNode::parser* methods and then
     10        adding delivery before each <script> element would be processed by
     11        the parser.
     12
     13        Test: fast/dom/MutationObserver/parser-mutations.html
     14
     15        * dom/ContainerNode.cpp:
     16        (WebCore::ContainerNode::takeAllChildrenFrom):
     17        (WebCore::ContainerNode::parserInsertBefore):
     18        (WebCore::ContainerNode::parserRemoveChild):
     19        (WebCore::ContainerNode::parserAppendChild):
     20        * html/parser/HTMLScriptRunner.cpp:
     21        (WebCore::HTMLScriptRunner::executeParsingBlockingScript):
     22        (WebCore::HTMLScriptRunner::executePendingScriptAndDispatchEvent):
     23        (WebCore::HTMLScriptRunner::execute):
     24        (WebCore::HTMLScriptRunner::executeScriptsWaitingForLoad):
     25        (WebCore::HTMLScriptRunner::executeScriptsWaitingForStylesheets):
     26        (WebCore::HTMLScriptRunner::executeScriptsWaitingForParsing):
     27        (WebCore::HTMLScriptRunner::runScript):
     28
    1292013-02-07  Kentaro Hara  <haraken@chromium.org>
    230
  • trunk/Source/WebCore/dom/ContainerNode.cpp

    r142126 r142204  
    106106    NodeVector children;
    107107    getChildNodes(oldParent, children);
     108
     109    if (oldParent->document()->hasMutationObserversOfType(MutationObserver::ChildList)) {
     110        ChildListMutationScope mutation(oldParent);
     111        for (unsigned i = 0; i < children.size(); ++i)
     112            mutation.willRemoveChild(children[i].get());
     113    }
     114
     115    // FIXME: We need to do notifyMutationObserversNodeWillDetach() for each child,
     116    // probably inside removeDetachedChildrenInContainer.
     117
    108118    oldParent->removeDetachedChildren();
    109119
     
    343353    newChild->updateAncestorConnectedSubframeCountForInsertion();
    344354
     355    ChildListMutationScope(this).childAdded(newChild.get());
     356
    345357    childrenChanged(true, newChild->previousSibling(), nextChild, 1);
    346358    ChildNodeInsertionNotifier(this).notify(newChild.get());
     
    565577
    566578    oldChild->updateAncestorConnectedSubframeCountForRemoval();
     579
     580    ChildListMutationScope(this).willRemoveChild(oldChild);
     581    oldChild->notifyMutationObserversNodeWillDetach();
    567582
    568583    removeBetween(prev, next, oldChild);
     
    716731
    717732    newChild->updateAncestorConnectedSubframeCountForInsertion();
     733
     734    ChildListMutationScope(this).childAdded(newChild.get());
    718735
    719736    childrenChanged(true, last, 0, 1);
  • trunk/Source/WebCore/html/parser/HTMLScriptRunner.cpp

    r139799 r142204  
    3737#include "HTMLScriptRunnerHost.h"
    3838#include "IgnoreDestructiveWriteCountIncrementer.h"
     39#include "MutationObserver.h"
    3940#include "NestingLevelIncrementer.h"
    4041#include "NotImplemented.h"
     
    111112{
    112113    ASSERT(m_document);
    113     ASSERT(!m_scriptNestingLevel);
     114    ASSERT(!isExecutingScript());
    114115    ASSERT(m_document->haveStylesheetsLoaded());
    115116    ASSERT(isPendingScriptReady(m_parserBlockingScript));
     
    127128    if (pendingScript.cachedScript() && pendingScript.watchingForLoad())
    128129        stopWatchingForLoad(pendingScript);
     130
     131    if (!isExecutingScript())
     132        MutationObserver::deliverAllMutations();
    129133
    130134    // Clear the pending script before possible rentrancy from executeScript()
     
    141145        }
    142146    }
    143     ASSERT(!m_scriptNestingLevel);
     147    ASSERT(!isExecutingScript());
    144148}
    145149
     
    171175
    172176    if (hasParserBlockingScript()) {
    173         if (m_scriptNestingLevel)
     177        if (isExecutingScript())
    174178            return; // Unwind to the outermost HTMLScriptRunner::execute before continuing parsing.
    175179        // If preload scanner got created, it is missing the source after the current insertion point. Append it and scan.
     
    193197void HTMLScriptRunner::executeScriptsWaitingForLoad(CachedResource* cachedScript)
    194198{
    195     ASSERT(!m_scriptNestingLevel);
     199    ASSERT(!isExecutingScript());
    196200    ASSERT(hasParserBlockingScript());
    197201    ASSERT_UNUSED(cachedScript, m_parserBlockingScript.cachedScript() == cachedScript);
     
    206210    // to prevent parser or script re-entry during </style> parsing.
    207211    ASSERT(hasScriptsWaitingForStylesheets());
    208     ASSERT(!m_scriptNestingLevel);
     212    ASSERT(!isExecutingScript());
    209213    ASSERT(m_document->haveStylesheetsLoaded());
    210214    executeParsingBlockingScripts();
     
    214218{
    215219    while (!m_scriptsToExecuteAfterParsing.isEmpty()) {
    216         ASSERT(!m_scriptNestingLevel);
     220        ASSERT(!isExecutingScript());
    217221        ASSERT(!hasParserBlockingScript());
    218222        ASSERT(m_scriptsToExecuteAfterParsing.first().cachedScript());
     
    275279    ASSERT(!hasParserBlockingScript());
    276280    {
    277         InsertionPointRecord insertionPointRecord(m_host->inputStream());
    278         NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
    279 
    280281        ScriptElement* scriptElement = toScriptElement(script);
    281282
     
    287288        if (!scriptElement)
    288289            return;
     290
     291        // FIXME: This may be too agressive as we always deliver mutations at
     292        // every script element, even if it's not ready to execute yet. There's
     293        // unfortuantely no obvious way to tell if prepareScript is going to
     294        // execute the script from out here.
     295        if (!isExecutingScript())
     296            MutationObserver::deliverAllMutations();
     297
     298        InsertionPointRecord insertionPointRecord(m_host->inputStream());
     299        NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
    289300
    290301        scriptElement->prepareScript(scriptStartPosition);
Note: See TracChangeset for help on using the changeset viewer.