| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. | 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, | 105 HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, |
| 106 Element* contextElement, | 106 Element* contextElement, |
| 107 ParserContentPolicy parserContentPolicy) | 107 ParserContentPolicy parserContentPolicy) |
| 108 : HTMLDocumentParser(fragment->document(), | 108 : HTMLDocumentParser(fragment->document(), |
| 109 parserContentPolicy, | 109 parserContentPolicy, |
| 110 ForceSynchronousParsing) { | 110 ForceSynchronousParsing) { |
| 111 // No m_scriptRunner in fragment parser. | 111 // No m_scriptRunner in fragment parser. |
| 112 m_treeBuilder = HTMLTreeBuilder::create(this, fragment, contextElement, | 112 m_treeBuilder = HTMLTreeBuilder::create(this, fragment, contextElement, |
| 113 parserContentPolicy, m_options); | 113 parserContentPolicy, m_options); |
| 114 | 114 |
| 115 bool reportErrors = | 115 // For now document fragment parsing never reports errors. |
| 116 false; // For now document fragment parsing never reports errors. | 116 bool reportErrors = false; |
| 117 m_tokenizer->setState( | 117 m_tokenizer->setState( |
| 118 tokenizerStateForContextElement(contextElement, reportErrors, m_options)); | 118 tokenizerStateForContextElement(contextElement, reportErrors, m_options)); |
| 119 m_xssAuditor.initForFragment(); | 119 m_xssAuditor.initForFragment(); |
| 120 } | 120 } |
| 121 | 121 |
| 122 HTMLDocumentParser::HTMLDocumentParser(Document& document, | 122 HTMLDocumentParser::HTMLDocumentParser(Document& document, |
| 123 ParserContentPolicy contentPolicy, | 123 ParserContentPolicy contentPolicy, |
| 124 ParserSynchronizationPolicy syncPolicy) | 124 ParserSynchronizationPolicy syncPolicy) |
| 125 : ScriptableDocumentParser(document, contentPolicy), | 125 : ScriptableDocumentParser(document, contentPolicy), |
| 126 m_options(&document), | 126 m_options(&document), |
| (...skipping 26 matching lines...) Expand all Loading... |
| 153 ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); | 153 ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); |
| 154 // Threading is not allowed in prefetch mode. | 154 // Threading is not allowed in prefetch mode. |
| 155 DCHECK(!document.isPrefetchOnly() || !shouldUseThreading()); | 155 DCHECK(!document.isPrefetchOnly() || !shouldUseThreading()); |
| 156 | 156 |
| 157 ThreadState::current()->registerPreFinalizer(this); | 157 ThreadState::current()->registerPreFinalizer(this); |
| 158 } | 158 } |
| 159 | 159 |
| 160 HTMLDocumentParser::~HTMLDocumentParser() {} | 160 HTMLDocumentParser::~HTMLDocumentParser() {} |
| 161 | 161 |
| 162 void HTMLDocumentParser::dispose() { | 162 void HTMLDocumentParser::dispose() { |
| 163 // In Oilpan, HTMLDocumentParser can die together with Document, and | 163 // In Oilpan, HTMLDocumentParser can die together with Document, and detach() |
| 164 // detach() is not called in this case. | 164 // is not called in this case. |
| 165 if (m_haveBackgroundParser) | 165 if (m_haveBackgroundParser) |
| 166 stopBackgroundParser(); | 166 stopBackgroundParser(); |
| 167 } | 167 } |
| 168 | 168 |
| 169 DEFINE_TRACE(HTMLDocumentParser) { | 169 DEFINE_TRACE(HTMLDocumentParser) { |
| 170 visitor->trace(m_treeBuilder); | 170 visitor->trace(m_treeBuilder); |
| 171 visitor->trace(m_parserScheduler); | 171 visitor->trace(m_parserScheduler); |
| 172 visitor->trace(m_xssAuditorDelegate); | 172 visitor->trace(m_xssAuditorDelegate); |
| 173 visitor->trace(m_scriptRunner); | 173 visitor->trace(m_scriptRunner); |
| 174 visitor->trace(m_preloader); | 174 visitor->trace(m_preloader); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 188 peakPendingTokenHistogram.count( | 188 peakPendingTokenHistogram.count( |
| 189 m_tokenizedChunkQueue->peakPendingTokenCount()); | 189 m_tokenizedChunkQueue->peakPendingTokenCount()); |
| 190 } | 190 } |
| 191 | 191 |
| 192 if (m_haveBackgroundParser) | 192 if (m_haveBackgroundParser) |
| 193 stopBackgroundParser(); | 193 stopBackgroundParser(); |
| 194 DocumentParser::detach(); | 194 DocumentParser::detach(); |
| 195 if (m_scriptRunner) | 195 if (m_scriptRunner) |
| 196 m_scriptRunner->detach(); | 196 m_scriptRunner->detach(); |
| 197 m_treeBuilder->detach(); | 197 m_treeBuilder->detach(); |
| 198 // FIXME: It seems wrong that we would have a preload scanner here. | 198 // FIXME: It seems wrong that we would have a preload scanner here. Yet during |
| 199 // Yet during fast/dom/HTMLScriptElement/script-load-events.html we do. | 199 // fast/dom/HTMLScriptElement/script-load-events.html we do. |
| 200 m_preloadScanner.reset(); | 200 m_preloadScanner.reset(); |
| 201 m_insertionPreloadScanner.reset(); | 201 m_insertionPreloadScanner.reset(); |
| 202 if (m_parserScheduler) { | 202 if (m_parserScheduler) { |
| 203 m_parserScheduler->detach(); | 203 m_parserScheduler->detach(); |
| 204 m_parserScheduler.clear(); | 204 m_parserScheduler.clear(); |
| 205 } | 205 } |
| 206 // Oilpan: It is important to clear m_token to deallocate backing memory of | 206 // Oilpan: It is important to clear m_token to deallocate backing memory of |
| 207 // HTMLToken::m_data and let the allocator reuse the memory for | 207 // HTMLToken::m_data and let the allocator reuse the memory for |
| 208 // HTMLToken::m_data of a next HTMLDocumentParser. We need to clear | 208 // HTMLToken::m_data of a next HTMLDocumentParser. We need to clear |
| 209 // m_tokenizer first because m_tokenizer has a raw pointer to m_token. | 209 // m_tokenizer first because m_tokenizer has a raw pointer to m_token. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 236 | 236 |
| 237 if (isStopped()) | 237 if (isStopped()) |
| 238 return; | 238 return; |
| 239 | 239 |
| 240 DocumentParser::prepareToStopParsing(); | 240 DocumentParser::prepareToStopParsing(); |
| 241 | 241 |
| 242 // We will not have a scriptRunner when parsing a DocumentFragment. | 242 // We will not have a scriptRunner when parsing a DocumentFragment. |
| 243 if (m_scriptRunner) | 243 if (m_scriptRunner) |
| 244 document()->setReadyState(Document::Interactive); | 244 document()->setReadyState(Document::Interactive); |
| 245 | 245 |
| 246 // Setting the ready state above can fire mutation event and detach us | 246 // Setting the ready state above can fire mutation event and detach us from |
| 247 // from underneath. In that case, just bail out. | 247 // underneath. In that case, just bail out. |
| 248 if (isDetached()) | 248 if (isDetached()) |
| 249 return; | 249 return; |
| 250 | 250 |
| 251 attemptToRunDeferredScriptsAndEnd(); | 251 attemptToRunDeferredScriptsAndEnd(); |
| 252 } | 252 } |
| 253 | 253 |
| 254 bool HTMLDocumentParser::isParsingFragment() const { | 254 bool HTMLDocumentParser::isParsingFragment() const { |
| 255 return m_treeBuilder->isParsingFragment(); | 255 return m_treeBuilder->isParsingFragment(); |
| 256 } | 256 } |
| 257 | 257 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 282 m_treeBuilder->takeScriptToProcess(scriptStartPosition); | 282 m_treeBuilder->takeScriptToProcess(scriptStartPosition); |
| 283 // We will not have a scriptRunner when parsing a DocumentFragment. | 283 // We will not have a scriptRunner when parsing a DocumentFragment. |
| 284 if (m_scriptRunner) | 284 if (m_scriptRunner) |
| 285 m_scriptRunner->execute(scriptElement, scriptStartPosition); | 285 m_scriptRunner->execute(scriptElement, scriptStartPosition); |
| 286 } | 286 } |
| 287 | 287 |
| 288 bool HTMLDocumentParser::canTakeNextToken() { | 288 bool HTMLDocumentParser::canTakeNextToken() { |
| 289 if (isStopped()) | 289 if (isStopped()) |
| 290 return false; | 290 return false; |
| 291 | 291 |
| 292 // If we're paused waiting for a script, we try to execute scripts before cont
inuing. | 292 // If we're paused waiting for a script, we try to execute scripts before |
| 293 // continuing. |
| 293 if (m_treeBuilder->hasParserBlockingScript()) | 294 if (m_treeBuilder->hasParserBlockingScript()) |
| 294 runScriptsForPausedTreeBuilder(); | 295 runScriptsForPausedTreeBuilder(); |
| 295 if (isStopped() || isWaitingForScripts()) | 296 if (isStopped() || isWaitingForScripts()) |
| 296 return false; | 297 return false; |
| 297 | 298 |
| 298 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the | 299 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the |
| 299 // LocalFrame, but this approach is how the old parser handled | 300 // LocalFrame, but this approach is how the old parser handled stopping when |
| 300 // stopping when the page assigns window.location. What really | 301 // the page assigns window.location. What really should happen is that |
| 301 // should happen is that assigning window.location causes the | 302 // assigning window.location causes the parser to stop parsing cleanly. The |
| 302 // parser to stop parsing cleanly. The problem is we're not | 303 // problem is we're not perpared to do that at every point where we run |
| 303 // perpared to do that at every point where we run JavaScript. | 304 // JavaScript. |
| 304 if (!isParsingFragment() && document()->frame() && | 305 if (!isParsingFragment() && document()->frame() && |
| 305 document()->frame()->navigationScheduler().locationChangePending()) | 306 document()->frame()->navigationScheduler().locationChangePending()) |
| 306 return false; | 307 return false; |
| 307 | 308 |
| 308 return true; | 309 return true; |
| 309 } | 310 } |
| 310 | 311 |
| 311 void HTMLDocumentParser::notifyPendingTokenizedChunks() { | 312 void HTMLDocumentParser::notifyPendingTokenizedChunks() { |
| 312 TRACE_EVENT0("blink", "HTMLDocumentParser::notifyPendingTokenizedChunks"); | 313 TRACE_EVENT0("blink", "HTMLDocumentParser::notifyPendingTokenizedChunks"); |
| 313 DCHECK(m_tokenizedChunkQueue); | 314 DCHECK(m_tokenizedChunkQueue); |
| 314 | 315 |
| 315 Vector<std::unique_ptr<TokenizedChunk>> pendingChunks; | 316 Vector<std::unique_ptr<TokenizedChunk>> pendingChunks; |
| 316 m_tokenizedChunkQueue->takeAll(pendingChunks); | 317 m_tokenizedChunkQueue->takeAll(pendingChunks); |
| 317 | 318 |
| 318 if (!isParsing()) | 319 if (!isParsing()) |
| 319 return; | 320 return; |
| 320 | 321 |
| 321 // ApplicationCache needs to be initialized before issuing preloads. | 322 // ApplicationCache needs to be initialized before issuing preloads. We |
| 322 // We suspend preload until HTMLHTMLElement is inserted and | 323 // suspend preload until HTMLHTMLElement is inserted and ApplicationCache is |
| 323 // ApplicationCache is initialized. Note: link rel preloads don't follow | 324 // initialized. Note: link rel preloads don't follow this policy per the spec. |
| 324 // this policy per the spec. These directives should initiate a fetch as | 325 // These directives should initiate a fetch as fast as possible. |
| 325 // fast as possible. | |
| 326 if (!m_triedLoadingLinkHeaders && document()->loader() && | 326 if (!m_triedLoadingLinkHeaders && document()->loader() && |
| 327 !pendingChunks.isEmpty()) { | 327 !pendingChunks.isEmpty()) { |
| 328 // Note that on commit, the loader dispatched preloads for all the | 328 // Note that on commit, the loader dispatched preloads for all the non-media |
| 329 // non-media links. | 329 // links. |
| 330 document()->loader()->dispatchLinkHeaderPreloads( | 330 document()->loader()->dispatchLinkHeaderPreloads( |
| 331 &pendingChunks.first()->viewport, LinkLoader::OnlyLoadMedia); | 331 &pendingChunks.first()->viewport, LinkLoader::OnlyLoadMedia); |
| 332 m_triedLoadingLinkHeaders = true; | 332 m_triedLoadingLinkHeaders = true; |
| 333 } | 333 } |
| 334 | 334 |
| 335 // Defer preloads if any of the chunks contains a <meta> csp tag. | 335 // Defer preloads if any of the chunks contains a <meta> csp tag. |
| 336 for (auto& chunk : pendingChunks) { | 336 for (auto& chunk : pendingChunks) { |
| 337 if (chunk->pendingCSPMetaTokenIndex != TokenizedChunk::noPendingToken) { | 337 if (chunk->pendingCSPMetaTokenIndex != TokenizedChunk::noPendingToken) { |
| 338 m_pendingCSPMetaToken = | 338 m_pendingCSPMetaToken = |
| 339 &chunk->tokens->at(chunk->pendingCSPMetaTokenIndex); | 339 &chunk->tokens->at(chunk->pendingCSPMetaTokenIndex); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 352 m_queuedPreloads.append(std::move(request)); | 352 m_queuedPreloads.append(std::move(request)); |
| 353 } | 353 } |
| 354 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { | 354 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { |
| 355 const CompactHTMLToken& token = chunk->tokens->at(index); | 355 const CompactHTMLToken& token = chunk->tokens->at(index); |
| 356 ASSERT(token.type() == HTMLToken::TokenType::Character); | 356 ASSERT(token.type() == HTMLToken::TokenType::Character); |
| 357 m_queuedDocumentWriteScripts.append(token.data()); | 357 m_queuedDocumentWriteScripts.append(token.data()); |
| 358 } | 358 } |
| 359 } | 359 } |
| 360 m_preloader->takeAndPreload(linkRelPreloads); | 360 m_preloader->takeAndPreload(linkRelPreloads); |
| 361 } else { | 361 } else { |
| 362 // We can safely assume that there are no queued preloads request after | 362 // We can safely assume that there are no queued preloads request after the |
| 363 // the document element is available, as we empty the queue immediately | 363 // document element is available, as we empty the queue immediately after |
| 364 // after the document element is created in documentElementAvailable(). | 364 // the document element is created in documentElementAvailable(). |
| 365 ASSERT(m_queuedPreloads.isEmpty()); | 365 ASSERT(m_queuedPreloads.isEmpty()); |
| 366 ASSERT(m_queuedDocumentWriteScripts.isEmpty()); | 366 ASSERT(m_queuedDocumentWriteScripts.isEmpty()); |
| 367 // Loop through the chunks to generate preloads before any | 367 // Loop through the chunks to generate preloads before any document.write |
| 368 // document.write script evaluation takes place. Preloading these | 368 // script evaluation takes place. Preloading these scripts is valuable and |
| 369 // scripts is valuable and comparably cheap, while evaluating JS can be | 369 // comparably cheap, while evaluating JS can be expensive. |
| 370 // expensive. | |
| 371 for (auto& chunk : pendingChunks) { | 370 for (auto& chunk : pendingChunks) { |
| 372 m_preloader->takeAndPreload(chunk->preloads); | 371 m_preloader->takeAndPreload(chunk->preloads); |
| 373 } | 372 } |
| 374 for (auto& chunk : pendingChunks) { | 373 for (auto& chunk : pendingChunks) { |
| 375 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { | 374 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { |
| 376 const CompactHTMLToken& token = chunk->tokens->at(index); | 375 const CompactHTMLToken& token = chunk->tokens->at(index); |
| 377 ASSERT(token.type() == HTMLToken::TokenType::Character); | 376 ASSERT(token.type() == HTMLToken::TokenType::Character); |
| 378 evaluateAndPreloadScriptForDocumentWrite(token.data()); | 377 evaluateAndPreloadScriptForDocumentWrite(token.data()); |
| 379 } | 378 } |
| 380 } | 379 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 393 | 392 |
| 394 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( | 393 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( |
| 395 const DocumentEncodingData& data) { | 394 const DocumentEncodingData& data) { |
| 396 document()->setEncodingData(data); | 395 document()->setEncodingData(data); |
| 397 } | 396 } |
| 398 | 397 |
| 399 void HTMLDocumentParser::validateSpeculations( | 398 void HTMLDocumentParser::validateSpeculations( |
| 400 std::unique_ptr<TokenizedChunk> chunk) { | 399 std::unique_ptr<TokenizedChunk> chunk) { |
| 401 ASSERT(chunk); | 400 ASSERT(chunk); |
| 402 if (isWaitingForScripts()) { | 401 if (isWaitingForScripts()) { |
| 403 // We're waiting on a network script, just save the chunk, we'll get | 402 // We're waiting on a network script, just save the chunk, we'll get a |
| 404 // a second validateSpeculations call after the script completes. | 403 // second validateSpeculations call after the script completes. This call |
| 405 // This call should have been made immediately after runScriptsForPausedTree
Builder | 404 // should have been made immediately after runScriptsForPausedTreeBuilder |
| 406 // which may have started a network load and left us waiting. | 405 // which may have started a network load and left us waiting. |
| 407 ASSERT(!m_lastChunkBeforeScript); | 406 ASSERT(!m_lastChunkBeforeScript); |
| 408 m_lastChunkBeforeScript = std::move(chunk); | 407 m_lastChunkBeforeScript = std::move(chunk); |
| 409 return; | 408 return; |
| 410 } | 409 } |
| 411 | 410 |
| 412 ASSERT(!m_lastChunkBeforeScript); | 411 ASSERT(!m_lastChunkBeforeScript); |
| 413 std::unique_ptr<HTMLTokenizer> tokenizer = std::move(m_tokenizer); | 412 std::unique_ptr<HTMLTokenizer> tokenizer = std::move(m_tokenizer); |
| 414 std::unique_ptr<HTMLToken> token = std::move(m_token); | 413 std::unique_ptr<HTMLToken> token = std::move(m_token); |
| 415 | 414 |
| 416 if (!tokenizer) { | 415 if (!tokenizer) { |
| 417 // There must not have been any changes to the HTMLTokenizer state on | 416 // There must not have been any changes to the HTMLTokenizer state on the |
| 418 // the main thread, which means the speculation buffer is correct. | 417 // main thread, which means the speculation buffer is correct. |
| 419 return; | 418 return; |
| 420 } | 419 } |
| 421 | 420 |
| 422 // Currently we're only smart enough to reuse the speculation buffer if the to
kenizer | 421 // Currently we're only smart enough to reuse the speculation buffer if the |
| 423 // both starts and ends in the DataState. That state is simplest because the H
TMLToken | 422 // tokenizer both starts and ends in the DataState. That state is simplest |
| 424 // is always in the Uninitialized state. We should consider whether we can reu
se the | 423 // because the HTMLToken is always in the Uninitialized state. We should |
| 425 // speculation buffer in other states, but we'd likely need to do something mo
re | 424 // consider whether we can reuse the speculation buffer in other states, but |
| 426 // sophisticated with the HTMLToken. | 425 // we'd likely need to do something more sophisticated with the HTMLToken. |
| 427 if (chunk->tokenizerState == HTMLTokenizer::DataState && | 426 if (chunk->tokenizerState == HTMLTokenizer::DataState && |
| 428 tokenizer->getState() == HTMLTokenizer::DataState && | 427 tokenizer->getState() == HTMLTokenizer::DataState && |
| 429 m_input.current().isEmpty() && | 428 m_input.current().isEmpty() && |
| 430 chunk->treeBuilderState == | 429 chunk->treeBuilderState == |
| 431 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get())) { | 430 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get())) { |
| 432 ASSERT(token->isUninitialized()); | 431 ASSERT(token->isUninitialized()); |
| 433 return; | 432 return; |
| 434 } | 433 } |
| 435 | 434 |
| 436 discardSpeculationsAndResumeFrom(std::move(chunk), std::move(token), | 435 discardSpeculationsAndResumeFrom(std::move(chunk), std::move(token), |
| (...skipping 22 matching lines...) Expand all Loading... |
| 459 wrapUnique(new BackgroundHTMLParser::Checkpoint); | 458 wrapUnique(new BackgroundHTMLParser::Checkpoint); |
| 460 checkpoint->parser = m_weakFactory.createWeakPtr(); | 459 checkpoint->parser = m_weakFactory.createWeakPtr(); |
| 461 checkpoint->token = std::move(token); | 460 checkpoint->token = std::move(token); |
| 462 checkpoint->tokenizer = std::move(tokenizer); | 461 checkpoint->tokenizer = std::move(tokenizer); |
| 463 checkpoint->treeBuilderState = | 462 checkpoint->treeBuilderState = |
| 464 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get()); | 463 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get()); |
| 465 checkpoint->inputCheckpoint = lastChunkBeforeScript->inputCheckpoint; | 464 checkpoint->inputCheckpoint = lastChunkBeforeScript->inputCheckpoint; |
| 466 checkpoint->preloadScannerCheckpoint = | 465 checkpoint->preloadScannerCheckpoint = |
| 467 lastChunkBeforeScript->preloadScannerCheckpoint; | 466 lastChunkBeforeScript->preloadScannerCheckpoint; |
| 468 checkpoint->unparsedInput = m_input.current().toString().isolatedCopy(); | 467 checkpoint->unparsedInput = m_input.current().toString().isolatedCopy(); |
| 469 m_input.current() | 468 // FIXME: This should be passed in instead of cleared. |
| 470 .clear(); // FIXME: This should be passed in instead of cleared. | 469 m_input.current().clear(); |
| 471 | 470 |
| 472 ASSERT(checkpoint->unparsedInput.isSafeToSendToAnotherThread()); | 471 ASSERT(checkpoint->unparsedInput.isSafeToSendToAnotherThread()); |
| 473 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::resumeFrom, | 472 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::resumeFrom, |
| 474 m_backgroundParser, passed(std::move(checkpoint))); | 473 m_backgroundParser, passed(std::move(checkpoint))); |
| 475 } | 474 } |
| 476 | 475 |
| 477 size_t HTMLDocumentParser::processTokenizedChunkFromBackgroundParser( | 476 size_t HTMLDocumentParser::processTokenizedChunkFromBackgroundParser( |
| 478 std::unique_ptr<TokenizedChunk> popChunk) { | 477 std::unique_ptr<TokenizedChunk> popChunk) { |
| 479 TRACE_EVENT_WITH_FLOW0( | 478 TRACE_EVENT_WITH_FLOW0( |
| 480 "blink,loading", | 479 "blink,loading", |
| (...skipping 18 matching lines...) Expand all Loading... |
| 499 postTaskToLookaheadParser(Asynchronous, | 498 postTaskToLookaheadParser(Asynchronous, |
| 500 &BackgroundHTMLParser::startedChunkWithCheckpoint, | 499 &BackgroundHTMLParser::startedChunkWithCheckpoint, |
| 501 m_backgroundParser, chunk->inputCheckpoint); | 500 m_backgroundParser, chunk->inputCheckpoint); |
| 502 | 501 |
| 503 for (const auto& xssInfo : chunk->xssInfos) { | 502 for (const auto& xssInfo : chunk->xssInfos) { |
| 504 m_textPosition = xssInfo->m_textPosition; | 503 m_textPosition = xssInfo->m_textPosition; |
| 505 m_xssAuditorDelegate.didBlockScript(*xssInfo); | 504 m_xssAuditorDelegate.didBlockScript(*xssInfo); |
| 506 if (isStopped()) | 505 if (isStopped()) |
| 507 break; | 506 break; |
| 508 } | 507 } |
| 509 // XSSAuditorDelegate can detach the parser if it decides to block the entire
current document. | 508 // XSSAuditorDelegate can detach the parser if it decides to block the entire |
| 509 // current document. |
| 510 if (isDetached()) | 510 if (isDetached()) |
| 511 return elementTokenCount; | 511 return elementTokenCount; |
| 512 | 512 |
| 513 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); | 513 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); |
| 514 it != tokens->end(); ++it) { | 514 it != tokens->end(); ++it) { |
| 515 ASSERT(!isWaitingForScripts()); | 515 ASSERT(!isWaitingForScripts()); |
| 516 | 516 |
| 517 if (!chunk->startingScript && | 517 if (!chunk->startingScript && |
| 518 (it->type() == HTMLToken::StartTag || it->type() == HTMLToken::EndTag)) | 518 (it->type() == HTMLToken::StartTag || it->type() == HTMLToken::EndTag)) |
| 519 elementTokenCount++; | 519 elementTokenCount++; |
| 520 | 520 |
| 521 if (document()->frame() && | 521 if (document()->frame() && |
| 522 document()->frame()->navigationScheduler().locationChangePending()) { | 522 document()->frame()->navigationScheduler().locationChangePending()) { |
| 523 // To match main-thread parser behavior (which never checks locationChange
Pending on the EOF path) | 523 // To match main-thread parser behavior (which never checks |
| 524 // we peek to see if this chunk has an EOF and process it anyway. | 524 // locationChangePending on the EOF path) we peek to see if this chunk has |
| 525 // an EOF and process it anyway. |
| 525 if (tokens->last().type() == HTMLToken::EndOfFile) { | 526 if (tokens->last().type() == HTMLToken::EndOfFile) { |
| 526 ASSERT( | 527 ASSERT( |
| 527 m_speculations | 528 m_speculations |
| 528 .isEmpty()); // There should never be any chunks after the EOF. | 529 .isEmpty()); // There should never be any chunks after the EOF. |
| 529 prepareToStopParsing(); | 530 prepareToStopParsing(); |
| 530 } | 531 } |
| 531 break; | 532 break; |
| 532 } | 533 } |
| 533 | 534 |
| 534 m_textPosition = it->textPosition(); | 535 m_textPosition = it->textPosition(); |
| 535 | 536 |
| 536 constructTreeFromCompactHTMLToken(*it); | 537 constructTreeFromCompactHTMLToken(*it); |
| 537 | 538 |
| 538 if (isStopped()) | 539 if (isStopped()) |
| 539 break; | 540 break; |
| 540 | 541 |
| 541 // Preloads were queued if there was a <meta> csp token in a tokenized | 542 // Preloads were queued if there was a <meta> csp token in a tokenized |
| 542 // chunk. | 543 // chunk. |
| 543 if (m_pendingCSPMetaToken && it == m_pendingCSPMetaToken) { | 544 if (m_pendingCSPMetaToken && it == m_pendingCSPMetaToken) { |
| 544 m_pendingCSPMetaToken = nullptr; | 545 m_pendingCSPMetaToken = nullptr; |
| 545 fetchQueuedPreloads(); | 546 fetchQueuedPreloads(); |
| 546 } | 547 } |
| 547 | 548 |
| 548 if (isWaitingForScripts()) { | 549 if (isWaitingForScripts()) { |
| 549 ASSERT( | 550 // The </script> is assumed to be the last token of this bunch. |
| 550 it + 1 == | 551 ASSERT(it + 1 == tokens->end()); |
| 551 tokens | |
| 552 ->end()); // The </script> is assumed to be the last token of thi
s bunch. | |
| 553 runScriptsForPausedTreeBuilder(); | 552 runScriptsForPausedTreeBuilder(); |
| 554 validateSpeculations(std::move(chunk)); | 553 validateSpeculations(std::move(chunk)); |
| 555 break; | 554 break; |
| 556 } | 555 } |
| 557 | 556 |
| 558 if (it->type() == HTMLToken::EndOfFile) { | 557 if (it->type() == HTMLToken::EndOfFile) { |
| 559 ASSERT( | 558 // The EOF is assumed to be the last token of this bunch. |
| 560 it + 1 == | 559 ASSERT(it + 1 == tokens->end()); |
| 561 tokens | 560 // There should never be any chunks after the EOF. |
| 562 ->end()); // The EOF is assumed to be the last token of this bunc
h. | 561 ASSERT(m_speculations.isEmpty()); |
| 563 ASSERT( | |
| 564 m_speculations | |
| 565 .isEmpty()); // There should never be any chunks after the EOF. | |
| 566 prepareToStopParsing(); | 562 prepareToStopParsing(); |
| 567 break; | 563 break; |
| 568 } | 564 } |
| 569 | 565 |
| 570 ASSERT(!m_tokenizer); | 566 ASSERT(!m_tokenizer); |
| 571 ASSERT(!m_token); | 567 ASSERT(!m_token); |
| 572 } | 568 } |
| 573 | 569 |
| 574 // Make sure all required pending text nodes are emitted before returning. | 570 // Make sure all required pending text nodes are emitted before returning. |
| 575 // This leaves "script", "style" and "svg" nodes text nodes intact. | 571 // This leaves "script", "style" and "svg" nodes text nodes intact. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 610 InspectorParseHtmlEvent::beginData( | 606 InspectorParseHtmlEvent::beginData( |
| 611 document(), lineNumber().zeroBasedInt())); | 607 document(), lineNumber().zeroBasedInt())); |
| 612 | 608 |
| 613 SpeculationsPumpSession session(m_pumpSpeculationsSessionNestingLevel); | 609 SpeculationsPumpSession session(m_pumpSpeculationsSessionNestingLevel); |
| 614 while (!m_speculations.isEmpty()) { | 610 while (!m_speculations.isEmpty()) { |
| 615 ASSERT(!isScheduledForResume()); | 611 ASSERT(!isScheduledForResume()); |
| 616 size_t elementTokenCount = | 612 size_t elementTokenCount = |
| 617 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); | 613 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); |
| 618 session.addedElementTokens(elementTokenCount); | 614 session.addedElementTokens(elementTokenCount); |
| 619 | 615 |
| 620 // Always check isParsing first as m_document may be null. | 616 // Always check isParsing first as m_document may be null. Surprisingly, |
| 621 // Surprisingly, isScheduledForResume() may be set here as a result of | 617 // isScheduledForResume() may be set here as a result of |
| 622 // processTokenizedChunkFromBackgroundParser running arbitrary javascript | 618 // processTokenizedChunkFromBackgroundParser running arbitrary javascript |
| 623 // which invokes nested event loops. (e.g. inspector breakpoints) | 619 // which invokes nested event loops. (e.g. inspector breakpoints) |
| 624 if (!isParsing() || isWaitingForScripts() || isScheduledForResume()) | 620 if (!isParsing() || isWaitingForScripts() || isScheduledForResume()) |
| 625 break; | 621 break; |
| 626 | 622 |
| 627 if (m_speculations.isEmpty() || | 623 if (m_speculations.isEmpty() || |
| 628 m_parserScheduler->yieldIfNeeded( | 624 m_parserScheduler->yieldIfNeeded( |
| 629 session, m_speculations.first()->startingScript)) | 625 session, m_speculations.first()->startingScript)) |
| 630 break; | 626 break; |
| 631 } | 627 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 654 m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); | 650 m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); |
| 655 } | 651 } |
| 656 | 652 |
| 657 void HTMLDocumentParser::pumpTokenizer() { | 653 void HTMLDocumentParser::pumpTokenizer() { |
| 658 ASSERT(!isStopped()); | 654 ASSERT(!isStopped()); |
| 659 ASSERT(m_tokenizer); | 655 ASSERT(m_tokenizer); |
| 660 ASSERT(m_token); | 656 ASSERT(m_token); |
| 661 | 657 |
| 662 PumpSession session(m_pumpSessionNestingLevel); | 658 PumpSession session(m_pumpSessionNestingLevel); |
| 663 | 659 |
| 664 // We tell the InspectorInstrumentation about every pump, even if we | 660 // We tell the InspectorInstrumentation about every pump, even if we end up |
| 665 // end up pumping nothing. It can filter out empty pumps itself. | 661 // pumping nothing. It can filter out empty pumps itself. |
| 666 // FIXME: m_input.current().length() is only accurate if we | 662 // FIXME: m_input.current().length() is only accurate if we end up parsing the |
| 667 // end up parsing the whole buffer in this pump. We should pass how | 663 // whole buffer in this pump. We should pass how much we parsed as part of |
| 668 // much we parsed as part of didWriteHTML instead of willWriteHTML. | 664 // didWriteHTML instead of willWriteHTML. |
| 669 TRACE_EVENT_BEGIN1( | 665 TRACE_EVENT_BEGIN1( |
| 670 "devtools.timeline", "ParseHTML", "beginData", | 666 "devtools.timeline", "ParseHTML", "beginData", |
| 671 InspectorParseHtmlEvent::beginData( | 667 InspectorParseHtmlEvent::beginData( |
| 672 document(), m_input.current().currentLine().zeroBasedInt())); | 668 document(), m_input.current().currentLine().zeroBasedInt())); |
| 673 | 669 |
| 674 if (!isParsingFragment()) | 670 if (!isParsingFragment()) |
| 675 m_xssAuditor.init(document(), &m_xssAuditorDelegate); | 671 m_xssAuditor.init(document(), &m_xssAuditorDelegate); |
| 676 | 672 |
| 677 while (canTakeNextToken()) { | 673 while (canTakeNextToken()) { |
| 678 if (m_xssAuditor.isEnabled()) | 674 if (m_xssAuditor.isEnabled()) |
| (...skipping 22 matching lines...) Expand all Loading... |
| 701 | 697 |
| 702 // There should only be PendingText left since the tree-builder always flushes | 698 // There should only be PendingText left since the tree-builder always flushes |
| 703 // the task queue before returning. In case that ever changes, crash. | 699 // the task queue before returning. In case that ever changes, crash. |
| 704 m_treeBuilder->flush(FlushAlways); | 700 m_treeBuilder->flush(FlushAlways); |
| 705 RELEASE_ASSERT(!isStopped()); | 701 RELEASE_ASSERT(!isStopped()); |
| 706 | 702 |
| 707 if (isWaitingForScripts()) { | 703 if (isWaitingForScripts()) { |
| 708 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); | 704 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); |
| 709 | 705 |
| 710 ASSERT(m_preloader); | 706 ASSERT(m_preloader); |
| 711 // TODO(kouhei): m_preloader should be always available for synchronous pars
ing case, | 707 // TODO(kouhei): m_preloader should be always available for synchronous |
| 712 // adding paranoia if for speculative crash fix for crbug.com/465478 | 708 // parsing case, adding paranoia if for speculative crash fix for |
| 709 // crbug.com/465478 |
| 713 if (m_preloader) { | 710 if (m_preloader) { |
| 714 if (!m_preloadScanner) { | 711 if (!m_preloadScanner) { |
| 715 m_preloadScanner = createPreloadScanner(); | 712 m_preloadScanner = createPreloadScanner(); |
| 716 m_preloadScanner->appendToEnd(m_input.current()); | 713 m_preloadScanner->appendToEnd(m_input.current()); |
| 717 } | 714 } |
| 718 m_preloadScanner->scanAndPreload( | 715 m_preloadScanner->scanAndPreload( |
| 719 m_preloader.get(), document()->validBaseElementURL(), nullptr); | 716 m_preloader.get(), document()->validBaseElementURL(), nullptr); |
| 720 } | 717 } |
| 721 } | 718 } |
| 722 | 719 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 753 } | 750 } |
| 754 } | 751 } |
| 755 | 752 |
| 756 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( | 753 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( |
| 757 const CompactHTMLToken& compactToken) { | 754 const CompactHTMLToken& compactToken) { |
| 758 AtomicHTMLToken token(compactToken); | 755 AtomicHTMLToken token(compactToken); |
| 759 m_treeBuilder->constructTree(&token); | 756 m_treeBuilder->constructTree(&token); |
| 760 } | 757 } |
| 761 | 758 |
| 762 bool HTMLDocumentParser::hasInsertionPoint() { | 759 bool HTMLDocumentParser::hasInsertionPoint() { |
| 763 // FIXME: The wasCreatedByScript() branch here might not be fully correct. | 760 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our |
| 764 // Our model of the EOF character differs slightly from the one in | 761 // model of the EOF character differs slightly from the one in the spec |
| 765 // the spec because our treatment is uniform between network-sourced | 762 // because our treatment is uniform between network-sourced and script-sourced |
| 766 // and script-sourced input streams whereas the spec treats them | 763 // input streams whereas the spec treats them differently. |
| 767 // differently. | |
| 768 return m_input.hasInsertionPoint() || | 764 return m_input.hasInsertionPoint() || |
| 769 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); | 765 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); |
| 770 } | 766 } |
| 771 | 767 |
| 772 void HTMLDocumentParser::insert(const SegmentedString& source) { | 768 void HTMLDocumentParser::insert(const SegmentedString& source) { |
| 773 if (isStopped()) | 769 if (isStopped()) |
| 774 return; | 770 return; |
| 775 | 771 |
| 776 TRACE_EVENT1("blink", "HTMLDocumentParser::insert", "source_length", | 772 TRACE_EVENT1("blink", "HTMLDocumentParser::insert", "source_length", |
| 777 source.length()); | 773 source.length()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 801 endIfDelayed(); | 797 endIfDelayed(); |
| 802 } | 798 } |
| 803 | 799 |
| 804 void HTMLDocumentParser::startBackgroundParser() { | 800 void HTMLDocumentParser::startBackgroundParser() { |
| 805 ASSERT(!isStopped()); | 801 ASSERT(!isStopped()); |
| 806 ASSERT(shouldUseThreading()); | 802 ASSERT(shouldUseThreading()); |
| 807 ASSERT(!m_haveBackgroundParser); | 803 ASSERT(!m_haveBackgroundParser); |
| 808 ASSERT(document()); | 804 ASSERT(document()); |
| 809 m_haveBackgroundParser = true; | 805 m_haveBackgroundParser = true; |
| 810 | 806 |
| 811 // TODO(alexclarke): Remove WebFrameScheduler::setDocumentParsingInBackground
when background parser goes away. | 807 // TODO(alexclarke): Remove WebFrameScheduler::setDocumentParsingInBackground |
| 808 // when background parser goes away. |
| 812 if (document()->frame() && document()->frame()->frameScheduler()) | 809 if (document()->frame() && document()->frame()->frameScheduler()) |
| 813 document()->frame()->frameScheduler()->setDocumentParsingInBackground(true); | 810 document()->frame()->frameScheduler()->setDocumentParsingInBackground(true); |
| 814 | 811 |
| 815 // Make sure that a resolver is set up, so that the correct viewport dimension
s will be fed to the background parser and preload scanner. | 812 // Make sure that a resolver is set up, so that the correct viewport |
| 813 // dimensions will be fed to the background parser and preload scanner. |
| 816 if (document()->loader()) | 814 if (document()->loader()) |
| 817 document()->ensureStyleResolver(); | 815 document()->ensureStyleResolver(); |
| 818 | 816 |
| 819 std::unique_ptr<BackgroundHTMLParser::Configuration> config = | 817 std::unique_ptr<BackgroundHTMLParser::Configuration> config = |
| 820 wrapUnique(new BackgroundHTMLParser::Configuration); | 818 wrapUnique(new BackgroundHTMLParser::Configuration); |
| 821 config->options = m_options; | 819 config->options = m_options; |
| 822 config->parser = m_weakFactory.createWeakPtr(); | 820 config->parser = m_weakFactory.createWeakPtr(); |
| 823 config->xssAuditor = wrapUnique(new XSSAuditor); | 821 config->xssAuditor = wrapUnique(new XSSAuditor); |
| 824 config->xssAuditor->init(document(), &m_xssAuditorDelegate); | 822 config->xssAuditor->init(document(), &m_xssAuditorDelegate); |
| 825 | 823 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 // ParseHTMLOnMainThread lands (the lookahead parser will be a member). | 864 // ParseHTMLOnMainThread lands (the lookahead parser will be a member). |
| 867 postTaskToLookaheadParser(Synchronous, &BackgroundHTMLParser::stop, | 865 postTaskToLookaheadParser(Synchronous, &BackgroundHTMLParser::stop, |
| 868 m_backgroundParser); | 866 m_backgroundParser); |
| 869 m_weakFactory.revokeAll(); | 867 m_weakFactory.revokeAll(); |
| 870 } | 868 } |
| 871 | 869 |
| 872 void HTMLDocumentParser::append(const String& inputSource) { | 870 void HTMLDocumentParser::append(const String& inputSource) { |
| 873 if (isStopped()) | 871 if (isStopped()) |
| 874 return; | 872 return; |
| 875 | 873 |
| 876 // We should never reach this point if we're using a parser thread, | 874 // We should never reach this point if we're using a parser thread, as |
| 877 // as appendBytes() will directly ship the data to the thread. | 875 // appendBytes() will directly ship the data to the thread. |
| 878 ASSERT(!shouldUseThreading()); | 876 ASSERT(!shouldUseThreading()); |
| 879 | 877 |
| 880 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), | 878 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), |
| 881 "HTMLDocumentParser::append", "size", inputSource.length()); | 879 "HTMLDocumentParser::append", "size", inputSource.length()); |
| 882 const SegmentedString source(inputSource); | 880 const SegmentedString source(inputSource); |
| 883 | 881 |
| 884 if (document()->isPrefetchOnly()) { | 882 if (document()->isPrefetchOnly()) { |
| 885 if (!m_preloadScanner) | 883 if (!m_preloadScanner) |
| 886 m_preloadScanner = createPreloadScanner(); | 884 m_preloadScanner = createPreloadScanner(); |
| 887 | 885 |
| 888 m_preloadScanner->appendToEnd(source); | 886 m_preloadScanner->appendToEnd(source); |
| 889 m_preloadScanner->scanAndPreload( | 887 m_preloadScanner->scanAndPreload( |
| 890 m_preloader.get(), document()->validBaseElementURL(), nullptr); | 888 m_preloader.get(), document()->validBaseElementURL(), nullptr); |
| 891 | 889 |
| 892 // Return after the preload scanner, do not actually parse the document. | 890 // Return after the preload scanner, do not actually parse the document. |
| 893 return; | 891 return; |
| 894 } | 892 } |
| 895 | 893 |
| 896 if (m_preloadScanner) { | 894 if (m_preloadScanner) { |
| 897 if (m_input.current().isEmpty() && !isWaitingForScripts()) { | 895 if (m_input.current().isEmpty() && !isWaitingForScripts()) { |
| 898 // We have parsed until the end of the current input and so are now moving
ahead of the preload scanner. | 896 // We have parsed until the end of the current input and so are now moving |
| 899 // Clear the scanner so we know to scan starting from the current input po
int if we block again. | 897 // ahead of the preload scanner. Clear the scanner so we know to scan |
| 898 // starting from the current input point if we block again. |
| 900 m_preloadScanner.reset(); | 899 m_preloadScanner.reset(); |
| 901 } else { | 900 } else { |
| 902 m_preloadScanner->appendToEnd(source); | 901 m_preloadScanner->appendToEnd(source); |
| 903 if (isWaitingForScripts()) | 902 if (isWaitingForScripts()) |
| 904 m_preloadScanner->scanAndPreload( | 903 m_preloadScanner->scanAndPreload( |
| 905 m_preloader.get(), document()->validBaseElementURL(), nullptr); | 904 m_preloader.get(), document()->validBaseElementURL(), nullptr); |
| 906 } | 905 } |
| 907 } | 906 } |
| 908 | 907 |
| 909 m_input.appendToEnd(source); | 908 m_input.appendToEnd(source); |
| 910 | 909 |
| 911 if (inPumpSession()) { | 910 if (inPumpSession()) { |
| 912 // We've gotten data off the network in a nested write. | 911 // We've gotten data off the network in a nested write. We don't want to |
| 913 // We don't want to consume any more of the input stream now. Do | 912 // consume any more of the input stream now. Do not worry. We'll consume |
| 914 // not worry. We'll consume this data in a less-nested write(). | 913 // this data in a less-nested write(). |
| 915 return; | 914 return; |
| 916 } | 915 } |
| 917 | 916 |
| 918 pumpTokenizerIfPossible(); | 917 pumpTokenizerIfPossible(); |
| 919 | 918 |
| 920 endIfDelayed(); | 919 endIfDelayed(); |
| 921 } | 920 } |
| 922 | 921 |
| 923 void HTMLDocumentParser::end() { | 922 void HTMLDocumentParser::end() { |
| 924 ASSERT(!isDetached()); | 923 ASSERT(!isDetached()); |
| 925 ASSERT(!isScheduledForResume()); | 924 ASSERT(!isScheduledForResume()); |
| 926 | 925 |
| 927 if (m_haveBackgroundParser) | 926 if (m_haveBackgroundParser) |
| 928 stopBackgroundParser(); | 927 stopBackgroundParser(); |
| 929 | 928 |
| 930 // Informs the the rest of WebCore that parsing is really finished (and delete
s this). | 929 // Informs the the rest of WebCore that parsing is really finished (and |
| 930 // deletes this). |
| 931 m_treeBuilder->finished(); | 931 m_treeBuilder->finished(); |
| 932 | 932 |
| 933 DocumentParser::stopParsing(); | 933 DocumentParser::stopParsing(); |
| 934 } | 934 } |
| 935 | 935 |
| 936 void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd() { | 936 void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd() { |
| 937 ASSERT(isStopping()); | 937 ASSERT(isStopping()); |
| 938 // FIXME: It may not be correct to disable this for the background parser. | 938 // FIXME: It may not be correct to disable this for the background parser. |
| 939 // That means hasInsertionPoint() may not be correct in some cases. | 939 // That means hasInsertionPoint() may not be correct in some cases. |
| 940 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); | 940 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 960 return; | 960 return; |
| 961 | 961 |
| 962 if (!m_endWasDelayed || shouldDelayEnd()) | 962 if (!m_endWasDelayed || shouldDelayEnd()) |
| 963 return; | 963 return; |
| 964 | 964 |
| 965 m_endWasDelayed = false; | 965 m_endWasDelayed = false; |
| 966 prepareToStopParsing(); | 966 prepareToStopParsing(); |
| 967 } | 967 } |
| 968 | 968 |
| 969 void HTMLDocumentParser::finish() { | 969 void HTMLDocumentParser::finish() { |
| 970 // FIXME: We should ASSERT(!m_parserStopped) here, since it does not | 970 // FIXME: We should ASSERT(!m_parserStopped) here, since it does not makes |
| 971 // makes sense to call any methods on DocumentParser once it's been stopped. | 971 // sense to call any methods on DocumentParser once it's been stopped. |
| 972 // However, FrameLoader::stop calls DocumentParser::finish unconditionally. | 972 // However, FrameLoader::stop calls DocumentParser::finish unconditionally. |
| 973 | 973 |
| 974 flush(); | 974 flush(); |
| 975 if (isDetached()) | 975 if (isDetached()) |
| 976 return; | 976 return; |
| 977 | 977 |
| 978 // Empty documents never got an append() call, and thus have never started | 978 // Empty documents never got an append() call, and thus have never started a |
| 979 // a background parser. In those cases, we ignore shouldUseThreading() | 979 // background parser. In those cases, we ignore shouldUseThreading() and fall |
| 980 // and fall through to the non-threading case. | 980 // through to the non-threading case. |
| 981 if (m_haveBackgroundParser) { | 981 if (m_haveBackgroundParser) { |
| 982 if (!m_input.haveSeenEndOfFile()) | 982 if (!m_input.haveSeenEndOfFile()) |
| 983 m_input.closeWithoutMarkingEndOfFile(); | 983 m_input.closeWithoutMarkingEndOfFile(); |
| 984 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::finish, | 984 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::finish, |
| 985 m_backgroundParser); | 985 m_backgroundParser); |
| 986 return; | 986 return; |
| 987 } | 987 } |
| 988 | 988 |
| 989 if (!m_tokenizer) { | 989 if (!m_tokenizer) { |
| 990 ASSERT(!m_token); | 990 ASSERT(!m_token); |
| 991 // We're finishing before receiving any data. Rather than booting up | 991 // We're finishing before receiving any data. Rather than booting up the |
| 992 // the background parser just to spin it down, we finish parsing | 992 // background parser just to spin it down, we finish parsing synchronously. |
| 993 // synchronously. | |
| 994 m_token = wrapUnique(new HTMLToken); | 993 m_token = wrapUnique(new HTMLToken); |
| 995 m_tokenizer = HTMLTokenizer::create(m_options); | 994 m_tokenizer = HTMLTokenizer::create(m_options); |
| 996 } | 995 } |
| 997 | 996 |
| 998 // We're not going to get any more data off the network, so we tell the | 997 // We're not going to get any more data off the network, so we tell the input |
| 999 // input stream we've reached the end of file. finish() can be called more | 998 // stream we've reached the end of file. finish() can be called more than |
| 1000 // than once, if the first time does not call end(). | 999 // once, if the first time does not call end(). |
| 1001 if (!m_input.haveSeenEndOfFile()) | 1000 if (!m_input.haveSeenEndOfFile()) |
| 1002 m_input.markEndOfFile(); | 1001 m_input.markEndOfFile(); |
| 1003 | 1002 |
| 1004 attemptToEnd(); | 1003 attemptToEnd(); |
| 1005 } | 1004 } |
| 1006 | 1005 |
| 1007 bool HTMLDocumentParser::isExecutingScript() const { | 1006 bool HTMLDocumentParser::isExecutingScript() const { |
| 1008 if (!m_scriptRunner) | 1007 if (!m_scriptRunner) |
| 1009 return false; | 1008 return false; |
| 1010 return m_scriptRunner->isExecutingScript(); | 1009 return m_scriptRunner->isExecutingScript(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1027 return m_textPosition; | 1026 return m_textPosition; |
| 1028 | 1027 |
| 1029 const SegmentedString& currentString = m_input.current(); | 1028 const SegmentedString& currentString = m_input.current(); |
| 1030 OrdinalNumber line = currentString.currentLine(); | 1029 OrdinalNumber line = currentString.currentLine(); |
| 1031 OrdinalNumber column = currentString.currentColumn(); | 1030 OrdinalNumber column = currentString.currentColumn(); |
| 1032 | 1031 |
| 1033 return TextPosition(line, column); | 1032 return TextPosition(line, column); |
| 1034 } | 1033 } |
| 1035 | 1034 |
| 1036 bool HTMLDocumentParser::isWaitingForScripts() const { | 1035 bool HTMLDocumentParser::isWaitingForScripts() const { |
| 1037 // When the TreeBuilder encounters a </script> tag, it returns to the HTMLDocu
mentParser | 1036 // When the TreeBuilder encounters a </script> tag, it returns to the |
| 1038 // where the script is transfered from the treebuilder to the script runner. | 1037 // HTMLDocumentParser where the script is transfered from the treebuilder to |
| 1039 // The script runner will hold the script until its loaded and run. During | 1038 // the script runner. The script runner will hold the script until its loaded |
| 1040 // any of this time, we want to count ourselves as "waiting for a script" and
thus | 1039 // and run. During any of this time, we want to count ourselves as "waiting |
| 1041 // run the preload scanner, as well as delay completion of parsing. | 1040 // for a script" and thus run the preload scanner, as well as delay completion |
| 1041 // of parsing. |
| 1042 bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript(); | 1042 bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript(); |
| 1043 bool scriptRunnerHasBlockingScript = | 1043 bool scriptRunnerHasBlockingScript = |
| 1044 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); | 1044 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); |
| 1045 // Since the parser is paused while a script runner has a blocking script, it
should | 1045 // Since the parser is paused while a script runner has a blocking script, it |
| 1046 // never be possible to end up with both objects holding a blocking script. | 1046 // should never be possible to end up with both objects holding a blocking |
| 1047 // script. |
| 1047 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); | 1048 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); |
| 1048 // If either object has a blocking script, the parser should be paused. | 1049 // If either object has a blocking script, the parser should be paused. |
| 1049 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || | 1050 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || |
| 1050 m_reentryPermit->parserPauseFlag(); | 1051 m_reentryPermit->parserPauseFlag(); |
| 1051 } | 1052 } |
| 1052 | 1053 |
| 1053 void HTMLDocumentParser::resumeParsingAfterScriptExecution() { | 1054 void HTMLDocumentParser::resumeParsingAfterScriptExecution() { |
| 1054 ASSERT(!isExecutingScript()); | 1055 ASSERT(!isExecutingScript()); |
| 1055 ASSERT(!isWaitingForScripts()); | 1056 ASSERT(!isWaitingForScripts()); |
| 1056 | 1057 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1085 attemptToRunDeferredScriptsAndEnd(); | 1086 attemptToRunDeferredScriptsAndEnd(); |
| 1086 return; | 1087 return; |
| 1087 } | 1088 } |
| 1088 | 1089 |
| 1089 m_scriptRunner->executeScriptsWaitingForLoad(cachedResource); | 1090 m_scriptRunner->executeScriptsWaitingForLoad(cachedResource); |
| 1090 if (!isWaitingForScripts()) | 1091 if (!isWaitingForScripts()) |
| 1091 resumeParsingAfterScriptExecution(); | 1092 resumeParsingAfterScriptExecution(); |
| 1092 } | 1093 } |
| 1093 | 1094 |
| 1094 void HTMLDocumentParser::executeScriptsWaitingForResources() { | 1095 void HTMLDocumentParser::executeScriptsWaitingForResources() { |
| 1095 // Document only calls this when the Document owns the DocumentParser | 1096 // Document only calls this when the Document owns the DocumentParser so this |
| 1096 // so this will not be called in the DocumentFragment case. | 1097 // will not be called in the DocumentFragment case. |
| 1097 ASSERT(m_scriptRunner); | 1098 ASSERT(m_scriptRunner); |
| 1098 // Ignore calls unless we have a script blocking the parser waiting on a | 1099 // Ignore calls unless we have a script blocking the parser waiting on a |
| 1099 // stylesheet load. Otherwise we are currently parsing and this | 1100 // stylesheet load. Otherwise we are currently parsing and this is a |
| 1100 // is a re-entrant call from encountering a </ style> tag. | 1101 // re-entrant call from encountering a </ style> tag. |
| 1101 if (!m_scriptRunner->hasScriptsWaitingForResources()) | 1102 if (!m_scriptRunner->hasScriptsWaitingForResources()) |
| 1102 return; | 1103 return; |
| 1103 m_scriptRunner->executeScriptsWaitingForResources(); | 1104 m_scriptRunner->executeScriptsWaitingForResources(); |
| 1104 if (!isWaitingForScripts()) | 1105 if (!isWaitingForScripts()) |
| 1105 resumeParsingAfterScriptExecution(); | 1106 resumeParsingAfterScriptExecution(); |
| 1106 } | 1107 } |
| 1107 | 1108 |
| 1108 void HTMLDocumentParser::parseDocumentFragment( | 1109 void HTMLDocumentParser::parseDocumentFragment( |
| 1109 const String& source, | 1110 const String& source, |
| 1110 DocumentFragment* fragment, | 1111 DocumentFragment* fragment, |
| 1111 Element* contextElement, | 1112 Element* contextElement, |
| 1112 ParserContentPolicy parserContentPolicy) { | 1113 ParserContentPolicy parserContentPolicy) { |
| 1113 HTMLDocumentParser* parser = | 1114 HTMLDocumentParser* parser = |
| 1114 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); | 1115 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); |
| 1115 parser->append(source); | 1116 parser->append(source); |
| 1116 parser->finish(); | 1117 parser->finish(); |
| 1117 parser | 1118 // Allows ~DocumentParser to assert it was detached before destruction. |
| 1118 ->detach(); // Allows ~DocumentParser to assert it was detached before de
struction. | 1119 parser->detach(); |
| 1119 } | 1120 } |
| 1120 | 1121 |
| 1121 void HTMLDocumentParser::suspendScheduledTasks() { | 1122 void HTMLDocumentParser::suspendScheduledTasks() { |
| 1122 ASSERT(!m_tasksWereSuspended); | 1123 ASSERT(!m_tasksWereSuspended); |
| 1123 m_tasksWereSuspended = true; | 1124 m_tasksWereSuspended = true; |
| 1124 if (m_parserScheduler) | 1125 if (m_parserScheduler) |
| 1125 m_parserScheduler->suspend(); | 1126 m_parserScheduler->suspend(); |
| 1126 } | 1127 } |
| 1127 | 1128 |
| 1128 void HTMLDocumentParser::resumeScheduledTasks() { | 1129 void HTMLDocumentParser::resumeScheduledTasks() { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1159 | 1160 |
| 1160 DecodedDataDocumentParser::appendBytes(data, length); | 1161 DecodedDataDocumentParser::appendBytes(data, length); |
| 1161 } | 1162 } |
| 1162 | 1163 |
| 1163 void HTMLDocumentParser::flush() { | 1164 void HTMLDocumentParser::flush() { |
| 1164 // If we've got no decoder, we never received any data. | 1165 // If we've got no decoder, we never received any data. |
| 1165 if (isDetached() || needsDecoder()) | 1166 if (isDetached() || needsDecoder()) |
| 1166 return; | 1167 return; |
| 1167 | 1168 |
| 1168 if (shouldUseThreading()) { | 1169 if (shouldUseThreading()) { |
| 1169 // In some cases, flush() is called without any invocation of | 1170 // In some cases, flush() is called without any invocation of appendBytes. |
| 1170 // appendBytes. Fallback to synchronous parsing in that case. | 1171 // Fallback to synchronous parsing in that case. |
| 1171 if (!m_haveBackgroundParser) { | 1172 if (!m_haveBackgroundParser) { |
| 1172 m_shouldUseThreading = false; | 1173 m_shouldUseThreading = false; |
| 1173 m_token = wrapUnique(new HTMLToken); | 1174 m_token = wrapUnique(new HTMLToken); |
| 1174 m_tokenizer = HTMLTokenizer::create(m_options); | 1175 m_tokenizer = HTMLTokenizer::create(m_options); |
| 1175 DecodedDataDocumentParser::flush(); | 1176 DecodedDataDocumentParser::flush(); |
| 1176 return; | 1177 return; |
| 1177 } | 1178 } |
| 1178 | 1179 |
| 1179 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::flush, | 1180 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::flush, |
| 1180 m_backgroundParser); | 1181 m_backgroundParser); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1294 case Asynchronous: | 1295 case Asynchronous: |
| 1295 m_loadingTaskRunner->postTask( | 1296 m_loadingTaskRunner->postTask( |
| 1296 BLINK_FROM_HERE, | 1297 BLINK_FROM_HERE, |
| 1297 WTF::bind(function, std::forward<Ps>(parameters)...)); | 1298 WTF::bind(function, std::forward<Ps>(parameters)...)); |
| 1298 return; | 1299 return; |
| 1299 } | 1300 } |
| 1300 NOTREACHED(); | 1301 NOTREACHED(); |
| 1301 } | 1302 } |
| 1302 | 1303 |
| 1303 } // namespace blink | 1304 } // namespace blink |
| OLD | NEW |