| Index: Source/core/html/parser/HTMLDocumentParser.cpp
|
| diff --git a/Source/core/html/parser/HTMLDocumentParser.cpp b/Source/core/html/parser/HTMLDocumentParser.cpp
|
| index 84c9197c309a3f36d5ee241d57a959ea31b771b2..0a3fe7df21e9754e94c78d244a57627a262ea75e 100644
|
| --- a/Source/core/html/parser/HTMLDocumentParser.cpp
|
| +++ b/Source/core/html/parser/HTMLDocumentParser.cpp
|
| @@ -33,13 +33,16 @@
|
| #include "core/html/parser/AtomicHTMLToken.h"
|
| #include "core/html/parser/BackgroundHTMLParser.h"
|
| #include "core/html/parser/HTMLParserScheduler.h"
|
| -#include "core/html/parser/HTMLParserThread.h"
|
| #include "core/html/parser/HTMLScriptRunner.h"
|
| #include "core/html/parser/HTMLTreeBuilder.h"
|
| #include "core/inspector/InspectorInstrumentation.h"
|
| #include "core/frame/Frame.h"
|
| +#include "core/loader/DocumentLoader.h"
|
| #include "platform/SharedBuffer.h"
|
| +#include "platform/Task.h"
|
| #include "platform/TraceEvent.h"
|
| +#include "public/platform/WebThread.h"
|
| +#include "public/platform/WebThreadedResourceProvider.h"
|
| #include "wtf/Functional.h"
|
|
|
| namespace WebCore {
|
| @@ -71,6 +74,25 @@ static HTMLTokenizer::State tokenizerStateForContextElement(Element* contextElem
|
| return HTMLTokenizer::DataState;
|
| }
|
|
|
| +class ParserResourceForegroundClient : public blink::WebThreadedResourceForegroundClient {
|
| +public:
|
| + ParserResourceForegroundClient(WeakPtr<HTMLDocumentParser> parser)
|
| + : m_parser(parser)
|
| + {
|
| + }
|
| +
|
| + // WebThreadedResourceForegroundClient
|
| + virtual void didSwitchedToBackgroundClient() OVERRIDE FINAL {
|
| + if (m_parser.get())
|
| + m_parser.get()->didSwitchedToBackgroundClient();
|
| + }
|
| +
|
| +private:
|
| + WeakPtr<HTMLDocumentParser> m_parser;
|
| +};
|
| +
|
| +blink::WebThread* HTMLDocumentParser::s_parserThread = 0;
|
| +
|
| HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors)
|
| : ScriptableDocumentParser(document)
|
| , m_options(document)
|
| @@ -86,6 +108,7 @@ HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors
|
| , m_endWasDelayed(false)
|
| , m_haveBackgroundParser(false)
|
| , m_pumpSessionNestingLevel(0)
|
| + , m_parserThreadIsStandalone(false)
|
| {
|
| ASSERT(shouldUseThreading() || (m_token && m_tokenizer));
|
| }
|
| @@ -104,6 +127,7 @@ HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, Element* cont
|
| , m_endWasDelayed(false)
|
| , m_haveBackgroundParser(false)
|
| , m_pumpSessionNestingLevel(0)
|
| + , m_parserThreadIsStandalone(false)
|
| {
|
| ASSERT(!shouldUseThreading());
|
| bool reportErrors = false; // For now document fragment parsing never reports errors.
|
| @@ -322,6 +346,11 @@ void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser(const Docume
|
| document()->setEncodingData(data);
|
| }
|
|
|
| +void HTMLDocumentParser::destroyResourceProvider(PassOwnPtr<blink::WebThreadedResourceProvider> resourceProvider)
|
| +{
|
| + // Here to let the resource bridge be destructed on the main thread.
|
| +}
|
| +
|
| void HTMLDocumentParser::validateSpeculations(PassOwnPtr<ParsedChunk> chunk)
|
| {
|
| ASSERT(chunk);
|
| @@ -377,7 +406,8 @@ void HTMLDocumentParser::discardSpeculationsAndResumeFrom(PassOwnPtr<ParsedChunk
|
| m_input.current().clear(); // FIXME: This should be passed in instead of cleared.
|
|
|
| ASSERT(checkpoint->unparsedInput.isSafeToSendToAnotherThread());
|
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::resumeFrom, m_backgroundParser, checkpoint.release()));
|
| + ASSERT(m_parserThread);
|
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::resumeFrom, m_backgroundParser, checkpoint.release())));
|
| }
|
|
|
| void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk> popChunk)
|
| @@ -394,13 +424,14 @@ void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Parse
|
| ASSERT(!m_tokenizer);
|
| ASSERT(!m_token);
|
| ASSERT(!m_lastChunkBeforeScript);
|
| + ASSERT(s_parserThread);
|
|
|
| ActiveParserSession session(contextForParsingSession());
|
|
|
| OwnPtr<ParsedChunk> chunk(popChunk);
|
| OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release();
|
|
|
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::startedChunkWithCheckpoint, m_backgroundParser, chunk->inputCheckpoint));
|
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::startedChunkWithCheckpoint, m_backgroundParser, chunk->inputCheckpoint)));
|
|
|
| for (XSSInfoStream::const_iterator it = chunk->xssInfos.begin(); it != chunk->xssInfos.end(); ++it) {
|
| m_textPosition = (*it)->m_textPosition;
|
| @@ -491,14 +522,12 @@ void HTMLDocumentParser::pumpPendingSpeculations()
|
|
|
| void HTMLDocumentParser::forcePlaintextForTextDocument()
|
| {
|
| - if (shouldUseThreading()) {
|
| - // This method is called before any data is appended, so we have to start
|
| - // the background parser ourselves.
|
| - if (!m_haveBackgroundParser)
|
| - startBackgroundParser();
|
| + if (shouldUseThreading() && !m_haveBackgroundParser)
|
| + startBackgroundParser();
|
|
|
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::forcePlaintextForTextDocument, m_backgroundParser));
|
| - } else
|
| + if (m_haveBackgroundParser)
|
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::forcePlaintextForTextDocument, m_backgroundParser)));
|
| + else
|
| m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState);
|
| }
|
|
|
| @@ -662,6 +691,26 @@ void HTMLDocumentParser::startBackgroundParser()
|
| ASSERT(!isStopped());
|
| ASSERT(shouldUseThreading());
|
| ASSERT(!m_haveBackgroundParser);
|
| +
|
| + OwnPtr<blink::WebThreadedResourceProvider> resourceProvider = document()->loader()->createThreadedResourceProvider();
|
| + if (resourceProvider) {
|
| + // The resource provider is responsible for destroying the client we create here.
|
| + resourceProvider->setForegroundClient(new ParserResourceForegroundClient(m_weakFactory.createWeakPtr()));
|
| + if (!s_parserThread)
|
| + s_parserThread = resourceProvider->resourceThread();
|
| + ASSERT(s_parserThread && s_parserThread == resourceProvider->resourceThread());
|
| + }
|
| +
|
| + if (!s_parserThread) {
|
| + // If we don't have a thread object, we can't use threading and must
|
| + // fall back to singlethreaded mode by having our own tokenizer.
|
| + if (!m_token)
|
| + m_token = adoptPtr(new HTMLToken);
|
| + if (!m_tokenizer)
|
| + m_tokenizer = HTMLTokenizer::create(m_options);
|
| + return;
|
| + }
|
| +
|
| m_haveBackgroundParser = true;
|
|
|
| RefPtr<WeakReference<BackgroundHTMLParser> > reference = WeakReference<BackgroundHTMLParser>::createUnbound();
|
| @@ -674,19 +723,21 @@ void HTMLDocumentParser::startBackgroundParser()
|
| config->xssAuditor->init(document(), &m_xssAuditorDelegate);
|
| config->preloadScanner = adoptPtr(new TokenPreloadScanner(document()->url().copy(), document()->devicePixelRatio()));
|
| config->decoder = takeDecoder();
|
| + config->resourceProvider = resourceProvider.release();
|
|
|
| ASSERT(config->xssAuditor->isSafeToSendToAnotherThread());
|
| ASSERT(config->preloadScanner->isSafeToSendToAnotherThread());
|
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::start, reference.release(), config.release()));
|
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::start, reference.release(), config.release())));
|
| }
|
|
|
| void HTMLDocumentParser::stopBackgroundParser()
|
| {
|
| ASSERT(shouldUseThreading());
|
| ASSERT(m_haveBackgroundParser);
|
| + ASSERT(s_parserThread);
|
| m_haveBackgroundParser = false;
|
|
|
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::stop, m_backgroundParser));
|
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::stop, m_backgroundParser)));
|
| m_weakFactory.revokeAll();
|
| }
|
|
|
| @@ -697,7 +748,7 @@ void HTMLDocumentParser::append(PassRefPtr<StringImpl> inputSource)
|
|
|
| // We should never reach this point if we're using a parser thread,
|
| // as appendBytes() will directly ship the data to the thread.
|
| - ASSERT(!shouldUseThreading());
|
| + ASSERT(!m_haveBackgroundParser);
|
|
|
| // pumpTokenizer can cause this parser to be detached from the Document,
|
| // but we need to ensure it isn't deleted yet.
|
| @@ -799,7 +850,7 @@ void HTMLDocumentParser::finish()
|
| if (m_haveBackgroundParser) {
|
| if (!m_input.haveSeenEndOfFile())
|
| m_input.closeWithoutMarkingEndOfFile();
|
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::finish, m_backgroundParser));
|
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::finish, m_backgroundParser)));
|
| return;
|
| }
|
|
|
| @@ -968,21 +1019,38 @@ void HTMLDocumentParser::appendBytes(const char* data, size_t length)
|
| if (!length || isStopped())
|
| return;
|
|
|
| - if (shouldUseThreading()) {
|
| - if (!m_haveBackgroundParser)
|
| - startBackgroundParser();
|
| + if (shouldUseThreading() && !m_haveBackgroundParser)
|
| + startBackgroundParser();
|
| +
|
| + if (m_haveBackgroundParser) {
|
| + if (m_parserThreadIsStandalone)
|
| + return; // If this is set, the parser thread will receive the data directly.
|
|
|
| OwnPtr<Vector<char> > buffer = adoptPtr(new Vector<char>(length));
|
| memcpy(buffer->data(), data, length);
|
| TRACE_EVENT1("net", "HTMLDocumentParser::appendBytes", "size", (unsigned)length);
|
|
|
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::appendBytes, m_backgroundParser, buffer.release()));
|
| + ASSERT(s_parserThread);
|
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::appendBytes, m_backgroundParser, buffer.release())));
|
| return;
|
| }
|
|
|
| DecodedDataDocumentParser::appendBytes(data, length);
|
| }
|
|
|
| +void HTMLDocumentParser::didSwitchedToBackgroundClient()
|
| +{
|
| + if (isDetached())
|
| + return;
|
| +
|
| + ASSERT(s_parserThread);
|
| + ASSERT(m_haveBackgroundParser);
|
| + // At this point the background parser will start receiving data chunks directly
|
| + // from the I/O thread and we no longer need to pass it any data.
|
| + m_parserThreadIsStandalone = true;
|
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::resourceFilterAdded, m_backgroundParser)));
|
| +}
|
| +
|
| void HTMLDocumentParser::flush()
|
| {
|
| // If we've got no decoder, we never received any data.
|
| @@ -990,7 +1058,7 @@ void HTMLDocumentParser::flush()
|
| return;
|
|
|
| if (m_haveBackgroundParser)
|
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::flush, m_backgroundParser));
|
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::flush, m_backgroundParser)));
|
| else
|
| DecodedDataDocumentParser::flush();
|
| }
|
| @@ -1001,7 +1069,7 @@ void HTMLDocumentParser::setDecoder(PassOwnPtr<TextResourceDecoder> decoder)
|
| DecodedDataDocumentParser::setDecoder(decoder);
|
|
|
| if (m_haveBackgroundParser)
|
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, takeDecoder()));
|
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, takeDecoder())));
|
| }
|
|
|
| }
|
|
|