Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(475)

Unified Diff: third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp

Issue 1772853002: Block the HTML parser on external stylesheets (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Simplified parser blocking logic Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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)

Powered by Google App Engine
This is Rietveld 408576698