summaryrefslogtreecommitdiff
path: root/Source/WebCore/html/parser/HTMLDocumentParser.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/html/parser/HTMLDocumentParser.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/html/parser/HTMLDocumentParser.cpp')
-rw-r--r--Source/WebCore/html/parser/HTMLDocumentParser.cpp358
1 files changed, 165 insertions, 193 deletions
diff --git a/Source/WebCore/html/parser/HTMLDocumentParser.cpp b/Source/WebCore/html/parser/HTMLDocumentParser.cpp
index 488862049..c3846db05 100644
--- a/Source/WebCore/html/parser/HTMLDocumentParser.cpp
+++ b/Source/WebCore/html/parser/HTMLDocumentParser.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,99 +27,70 @@
#include "config.h"
#include "HTMLDocumentParser.h"
-#include "ContentSecurityPolicy.h"
#include "DocumentFragment.h"
-#include "DocumentLoader.h"
#include "Frame.h"
+#include "HTMLDocument.h"
#include "HTMLParserScheduler.h"
+#include "HTMLPreloadScanner.h"
#include "HTMLScriptRunner.h"
#include "HTMLTreeBuilder.h"
-#include "HTMLDocument.h"
-#include "InspectorInstrumentation.h"
-#include "Settings.h"
-#include <wtf/Ref.h>
+#include "HTMLUnknownElement.h"
+#include "JSCustomElementInterface.h"
+#include "ScriptElement.h"
namespace WebCore {
using namespace HTMLNames;
-// This is a direct transcription of step 4 from:
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case
-static HTMLTokenizer::State tokenizerStateForContextElement(Element* contextElement, bool reportErrors, const HTMLParserOptions& options)
-{
- if (!contextElement)
- return HTMLTokenizer::DataState;
-
- const QualifiedName& contextTag = contextElement->tagQName();
-
- if (contextTag.matches(titleTag) || contextTag.matches(textareaTag))
- return HTMLTokenizer::RCDATAState;
- if (contextTag.matches(styleTag)
- || contextTag.matches(xmpTag)
- || contextTag.matches(iframeTag)
- || (contextTag.matches(noembedTag) && options.pluginsEnabled)
- || (contextTag.matches(noscriptTag) && options.scriptEnabled)
- || contextTag.matches(noframesTag))
- return reportErrors ? HTMLTokenizer::RAWTEXTState : HTMLTokenizer::PLAINTEXTState;
- if (contextTag.matches(scriptTag))
- return reportErrors ? HTMLTokenizer::ScriptDataState : HTMLTokenizer::PLAINTEXTState;
- if (contextTag.matches(plaintextTag))
- return HTMLTokenizer::PLAINTEXTState;
- return HTMLTokenizer::DataState;
-}
-
HTMLDocumentParser::HTMLDocumentParser(HTMLDocument& document)
: ScriptableDocumentParser(document)
, m_options(document)
- , m_token(std::make_unique<HTMLToken>())
- , m_tokenizer(std::make_unique<HTMLTokenizer>(m_options))
+ , m_tokenizer(m_options)
, m_scriptRunner(std::make_unique<HTMLScriptRunner>(document, static_cast<HTMLScriptRunnerHost&>(*this)))
, m_treeBuilder(std::make_unique<HTMLTreeBuilder>(*this, document, parserContentPolicy(), m_options))
, m_parserScheduler(std::make_unique<HTMLParserScheduler>(*this))
, m_xssAuditorDelegate(document)
, m_preloader(std::make_unique<HTMLResourcePreloader>(document))
- , m_endWasDelayed(false)
- , m_haveBackgroundParser(false)
- , m_pumpSessionNestingLevel(0)
{
- ASSERT(m_token);
- ASSERT(m_tokenizer);
}
-// FIXME: Member variables should be grouped into self-initializing structs to
-// minimize code duplication between these constructors.
-HTMLDocumentParser::HTMLDocumentParser(DocumentFragment& fragment, Element* contextElement, ParserContentPolicy parserContentPolicy)
- : ScriptableDocumentParser(fragment.document(), parserContentPolicy)
+Ref<HTMLDocumentParser> HTMLDocumentParser::create(HTMLDocument& document)
+{
+ return adoptRef(*new HTMLDocumentParser(document));
+}
+
+inline HTMLDocumentParser::HTMLDocumentParser(DocumentFragment& fragment, Element& contextElement, ParserContentPolicy rawPolicy)
+ : ScriptableDocumentParser(fragment.document(), rawPolicy)
, m_options(fragment.document())
- , m_token(std::make_unique<HTMLToken>())
- , m_tokenizer(std::make_unique<HTMLTokenizer>(m_options))
- , m_treeBuilder(std::make_unique<HTMLTreeBuilder>(*this, fragment, contextElement, this->parserContentPolicy(), m_options))
+ , m_tokenizer(m_options)
+ , m_treeBuilder(std::make_unique<HTMLTreeBuilder>(*this, fragment, contextElement, parserContentPolicy(), m_options))
, m_xssAuditorDelegate(fragment.document())
- , m_endWasDelayed(false)
- , m_haveBackgroundParser(false)
- , m_pumpSessionNestingLevel(0)
{
- bool reportErrors = false; // For now document fragment parsing never reports errors.
- m_tokenizer->setState(tokenizerStateForContextElement(contextElement, reportErrors, m_options));
+ // https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments
+ if (contextElement.isHTMLElement())
+ m_tokenizer.updateStateFor(contextElement.tagQName().localName());
m_xssAuditor.initForFragment();
}
+inline Ref<HTMLDocumentParser> HTMLDocumentParser::create(DocumentFragment& fragment, Element& contextElement, ParserContentPolicy parserContentPolicy)
+{
+ return adoptRef(*new HTMLDocumentParser(fragment, contextElement, parserContentPolicy));
+}
+
HTMLDocumentParser::~HTMLDocumentParser()
{
ASSERT(!m_parserScheduler);
ASSERT(!m_pumpSessionNestingLevel);
ASSERT(!m_preloadScanner);
ASSERT(!m_insertionPreloadScanner);
- ASSERT(!m_haveBackgroundParser);
}
void HTMLDocumentParser::detach()
{
- DocumentParser::detach();
+ ScriptableDocumentParser::detach();
if (m_scriptRunner)
m_scriptRunner->detach();
- m_treeBuilder->detach();
// FIXME: It seems wrong that we would have a preload scanner here.
// Yet during fast/dom/HTMLScriptElement/script-load-events.html we do.
m_preloadScanner = nullptr;
@@ -133,16 +105,14 @@ void HTMLDocumentParser::stopParsing()
}
// This kicks off "Once the user agent stops parsing" as described by:
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the-end
+// https://html.spec.whatwg.org/multipage/syntax.html#the-end
void HTMLDocumentParser::prepareToStopParsing()
{
- // FIXME: It may not be correct to disable this for the background parser.
- // That means hasInsertionPoint() may not be correct in some cases.
- ASSERT(!hasInsertionPoint() || m_haveBackgroundParser);
+ ASSERT(!hasInsertionPoint());
// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
- Ref<HTMLDocumentParser> protect(*this);
+ Ref<HTMLDocumentParser> protectedThis(*this);
// NOTE: This pump should only ever emit buffered character tokens,
// so ForceSynchronous vs. AllowYield should be meaningless.
@@ -165,6 +135,16 @@ void HTMLDocumentParser::prepareToStopParsing()
attemptToRunDeferredScriptsAndEnd();
}
+inline bool HTMLDocumentParser::inPumpSession() const
+{
+ return m_pumpSessionNestingLevel > 0;
+}
+
+inline bool HTMLDocumentParser::shouldDelayEnd() const
+{
+ return inPumpSession() || isWaitingForScripts() || isScheduledForResume() || isExecutingScript();
+}
+
bool HTMLDocumentParser::isParsingFragment() const
{
return m_treeBuilder->isParsingFragment();
@@ -172,7 +152,7 @@ bool HTMLDocumentParser::isParsingFragment() const
bool HTMLDocumentParser::processingData() const
{
- return isScheduledForResume() || inPumpSession() || m_haveBackgroundParser;
+ return isScheduledForResume() || inPumpSession();
}
void HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode)
@@ -199,10 +179,10 @@ void HTMLDocumentParser::resumeParsingAfterYield()
{
// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
- Ref<HTMLDocumentParser> protect(*this);
+ Ref<HTMLDocumentParser> protectedThis(*this);
- // We should never be here unless we can pump immediately. Call pumpTokenizer()
- // directly so that ASSERTS will fire if we're wrong.
+ // We should never be here unless we can pump immediately.
+ // Call pumpTokenizer() directly so that ASSERTS will fire if we're wrong.
pumpTokenizer(AllowYield);
endIfDelayed();
}
@@ -211,53 +191,23 @@ void HTMLDocumentParser::runScriptsForPausedTreeBuilder()
{
ASSERT(scriptingContentIsAllowed(parserContentPolicy()));
- TextPosition scriptStartPosition = TextPosition::belowRangePosition();
- RefPtr<Element> scriptElement = m_treeBuilder->takeScriptToProcess(scriptStartPosition);
- // We will not have a scriptRunner when parsing a DocumentFragment.
- if (m_scriptRunner)
- m_scriptRunner->execute(scriptElement.release(), scriptStartPosition);
-}
-
-bool HTMLDocumentParser::canTakeNextToken(SynchronousMode mode, PumpSession& session)
-{
- if (isStopped())
- return false;
-
- ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous);
+ if (std::unique_ptr<CustomElementConstructionData> constructionData = m_treeBuilder->takeCustomElementConstructionData()) {
+ ASSERT(!m_treeBuilder->hasParserBlockingScriptWork());
- if (isWaitingForScripts()) {
- if (mode == AllowYield)
- m_parserScheduler->checkForYieldBeforeScript(session);
-
- // If we don't run the script, we cannot allow the next token to be taken.
- if (session.needsYield)
- return false;
-
- // If we're paused waiting for a script, we try to execute scripts before continuing.
- runScriptsForPausedTreeBuilder();
- if (isWaitingForScripts() || isStopped())
- return false;
+ // https://html.spec.whatwg.org/#create-an-element-for-the-token
+ auto& elementInterface = constructionData->elementInterface.get();
+ auto newElement = elementInterface.constructElementWithFallback(*document(), constructionData->name);
+ m_treeBuilder->didCreateCustomOrCallbackElement(WTFMove(newElement), *constructionData);
+ return;
}
- // FIXME: It's wrong for the HTMLDocumentParser to reach back to the
- // Frame, but this approach is how the old parser handled
- // stopping when the page assigns window.location. What really
- // should happen is that assigning window.location causes the
- // parser to stop parsing cleanly. The problem is we're not
- // perpared to do that at every point where we run JavaScript.
- if (!isParsingFragment()
- && document()->frame() && document()->frame()->navigationScheduler().locationChangePending())
- return false;
-
- if (mode == AllowYield)
- m_parserScheduler->checkForYieldBeforeToken(session);
-
- return true;
-}
-
-void HTMLDocumentParser::forcePlaintextForTextDocument()
-{
- m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState);
+ TextPosition scriptStartPosition = TextPosition::belowRangePosition();
+ if (auto scriptElement = m_treeBuilder->takeScriptToProcess(scriptStartPosition)) {
+ ASSERT(!m_treeBuilder->hasParserBlockingScriptWork());
+ // We will not have a scriptRunner when parsing a DocumentFragment.
+ if (m_scriptRunner)
+ m_scriptRunner->execute(scriptElement.releaseNonNull(), scriptStartPosition);
+ }
}
Document* HTMLDocumentParser::contextForParsingSession()
@@ -265,50 +215,67 @@ Document* HTMLDocumentParser::contextForParsingSession()
// The parsing session should interact with the document only when parsing
// non-fragments. Otherwise, we might delay the load event mistakenly.
if (isParsingFragment())
- return 0;
+ return nullptr;
return document();
}
-void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
+bool HTMLDocumentParser::pumpTokenizerLoop(SynchronousMode mode, bool parsingFragment, PumpSession& session)
{
- ASSERT(!isStopped());
- ASSERT(!isScheduledForResume());
- // ASSERT that this object is both attached to the Document and protected.
- ASSERT(refCount() >= 2);
- ASSERT(m_tokenizer);
- ASSERT(m_token);
- ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous);
-
- PumpSession session(m_pumpSessionNestingLevel, contextForParsingSession());
+ do {
+ if (UNLIKELY(isWaitingForScripts())) {
+ if (mode == AllowYield && m_parserScheduler->shouldYieldBeforeExecutingScript(session))
+ return true;
+ runScriptsForPausedTreeBuilder();
+ // If we're paused waiting for a script, we try to execute scripts before continuing.
+ if (isWaitingForScripts() || isStopped())
+ return false;
+ }
- // We tell the InspectorInstrumentation about every pump, even if we
- // end up pumping nothing. It can filter out empty pumps itself.
- // FIXME: m_input.current().length() is only accurate if we
- // end up parsing the whole buffer in this pump. We should pass how
- // much we parsed as part of didWriteHTML instead of willWriteHTML.
- InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteHTML(document(), m_input.current().currentLine().zeroBasedInt());
+ // FIXME: It's wrong for the HTMLDocumentParser to reach back to the Frame, but this approach is
+ // how the parser has always handled stopping when the page assigns window.location. What should
+ // happen instead is that assigning window.location causes the parser to stop parsing cleanly.
+ // The problem is we're not prepared to do that at every point where we run JavaScript.
+ if (UNLIKELY(!parsingFragment && document()->frame() && document()->frame()->navigationScheduler().locationChangePending()))
+ return false;
- m_xssAuditor.init(document(), &m_xssAuditorDelegate);
+ if (UNLIKELY(mode == AllowYield && m_parserScheduler->shouldYieldBeforeToken(session)))
+ return true;
- while (canTakeNextToken(mode, session) && !session.needsYield) {
- if (!isParsingFragment())
- m_sourceTracker.start(m_input.current(), m_tokenizer.get(), token());
+ if (!parsingFragment)
+ m_sourceTracker.startToken(m_input.current(), m_tokenizer);
- if (!m_tokenizer->nextToken(m_input.current(), token()))
- break;
+ auto token = m_tokenizer.nextToken(m_input.current());
+ if (!token)
+ return false;
- if (!isParsingFragment()) {
- m_sourceTracker.end(m_input.current(), m_tokenizer.get(), token());
+ if (!parsingFragment) {
+ m_sourceTracker.endToken(m_input.current(), m_tokenizer);
// We do not XSS filter innerHTML, which means we (intentionally) fail
// http/tests/security/xssAuditor/dom-write-innerHTML.html
- if (auto xssInfo = m_xssAuditor.filterToken(FilterTokenRequest(token(), m_sourceTracker, m_tokenizer->shouldAllowCDATA())))
+ if (auto xssInfo = m_xssAuditor.filterToken(FilterTokenRequest(*token, m_sourceTracker, m_tokenizer.shouldAllowCDATA())))
m_xssAuditorDelegate.didBlockScript(*xssInfo);
}
- constructTreeFromHTMLToken(token());
- ASSERT(token().isUninitialized());
- }
+ constructTreeFromHTMLToken(token);
+ } while (!isStopped());
+
+ return false;
+}
+
+void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
+{
+ ASSERT(!isStopped());
+ ASSERT(!isScheduledForResume());
+
+ // This is an attempt to check that this object is both attached to the Document and protected by something.
+ ASSERT(refCount() >= 2);
+
+ PumpSession session(m_pumpSessionNestingLevel, contextForParsingSession());
+
+ m_xssAuditor.init(document(), &m_xssAuditorDelegate);
+
+ bool shouldResume = pumpTokenizerLoop(mode, isParsingFragment(), session);
// Ensure we haven't been totally deref'ed after pumping. Any caller of this
// function should be holding a RefPtr to this to ensure we weren't deleted.
@@ -317,24 +284,22 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
if (isStopped())
return;
- if (session.needsYield)
+ if (shouldResume)
m_parserScheduler->scheduleForResume();
if (isWaitingForScripts()) {
- ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState);
+ ASSERT(m_tokenizer.isInDataState());
if (!m_preloadScanner) {
m_preloadScanner = std::make_unique<HTMLPreloadScanner>(m_options, document()->url(), document()->deviceScaleFactor());
m_preloadScanner->appendToEnd(m_input.current());
}
- m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
+ m_preloadScanner->scan(*m_preloader, *document());
}
-
- InspectorInstrumentation::didWriteHTML(cookie, m_input.current().currentLine().zeroBasedInt());
}
-void HTMLDocumentParser::constructTreeFromHTMLToken(HTMLToken& rawToken)
+void HTMLDocumentParser::constructTreeFromHTMLToken(HTMLTokenizer::TokenPtr& rawToken)
{
- AtomicHTMLToken token(rawToken);
+ AtomicHTMLToken token(*rawToken);
// We clear the rawToken in case constructTreeFromAtomicToken
// synchronously re-enters the parser. We don't clear the token immedately
@@ -346,63 +311,59 @@ void HTMLDocumentParser::constructTreeFromHTMLToken(HTMLToken& rawToken)
// FIXME: Stop clearing the rawToken once we start running the parser off
// the main thread or once we stop allowing synchronous JavaScript
// execution from parseAttribute.
- if (rawToken.type() != HTMLToken::Character)
- rawToken.clear();
-
- m_treeBuilder->constructTree(&token);
-
- if (!rawToken.isUninitialized()) {
- ASSERT(rawToken.type() == HTMLToken::Character);
+ if (rawToken->type() != HTMLToken::Character) {
+ // Clearing the TokenPtr makes sure we don't clear the HTMLToken a second time
+ // later when the TokenPtr is destroyed.
rawToken.clear();
}
+
+ m_treeBuilder->constructTree(WTFMove(token));
}
bool HTMLDocumentParser::hasInsertionPoint()
{
// FIXME: The wasCreatedByScript() branch here might not be fully correct.
- // Our model of the EOF character differs slightly from the one in
- // the spec because our treatment is uniform between network-sourced
- // and script-sourced input streams whereas the spec treats them
- // differently.
+ // Our model of the EOF character differs slightly from the one in the spec
+ // because our treatment is uniform between network-sourced and script-sourced
+ // input streams whereas the spec treats them differently.
return m_input.hasInsertionPoint() || (wasCreatedByScript() && !m_input.haveSeenEndOfFile());
}
-void HTMLDocumentParser::insert(const SegmentedString& source)
+void HTMLDocumentParser::insert(SegmentedString&& source)
{
if (isStopped())
return;
// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
- Ref<HTMLDocumentParser> protect(*this);
+ Ref<HTMLDocumentParser> protectedThis(*this);
- SegmentedString excludedLineNumberSource(source);
- excludedLineNumberSource.setExcludeLineNumbers();
- m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource);
+ source.setExcludeLineNumbers();
+ m_input.insertAtCurrentInsertionPoint(WTFMove(source));
pumpTokenizerIfPossible(ForceSynchronous);
if (isWaitingForScripts()) {
// Check the document.write() output with a separate preload scanner as
// the main scanner can't deal with insertions.
- if (!m_insertionPreloadScanner) {
+ if (!m_insertionPreloadScanner)
m_insertionPreloadScanner = std::make_unique<HTMLPreloadScanner>(m_options, document()->url(), document()->deviceScaleFactor());
- }
m_insertionPreloadScanner->appendToEnd(source);
- m_insertionPreloadScanner->scan(m_preloader.get(), document()->baseElementURL());
+ m_insertionPreloadScanner->scan(*m_preloader, *document());
}
endIfDelayed();
}
-void HTMLDocumentParser::append(PassRefPtr<StringImpl> inputSource)
+void HTMLDocumentParser::append(RefPtr<StringImpl>&& inputSource)
{
if (isStopped())
return;
// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
- Ref<HTMLDocumentParser> protect(*this);
- String source(inputSource);
+ Ref<HTMLDocumentParser> protectedThis(*this);
+
+ String source { WTFMove(inputSource) };
if (m_preloadScanner) {
if (m_input.current().isEmpty() && !isWaitingForScripts()) {
@@ -412,7 +373,7 @@ void HTMLDocumentParser::append(PassRefPtr<StringImpl> inputSource)
} else {
m_preloadScanner->appendToEnd(source);
if (isWaitingForScripts())
- m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
+ m_preloadScanner->scan(*m_preloader, *document());
}
}
@@ -442,9 +403,7 @@ void HTMLDocumentParser::end()
void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd()
{
ASSERT(isStopping());
- // FIXME: It may not be correct to disable this for the background parser.
- // That means hasInsertionPoint() may not be correct in some cases.
- ASSERT(!hasInsertionPoint() || m_haveBackgroundParser);
+ ASSERT(!hasInsertionPoint());
if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing())
return;
end();
@@ -492,18 +451,18 @@ void HTMLDocumentParser::finish()
bool HTMLDocumentParser::isExecutingScript() const
{
- if (!m_scriptRunner)
- return false;
- return m_scriptRunner->isExecutingScript();
+ return m_scriptRunner && m_scriptRunner->isExecutingScript();
}
TextPosition HTMLDocumentParser::textPosition() const
{
- const SegmentedString& currentString = m_input.current();
- OrdinalNumber line = currentString.currentLine();
- OrdinalNumber column = currentString.currentColumn();
+ auto& currentString = m_input.current();
+ return TextPosition(currentString.currentLine(), currentString.currentColumn());
+}
- return TextPosition(line, column);
+bool HTMLDocumentParser::shouldAssociateConsoleMessagesWithTextPosition() const
+{
+ return inPumpSession() && !isExecutingScript();
}
bool HTMLDocumentParser::isWaitingForScripts() const
@@ -513,7 +472,7 @@ bool HTMLDocumentParser::isWaitingForScripts() const
// The script runner will hold the script until its loaded and run. During
// any of this time, we want to count ourselves as "waiting for a script" and thus
// run the preload scanner, as well as delay completion of parsing.
- bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript();
+ bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScriptWork();
bool scriptRunnerHasBlockingScript = m_scriptRunner && m_scriptRunner->hasParserBlockingScript();
// Since the parser is paused while a script runner has a blocking script, it should
// never be possible to end up with both objects holding a blocking script.
@@ -527,37 +486,45 @@ void HTMLDocumentParser::resumeParsingAfterScriptExecution()
ASSERT(!isExecutingScript());
ASSERT(!isWaitingForScripts());
+ // pumpTokenizer can cause this parser to be detached from the Document,
+ // but we need to ensure it isn't deleted yet.
+ Ref<HTMLDocumentParser> protectedThis(*this);
+
m_insertionPreloadScanner = nullptr;
pumpTokenizerIfPossible(AllowYield);
endIfDelayed();
}
-void HTMLDocumentParser::watchForLoad(CachedResource* cachedScript)
+void HTMLDocumentParser::watchForLoad(PendingScript& pendingScript)
{
- ASSERT(!cachedScript->isLoaded());
- // addClient would call notifyFinished if the load were complete.
+ ASSERT(!pendingScript.isLoaded());
+ // setClient would call notifyFinished if the load were complete.
// Callers do not expect to be re-entered from this call, so they should
- // not an already-loaded CachedResource.
- cachedScript->addClient(this);
+ // not an already-loaded PendingScript.
+ pendingScript.setClient(*this);
}
-void HTMLDocumentParser::stopWatchingForLoad(CachedResource* cachedScript)
+void HTMLDocumentParser::stopWatchingForLoad(PendingScript& pendingScript)
{
- cachedScript->removeClient(this);
+ pendingScript.clearClient();
}
-
+
void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan()
{
ASSERT(m_preloadScanner);
m_preloadScanner->appendToEnd(m_input.current());
- m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
+ m_preloadScanner->scan(*m_preloader, *document());
}
-void HTMLDocumentParser::notifyFinished(CachedResource* cachedResource)
+void HTMLDocumentParser::notifyFinished(PendingScript& pendingScript)
{
// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
- Ref<HTMLDocumentParser> protect(*this);
+ Ref<HTMLDocumentParser> protectedThis(*this);
+
+ // After Document parser is stopped or detached, the parser-inserted deferred script execution should be ignored.
+ if (isStopped())
+ return;
ASSERT(m_scriptRunner);
ASSERT(!isExecutingScript());
@@ -566,11 +533,16 @@ void HTMLDocumentParser::notifyFinished(CachedResource* cachedResource)
return;
}
- m_scriptRunner->executeScriptsWaitingForLoad(cachedResource);
+ m_scriptRunner->executeScriptsWaitingForLoad(pendingScript);
if (!isWaitingForScripts())
resumeParsingAfterScriptExecution();
}
+bool HTMLDocumentParser::hasScriptsWaitingForStylesheets() const
+{
+ return m_scriptRunner && m_scriptRunner->hasScriptsWaitingForStylesheets();
+}
+
void HTMLDocumentParser::executeScriptsWaitingForStylesheets()
{
// Document only calls this when the Document owns the DocumentParser
@@ -584,19 +556,19 @@ void HTMLDocumentParser::executeScriptsWaitingForStylesheets()
// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
- Ref<HTMLDocumentParser> protect(*this);
+ Ref<HTMLDocumentParser> protectedThis(*this);
m_scriptRunner->executeScriptsWaitingForStylesheets();
if (!isWaitingForScripts())
resumeParsingAfterScriptExecution();
}
-void HTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFragment& fragment, Element* contextElement, ParserContentPolicy parserContentPolicy)
+void HTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFragment& fragment, Element& contextElement, ParserContentPolicy parserContentPolicy)
{
- RefPtr<HTMLDocumentParser> parser = HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy);
+ auto parser = create(fragment, contextElement, parserContentPolicy);
parser->insert(source); // Use insert() so that the parser will not yield.
parser->finish();
- ASSERT(!parser->processingData()); // Make sure we're done. <rdar://problem/3963151>
- parser->detach(); // Allows ~DocumentParser to assert it was detached before destruction.
+ ASSERT(!parser->processingData());
+ parser->detach();
}
void HTMLDocumentParser::suspendScheduledTasks()