| Index: third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
|
| diff --git a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
|
| index 0ed9b645e97913e65ae42861cfb2848a1a67024c..c986b693356515ae49a093936b1a9e7fb8e84058 100644
|
| --- a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
|
| +++ b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
|
| @@ -31,6 +31,7 @@
|
| #include "core/dom/DocumentFragment.h"
|
| #include "core/dom/DocumentLifecycleObserver.h"
|
| #include "core/dom/Element.h"
|
| +#include "core/dom/StyleEngine.h"
|
| #include "core/frame/LocalFrame.h"
|
| #include "core/frame/Settings.h"
|
| #include "core/html/HTMLDocument.h"
|
| @@ -44,6 +45,7 @@
|
| #include "core/inspector/InspectorTraceEvents.h"
|
| #include "core/loader/DocumentLoader.h"
|
| #include "core/loader/NavigationScheduler.h"
|
| +#include "platform/RuntimeEnabledFeatures.h"
|
| #include "platform/SharedBuffer.h"
|
| #include "platform/ThreadSafeFunctional.h"
|
| #include "platform/TraceEvent.h"
|
| @@ -266,7 +268,7 @@ bool HTMLDocumentParser::processingData() const
|
|
|
| void HTMLDocumentParser::pumpTokenizerIfPossible()
|
| {
|
| - if (isStopped() || isWaitingForScripts())
|
| + if (isStopped() || isWaitingForBlockingResource())
|
| return;
|
|
|
| pumpTokenizer();
|
| @@ -314,6 +316,9 @@ bool HTMLDocumentParser::canTakeNextToken()
|
| return false;
|
| }
|
|
|
| + if (isWaitingForStyles() || isWaitingForImports())
|
| + return false;
|
| +
|
| // FIXME: It's wrong for the HTMLDocumentParser to reach back to the
|
| // LocalFrame, but this approach is how the old parser handled
|
| // stopping when the page assigns window.location. What really
|
| @@ -358,7 +363,7 @@ void HTMLDocumentParser::notifyPendingParsedChunks()
|
| for (auto& chunk : pendingChunks)
|
| m_speculations.append(chunk.release());
|
|
|
| - if (!isWaitingForScripts() && !isScheduledForResume()) {
|
| + if (!isWaitingForBlockingResource() && !isScheduledForResume()) {
|
| if (m_tasksWereSuspended)
|
| m_parserScheduler->forceResumeAfterYield();
|
| else
|
| @@ -374,17 +379,17 @@ void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser(const Docume
|
| void HTMLDocumentParser::validateSpeculations(PassOwnPtr<ParsedChunk> chunk)
|
| {
|
| ASSERT(chunk);
|
| - if (isWaitingForScripts()) {
|
| - // We're waiting on a network script, just save the chunk, we'll get
|
| - // a second validateSpeculations call after the script completes.
|
| + if (isWaitingForBlockingResource()) {
|
| + // We're waiting on a blocking resource, just save the chunk, we'll get
|
| + // a second validateSpeculations call after the resource completes.
|
| // This call should have been made immediately after runScriptsForPausedTreeBuilder
|
| - // which may have started a network load and left us waiting.
|
| - ASSERT(!m_lastChunkBeforeScript);
|
| - m_lastChunkBeforeScript = chunk;
|
| + // in the case of a script which may have started a network load and left us waiting.
|
| + ASSERT(!m_lastChunkBeforeBlockingResource);
|
| + m_lastChunkBeforeBlockingResource = chunk;
|
| return;
|
| }
|
|
|
| - ASSERT(!m_lastChunkBeforeScript);
|
| + ASSERT(!m_lastChunkBeforeBlockingResource);
|
| OwnPtr<HTMLTokenizer> tokenizer = m_tokenizer.release();
|
| OwnPtr<HTMLToken> token = m_token.release();
|
|
|
| @@ -436,7 +441,7 @@ size_t HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Par
|
|
|
| ASSERT_WITH_SECURITY_IMPLICATION(document()->activeParserCount() == 1);
|
| ASSERT(!isParsingFragment());
|
| - ASSERT(!isWaitingForScripts());
|
| + ASSERT(!isWaitingForBlockingResource());
|
| ASSERT(!isStopped());
|
| #if !ENABLE(OILPAN)
|
| // ASSERT that this object is both attached to the Document and protected.
|
| @@ -445,7 +450,7 @@ size_t HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Par
|
| ASSERT(shouldUseThreading());
|
| ASSERT(!m_tokenizer);
|
| ASSERT(!m_token);
|
| - ASSERT(!m_lastChunkBeforeScript);
|
| + ASSERT(!m_lastChunkBeforeBlockingResource);
|
|
|
| OwnPtr<ParsedChunk> chunk(popChunk);
|
| OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release();
|
| @@ -464,7 +469,7 @@ size_t HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Par
|
| return elementTokenCount;
|
|
|
| for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); it != tokens->end(); ++it) {
|
| - ASSERT(!isWaitingForScripts());
|
| + ASSERT(!isWaitingForBlockingResource());
|
|
|
| if (!chunk->startingScript && (it->type() == HTMLToken::StartTag || it->type() == HTMLToken::EndTag))
|
| elementTokenCount++;
|
| @@ -497,6 +502,12 @@ size_t HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Par
|
| break;
|
| }
|
|
|
| + if (isWaitingForStyles() || isWaitingForImports()) {
|
| + ASSERT(it + 1 == tokens->end()); // The token is assumed to be the last token of this bunch.
|
| + validateSpeculations(chunk.release());
|
| + break;
|
| + }
|
| +
|
| if (it->type() == HTMLToken::EndOfFile) {
|
| ASSERT(it + 1 == tokens->end()); // The EOF is assumed to be the last token of this bunch.
|
| ASSERT(m_speculations.isEmpty()); // There should never be any chunks after the EOF.
|
| @@ -528,15 +539,15 @@ void HTMLDocumentParser::pumpPendingSpeculations()
|
| // m_tokenizer and m_token don't have state that invalidates m_speculations.
|
| ASSERT(!m_tokenizer);
|
| ASSERT(!m_token);
|
| - ASSERT(!m_lastChunkBeforeScript);
|
| - ASSERT(!isWaitingForScripts());
|
| + ASSERT(!m_lastChunkBeforeBlockingResource);
|
| + ASSERT(!isWaitingForBlockingResource());
|
| ASSERT(!isStopped());
|
| ASSERT(!isScheduledForResume());
|
| ASSERT(!inPumpSession());
|
|
|
| // FIXME: Here should never be reached when there is a blocking script,
|
| // but it happens in unknown scenarios. See https://crbug.com/440901
|
| - if (isWaitingForScripts()) {
|
| + if (isWaitingForBlockingResource()) {
|
| m_parserScheduler->scheduleForResume();
|
| return;
|
| }
|
| @@ -560,7 +571,7 @@ void HTMLDocumentParser::pumpPendingSpeculations()
|
| // Surprisingly, isScheduledForResume() may be set here as a result of
|
| // processParsedChunkFromBackgroundParser running arbitrary javascript
|
| // which invokes nested event loops. (e.g. inspector breakpoints)
|
| - if (!isParsing() || isWaitingForScripts() || isScheduledForResume())
|
| + if (!isParsing() || isWaitingForBlockingResource() || isScheduledForResume())
|
| break;
|
|
|
| if (m_speculations.isEmpty() || m_parserScheduler->yieldIfNeeded(session, m_speculations.first()->startingScript))
|
| @@ -649,7 +660,7 @@ void HTMLDocumentParser::pumpTokenizer()
|
| m_treeBuilder->flush(FlushAlways);
|
| RELEASE_ASSERT(!isStopped());
|
|
|
| - if (isWaitingForScripts()) {
|
| + if (isWaitingForBlockingResource()) {
|
| ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState);
|
|
|
| ASSERT(m_preloader);
|
| @@ -739,7 +750,7 @@ void HTMLDocumentParser::insert(const SegmentedString& source)
|
| m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource);
|
| pumpTokenizerIfPossible();
|
|
|
| - if (isWaitingForScripts()) {
|
| + if (isWaitingForBlockingResource()) {
|
| // Check the document.write() output with a separate preload scanner as
|
| // the main scanner can't deal with insertions.
|
| if (!m_insertionPreloadScanner) {
|
| @@ -824,13 +835,13 @@ void HTMLDocumentParser::append(const String& inputSource)
|
| const SegmentedString source(inputSource);
|
|
|
| if (m_preloadScanner) {
|
| - if (m_input.current().isEmpty() && !isWaitingForScripts()) {
|
| + if (m_input.current().isEmpty() && !isWaitingForBlockingResource()) {
|
| // We have parsed until the end of the current input and so are now moving ahead of the preload scanner.
|
| // Clear the scanner so we know to scan starting from the current input point if we block again.
|
| m_preloadScanner.clear();
|
| } else {
|
| m_preloadScanner->appendToEnd(source);
|
| - if (isWaitingForScripts())
|
| + if (isWaitingForBlockingResource())
|
| m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
|
| }
|
| }
|
| @@ -987,14 +998,29 @@ bool HTMLDocumentParser::isWaitingForScripts() const
|
| return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript;
|
| }
|
|
|
| -void HTMLDocumentParser::resumeParsingAfterScriptExecution()
|
| +bool HTMLDocumentParser::isWaitingForStyles() const
|
| +{
|
| + return RuntimeEnabledFeatures::htmlParserBlocksOnCSSEnabled() && document() && document()->styleEngine().hasPendingSheets();
|
| +}
|
| +
|
| +bool HTMLDocumentParser::isWaitingForImports() const
|
| +{
|
| + return RuntimeEnabledFeatures::htmlParserBlocksOnCSSEnabled() && document() && !document()->haveImportsLoaded();
|
| +}
|
| +
|
| +bool HTMLDocumentParser::isWaitingForBlockingResource() const
|
| +{
|
| + return isWaitingForScripts() || isWaitingForStyles() || isWaitingForImports();
|
| +}
|
| +
|
| +void HTMLDocumentParser::resumeParsingAfterBlock()
|
| {
|
| ASSERT(!isExecutingScript());
|
| - ASSERT(!isWaitingForScripts());
|
| + ASSERT(!isWaitingForBlockingResource());
|
|
|
| if (m_haveBackgroundParser) {
|
| - validateSpeculations(m_lastChunkBeforeScript.release());
|
| - ASSERT(!m_lastChunkBeforeScript);
|
| + validateSpeculations(m_lastChunkBeforeBlockingResource.release());
|
| + ASSERT(!m_lastChunkBeforeBlockingResource);
|
| // processParsedChunkFromBackgroundParser can cause this parser to be detached from the Document,
|
| // but we need to ensure it isn't deleted yet.
|
| RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this);
|
| @@ -1033,8 +1059,8 @@ void HTMLDocumentParser::notifyScriptLoaded(Resource* cachedResource)
|
| }
|
|
|
| m_scriptRunner->executeScriptsWaitingForLoad(cachedResource);
|
| - if (!isWaitingForScripts())
|
| - resumeParsingAfterScriptExecution();
|
| + if (!isWaitingForBlockingResource())
|
| + resumeParsingAfterBlock();
|
| }
|
|
|
| void HTMLDocumentParser::executeScriptsWaitingForResources()
|
| @@ -1042,18 +1068,17 @@ void HTMLDocumentParser::executeScriptsWaitingForResources()
|
| // Document only calls this when the Document owns the DocumentParser
|
| // so this will not be called in the DocumentFragment case.
|
| ASSERT(m_scriptRunner);
|
| - // Ignore calls unless we have a script blocking the parser waiting on a
|
| - // stylesheet load. Otherwise we are currently parsing and this
|
| - // is a re-entrant call from encountering a </ style> tag.
|
| - if (!m_scriptRunner->hasScriptsWaitingForResources())
|
| - return;
|
|
|
| - // pumpTokenizer can cause this parser to be detached from the Document,
|
| - // but we need to ensure it isn't deleted yet.
|
| - RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this);
|
| - m_scriptRunner->executeScriptsWaitingForResources();
|
| - if (!isWaitingForScripts())
|
| - resumeParsingAfterScriptExecution();
|
| + if (m_scriptRunner->hasScriptsWaitingForResources()) {
|
| + // pumpTokenizer can cause this parser to be detached from the Document,
|
| + // but we need to ensure it isn't deleted yet.
|
| + RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this);
|
| + m_scriptRunner->executeScriptsWaitingForResources();
|
| + if (!isWaitingForBlockingResource())
|
| + resumeParsingAfterBlock();
|
| + } else if (RuntimeEnabledFeatures::htmlParserBlocksOnCSSEnabled() && !inPumpSession() && !isWaitingForBlockingResource()) {
|
| + resumeParsingAfterBlock();
|
| + }
|
| }
|
|
|
| void HTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFragment* fragment, Element* contextElement, ParserContentPolicy parserContentPolicy)
|
|
|