| 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 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 m_shouldUseThreading(syncPolicy == AllowAsynchronousParsing), | 146 m_shouldUseThreading(syncPolicy == AllowAsynchronousParsing), |
| 147 m_endWasDelayed(false), | 147 m_endWasDelayed(false), |
| 148 m_haveBackgroundParser(false), | 148 m_haveBackgroundParser(false), |
| 149 m_tasksWereSuspended(false), | 149 m_tasksWereSuspended(false), |
| 150 m_pumpSessionNestingLevel(0), | 150 m_pumpSessionNestingLevel(0), |
| 151 m_pumpSpeculationsSessionNestingLevel(0), | 151 m_pumpSpeculationsSessionNestingLevel(0), |
| 152 m_isParsingAtLineNumber(false), | 152 m_isParsingAtLineNumber(false), |
| 153 m_triedLoadingLinkHeaders(false), | 153 m_triedLoadingLinkHeaders(false), |
| 154 m_addedPendingStylesheetInBody(false), | 154 m_addedPendingStylesheetInBody(false), |
| 155 m_isWaitingForStylesheets(false) { | 155 m_isWaitingForStylesheets(false) { |
| 156 ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); | 156 DCHECK(shouldUseThreading() || (m_token && m_tokenizer)); |
| 157 // Threading is not allowed in prefetch mode. | 157 // Threading is not allowed in prefetch mode. |
| 158 DCHECK(!document.isPrefetchOnly() || !shouldUseThreading()); | 158 DCHECK(!document.isPrefetchOnly() || !shouldUseThreading()); |
| 159 } | 159 } |
| 160 | 160 |
| 161 HTMLDocumentParser::~HTMLDocumentParser() {} | 161 HTMLDocumentParser::~HTMLDocumentParser() {} |
| 162 | 162 |
| 163 void HTMLDocumentParser::dispose() { | 163 void HTMLDocumentParser::dispose() { |
| 164 // In Oilpan, HTMLDocumentParser can die together with Document, and detach() | 164 // In Oilpan, HTMLDocumentParser can die together with Document, and detach() |
| 165 // is not called in this case. | 165 // is not called in this case. |
| 166 if (m_haveBackgroundParser) | 166 if (m_haveBackgroundParser) |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 } | 220 } |
| 221 if (m_haveBackgroundParser) | 221 if (m_haveBackgroundParser) |
| 222 stopBackgroundParser(); | 222 stopBackgroundParser(); |
| 223 } | 223 } |
| 224 | 224 |
| 225 // This kicks off "Once the user agent stops parsing" as described by: | 225 // This kicks off "Once the user agent stops parsing" as described by: |
| 226 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the-
end | 226 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the-
end |
| 227 void HTMLDocumentParser::prepareToStopParsing() { | 227 void HTMLDocumentParser::prepareToStopParsing() { |
| 228 // FIXME: It may not be correct to disable this for the background parser. | 228 // FIXME: It may not be correct to disable this for the background parser. |
| 229 // That means hasInsertionPoint() may not be correct in some cases. | 229 // That means hasInsertionPoint() may not be correct in some cases. |
| 230 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); | 230 DCHECK(!hasInsertionPoint() || m_haveBackgroundParser); |
| 231 | 231 |
| 232 // NOTE: This pump should only ever emit buffered character tokens. | 232 // NOTE: This pump should only ever emit buffered character tokens. |
| 233 if (m_tokenizer) { | 233 if (m_tokenizer) { |
| 234 ASSERT(!m_haveBackgroundParser); | 234 DCHECK(!m_haveBackgroundParser); |
| 235 pumpTokenizerIfPossible(); | 235 pumpTokenizerIfPossible(); |
| 236 } | 236 } |
| 237 | 237 |
| 238 if (isStopped()) | 238 if (isStopped()) |
| 239 return; | 239 return; |
| 240 | 240 |
| 241 DocumentParser::prepareToStopParsing(); | 241 DocumentParser::prepareToStopParsing(); |
| 242 | 242 |
| 243 // We will not have a scriptRunner when parsing a DocumentFragment. | 243 // We will not have a scriptRunner when parsing a DocumentFragment. |
| 244 if (m_scriptRunner) | 244 if (m_scriptRunner) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 263 | 263 |
| 264 pumpTokenizer(); | 264 pumpTokenizer(); |
| 265 } | 265 } |
| 266 | 266 |
| 267 bool HTMLDocumentParser::isScheduledForResume() const { | 267 bool HTMLDocumentParser::isScheduledForResume() const { |
| 268 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); | 268 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); |
| 269 } | 269 } |
| 270 | 270 |
| 271 // Used by HTMLParserScheduler | 271 // Used by HTMLParserScheduler |
| 272 void HTMLDocumentParser::resumeParsingAfterYield() { | 272 void HTMLDocumentParser::resumeParsingAfterYield() { |
| 273 ASSERT(shouldUseThreading()); | 273 DCHECK(shouldUseThreading()); |
| 274 ASSERT(m_haveBackgroundParser); | 274 DCHECK(m_haveBackgroundParser); |
| 275 | 275 |
| 276 checkIfBodyStylesheetAdded(); | 276 checkIfBodyStylesheetAdded(); |
| 277 if (isStopped() || isPaused()) | 277 if (isStopped() || isPaused()) |
| 278 return; | 278 return; |
| 279 | 279 |
| 280 pumpPendingSpeculations(); | 280 pumpPendingSpeculations(); |
| 281 } | 281 } |
| 282 | 282 |
| 283 void HTMLDocumentParser::runScriptsForPausedTreeBuilder() { | 283 void HTMLDocumentParser::runScriptsForPausedTreeBuilder() { |
| 284 ASSERT(scriptingContentIsAllowed(getParserContentPolicy())); | 284 DCHECK(scriptingContentIsAllowed(getParserContentPolicy())); |
| 285 | 285 |
| 286 TextPosition scriptStartPosition = TextPosition::belowRangePosition(); | 286 TextPosition scriptStartPosition = TextPosition::belowRangePosition(); |
| 287 Element* scriptElement = | 287 Element* scriptElement = |
| 288 m_treeBuilder->takeScriptToProcess(scriptStartPosition); | 288 m_treeBuilder->takeScriptToProcess(scriptStartPosition); |
| 289 // We will not have a scriptRunner when parsing a DocumentFragment. | 289 // We will not have a scriptRunner when parsing a DocumentFragment. |
| 290 if (m_scriptRunner) | 290 if (m_scriptRunner) |
| 291 m_scriptRunner->processScriptElement(scriptElement, scriptStartPosition); | 291 m_scriptRunner->processScriptElement(scriptElement, scriptStartPosition); |
| 292 checkIfBodyStylesheetAdded(); | 292 checkIfBodyStylesheetAdded(); |
| 293 } | 293 } |
| 294 | 294 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 for (auto& request : chunk->preloads) { | 353 for (auto& request : chunk->preloads) { |
| 354 // Link rel preloads don't need to wait for AppCache but they | 354 // Link rel preloads don't need to wait for AppCache but they |
| 355 // should probably wait for CSP. | 355 // should probably wait for CSP. |
| 356 if (!m_pendingCSPMetaToken && request->isLinkRelPreload()) | 356 if (!m_pendingCSPMetaToken && request->isLinkRelPreload()) |
| 357 linkRelPreloads.push_back(std::move(request)); | 357 linkRelPreloads.push_back(std::move(request)); |
| 358 else | 358 else |
| 359 m_queuedPreloads.push_back(std::move(request)); | 359 m_queuedPreloads.push_back(std::move(request)); |
| 360 } | 360 } |
| 361 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { | 361 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { |
| 362 const CompactHTMLToken& token = chunk->tokens->at(index); | 362 const CompactHTMLToken& token = chunk->tokens->at(index); |
| 363 ASSERT(token.type() == HTMLToken::TokenType::Character); | 363 DCHECK_EQ(token.type(), HTMLToken::TokenType::Character); |
| 364 m_queuedDocumentWriteScripts.push_back(token.data()); | 364 m_queuedDocumentWriteScripts.push_back(token.data()); |
| 365 } | 365 } |
| 366 } | 366 } |
| 367 m_preloader->takeAndPreload(linkRelPreloads); | 367 m_preloader->takeAndPreload(linkRelPreloads); |
| 368 } else { | 368 } else { |
| 369 // We can safely assume that there are no queued preloads request after the | 369 // We can safely assume that there are no queued preloads request after the |
| 370 // document element is available, as we empty the queue immediately after | 370 // document element is available, as we empty the queue immediately after |
| 371 // the document element is created in documentElementAvailable(). | 371 // the document element is created in documentElementAvailable(). |
| 372 ASSERT(m_queuedPreloads.isEmpty()); | 372 DCHECK(m_queuedPreloads.isEmpty()); |
| 373 ASSERT(m_queuedDocumentWriteScripts.isEmpty()); | 373 DCHECK(m_queuedDocumentWriteScripts.isEmpty()); |
| 374 // Loop through the chunks to generate preloads before any document.write | 374 // Loop through the chunks to generate preloads before any document.write |
| 375 // script evaluation takes place. Preloading these scripts is valuable and | 375 // script evaluation takes place. Preloading these scripts is valuable and |
| 376 // comparably cheap, while evaluating JS can be expensive. | 376 // comparably cheap, while evaluating JS can be expensive. |
| 377 for (auto& chunk : pendingChunks) | 377 for (auto& chunk : pendingChunks) |
| 378 m_preloader->takeAndPreload(chunk->preloads); | 378 m_preloader->takeAndPreload(chunk->preloads); |
| 379 for (auto& chunk : pendingChunks) { | 379 for (auto& chunk : pendingChunks) { |
| 380 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { | 380 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { |
| 381 const CompactHTMLToken& token = chunk->tokens->at(index); | 381 const CompactHTMLToken& token = chunk->tokens->at(index); |
| 382 ASSERT(token.type() == HTMLToken::TokenType::Character); | 382 DCHECK_EQ(token.type(), HTMLToken::TokenType::Character); |
| 383 evaluateAndPreloadScriptForDocumentWrite(token.data()); | 383 evaluateAndPreloadScriptForDocumentWrite(token.data()); |
| 384 } | 384 } |
| 385 } | 385 } |
| 386 } | 386 } |
| 387 | 387 |
| 388 for (auto& chunk : pendingChunks) | 388 for (auto& chunk : pendingChunks) |
| 389 m_speculations.push_back(std::move(chunk)); | 389 m_speculations.push_back(std::move(chunk)); |
| 390 | 390 |
| 391 if (!isPaused() && !isScheduledForResume()) { | 391 if (!isPaused() && !isScheduledForResume()) { |
| 392 if (m_tasksWereSuspended) | 392 if (m_tasksWereSuspended) |
| 393 m_parserScheduler->forceResumeAfterYield(); | 393 m_parserScheduler->forceResumeAfterYield(); |
| 394 else | 394 else |
| 395 m_parserScheduler->scheduleForResume(); | 395 m_parserScheduler->scheduleForResume(); |
| 396 } | 396 } |
| 397 } | 397 } |
| 398 | 398 |
| 399 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( | 399 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( |
| 400 const DocumentEncodingData& data) { | 400 const DocumentEncodingData& data) { |
| 401 document()->setEncodingData(data); | 401 document()->setEncodingData(data); |
| 402 } | 402 } |
| 403 | 403 |
| 404 void HTMLDocumentParser::validateSpeculations( | 404 void HTMLDocumentParser::validateSpeculations( |
| 405 std::unique_ptr<TokenizedChunk> chunk) { | 405 std::unique_ptr<TokenizedChunk> chunk) { |
| 406 ASSERT(chunk); | 406 DCHECK(chunk); |
| 407 // TODO(kouhei): We should simplify codepath here by disallowing | 407 // TODO(kouhei): We should simplify codepath here by disallowing |
| 408 // validateSpeculations | 408 // validateSpeculations |
| 409 // while isPaused, and m_lastChunkBeforePause can simply be | 409 // while isPaused, and m_lastChunkBeforePause can simply be |
| 410 // pushed to m_speculations. | 410 // pushed to m_speculations. |
| 411 if (isPaused()) { | 411 if (isPaused()) { |
| 412 // We're waiting on a network script or stylesheet, just save the chunk, | 412 // We're waiting on a network script or stylesheet, just save the chunk, |
| 413 // we'll get a second validateSpeculations call after the script or | 413 // we'll get a second validateSpeculations call after the script or |
| 414 // stylesheet completes. This call should have been made immediately after | 414 // stylesheet completes. This call should have been made immediately after |
| 415 // runScriptsForPausedTreeBuilder in the script case which may have started | 415 // runScriptsForPausedTreeBuilder in the script case which may have started |
| 416 // a network load and left us waiting. | 416 // a network load and left us waiting. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 432 // Currently we're only smart enough to reuse the speculation buffer if the | 432 // Currently we're only smart enough to reuse the speculation buffer if the |
| 433 // tokenizer both starts and ends in the DataState. That state is simplest | 433 // tokenizer both starts and ends in the DataState. That state is simplest |
| 434 // because the HTMLToken is always in the Uninitialized state. We should | 434 // because the HTMLToken is always in the Uninitialized state. We should |
| 435 // consider whether we can reuse the speculation buffer in other states, but | 435 // consider whether we can reuse the speculation buffer in other states, but |
| 436 // we'd likely need to do something more sophisticated with the HTMLToken. | 436 // we'd likely need to do something more sophisticated with the HTMLToken. |
| 437 if (chunk->tokenizerState == HTMLTokenizer::DataState && | 437 if (chunk->tokenizerState == HTMLTokenizer::DataState && |
| 438 tokenizer->getState() == HTMLTokenizer::DataState && | 438 tokenizer->getState() == HTMLTokenizer::DataState && |
| 439 m_input.current().isEmpty() && | 439 m_input.current().isEmpty() && |
| 440 chunk->treeBuilderState == | 440 chunk->treeBuilderState == |
| 441 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get())) { | 441 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get())) { |
| 442 ASSERT(token->isUninitialized()); | 442 DCHECK(token->isUninitialized()); |
| 443 return; | 443 return; |
| 444 } | 444 } |
| 445 | 445 |
| 446 discardSpeculationsAndResumeFrom(std::move(chunk), std::move(token), | 446 discardSpeculationsAndResumeFrom(std::move(chunk), std::move(token), |
| 447 std::move(tokenizer)); | 447 std::move(tokenizer)); |
| 448 } | 448 } |
| 449 | 449 |
| 450 void HTMLDocumentParser::discardSpeculationsAndResumeFrom( | 450 void HTMLDocumentParser::discardSpeculationsAndResumeFrom( |
| 451 std::unique_ptr<TokenizedChunk> lastChunkBeforeScript, | 451 std::unique_ptr<TokenizedChunk> lastChunkBeforeScript, |
| 452 std::unique_ptr<HTMLToken> token, | 452 std::unique_ptr<HTMLToken> token, |
| (...skipping 19 matching lines...) Expand all Loading... |
| 472 checkpoint->tokenizer = std::move(tokenizer); | 472 checkpoint->tokenizer = std::move(tokenizer); |
| 473 checkpoint->treeBuilderState = | 473 checkpoint->treeBuilderState = |
| 474 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get()); | 474 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get()); |
| 475 checkpoint->inputCheckpoint = lastChunkBeforeScript->inputCheckpoint; | 475 checkpoint->inputCheckpoint = lastChunkBeforeScript->inputCheckpoint; |
| 476 checkpoint->preloadScannerCheckpoint = | 476 checkpoint->preloadScannerCheckpoint = |
| 477 lastChunkBeforeScript->preloadScannerCheckpoint; | 477 lastChunkBeforeScript->preloadScannerCheckpoint; |
| 478 checkpoint->unparsedInput = m_input.current().toString().isolatedCopy(); | 478 checkpoint->unparsedInput = m_input.current().toString().isolatedCopy(); |
| 479 // FIXME: This should be passed in instead of cleared. | 479 // FIXME: This should be passed in instead of cleared. |
| 480 m_input.current().clear(); | 480 m_input.current().clear(); |
| 481 | 481 |
| 482 ASSERT(checkpoint->unparsedInput.isSafeToSendToAnotherThread()); | 482 DCHECK(checkpoint->unparsedInput.isSafeToSendToAnotherThread()); |
| 483 m_loadingTaskRunner->postTask( | 483 m_loadingTaskRunner->postTask( |
| 484 BLINK_FROM_HERE, | 484 BLINK_FROM_HERE, |
| 485 WTF::bind(&BackgroundHTMLParser::resumeFrom, m_backgroundParser, | 485 WTF::bind(&BackgroundHTMLParser::resumeFrom, m_backgroundParser, |
| 486 WTF::passed(std::move(checkpoint)))); | 486 WTF::passed(std::move(checkpoint)))); |
| 487 } | 487 } |
| 488 | 488 |
| 489 size_t HTMLDocumentParser::processTokenizedChunkFromBackgroundParser( | 489 size_t HTMLDocumentParser::processTokenizedChunkFromBackgroundParser( |
| 490 std::unique_ptr<TokenizedChunk> popChunk) { | 490 std::unique_ptr<TokenizedChunk> popChunk) { |
| 491 TRACE_EVENT_WITH_FLOW0( | 491 TRACE_EVENT_WITH_FLOW0( |
| 492 "blink,loading", | 492 "blink,loading", |
| 493 "HTMLDocumentParser::processTokenizedChunkFromBackgroundParser", | 493 "HTMLDocumentParser::processTokenizedChunkFromBackgroundParser", |
| 494 popChunk.get(), TRACE_EVENT_FLAG_FLOW_IN); | 494 popChunk.get(), TRACE_EVENT_FLAG_FLOW_IN); |
| 495 AutoReset<bool> hasLineNumber(&m_isParsingAtLineNumber, true); | 495 AutoReset<bool> hasLineNumber(&m_isParsingAtLineNumber, true); |
| 496 | 496 |
| 497 SECURITY_DCHECK(m_pumpSpeculationsSessionNestingLevel == 1); | 497 SECURITY_DCHECK(m_pumpSpeculationsSessionNestingLevel == 1); |
| 498 SECURITY_DCHECK(!inPumpSession()); | 498 SECURITY_DCHECK(!inPumpSession()); |
| 499 ASSERT(!isParsingFragment()); | 499 DCHECK(!isParsingFragment()); |
| 500 DCHECK(!isPaused()); | 500 DCHECK(!isPaused()); |
| 501 ASSERT(!isStopped()); | 501 DCHECK(!isStopped()); |
| 502 ASSERT(shouldUseThreading()); | 502 DCHECK(shouldUseThreading()); |
| 503 ASSERT(!m_tokenizer); | 503 DCHECK(!m_tokenizer); |
| 504 ASSERT(!m_token); | 504 DCHECK(!m_token); |
| 505 DCHECK(!m_lastChunkBeforePause); | 505 DCHECK(!m_lastChunkBeforePause); |
| 506 | 506 |
| 507 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); | 507 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); |
| 508 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); | 508 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); |
| 509 size_t elementTokenCount = 0; | 509 size_t elementTokenCount = 0; |
| 510 | 510 |
| 511 m_loadingTaskRunner->postTask( | 511 m_loadingTaskRunner->postTask( |
| 512 BLINK_FROM_HERE, | 512 BLINK_FROM_HERE, |
| 513 WTF::bind(&BackgroundHTMLParser::startedChunkWithCheckpoint, | 513 WTF::bind(&BackgroundHTMLParser::startedChunkWithCheckpoint, |
| 514 m_backgroundParser, chunk->inputCheckpoint)); | 514 m_backgroundParser, chunk->inputCheckpoint)); |
| 515 | 515 |
| 516 for (const auto& xssInfo : chunk->xssInfos) { | 516 for (const auto& xssInfo : chunk->xssInfos) { |
| 517 m_textPosition = xssInfo->m_textPosition; | 517 m_textPosition = xssInfo->m_textPosition; |
| 518 m_xssAuditorDelegate.didBlockScript(*xssInfo); | 518 m_xssAuditorDelegate.didBlockScript(*xssInfo); |
| 519 if (isStopped()) | 519 if (isStopped()) |
| 520 break; | 520 break; |
| 521 } | 521 } |
| 522 // XSSAuditorDelegate can detach the parser if it decides to block the entire | 522 // XSSAuditorDelegate can detach the parser if it decides to block the entire |
| 523 // current document. | 523 // current document. |
| 524 if (isDetached()) | 524 if (isDetached()) |
| 525 return elementTokenCount; | 525 return elementTokenCount; |
| 526 | 526 |
| 527 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); | 527 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); |
| 528 it != tokens->end(); ++it) { | 528 it != tokens->end(); ++it) { |
| 529 ASSERT(!isWaitingForScripts()); | 529 DCHECK(!isWaitingForScripts()); |
| 530 | 530 |
| 531 if (!chunk->startingScript && | 531 if (!chunk->startingScript && |
| 532 (it->type() == HTMLToken::StartTag || it->type() == HTMLToken::EndTag)) | 532 (it->type() == HTMLToken::StartTag || it->type() == HTMLToken::EndTag)) |
| 533 elementTokenCount++; | 533 elementTokenCount++; |
| 534 | 534 |
| 535 if (document()->frame() && | 535 if (document()->frame() && |
| 536 document()->frame()->navigationScheduler().locationChangePending()) { | 536 document()->frame()->navigationScheduler().locationChangePending()) { |
| 537 // To match main-thread parser behavior (which never checks | 537 // To match main-thread parser behavior (which never checks |
| 538 // locationChangePending on the EOF path) we peek to see if this chunk has | 538 // locationChangePending on the EOF path) we peek to see if this chunk has |
| 539 // an EOF and process it anyway. | 539 // an EOF and process it anyway. |
| 540 if (tokens->back().type() == HTMLToken::EndOfFile) { | 540 if (tokens->back().type() == HTMLToken::EndOfFile) { |
| 541 ASSERT( | 541 DCHECK( |
| 542 m_speculations | 542 m_speculations |
| 543 .isEmpty()); // There should never be any chunks after the EOF. | 543 .isEmpty()); // There should never be any chunks after the EOF. |
| 544 prepareToStopParsing(); | 544 prepareToStopParsing(); |
| 545 } | 545 } |
| 546 break; | 546 break; |
| 547 } | 547 } |
| 548 | 548 |
| 549 m_textPosition = it->textPosition(); | 549 m_textPosition = it->textPosition(); |
| 550 | 550 |
| 551 constructTreeFromCompactHTMLToken(*it); | 551 constructTreeFromCompactHTMLToken(*it); |
| 552 | 552 |
| 553 if (isStopped()) | 553 if (isStopped()) |
| 554 break; | 554 break; |
| 555 | 555 |
| 556 // Preloads were queued if there was a <meta> csp token in a tokenized | 556 // Preloads were queued if there was a <meta> csp token in a tokenized |
| 557 // chunk. | 557 // chunk. |
| 558 if (m_pendingCSPMetaToken && it == m_pendingCSPMetaToken) { | 558 if (m_pendingCSPMetaToken && it == m_pendingCSPMetaToken) { |
| 559 m_pendingCSPMetaToken = nullptr; | 559 m_pendingCSPMetaToken = nullptr; |
| 560 fetchQueuedPreloads(); | 560 fetchQueuedPreloads(); |
| 561 } | 561 } |
| 562 | 562 |
| 563 if (isPaused()) { | 563 if (isPaused()) { |
| 564 // The script or stylesheet should be the last token of this bunch. | 564 // The script or stylesheet should be the last token of this bunch. |
| 565 ASSERT(it + 1 == tokens->end()); | 565 DCHECK_EQ(it + 1, tokens->end()); |
| 566 if (isWaitingForScripts()) | 566 if (isWaitingForScripts()) |
| 567 runScriptsForPausedTreeBuilder(); | 567 runScriptsForPausedTreeBuilder(); |
| 568 validateSpeculations(std::move(chunk)); | 568 validateSpeculations(std::move(chunk)); |
| 569 break; | 569 break; |
| 570 } | 570 } |
| 571 | 571 |
| 572 if (it->type() == HTMLToken::EndOfFile) { | 572 if (it->type() == HTMLToken::EndOfFile) { |
| 573 // The EOF is assumed to be the last token of this bunch. | 573 // The EOF is assumed to be the last token of this bunch. |
| 574 ASSERT(it + 1 == tokens->end()); | 574 DCHECK_EQ(it + 1, tokens->end()); |
| 575 // There should never be any chunks after the EOF. | 575 // There should never be any chunks after the EOF. |
| 576 ASSERT(m_speculations.isEmpty()); | 576 DCHECK(m_speculations.isEmpty()); |
| 577 prepareToStopParsing(); | 577 prepareToStopParsing(); |
| 578 break; | 578 break; |
| 579 } | 579 } |
| 580 | 580 |
| 581 ASSERT(!m_tokenizer); | 581 DCHECK(!m_tokenizer); |
| 582 ASSERT(!m_token); | 582 DCHECK(!m_token); |
| 583 } | 583 } |
| 584 | 584 |
| 585 // Make sure all required pending text nodes are emitted before returning. | 585 // Make sure all required pending text nodes are emitted before returning. |
| 586 // This leaves "script", "style" and "svg" nodes text nodes intact. | 586 // This leaves "script", "style" and "svg" nodes text nodes intact. |
| 587 if (!isStopped()) | 587 if (!isStopped()) |
| 588 m_treeBuilder->flush(FlushIfAtTextLimit); | 588 m_treeBuilder->flush(FlushIfAtTextLimit); |
| 589 | 589 |
| 590 m_isParsingAtLineNumber = false; | 590 m_isParsingAtLineNumber = false; |
| 591 | 591 |
| 592 return elementTokenCount; | 592 return elementTokenCount; |
| 593 } | 593 } |
| 594 | 594 |
| 595 void HTMLDocumentParser::pumpPendingSpeculations() { | 595 void HTMLDocumentParser::pumpPendingSpeculations() { |
| 596 // If this assert fails, you need to call validateSpeculations to make sure | 596 // If this assert fails, you need to call validateSpeculations to make sure |
| 597 // m_tokenizer and m_token don't have state that invalidates m_speculations. | 597 // m_tokenizer and m_token don't have state that invalidates m_speculations. |
| 598 ASSERT(!m_tokenizer); | 598 DCHECK(!m_tokenizer); |
| 599 ASSERT(!m_token); | 599 DCHECK(!m_token); |
| 600 DCHECK(!m_lastChunkBeforePause); | 600 DCHECK(!m_lastChunkBeforePause); |
| 601 DCHECK(!isPaused()); | 601 DCHECK(!isPaused()); |
| 602 ASSERT(!isStopped()); | 602 DCHECK(!isStopped()); |
| 603 ASSERT(!isScheduledForResume()); | 603 DCHECK(!isScheduledForResume()); |
| 604 ASSERT(!inPumpSession()); | 604 DCHECK(!inPumpSession()); |
| 605 | 605 |
| 606 // FIXME: Here should never be reached when there is a blocking script, | 606 // FIXME: Here should never be reached when there is a blocking script, |
| 607 // but it happens in unknown scenarios. See https://crbug.com/440901 | 607 // but it happens in unknown scenarios. See https://crbug.com/440901 |
| 608 if (isWaitingForScripts()) { | 608 if (isWaitingForScripts()) { |
| 609 m_parserScheduler->scheduleForResume(); | 609 m_parserScheduler->scheduleForResume(); |
| 610 return; | 610 return; |
| 611 } | 611 } |
| 612 | 612 |
| 613 // Do not allow pumping speculations in nested event loops. | 613 // Do not allow pumping speculations in nested event loops. |
| 614 if (m_pumpSpeculationsSessionNestingLevel) { | 614 if (m_pumpSpeculationsSessionNestingLevel) { |
| 615 m_parserScheduler->scheduleForResume(); | 615 m_parserScheduler->scheduleForResume(); |
| 616 return; | 616 return; |
| 617 } | 617 } |
| 618 | 618 |
| 619 probe::ParseHTML probe(document(), this); | 619 probe::ParseHTML probe(document(), this); |
| 620 | 620 |
| 621 SpeculationsPumpSession session(m_pumpSpeculationsSessionNestingLevel); | 621 SpeculationsPumpSession session(m_pumpSpeculationsSessionNestingLevel); |
| 622 while (!m_speculations.isEmpty()) { | 622 while (!m_speculations.isEmpty()) { |
| 623 ASSERT(!isScheduledForResume()); | 623 DCHECK(!isScheduledForResume()); |
| 624 size_t elementTokenCount = | 624 size_t elementTokenCount = |
| 625 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); | 625 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); |
| 626 session.addedElementTokens(elementTokenCount); | 626 session.addedElementTokens(elementTokenCount); |
| 627 | 627 |
| 628 // Always check isParsing first as m_document may be null. Surprisingly, | 628 // Always check isParsing first as m_document may be null. Surprisingly, |
| 629 // isScheduledForResume() may be set here as a result of | 629 // isScheduledForResume() may be set here as a result of |
| 630 // processTokenizedChunkFromBackgroundParser running arbitrary javascript | 630 // processTokenizedChunkFromBackgroundParser running arbitrary javascript |
| 631 // which invokes nested event loops. (e.g. inspector breakpoints) | 631 // which invokes nested event loops. (e.g. inspector breakpoints) |
| 632 checkIfBodyStylesheetAdded(); | 632 checkIfBodyStylesheetAdded(); |
| 633 if (!isParsing() || isPaused() || isScheduledForResume()) | 633 if (!isParsing() || isPaused() || isScheduledForResume()) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 648 startBackgroundParser(); | 648 startBackgroundParser(); |
| 649 | 649 |
| 650 // This task should be synchronous, because otherwise synchronous | 650 // This task should be synchronous, because otherwise synchronous |
| 651 // tokenizing can happen before plaintext is forced. | 651 // tokenizing can happen before plaintext is forced. |
| 652 m_backgroundParser->forcePlaintextForTextDocument(); | 652 m_backgroundParser->forcePlaintextForTextDocument(); |
| 653 } else | 653 } else |
| 654 m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); | 654 m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); |
| 655 } | 655 } |
| 656 | 656 |
| 657 void HTMLDocumentParser::pumpTokenizer() { | 657 void HTMLDocumentParser::pumpTokenizer() { |
| 658 ASSERT(!isStopped()); | 658 DCHECK(!isStopped()); |
| 659 ASSERT(m_tokenizer); | 659 DCHECK(m_tokenizer); |
| 660 ASSERT(m_token); | 660 DCHECK(m_token); |
| 661 | 661 |
| 662 PumpSession session(m_pumpSessionNestingLevel); | 662 PumpSession session(m_pumpSessionNestingLevel); |
| 663 | 663 |
| 664 // We tell the InspectorInstrumentation about every pump, even if we end up | 664 // We tell the InspectorInstrumentation about every pump, even if we end up |
| 665 // pumping nothing. It can filter out empty pumps itself. | 665 // pumping nothing. It can filter out empty pumps itself. |
| 666 // FIXME: m_input.current().length() is only accurate if we end up parsing the | 666 // FIXME: m_input.current().length() is only accurate if we end up parsing the |
| 667 // whole buffer in this pump. We should pass how much we parsed as part of | 667 // whole buffer in this pump. We should pass how much we parsed as part of |
| 668 // didWriteHTML instead of willWriteHTML. | 668 // didWriteHTML instead of willWriteHTML. |
| 669 TRACE_EVENT_BEGIN1( | 669 TRACE_EVENT_BEGIN1( |
| 670 "devtools.timeline", "ParseHTML", "beginData", | 670 "devtools.timeline", "ParseHTML", "beginData", |
| (...skipping 20 matching lines...) Expand all Loading... |
| 691 token(), m_sourceTracker, m_tokenizer->shouldAllowCDATA()))) { | 691 token(), m_sourceTracker, m_tokenizer->shouldAllowCDATA()))) { |
| 692 m_xssAuditorDelegate.didBlockScript(*xssInfo); | 692 m_xssAuditorDelegate.didBlockScript(*xssInfo); |
| 693 // If we're in blocking mode, we might stop the parser in | 693 // If we're in blocking mode, we might stop the parser in |
| 694 // 'didBlockScript()'. In that case, exit early. | 694 // 'didBlockScript()'. In that case, exit early. |
| 695 if (!isParsing()) | 695 if (!isParsing()) |
| 696 return; | 696 return; |
| 697 } | 697 } |
| 698 } | 698 } |
| 699 | 699 |
| 700 constructTreeFromHTMLToken(); | 700 constructTreeFromHTMLToken(); |
| 701 ASSERT(isStopped() || token().isUninitialized()); | 701 DCHECK(isStopped() || token().isUninitialized()); |
| 702 } | 702 } |
| 703 | 703 |
| 704 if (isStopped()) | 704 if (isStopped()) |
| 705 return; | 705 return; |
| 706 | 706 |
| 707 // There should only be PendingText left since the tree-builder always flushes | 707 // There should only be PendingText left since the tree-builder always flushes |
| 708 // the task queue before returning. In case that ever changes, crash. | 708 // the task queue before returning. In case that ever changes, crash. |
| 709 m_treeBuilder->flush(FlushAlways); | 709 m_treeBuilder->flush(FlushAlways); |
| 710 RELEASE_ASSERT(!isStopped()); | 710 CHECK(!isStopped()); |
| 711 | 711 |
| 712 if (isPaused()) { | 712 if (isPaused()) { |
| 713 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); | 713 DCHECK_EQ(m_tokenizer->getState(), HTMLTokenizer::DataState); |
| 714 | 714 |
| 715 ASSERT(m_preloader); | 715 DCHECK(m_preloader); |
| 716 // TODO(kouhei): m_preloader should be always available for synchronous | 716 // TODO(kouhei): m_preloader should be always available for synchronous |
| 717 // parsing case, adding paranoia if for speculative crash fix for | 717 // parsing case, adding paranoia if for speculative crash fix for |
| 718 // crbug.com/465478 | 718 // crbug.com/465478 |
| 719 if (m_preloader) { | 719 if (m_preloader) { |
| 720 if (!m_preloadScanner) { | 720 if (!m_preloadScanner) { |
| 721 m_preloadScanner = createPreloadScanner(); | 721 m_preloadScanner = createPreloadScanner(); |
| 722 m_preloadScanner->appendToEnd(m_input.current()); | 722 m_preloadScanner->appendToEnd(m_input.current()); |
| 723 } | 723 } |
| 724 scanAndPreload(m_preloadScanner.get()); | 724 scanAndPreload(m_preloadScanner.get()); |
| 725 } | 725 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 747 token().clear(); | 747 token().clear(); |
| 748 | 748 |
| 749 m_treeBuilder->constructTree(&atomicToken); | 749 m_treeBuilder->constructTree(&atomicToken); |
| 750 checkIfBodyStylesheetAdded(); | 750 checkIfBodyStylesheetAdded(); |
| 751 | 751 |
| 752 // FIXME: constructTree may synchronously cause Document to be detached. | 752 // FIXME: constructTree may synchronously cause Document to be detached. |
| 753 if (!m_token) | 753 if (!m_token) |
| 754 return; | 754 return; |
| 755 | 755 |
| 756 if (!token().isUninitialized()) { | 756 if (!token().isUninitialized()) { |
| 757 ASSERT(token().type() == HTMLToken::Character); | 757 DCHECK_EQ(token().type(), HTMLToken::Character); |
| 758 token().clear(); | 758 token().clear(); |
| 759 } | 759 } |
| 760 } | 760 } |
| 761 | 761 |
| 762 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( | 762 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( |
| 763 const CompactHTMLToken& compactToken) { | 763 const CompactHTMLToken& compactToken) { |
| 764 AtomicHTMLToken token(compactToken); | 764 AtomicHTMLToken token(compactToken); |
| 765 m_treeBuilder->constructTree(&token); | 765 m_treeBuilder->constructTree(&token); |
| 766 checkIfBodyStylesheetAdded(); | 766 checkIfBodyStylesheetAdded(); |
| 767 } | 767 } |
| 768 | 768 |
| 769 bool HTMLDocumentParser::hasInsertionPoint() { | 769 bool HTMLDocumentParser::hasInsertionPoint() { |
| 770 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our | 770 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our |
| 771 // model of the EOF character differs slightly from the one in the spec | 771 // model of the EOF character differs slightly from the one in the spec |
| 772 // because our treatment is uniform between network-sourced and script-sourced | 772 // because our treatment is uniform between network-sourced and script-sourced |
| 773 // input streams whereas the spec treats them differently. | 773 // input streams whereas the spec treats them differently. |
| 774 return m_input.hasInsertionPoint() || | 774 return m_input.hasInsertionPoint() || |
| 775 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); | 775 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); |
| 776 } | 776 } |
| 777 | 777 |
| 778 void HTMLDocumentParser::insert(const SegmentedString& source) { | 778 void HTMLDocumentParser::insert(const SegmentedString& source) { |
| 779 if (isStopped()) | 779 if (isStopped()) |
| 780 return; | 780 return; |
| 781 | 781 |
| 782 TRACE_EVENT1("blink", "HTMLDocumentParser::insert", "source_length", | 782 TRACE_EVENT1("blink", "HTMLDocumentParser::insert", "source_length", |
| 783 source.length()); | 783 source.length()); |
| 784 | 784 |
| 785 if (!m_tokenizer) { | 785 if (!m_tokenizer) { |
| 786 ASSERT(!inPumpSession()); | 786 DCHECK(!inPumpSession()); |
| 787 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); | 787 DCHECK(m_haveBackgroundParser || wasCreatedByScript()); |
| 788 m_token = WTF::wrapUnique(new HTMLToken); | 788 m_token = WTF::wrapUnique(new HTMLToken); |
| 789 m_tokenizer = HTMLTokenizer::create(m_options); | 789 m_tokenizer = HTMLTokenizer::create(m_options); |
| 790 } | 790 } |
| 791 | 791 |
| 792 SegmentedString excludedLineNumberSource(source); | 792 SegmentedString excludedLineNumberSource(source); |
| 793 excludedLineNumberSource.setExcludeLineNumbers(); | 793 excludedLineNumberSource.setExcludeLineNumbers(); |
| 794 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); | 794 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); |
| 795 pumpTokenizerIfPossible(); | 795 pumpTokenizerIfPossible(); |
| 796 | 796 |
| 797 if (isPaused()) { | 797 if (isPaused()) { |
| 798 // Check the document.write() output with a separate preload scanner as | 798 // Check the document.write() output with a separate preload scanner as |
| 799 // the main scanner can't deal with insertions. | 799 // the main scanner can't deal with insertions. |
| 800 if (!m_insertionPreloadScanner) | 800 if (!m_insertionPreloadScanner) |
| 801 m_insertionPreloadScanner = createPreloadScanner(); | 801 m_insertionPreloadScanner = createPreloadScanner(); |
| 802 m_insertionPreloadScanner->appendToEnd(source); | 802 m_insertionPreloadScanner->appendToEnd(source); |
| 803 scanAndPreload(m_insertionPreloadScanner.get()); | 803 scanAndPreload(m_insertionPreloadScanner.get()); |
| 804 } | 804 } |
| 805 | 805 |
| 806 endIfDelayed(); | 806 endIfDelayed(); |
| 807 } | 807 } |
| 808 | 808 |
| 809 void HTMLDocumentParser::startBackgroundParser() { | 809 void HTMLDocumentParser::startBackgroundParser() { |
| 810 ASSERT(!isStopped()); | 810 DCHECK(!isStopped()); |
| 811 ASSERT(shouldUseThreading()); | 811 DCHECK(shouldUseThreading()); |
| 812 ASSERT(!m_haveBackgroundParser); | 812 DCHECK(!m_haveBackgroundParser); |
| 813 ASSERT(document()); | 813 DCHECK(document()); |
| 814 m_haveBackgroundParser = true; | 814 m_haveBackgroundParser = true; |
| 815 | 815 |
| 816 // TODO(alexclarke): Remove WebFrameScheduler::setDocumentParsingInBackground | 816 // TODO(alexclarke): Remove WebFrameScheduler::setDocumentParsingInBackground |
| 817 // when background parser goes away. | 817 // when background parser goes away. |
| 818 if (document()->frame() && document()->frame()->frameScheduler()) | 818 if (document()->frame() && document()->frame()->frameScheduler()) |
| 819 document()->frame()->frameScheduler()->setDocumentParsingInBackground(true); | 819 document()->frame()->frameScheduler()->setDocumentParsingInBackground(true); |
| 820 | 820 |
| 821 // Make sure that a resolver is set up, so that the correct viewport | 821 // Make sure that a resolver is set up, so that the correct viewport |
| 822 // dimensions will be fed to the background parser and preload scanner. | 822 // dimensions will be fed to the background parser and preload scanner. |
| 823 if (document()->loader()) | 823 if (document()->loader()) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 840 document() | 840 document() |
| 841 ->settings() | 841 ->settings() |
| 842 ->getBackgroundHtmlParserOutstandingTokenLimit(); | 842 ->getBackgroundHtmlParserOutstandingTokenLimit(); |
| 843 } | 843 } |
| 844 if (document()->settings()->getBackgroundHtmlParserPendingTokenLimit()) { | 844 if (document()->settings()->getBackgroundHtmlParserPendingTokenLimit()) { |
| 845 config->pendingTokenLimit = | 845 config->pendingTokenLimit = |
| 846 document()->settings()->getBackgroundHtmlParserPendingTokenLimit(); | 846 document()->settings()->getBackgroundHtmlParserPendingTokenLimit(); |
| 847 } | 847 } |
| 848 } | 848 } |
| 849 | 849 |
| 850 ASSERT(config->xssAuditor->isSafeToSendToAnotherThread()); | 850 DCHECK(config->xssAuditor->isSafeToSendToAnotherThread()); |
| 851 | 851 |
| 852 // The background parser is created on the main thread, but may otherwise | 852 // The background parser is created on the main thread, but may otherwise |
| 853 // only be used from the parser thread. | 853 // only be used from the parser thread. |
| 854 m_backgroundParser = | 854 m_backgroundParser = |
| 855 BackgroundHTMLParser::create(std::move(config), m_loadingTaskRunner); | 855 BackgroundHTMLParser::create(std::move(config), m_loadingTaskRunner); |
| 856 // TODO(csharrison): This is a hack to initialize MediaValuesCached on the | 856 // TODO(csharrison): This is a hack to initialize MediaValuesCached on the |
| 857 // correct thread. We should get rid of it. | 857 // correct thread. We should get rid of it. |
| 858 m_backgroundParser->init( | 858 m_backgroundParser->init( |
| 859 document()->url(), CachedDocumentParameters::create(document()), | 859 document()->url(), CachedDocumentParameters::create(document()), |
| 860 MediaValuesCached::MediaValuesCachedData(*document())); | 860 MediaValuesCached::MediaValuesCachedData(*document())); |
| 861 } | 861 } |
| 862 | 862 |
| 863 void HTMLDocumentParser::stopBackgroundParser() { | 863 void HTMLDocumentParser::stopBackgroundParser() { |
| 864 ASSERT(shouldUseThreading()); | 864 DCHECK(shouldUseThreading()); |
| 865 ASSERT(m_haveBackgroundParser); | 865 DCHECK(m_haveBackgroundParser); |
| 866 | 866 |
| 867 if (m_haveBackgroundParser && document()->frame() && | 867 if (m_haveBackgroundParser && document()->frame() && |
| 868 document()->frame()->frameScheduler()) | 868 document()->frame()->frameScheduler()) |
| 869 document()->frame()->frameScheduler()->setDocumentParsingInBackground( | 869 document()->frame()->frameScheduler()->setDocumentParsingInBackground( |
| 870 false); | 870 false); |
| 871 | 871 |
| 872 m_haveBackgroundParser = false; | 872 m_haveBackgroundParser = false; |
| 873 | 873 |
| 874 // Make this sync, as lsan triggers on some unittests if the task runner is | 874 // Make this sync, as lsan triggers on some unittests if the task runner is |
| 875 // used. | 875 // used. |
| 876 m_backgroundParser->stop(); | 876 m_backgroundParser->stop(); |
| 877 m_weakFactory.revokeAll(); | 877 m_weakFactory.revokeAll(); |
| 878 } | 878 } |
| 879 | 879 |
| 880 void HTMLDocumentParser::append(const String& inputSource) { | 880 void HTMLDocumentParser::append(const String& inputSource) { |
| 881 if (isStopped()) | 881 if (isStopped()) |
| 882 return; | 882 return; |
| 883 | 883 |
| 884 // We should never reach this point if we're using a parser thread, as | 884 // We should never reach this point if we're using a parser thread, as |
| 885 // appendBytes() will directly ship the data to the thread. | 885 // appendBytes() will directly ship the data to the thread. |
| 886 ASSERT(!shouldUseThreading()); | 886 DCHECK(!shouldUseThreading()); |
| 887 | 887 |
| 888 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), | 888 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), |
| 889 "HTMLDocumentParser::append", "size", inputSource.length()); | 889 "HTMLDocumentParser::append", "size", inputSource.length()); |
| 890 const SegmentedString source(inputSource); | 890 const SegmentedString source(inputSource); |
| 891 | 891 |
| 892 if (document()->isPrefetchOnly()) { | 892 if (document()->isPrefetchOnly()) { |
| 893 if (!m_preloadScanner) | 893 if (!m_preloadScanner) |
| 894 m_preloadScanner = createPreloadScanner(); | 894 m_preloadScanner = createPreloadScanner(); |
| 895 | 895 |
| 896 m_preloadScanner->appendToEnd(source); | 896 m_preloadScanner->appendToEnd(source); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 921 // this data in a less-nested write(). | 921 // this data in a less-nested write(). |
| 922 return; | 922 return; |
| 923 } | 923 } |
| 924 | 924 |
| 925 pumpTokenizerIfPossible(); | 925 pumpTokenizerIfPossible(); |
| 926 | 926 |
| 927 endIfDelayed(); | 927 endIfDelayed(); |
| 928 } | 928 } |
| 929 | 929 |
| 930 void HTMLDocumentParser::end() { | 930 void HTMLDocumentParser::end() { |
| 931 ASSERT(!isDetached()); | 931 DCHECK(!isDetached()); |
| 932 ASSERT(!isScheduledForResume()); | 932 DCHECK(!isScheduledForResume()); |
| 933 | 933 |
| 934 if (m_haveBackgroundParser) | 934 if (m_haveBackgroundParser) |
| 935 stopBackgroundParser(); | 935 stopBackgroundParser(); |
| 936 | 936 |
| 937 // Informs the the rest of WebCore that parsing is really finished (and | 937 // Informs the the rest of WebCore that parsing is really finished (and |
| 938 // deletes this). | 938 // deletes this). |
| 939 m_treeBuilder->finished(); | 939 m_treeBuilder->finished(); |
| 940 | 940 |
| 941 DocumentParser::stopParsing(); | 941 DocumentParser::stopParsing(); |
| 942 } | 942 } |
| 943 | 943 |
| 944 void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd() { | 944 void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd() { |
| 945 ASSERT(isStopping()); | 945 DCHECK(isStopping()); |
| 946 // FIXME: It may not be correct to disable this for the background parser. | 946 // FIXME: It may not be correct to disable this for the background parser. |
| 947 // That means hasInsertionPoint() may not be correct in some cases. | 947 // That means hasInsertionPoint() may not be correct in some cases. |
| 948 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); | 948 DCHECK(!hasInsertionPoint() || m_haveBackgroundParser); |
| 949 if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing()) | 949 if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing()) |
| 950 return; | 950 return; |
| 951 end(); | 951 end(); |
| 952 } | 952 } |
| 953 | 953 |
| 954 void HTMLDocumentParser::attemptToEnd() { | 954 void HTMLDocumentParser::attemptToEnd() { |
| 955 // finish() indicates we will not receive any more data. If we are waiting on | 955 // finish() indicates we will not receive any more data. If we are waiting on |
| 956 // an external script to load, we can't finish parsing quite yet. | 956 // an external script to load, we can't finish parsing quite yet. |
| 957 | 957 |
| 958 if (shouldDelayEnd()) { | 958 if (shouldDelayEnd()) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 989 if (m_haveBackgroundParser) { | 989 if (m_haveBackgroundParser) { |
| 990 if (!m_input.haveSeenEndOfFile()) | 990 if (!m_input.haveSeenEndOfFile()) |
| 991 m_input.closeWithoutMarkingEndOfFile(); | 991 m_input.closeWithoutMarkingEndOfFile(); |
| 992 m_loadingTaskRunner->postTask( | 992 m_loadingTaskRunner->postTask( |
| 993 BLINK_FROM_HERE, | 993 BLINK_FROM_HERE, |
| 994 WTF::bind(&BackgroundHTMLParser::finish, m_backgroundParser)); | 994 WTF::bind(&BackgroundHTMLParser::finish, m_backgroundParser)); |
| 995 return; | 995 return; |
| 996 } | 996 } |
| 997 | 997 |
| 998 if (!m_tokenizer) { | 998 if (!m_tokenizer) { |
| 999 ASSERT(!m_token); | 999 DCHECK(!m_token); |
| 1000 // We're finishing before receiving any data. Rather than booting up the | 1000 // We're finishing before receiving any data. Rather than booting up the |
| 1001 // background parser just to spin it down, we finish parsing synchronously. | 1001 // background parser just to spin it down, we finish parsing synchronously. |
| 1002 m_token = WTF::wrapUnique(new HTMLToken); | 1002 m_token = WTF::wrapUnique(new HTMLToken); |
| 1003 m_tokenizer = HTMLTokenizer::create(m_options); | 1003 m_tokenizer = HTMLTokenizer::create(m_options); |
| 1004 } | 1004 } |
| 1005 | 1005 |
| 1006 // We're not going to get any more data off the network, so we tell the input | 1006 // We're not going to get any more data off the network, so we tell the input |
| 1007 // stream we've reached the end of file. finish() can be called more than | 1007 // stream we've reached the end of file. finish() can be called more than |
| 1008 // once, if the first time does not call end(). | 1008 // once, if the first time does not call end(). |
| 1009 if (!m_input.haveSeenEndOfFile()) | 1009 if (!m_input.haveSeenEndOfFile()) |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1047 // the script runner. The script runner will hold the script until its loaded | 1047 // the script runner. The script runner will hold the script until its loaded |
| 1048 // and run. During any of this time, we want to count ourselves as "waiting | 1048 // and run. During any of this time, we want to count ourselves as "waiting |
| 1049 // for a script" and thus run the preload scanner, as well as delay completion | 1049 // for a script" and thus run the preload scanner, as well as delay completion |
| 1050 // of parsing. | 1050 // of parsing. |
| 1051 bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript(); | 1051 bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript(); |
| 1052 bool scriptRunnerHasBlockingScript = | 1052 bool scriptRunnerHasBlockingScript = |
| 1053 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); | 1053 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); |
| 1054 // Since the parser is paused while a script runner has a blocking script, it | 1054 // Since the parser is paused while a script runner has a blocking script, it |
| 1055 // should never be possible to end up with both objects holding a blocking | 1055 // should never be possible to end up with both objects holding a blocking |
| 1056 // script. | 1056 // script. |
| 1057 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); | 1057 DCHECK(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); |
| 1058 // If either object has a blocking script, the parser should be paused. | 1058 // If either object has a blocking script, the parser should be paused. |
| 1059 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || | 1059 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || |
| 1060 m_reentryPermit->parserPauseFlag(); | 1060 m_reentryPermit->parserPauseFlag(); |
| 1061 } | 1061 } |
| 1062 | 1062 |
| 1063 void HTMLDocumentParser::resumeParsingAfterPause() { | 1063 void HTMLDocumentParser::resumeParsingAfterPause() { |
| 1064 ASSERT(!isExecutingScript()); | 1064 DCHECK(!isExecutingScript()); |
| 1065 DCHECK(!isPaused()); | 1065 DCHECK(!isPaused()); |
| 1066 | 1066 |
| 1067 checkIfBodyStylesheetAdded(); | 1067 checkIfBodyStylesheetAdded(); |
| 1068 if (isPaused()) | 1068 if (isPaused()) |
| 1069 return; | 1069 return; |
| 1070 | 1070 |
| 1071 if (m_haveBackgroundParser) { | 1071 if (m_haveBackgroundParser) { |
| 1072 if (m_lastChunkBeforePause) { | 1072 if (m_lastChunkBeforePause) { |
| 1073 validateSpeculations(std::move(m_lastChunkBeforePause)); | 1073 validateSpeculations(std::move(m_lastChunkBeforePause)); |
| 1074 DCHECK(!m_lastChunkBeforePause); | 1074 DCHECK(!m_lastChunkBeforePause); |
| 1075 pumpPendingSpeculations(); | 1075 pumpPendingSpeculations(); |
| 1076 } | 1076 } |
| 1077 return; | 1077 return; |
| 1078 } | 1078 } |
| 1079 | 1079 |
| 1080 m_insertionPreloadScanner.reset(); | 1080 m_insertionPreloadScanner.reset(); |
| 1081 if (m_tokenizer) { | 1081 if (m_tokenizer) { |
| 1082 pumpTokenizerIfPossible(); | 1082 pumpTokenizerIfPossible(); |
| 1083 } | 1083 } |
| 1084 endIfDelayed(); | 1084 endIfDelayed(); |
| 1085 } | 1085 } |
| 1086 | 1086 |
| 1087 void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan() { | 1087 void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan() { |
| 1088 ASSERT(m_preloadScanner); | 1088 DCHECK(m_preloadScanner); |
| 1089 m_preloadScanner->appendToEnd(m_input.current()); | 1089 m_preloadScanner->appendToEnd(m_input.current()); |
| 1090 scanAndPreload(m_preloadScanner.get()); | 1090 scanAndPreload(m_preloadScanner.get()); |
| 1091 } | 1091 } |
| 1092 | 1092 |
| 1093 void HTMLDocumentParser::notifyScriptLoaded(PendingScript* pendingScript) { | 1093 void HTMLDocumentParser::notifyScriptLoaded(PendingScript* pendingScript) { |
| 1094 ASSERT(m_scriptRunner); | 1094 DCHECK(m_scriptRunner); |
| 1095 ASSERT(!isExecutingScript()); | 1095 DCHECK(!isExecutingScript()); |
| 1096 | 1096 |
| 1097 if (isStopped()) { | 1097 if (isStopped()) { |
| 1098 return; | 1098 return; |
| 1099 } | 1099 } |
| 1100 | 1100 |
| 1101 if (isStopping()) { | 1101 if (isStopping()) { |
| 1102 attemptToRunDeferredScriptsAndEnd(); | 1102 attemptToRunDeferredScriptsAndEnd(); |
| 1103 return; | 1103 return; |
| 1104 } | 1104 } |
| 1105 | 1105 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1155 ParserContentPolicy parserContentPolicy) { | 1155 ParserContentPolicy parserContentPolicy) { |
| 1156 HTMLDocumentParser* parser = | 1156 HTMLDocumentParser* parser = |
| 1157 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); | 1157 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); |
| 1158 parser->append(source); | 1158 parser->append(source); |
| 1159 parser->finish(); | 1159 parser->finish(); |
| 1160 // Allows ~DocumentParser to assert it was detached before destruction. | 1160 // Allows ~DocumentParser to assert it was detached before destruction. |
| 1161 parser->detach(); | 1161 parser->detach(); |
| 1162 } | 1162 } |
| 1163 | 1163 |
| 1164 void HTMLDocumentParser::suspendScheduledTasks() { | 1164 void HTMLDocumentParser::suspendScheduledTasks() { |
| 1165 ASSERT(!m_tasksWereSuspended); | 1165 DCHECK(!m_tasksWereSuspended); |
| 1166 m_tasksWereSuspended = true; | 1166 m_tasksWereSuspended = true; |
| 1167 if (m_parserScheduler) | 1167 if (m_parserScheduler) |
| 1168 m_parserScheduler->suspend(); | 1168 m_parserScheduler->suspend(); |
| 1169 } | 1169 } |
| 1170 | 1170 |
| 1171 void HTMLDocumentParser::resumeScheduledTasks() { | 1171 void HTMLDocumentParser::resumeScheduledTasks() { |
| 1172 ASSERT(m_tasksWereSuspended); | 1172 DCHECK(m_tasksWereSuspended); |
| 1173 m_tasksWereSuspended = false; | 1173 m_tasksWereSuspended = false; |
| 1174 if (m_parserScheduler) | 1174 if (m_parserScheduler) |
| 1175 m_parserScheduler->resume(); | 1175 m_parserScheduler->resume(); |
| 1176 } | 1176 } |
| 1177 | 1177 |
| 1178 void HTMLDocumentParser::appendBytes(const char* data, size_t length) { | 1178 void HTMLDocumentParser::appendBytes(const char* data, size_t length) { |
| 1179 if (!length || isStopped()) | 1179 if (!length || isStopped()) |
| 1180 return; | 1180 return; |
| 1181 | 1181 |
| 1182 if (shouldUseThreading()) { | 1182 if (shouldUseThreading()) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1220 m_loadingTaskRunner->postTask( | 1220 m_loadingTaskRunner->postTask( |
| 1221 BLINK_FROM_HERE, | 1221 BLINK_FROM_HERE, |
| 1222 WTF::bind(&BackgroundHTMLParser::flush, m_backgroundParser)); | 1222 WTF::bind(&BackgroundHTMLParser::flush, m_backgroundParser)); |
| 1223 } else { | 1223 } else { |
| 1224 DecodedDataDocumentParser::flush(); | 1224 DecodedDataDocumentParser::flush(); |
| 1225 } | 1225 } |
| 1226 } | 1226 } |
| 1227 | 1227 |
| 1228 void HTMLDocumentParser::setDecoder( | 1228 void HTMLDocumentParser::setDecoder( |
| 1229 std::unique_ptr<TextResourceDecoder> decoder) { | 1229 std::unique_ptr<TextResourceDecoder> decoder) { |
| 1230 ASSERT(decoder); | 1230 DCHECK(decoder); |
| 1231 DecodedDataDocumentParser::setDecoder(std::move(decoder)); | 1231 DecodedDataDocumentParser::setDecoder(std::move(decoder)); |
| 1232 | 1232 |
| 1233 if (m_haveBackgroundParser) { | 1233 if (m_haveBackgroundParser) { |
| 1234 m_loadingTaskRunner->postTask( | 1234 m_loadingTaskRunner->postTask( |
| 1235 BLINK_FROM_HERE, | 1235 BLINK_FROM_HERE, |
| 1236 WTF::bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, | 1236 WTF::bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, |
| 1237 WTF::passed(takeDecoder()))); | 1237 WTF::passed(takeDecoder()))); |
| 1238 } | 1238 } |
| 1239 } | 1239 } |
| 1240 | 1240 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1320 successHistogram.count(duration); | 1320 successHistogram.count(duration); |
| 1321 } else { | 1321 } else { |
| 1322 DEFINE_STATIC_LOCAL( | 1322 DEFINE_STATIC_LOCAL( |
| 1323 CustomCountHistogram, failureHistogram, | 1323 CustomCountHistogram, failureHistogram, |
| 1324 ("PreloadScanner.DocumentWrite.ExecutionTime.Failure", 1, 10000, 50)); | 1324 ("PreloadScanner.DocumentWrite.ExecutionTime.Failure", 1, 10000, 50)); |
| 1325 failureHistogram.count(duration); | 1325 failureHistogram.count(duration); |
| 1326 } | 1326 } |
| 1327 } | 1327 } |
| 1328 | 1328 |
| 1329 } // namespace blink | 1329 } // namespace blink |
| OLD | NEW |