Index: third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp |
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp |
index df5a192b494f7b44dadc76c28874f2b2bdb920fe..3e25498464fb2d31de3e0953a636f297a7c036ba 100644 |
--- a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp |
+++ b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp |
@@ -188,6 +188,14 @@ bool HTMLParserScriptRunner::isParserBlockingScriptReady() { |
return m_parserBlockingScript->isReady(); |
} |
+// This has two callers and corresponds to different concepts in the spec: |
+// - When called from executeParsingBlockingScripts(), this corresponds to some |
+// steps of the "Otherwise" Clause of 'An end tag whose tag name is "script"' |
+// https://html.spec.whatwg.org/#scriptEndTag |
+// - When called from executeScriptsWaitingForParsing(), this corresponds |
+// https://html.spec.whatwg.org/#execute-the-script-block |
+// and thus currently this function does more than specced. |
+// TODO(hiroshige): Make the spec and implementation consistent. |
void HTMLParserScriptRunner::executePendingScriptAndDispatchEvent( |
PendingScript* pendingScript, |
ScriptStreamer::Type pendingScriptType) { |
@@ -214,16 +222,24 @@ void HTMLParserScriptRunner::executePendingScriptAndDispatchEvent( |
TextPosition scriptStartPosition = pendingScript->startingPosition(); |
double scriptParserBlockingTime = |
pendingScript->parserBlockingLoadStartTime(); |
- // Clear the pending script before possible re-entrancy from executeScript() |
Element* element = pendingScript->element(); |
+ |
+ // 1. "Let the script be the pending parsing-blocking script. |
+ // There is no longer a pending parsing-blocking script." |
+ // Clear the pending script before possible re-entrancy from executeScript() |
pendingScript->dispose(); |
if (ScriptLoader* scriptLoader = toScriptLoaderIfPossible(element)) { |
+ // 7. "Increment the parser's script nesting level by one (it should be |
+ // zero before this step, so this sets it to one)." |
HTMLParserReentryPermit::ScriptNestingLevelIncrementer |
nestingLevelIncrementer = |
m_reentryPermit->incrementScriptNestingLevel(); |
+ |
IgnoreDestructiveWriteCountIncrementer |
ignoreDestructiveWriteCountIncrementer(m_document); |
+ |
+ // 8. "Execute the script." |
if (errorOccurred) { |
TRACE_EVENT_WITH_FLOW1( |
"blink", "HTMLParserScriptRunner ExecuteScriptFailed", element, |
@@ -244,6 +260,12 @@ void HTMLParserScriptRunner::executePendingScriptAndDispatchEvent( |
element->dispatchEvent(Event::create(EventTypeNames::load)); |
} |
} |
+ |
+ // 9. "Decrement the parser's script nesting level by one. |
+ // If the parser's script nesting level is zero |
+ // (which it always should be at this point), |
+ // then set the parser pause flag to false." |
+ // This is implemented by scope out of ScriptNestingLevelIncrementer. |
} |
DCHECK(!isExecutingScript()); |
@@ -345,7 +367,7 @@ void HTMLParserScriptRunner::pendingScriptFinished( |
} |
// Implements the steps for 'An end tag whose tag name is "script"' |
-// http://whatwg.org/html#scriptEndTag |
+// https://html.spec.whatwg.org/#scriptEndTag |
// Script handling lives outside the tree builder to keep each class simple. |
void HTMLParserScriptRunner::processScriptElement( |
Element* scriptElement, |
@@ -358,16 +380,27 @@ void HTMLParserScriptRunner::processScriptElement( |
bool hadPreloadScanner = m_host->hasPreloadScanner(); |
+ // Initial steps of 'An end tag whose tag name is "script"'. |
// Try to execute the script given to us. |
processScriptElementInternal(scriptElement, scriptStartPosition); |
+ // "At this stage, if there is a pending parsing-blocking script, then:" |
if (hasParserBlockingScript()) { |
+ // - "If the script nesting level is not zero:" |
if (isExecutingScript()) { |
+ // "Set the parser pause flag to true, and abort the processing of any |
+ // nested invocations of the tokenizer, yielding control back to the |
+ // caller. (Tokenization will resume when the caller returns to the |
+ // "outer" tree construction stage.)" |
+ // TODO(hiroshige): set the parser pause flag to true here. |
+ |
// Unwind to the outermost HTMLParserScriptRunner::processScriptElement |
// before continuing parsing. |
return; |
} |
+ // - "Otherwise": |
+ |
traceParserBlockingScript(m_parserBlockingScript.get(), |
!m_document->isScriptExecutionReady()); |
m_parserBlockingScript->markParserBlockingLoadStartTime(); |
@@ -376,6 +409,7 @@ void HTMLParserScriptRunner::processScriptElement( |
// current insertion point. Append it and scan. |
if (!hadPreloadScanner && m_host->hasPreloadScanner()) |
m_host->appendCurrentInputStreamToPreloadScannerAndScan(); |
+ |
executeParsingBlockingScripts(); |
} |
} |
@@ -384,15 +418,36 @@ bool HTMLParserScriptRunner::hasParserBlockingScript() const { |
return !!m_parserBlockingScript->element(); |
} |
+// Implements the "Otherwise" Clause of 'An end tag whose tag name is "script"' |
dominicc (has gone to gerrit)
2017/02/16 08:41:00
I would make this more succinct by dropping "imple
hiroshige
2017/02/20 23:56:40
Done.
|
+// https://html.spec.whatwg.org/#scriptEndTag |
void HTMLParserScriptRunner::executeParsingBlockingScripts() { |
+ // 3. "If (1) the parser's Document has a style sheet that is blocking scripts |
+ // or (2) the script's "ready to be parser-executed" flag is not set: |
+ // spin the event loop |
+ // until the parser's Document has no style sheet that is blocking scripts |
+ // and the script's "ready to be parser-executed" flag is set." |
+ // These conditions correspond to isParserBlockingScriptReady() and |
dominicc (has gone to gerrit)
2017/02/16 08:41:00
Great comment; thank you so much for doing this.
hiroshige
2017/02/20 23:56:40
Done.
|
+ // if it is false, executeParsingBlockingScripts() will be called later |
+ // when isParserBlockingScriptReady() becomes true: |
+ // (1) from HTMLParserScriptRunner::executeScriptsWaitingForResources(), or |
+ // (2) from HTMLParserScriptRunner::executeScriptsWaitingForLoad(). |
while (hasParserBlockingScript() && isParserBlockingScriptReady()) { |
DCHECK(m_document); |
DCHECK(!isExecutingScript()); |
DCHECK(m_document->isScriptExecutionReady()); |
+ // 6. "Let the insertion point be just before the next input character." |
InsertionPointRecord insertionPointRecord(m_host->inputStream()); |
+ |
+ // 1., 7.--9. |
executePendingScriptAndDispatchEvent(m_parserBlockingScript.get(), |
ScriptStreamer::ParsingBlocking); |
+ |
+ // 10. "Let the insertion point be undefined again." |
+ // Implemented as scope out of InsertionPointRecord. |
dominicc (has gone to gerrit)
2017/02/16 08:41:00
"scope out of" is a bit awkward. Maybe say somethi
hiroshige
2017/02/20 23:56:40
Done.
|
+ |
+ // 11. "If there is once again a pending parsing-blocking script, then |
+ // repeat these steps from step 1." |
} |
} |
@@ -415,13 +470,23 @@ void HTMLParserScriptRunner::executeScriptsWaitingForResources() { |
executeParsingBlockingScripts(); |
} |
+// Step 3 of https://html.spec.whatwg.org/#the-end: |
+// "If the list of scripts that will execute when the document has |
+// finished parsing is not empty, run these substeps:" |
bool HTMLParserScriptRunner::executeScriptsWaitingForParsing() { |
TRACE_EVENT0("blink", |
"HTMLParserScriptRunner::executeScriptsWaitingForParsing"); |
+ |
while (!m_scriptsToExecuteAfterParsing.isEmpty()) { |
DCHECK(!isExecutingScript()); |
DCHECK(!hasParserBlockingScript()); |
DCHECK(m_scriptsToExecuteAfterParsing.first()->resource()); |
+ |
+ // 1. "Spin the event loop until the first script in the list of scripts |
+ // that will execute when the document has finished parsing |
+ // has its "ready to be parser-executed" flag set and |
+ // the parser's Document has no style sheet that is blocking scripts." |
+ // TODO(hiroshige): Is the latter part checked anywhere? |
if (!m_scriptsToExecuteAfterParsing.first()->isReady()) { |
m_scriptsToExecuteAfterParsing.first()->watchForLoad(this); |
traceParserBlockingScript(m_scriptsToExecuteAfterParsing.first().get(), |
@@ -429,11 +494,23 @@ bool HTMLParserScriptRunner::executeScriptsWaitingForParsing() { |
m_scriptsToExecuteAfterParsing.first()->markParserBlockingLoadStartTime(); |
return false; |
} |
+ |
+ // 3. "Remove the first script element from the list of scripts that will |
+ // execute when the document has finished parsing (i.e. shift out the |
+ // first entry in the list)." |
PendingScript* first = m_scriptsToExecuteAfterParsing.takeFirst(); |
+ |
+ // 2. "Execute the first script in the list of scripts that will execute |
+ // when the document has finished parsing." |
executePendingScriptAndDispatchEvent(first, ScriptStreamer::Deferred); |
+ |
// FIXME: What is this m_document check for? |
if (!m_document) |
return false; |
+ |
+ // 4. "If the list of scripts that will execute when the document has |
+ // finished parsing is still not empty, repeat these substeps again |
+ // from substep 1." |
} |
return true; |
} |
@@ -505,7 +582,7 @@ bool HTMLParserScriptRunner::requestPendingScript(PendingScript* pendingScript, |
} |
// Implements the initial steps for 'An end tag whose tag name is "script"' |
-// http://whatwg.org/html#scriptEndTag |
+// https://html.spec.whatwg.org/#scriptEndTag |
void HTMLParserScriptRunner::processScriptElementInternal( |
Element* script, |
const TextPosition& scriptStartPosition) { |
@@ -527,11 +604,20 @@ void HTMLParserScriptRunner::processScriptElementInternal( |
if (!isExecutingScript()) |
Microtask::performCheckpoint(V8PerIsolateData::mainThreadIsolate()); |
+ // "Let the old insertion point have the same value as the current |
+ // insertion point. |
+ // Let the insertion point be just before the next input character." |
InsertionPointRecord insertionPointRecord(m_host->inputStream()); |
+ |
+ // "Increment the parser's script nesting level by one." |
HTMLParserReentryPermit::ScriptNestingLevelIncrementer |
nestingLevelIncrementer = |
m_reentryPermit->incrementScriptNestingLevel(); |
+ // "Prepare the script. This might cause some script to execute, which |
+ // might cause new characters to be inserted into the tokenizer, and |
+ // might cause the tokenizer to output more tokens, resulting in a |
+ // reentrant invocation of the parser." |
scriptLoader->prepareScript(scriptStartPosition); |
// A part of Step 23 of https://html.spec.whatwg.org/#prepare-a-script: |
@@ -567,6 +653,14 @@ void HTMLParserScriptRunner::processScriptElementInternal( |
// 2nd Clause of Step 23. |
requestParsingBlockingScript(script); |
} |
+ |
+ // "Decrement the parser's script nesting level by one. |
+ // If the parser's script nesting level is zero, then set the parser |
+ // pause flag to false." |
+ // Implemented by scope out of ScriptNestingLevelIncrementer. |
+ |
+ // "Let the insertion point have the value of the old insertion point." |
+ // Implemented by scope out of InsertionPointRecord. |
} |
} |