diff options
Diffstat (limited to 'WebCore/html/HTMLDocumentParser.cpp')
-rw-r--r-- | WebCore/html/HTMLDocumentParser.cpp | 109 |
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. } } |