summaryrefslogtreecommitdiffstats
path: root/WebCore/html/HTMLDocumentParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html/HTMLDocumentParser.cpp')
-rw-r--r--WebCore/html/HTMLDocumentParser.cpp109
1 files changed, 85 insertions, 24 deletions
diff --git a/WebCore/html/HTMLDocumentParser.cpp b/WebCore/html/HTMLDocumentParser.cpp
index bd2c590..a271603 100644
--- a/WebCore/html/HTMLDocumentParser.cpp
+++ b/WebCore/html/HTMLDocumentParser.cpp
@@ -99,10 +99,10 @@ HTMLTokenizer::State tokenizerStateForContextElement(Element* contextElement, bo
HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors)
: ScriptableDocumentParser(document)
- , m_tokenizer(new HTMLTokenizer)
- , m_scriptRunner(new HTMLScriptRunner(document, this))
- , m_treeBuilder(new HTMLTreeBuilder(m_tokenizer.get(), document, reportErrors))
- , m_parserScheduler(new HTMLParserScheduler(this))
+ , m_tokenizer(HTMLTokenizer::create())
+ , m_scriptRunner(HTMLScriptRunner::create(document, this))
+ , m_treeBuilder(HTMLTreeBuilder::create(m_tokenizer.get(), document, reportErrors))
+ , m_parserScheduler(HTMLParserScheduler::create(this))
, m_endWasDelayed(false)
, m_writeNestingLevel(0)
{
@@ -112,8 +112,8 @@ HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors
// minimize code duplication between these constructors.
HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, Element* contextElement, FragmentScriptingPermission scriptingPermission)
: ScriptableDocumentParser(fragment->document())
- , m_tokenizer(new HTMLTokenizer)
- , m_treeBuilder(new HTMLTreeBuilder(m_tokenizer.get(), fragment, contextElement, scriptingPermission))
+ , m_tokenizer(HTMLTokenizer::create())
+ , m_treeBuilder(HTMLTreeBuilder::create(m_tokenizer.get(), fragment, contextElement, scriptingPermission))
, m_endWasDelayed(false)
, m_writeNestingLevel(0)
{
@@ -123,10 +123,21 @@ HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, Element* cont
HTMLDocumentParser::~HTMLDocumentParser()
{
- // FIXME: We'd like to ASSERT that normal operation of this class clears
- // out any delayed actions, but we can't because we're unceremoniously
- // deleted. If there were a required call to some sort of cancel function,
- // then we could ASSERT some invariants here.
+ ASSERT(!m_parserScheduler);
+ ASSERT(!m_writeNestingLevel);
+ ASSERT(!m_preloadScanner);
+}
+
+void HTMLDocumentParser::detach()
+{
+ DocumentParser::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.clear();
+ m_parserScheduler.clear(); // Deleting the scheduler will clear any timers.
}
void HTMLDocumentParser::stopParsing()
@@ -162,6 +173,10 @@ bool HTMLDocumentParser::isScheduledForResume() const
// Used by HTMLParserScheduler
void HTMLDocumentParser::resumeParsingAfterYield()
{
+ // pumpTokenizer can cause this parser to be detached from the Document,
+ // but we need to ensure it isn't deleted yet.
+ RefPtr<HTMLDocumentParser> protect(this);
+
// We should never be here unless we can pump immediately. Call pumpTokenizer()
// directly so that ASSERTS will fire if we're wrong.
pumpTokenizer(AllowYield);
@@ -182,9 +197,12 @@ bool HTMLDocumentParser::runScriptsForPausedTreeBuilder()
void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
{
+ ASSERT(!isDetached());
ASSERT(!m_parserStopped);
ASSERT(!m_treeBuilder->isPaused());
ASSERT(!isScheduledForResume());
+ // ASSERT that this object is both attached to the Document and protected.
+ ASSERT(refCount() >= 2);
// We tell the InspectorTimelineAgent about every pump, even if we
// end up pumping nothing. It can filter out empty pumps itself.
@@ -192,13 +210,17 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
HTMLParserScheduler::PumpSession session;
// FIXME: This loop body has is now too long and needs cleanup.
- while (mode == ForceSynchronous || (!m_parserStopped && m_parserScheduler->shouldContinueParsing(session))) {
+ while (mode == ForceSynchronous || m_parserScheduler->shouldContinueParsing(session)) {
if (!m_tokenizer->nextToken(m_input.current(), m_token))
break;
m_treeBuilder->constructTreeFromToken(m_token);
m_token.clear();
+ // JavaScript may have stopped or detached the parser.
+ if (isDetached() || m_parserStopped)
+ return;
+
// The parser will pause itself when waiting on a script to load or run.
if (!m_treeBuilder->isPaused())
continue;
@@ -206,14 +228,23 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
// If we're paused waiting for a script, we try to execute scripts before continuing.
bool shouldContinueParsing = runScriptsForPausedTreeBuilder();
m_treeBuilder->setPaused(!shouldContinueParsing);
+
+ // JavaScript may have stopped or detached the parser.
+ if (isDetached() || m_parserStopped)
+ return;
+
if (!shouldContinueParsing)
break;
}
+ // 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.
+ ASSERT(refCount() >= 1);
+
if (isWaitingForScripts()) {
ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState);
if (!m_preloadScanner) {
- m_preloadScanner.set(new HTMLPreloadScanner(m_document));
+ m_preloadScanner.set(new HTMLPreloadScanner(document()));
m_preloadScanner->appendToEnd(m_input.current());
}
m_preloadScanner->scan();
@@ -228,7 +259,7 @@ void HTMLDocumentParser::willPumpLexer()
// 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.
- if (InspectorTimelineAgent* timelineAgent = m_document->inspectorTimelineAgent())
+ if (InspectorTimelineAgent* timelineAgent = document()->inspectorTimelineAgent())
timelineAgent->willWriteHTML(m_input.current().length(), m_tokenizer->lineNumber());
#endif
}
@@ -236,7 +267,7 @@ void HTMLDocumentParser::willPumpLexer()
void HTMLDocumentParser::didPumpLexer()
{
#if ENABLE(INSPECTOR)
- if (InspectorTimelineAgent* timelineAgent = m_document->inspectorTimelineAgent())
+ if (InspectorTimelineAgent* timelineAgent = document()->inspectorTimelineAgent())
timelineAgent->didWriteHTML(m_tokenizer->lineNumber());
#endif
}
@@ -251,9 +282,15 @@ void HTMLDocumentParser::insert(const SegmentedString& source)
if (m_parserStopped)
return;
+<<<<<<< HEAD
#ifdef ANDROID_INSTRUMENT
android::TimeCounter::start(android::TimeCounter::ParsingTimeCounter);
#endif
+=======
+ // pumpTokenizer can cause this parser to be detached from the Document,
+ // but we need to ensure it isn't deleted yet.
+ RefPtr<HTMLDocumentParser> protect(this);
+>>>>>>> webkit.org at r66079
{
NestingLevelIncrementer nestingLevelIncrementer(m_writeNestingLevel);
@@ -272,6 +309,10 @@ void HTMLDocumentParser::append(const SegmentedString& source)
if (m_parserStopped)
return;
+ // pumpTokenizer can cause this parser to be detached from the Document,
+ // but we need to ensure it isn't deleted yet.
+ RefPtr<HTMLDocumentParser> protect(this);
+
{
NestingLevelIncrementer nestingLevelIncrementer(m_writeNestingLevel);
@@ -300,7 +341,13 @@ void HTMLDocumentParser::append(const SegmentedString& source)
void HTMLDocumentParser::end()
{
+ ASSERT(!isDetached());
ASSERT(!isScheduledForResume());
+
+ // pumpTokenizer can cause this parser to be detached from the Document,
+ // but we need to ensure it isn't deleted yet.
+ RefPtr<HTMLDocumentParser> protect(this);
+
// NOTE: This pump should only ever emit buffered character tokens,
// so ForceSynchronous vs. AllowYield should be meaningless.
pumpTokenizerIfPossible(ForceSynchronous);
@@ -323,6 +370,10 @@ void HTMLDocumentParser::attemptToEnd()
void HTMLDocumentParser::endIfDelayed()
{
+ // If we've already been detached, don't bother ending.
+ if (isDetached())
+ return;
+
if (!m_endWasDelayed || shouldDelayEnd())
return;
@@ -332,6 +383,11 @@ void HTMLDocumentParser::endIfDelayed()
void HTMLDocumentParser::finish()
{
+ // FIXME: We should ASSERT(!m_parserStopped) here, since it does not
+ // makes sense to call any methods on DocumentParser once it's been stopped.
+ // However, FrameLoader::stop calls Document::finishParsing unconditionally
+ // which in turn calls m_parser->finish().
+
// We're not going to get any more data off the network, so we tell the
// input stream we've reached the end of file. finish() can be called more
// than once, if the first time does not call end().
@@ -369,11 +425,6 @@ int HTMLDocumentParser::columnNumber() const
return m_tokenizer->columnNumber();
}
-LegacyHTMLTreeBuilder* HTMLDocumentParser::htmlTreeBuilder() const
-{
- return m_treeBuilder->legacyTreeBuilder();
-}
-
bool HTMLDocumentParser::isWaitingForScripts() const
{
return m_treeBuilder->isPaused();
@@ -412,6 +463,10 @@ bool HTMLDocumentParser::shouldLoadExternalScriptFromSrc(const AtomicString& src
void HTMLDocumentParser::notifyFinished(CachedResource* cachedResource)
{
+ // pumpTokenizer can cause this parser to be detached from the Document,
+ // but we need to ensure it isn't deleted yet.
+ RefPtr<HTMLDocumentParser> protect(this);
+
ASSERT(m_scriptRunner);
ASSERT(!inScriptExecution());
ASSERT(m_treeBuilder->isPaused());
@@ -434,6 +489,11 @@ void HTMLDocumentParser::executeScriptsWaitingForStylesheets()
// is a re-entrant call from encountering a </ style> tag.
if (!m_scriptRunner->hasScriptsWaitingForStylesheets())
return;
+
+ // pumpTokenizer can cause this parser to be detached from the Document,
+ // but we need to ensure it isn't deleted yet.
+ RefPtr<HTMLDocumentParser> protect(this);
+
ASSERT(!m_scriptRunner->isExecutingScript());
ASSERT(m_treeBuilder->isPaused());
// Note: We only ever wait on one script at a time, so we always know this
@@ -447,15 +507,16 @@ void HTMLDocumentParser::executeScriptsWaitingForStylesheets()
ScriptController* HTMLDocumentParser::script() const
{
- return m_document->frame() ? m_document->frame()->script() : 0;
+ return document()->frame() ? document()->frame()->script() : 0;
}
void HTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFragment* fragment, Element* contextElement, FragmentScriptingPermission scriptingPermission)
{
- HTMLDocumentParser parser(fragment, contextElement, scriptingPermission);
- 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>
+ RefPtr<HTMLDocumentParser> parser = HTMLDocumentParser::create(fragment, contextElement, scriptingPermission);
+ 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.
}
}