| 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 probe::ParseHTML probe(document(), this); | 669 probe::ParseHTML probe(document(), this); |
| 670 | 670 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 688 token(), m_sourceTracker, m_tokenizer->shouldAllowCDATA()))) { | 688 token(), m_sourceTracker, m_tokenizer->shouldAllowCDATA()))) { |
| 689 m_xssAuditorDelegate.didBlockScript(*xssInfo); | 689 m_xssAuditorDelegate.didBlockScript(*xssInfo); |
| 690 // If we're in blocking mode, we might stop the parser in | 690 // If we're in blocking mode, we might stop the parser in |
| 691 // 'didBlockScript()'. In that case, exit early. | 691 // 'didBlockScript()'. In that case, exit early. |
| 692 if (!isParsing()) | 692 if (!isParsing()) |
| 693 return; | 693 return; |
| 694 } | 694 } |
| 695 } | 695 } |
| 696 | 696 |
| 697 constructTreeFromHTMLToken(); | 697 constructTreeFromHTMLToken(); |
| 698 ASSERT(isStopped() || token().isUninitialized()); | 698 DCHECK(isStopped() || token().isUninitialized()); |
| 699 } | 699 } |
| 700 | 700 |
| 701 if (isStopped()) | 701 if (isStopped()) |
| 702 return; | 702 return; |
| 703 | 703 |
| 704 // There should only be PendingText left since the tree-builder always flushes | 704 // There should only be PendingText left since the tree-builder always flushes |
| 705 // the task queue before returning. In case that ever changes, crash. | 705 // the task queue before returning. In case that ever changes, crash. |
| 706 m_treeBuilder->flush(FlushAlways); | 706 m_treeBuilder->flush(FlushAlways); |
| 707 RELEASE_ASSERT(!isStopped()); | 707 CHECK(!isStopped()); |
| 708 | 708 |
| 709 if (isPaused()) { | 709 if (isPaused()) { |
| 710 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); | 710 DCHECK_EQ(m_tokenizer->getState(), HTMLTokenizer::DataState); |
| 711 | 711 |
| 712 ASSERT(m_preloader); | 712 DCHECK(m_preloader); |
| 713 // TODO(kouhei): m_preloader should be always available for synchronous | 713 // TODO(kouhei): m_preloader should be always available for synchronous |
| 714 // parsing case, adding paranoia if for speculative crash fix for | 714 // parsing case, adding paranoia if for speculative crash fix for |
| 715 // crbug.com/465478 | 715 // crbug.com/465478 |
| 716 if (m_preloader) { | 716 if (m_preloader) { |
| 717 if (!m_preloadScanner) { | 717 if (!m_preloadScanner) { |
| 718 m_preloadScanner = createPreloadScanner(); | 718 m_preloadScanner = createPreloadScanner(); |
| 719 m_preloadScanner->appendToEnd(m_input.current()); | 719 m_preloadScanner->appendToEnd(m_input.current()); |
| 720 } | 720 } |
| 721 scanAndPreload(m_preloadScanner.get()); | 721 scanAndPreload(m_preloadScanner.get()); |
| 722 } | 722 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 740 token().clear(); | 740 token().clear(); |
| 741 | 741 |
| 742 m_treeBuilder->constructTree(&atomicToken); | 742 m_treeBuilder->constructTree(&atomicToken); |
| 743 checkIfBodyStylesheetAdded(); | 743 checkIfBodyStylesheetAdded(); |
| 744 | 744 |
| 745 // FIXME: constructTree may synchronously cause Document to be detached. | 745 // FIXME: constructTree may synchronously cause Document to be detached. |
| 746 if (!m_token) | 746 if (!m_token) |
| 747 return; | 747 return; |
| 748 | 748 |
| 749 if (!token().isUninitialized()) { | 749 if (!token().isUninitialized()) { |
| 750 ASSERT(token().type() == HTMLToken::Character); | 750 DCHECK_EQ(token().type(), HTMLToken::Character); |
| 751 token().clear(); | 751 token().clear(); |
| 752 } | 752 } |
| 753 } | 753 } |
| 754 | 754 |
| 755 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( | 755 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( |
| 756 const CompactHTMLToken& compactToken) { | 756 const CompactHTMLToken& compactToken) { |
| 757 AtomicHTMLToken token(compactToken); | 757 AtomicHTMLToken token(compactToken); |
| 758 m_treeBuilder->constructTree(&token); | 758 m_treeBuilder->constructTree(&token); |
| 759 checkIfBodyStylesheetAdded(); | 759 checkIfBodyStylesheetAdded(); |
| 760 } | 760 } |
| 761 | 761 |
| 762 bool HTMLDocumentParser::hasInsertionPoint() { | 762 bool HTMLDocumentParser::hasInsertionPoint() { |
| 763 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our | 763 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our |
| 764 // model of the EOF character differs slightly from the one in the spec | 764 // model of the EOF character differs slightly from the one in the spec |
| 765 // because our treatment is uniform between network-sourced and script-sourced | 765 // because our treatment is uniform between network-sourced and script-sourced |
| 766 // input streams whereas the spec treats them differently. | 766 // input streams whereas the spec treats them differently. |
| 767 return m_input.hasInsertionPoint() || | 767 return m_input.hasInsertionPoint() || |
| 768 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); | 768 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); |
| 769 } | 769 } |
| 770 | 770 |
| 771 void HTMLDocumentParser::insert(const SegmentedString& source) { | 771 void HTMLDocumentParser::insert(const SegmentedString& source) { |
| 772 if (isStopped()) | 772 if (isStopped()) |
| 773 return; | 773 return; |
| 774 | 774 |
| 775 TRACE_EVENT1("blink", "HTMLDocumentParser::insert", "source_length", | 775 TRACE_EVENT1("blink", "HTMLDocumentParser::insert", "source_length", |
| 776 source.length()); | 776 source.length()); |
| 777 | 777 |
| 778 if (!m_tokenizer) { | 778 if (!m_tokenizer) { |
| 779 ASSERT(!inPumpSession()); | 779 DCHECK(!inPumpSession()); |
| 780 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); | 780 DCHECK(m_haveBackgroundParser || wasCreatedByScript()); |
| 781 m_token = WTF::wrapUnique(new HTMLToken); | 781 m_token = WTF::wrapUnique(new HTMLToken); |
| 782 m_tokenizer = HTMLTokenizer::create(m_options); | 782 m_tokenizer = HTMLTokenizer::create(m_options); |
| 783 } | 783 } |
| 784 | 784 |
| 785 SegmentedString excludedLineNumberSource(source); | 785 SegmentedString excludedLineNumberSource(source); |
| 786 excludedLineNumberSource.setExcludeLineNumbers(); | 786 excludedLineNumberSource.setExcludeLineNumbers(); |
| 787 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); | 787 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); |
| 788 pumpTokenizerIfPossible(); | 788 pumpTokenizerIfPossible(); |
| 789 | 789 |
| 790 if (isPaused()) { | 790 if (isPaused()) { |
| 791 // Check the document.write() output with a separate preload scanner as | 791 // Check the document.write() output with a separate preload scanner as |
| 792 // the main scanner can't deal with insertions. | 792 // the main scanner can't deal with insertions. |
| 793 if (!m_insertionPreloadScanner) | 793 if (!m_insertionPreloadScanner) |
| 794 m_insertionPreloadScanner = createPreloadScanner(); | 794 m_insertionPreloadScanner = createPreloadScanner(); |
| 795 m_insertionPreloadScanner->appendToEnd(source); | 795 m_insertionPreloadScanner->appendToEnd(source); |
| 796 scanAndPreload(m_insertionPreloadScanner.get()); | 796 scanAndPreload(m_insertionPreloadScanner.get()); |
| 797 } | 797 } |
| 798 | 798 |
| 799 endIfDelayed(); | 799 endIfDelayed(); |
| 800 } | 800 } |
| 801 | 801 |
| 802 void HTMLDocumentParser::startBackgroundParser() { | 802 void HTMLDocumentParser::startBackgroundParser() { |
| 803 ASSERT(!isStopped()); | 803 DCHECK(!isStopped()); |
| 804 ASSERT(shouldUseThreading()); | 804 DCHECK(shouldUseThreading()); |
| 805 ASSERT(!m_haveBackgroundParser); | 805 DCHECK(!m_haveBackgroundParser); |
| 806 ASSERT(document()); | 806 DCHECK(document()); |
| 807 m_haveBackgroundParser = true; | 807 m_haveBackgroundParser = true; |
| 808 | 808 |
| 809 // TODO(alexclarke): Remove WebFrameScheduler::setDocumentParsingInBackground | 809 // TODO(alexclarke): Remove WebFrameScheduler::setDocumentParsingInBackground |
| 810 // when background parser goes away. | 810 // when background parser goes away. |
| 811 if (document()->frame() && document()->frame()->frameScheduler()) | 811 if (document()->frame() && document()->frame()->frameScheduler()) |
| 812 document()->frame()->frameScheduler()->setDocumentParsingInBackground(true); | 812 document()->frame()->frameScheduler()->setDocumentParsingInBackground(true); |
| 813 | 813 |
| 814 // Make sure that a resolver is set up, so that the correct viewport | 814 // Make sure that a resolver is set up, so that the correct viewport |
| 815 // dimensions will be fed to the background parser and preload scanner. | 815 // dimensions will be fed to the background parser and preload scanner. |
| 816 if (document()->loader()) | 816 if (document()->loader()) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 833 document() | 833 document() |
| 834 ->settings() | 834 ->settings() |
| 835 ->getBackgroundHtmlParserOutstandingTokenLimit(); | 835 ->getBackgroundHtmlParserOutstandingTokenLimit(); |
| 836 } | 836 } |
| 837 if (document()->settings()->getBackgroundHtmlParserPendingTokenLimit()) { | 837 if (document()->settings()->getBackgroundHtmlParserPendingTokenLimit()) { |
| 838 config->pendingTokenLimit = | 838 config->pendingTokenLimit = |
| 839 document()->settings()->getBackgroundHtmlParserPendingTokenLimit(); | 839 document()->settings()->getBackgroundHtmlParserPendingTokenLimit(); |
| 840 } | 840 } |
| 841 } | 841 } |
| 842 | 842 |
| 843 ASSERT(config->xssAuditor->isSafeToSendToAnotherThread()); | 843 DCHECK(config->xssAuditor->isSafeToSendToAnotherThread()); |
| 844 | 844 |
| 845 // The background parser is created on the main thread, but may otherwise | 845 // The background parser is created on the main thread, but may otherwise |
| 846 // only be used from the parser thread. | 846 // only be used from the parser thread. |
| 847 m_backgroundParser = | 847 m_backgroundParser = |
| 848 BackgroundHTMLParser::create(std::move(config), m_loadingTaskRunner); | 848 BackgroundHTMLParser::create(std::move(config), m_loadingTaskRunner); |
| 849 // TODO(csharrison): This is a hack to initialize MediaValuesCached on the | 849 // TODO(csharrison): This is a hack to initialize MediaValuesCached on the |
| 850 // correct thread. We should get rid of it. | 850 // correct thread. We should get rid of it. |
| 851 m_backgroundParser->init( | 851 m_backgroundParser->init( |
| 852 document()->url(), CachedDocumentParameters::create(document()), | 852 document()->url(), CachedDocumentParameters::create(document()), |
| 853 MediaValuesCached::MediaValuesCachedData(*document())); | 853 MediaValuesCached::MediaValuesCachedData(*document())); |
| 854 } | 854 } |
| 855 | 855 |
| 856 void HTMLDocumentParser::stopBackgroundParser() { | 856 void HTMLDocumentParser::stopBackgroundParser() { |
| 857 ASSERT(shouldUseThreading()); | 857 DCHECK(shouldUseThreading()); |
| 858 ASSERT(m_haveBackgroundParser); | 858 DCHECK(m_haveBackgroundParser); |
| 859 | 859 |
| 860 if (m_haveBackgroundParser && document()->frame() && | 860 if (m_haveBackgroundParser && document()->frame() && |
| 861 document()->frame()->frameScheduler()) | 861 document()->frame()->frameScheduler()) |
| 862 document()->frame()->frameScheduler()->setDocumentParsingInBackground( | 862 document()->frame()->frameScheduler()->setDocumentParsingInBackground( |
| 863 false); | 863 false); |
| 864 | 864 |
| 865 m_haveBackgroundParser = false; | 865 m_haveBackgroundParser = false; |
| 866 | 866 |
| 867 // Make this sync, as lsan triggers on some unittests if the task runner is | 867 // Make this sync, as lsan triggers on some unittests if the task runner is |
| 868 // used. | 868 // used. |
| 869 m_backgroundParser->stop(); | 869 m_backgroundParser->stop(); |
| 870 m_weakFactory.revokeAll(); | 870 m_weakFactory.revokeAll(); |
| 871 } | 871 } |
| 872 | 872 |
| 873 void HTMLDocumentParser::append(const String& inputSource) { | 873 void HTMLDocumentParser::append(const String& inputSource) { |
| 874 if (isStopped()) | 874 if (isStopped()) |
| 875 return; | 875 return; |
| 876 | 876 |
| 877 // We should never reach this point if we're using a parser thread, as | 877 // We should never reach this point if we're using a parser thread, as |
| 878 // appendBytes() will directly ship the data to the thread. | 878 // appendBytes() will directly ship the data to the thread. |
| 879 ASSERT(!shouldUseThreading()); | 879 DCHECK(!shouldUseThreading()); |
| 880 | 880 |
| 881 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), | 881 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), |
| 882 "HTMLDocumentParser::append", "size", inputSource.length()); | 882 "HTMLDocumentParser::append", "size", inputSource.length()); |
| 883 const SegmentedString source(inputSource); | 883 const SegmentedString source(inputSource); |
| 884 | 884 |
| 885 if (document()->isPrefetchOnly()) { | 885 if (document()->isPrefetchOnly()) { |
| 886 if (!m_preloadScanner) | 886 if (!m_preloadScanner) |
| 887 m_preloadScanner = createPreloadScanner(); | 887 m_preloadScanner = createPreloadScanner(); |
| 888 | 888 |
| 889 m_preloadScanner->appendToEnd(source); | 889 m_preloadScanner->appendToEnd(source); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 914 // this data in a less-nested write(). | 914 // this data in a less-nested write(). |
| 915 return; | 915 return; |
| 916 } | 916 } |
| 917 | 917 |
| 918 pumpTokenizerIfPossible(); | 918 pumpTokenizerIfPossible(); |
| 919 | 919 |
| 920 endIfDelayed(); | 920 endIfDelayed(); |
| 921 } | 921 } |
| 922 | 922 |
| 923 void HTMLDocumentParser::end() { | 923 void HTMLDocumentParser::end() { |
| 924 ASSERT(!isDetached()); | 924 DCHECK(!isDetached()); |
| 925 ASSERT(!isScheduledForResume()); | 925 DCHECK(!isScheduledForResume()); |
| 926 | 926 |
| 927 if (m_haveBackgroundParser) | 927 if (m_haveBackgroundParser) |
| 928 stopBackgroundParser(); | 928 stopBackgroundParser(); |
| 929 | 929 |
| 930 // Informs the the rest of WebCore that parsing is really finished (and | 930 // Informs the the rest of WebCore that parsing is really finished (and |
| 931 // deletes this). | 931 // deletes this). |
| 932 m_treeBuilder->finished(); | 932 m_treeBuilder->finished(); |
| 933 | 933 |
| 934 DocumentParser::stopParsing(); | 934 DocumentParser::stopParsing(); |
| 935 } | 935 } |
| 936 | 936 |
| 937 void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd() { | 937 void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd() { |
| 938 ASSERT(isStopping()); | 938 DCHECK(isStopping()); |
| 939 // FIXME: It may not be correct to disable this for the background parser. | 939 // FIXME: It may not be correct to disable this for the background parser. |
| 940 // That means hasInsertionPoint() may not be correct in some cases. | 940 // That means hasInsertionPoint() may not be correct in some cases. |
| 941 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); | 941 DCHECK(!hasInsertionPoint() || m_haveBackgroundParser); |
| 942 if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing()) | 942 if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing()) |
| 943 return; | 943 return; |
| 944 end(); | 944 end(); |
| 945 } | 945 } |
| 946 | 946 |
| 947 void HTMLDocumentParser::attemptToEnd() { | 947 void HTMLDocumentParser::attemptToEnd() { |
| 948 // finish() indicates we will not receive any more data. If we are waiting on | 948 // finish() indicates we will not receive any more data. If we are waiting on |
| 949 // an external script to load, we can't finish parsing quite yet. | 949 // an external script to load, we can't finish parsing quite yet. |
| 950 | 950 |
| 951 if (shouldDelayEnd()) { | 951 if (shouldDelayEnd()) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 982 if (m_haveBackgroundParser) { | 982 if (m_haveBackgroundParser) { |
| 983 if (!m_input.haveSeenEndOfFile()) | 983 if (!m_input.haveSeenEndOfFile()) |
| 984 m_input.closeWithoutMarkingEndOfFile(); | 984 m_input.closeWithoutMarkingEndOfFile(); |
| 985 m_loadingTaskRunner->postTask( | 985 m_loadingTaskRunner->postTask( |
| 986 BLINK_FROM_HERE, | 986 BLINK_FROM_HERE, |
| 987 WTF::bind(&BackgroundHTMLParser::finish, m_backgroundParser)); | 987 WTF::bind(&BackgroundHTMLParser::finish, m_backgroundParser)); |
| 988 return; | 988 return; |
| 989 } | 989 } |
| 990 | 990 |
| 991 if (!m_tokenizer) { | 991 if (!m_tokenizer) { |
| 992 ASSERT(!m_token); | 992 DCHECK(!m_token); |
| 993 // We're finishing before receiving any data. Rather than booting up the | 993 // We're finishing before receiving any data. Rather than booting up the |
| 994 // background parser just to spin it down, we finish parsing synchronously. | 994 // background parser just to spin it down, we finish parsing synchronously. |
| 995 m_token = WTF::wrapUnique(new HTMLToken); | 995 m_token = WTF::wrapUnique(new HTMLToken); |
| 996 m_tokenizer = HTMLTokenizer::create(m_options); | 996 m_tokenizer = HTMLTokenizer::create(m_options); |
| 997 } | 997 } |
| 998 | 998 |
| 999 // We're not going to get any more data off the network, so we tell the input | 999 // We're not going to get any more data off the network, so we tell the input |
| 1000 // stream we've reached the end of file. finish() can be called more than | 1000 // stream we've reached the end of file. finish() can be called more than |
| 1001 // once, if the first time does not call end(). | 1001 // once, if the first time does not call end(). |
| 1002 if (!m_input.haveSeenEndOfFile()) | 1002 if (!m_input.haveSeenEndOfFile()) |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1040 // the script runner. The script runner will hold the script until its loaded | 1040 // the script runner. The script runner will hold the script until its loaded |
| 1041 // and run. During any of this time, we want to count ourselves as "waiting | 1041 // and run. During any of this time, we want to count ourselves as "waiting |
| 1042 // for a script" and thus run the preload scanner, as well as delay completion | 1042 // for a script" and thus run the preload scanner, as well as delay completion |
| 1043 // of parsing. | 1043 // of parsing. |
| 1044 bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript(); | 1044 bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript(); |
| 1045 bool scriptRunnerHasBlockingScript = | 1045 bool scriptRunnerHasBlockingScript = |
| 1046 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); | 1046 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); |
| 1047 // Since the parser is paused while a script runner has a blocking script, it | 1047 // Since the parser is paused while a script runner has a blocking script, it |
| 1048 // should never be possible to end up with both objects holding a blocking | 1048 // should never be possible to end up with both objects holding a blocking |
| 1049 // script. | 1049 // script. |
| 1050 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); | 1050 DCHECK(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); |
| 1051 // If either object has a blocking script, the parser should be paused. | 1051 // If either object has a blocking script, the parser should be paused. |
| 1052 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || | 1052 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || |
| 1053 m_reentryPermit->parserPauseFlag(); | 1053 m_reentryPermit->parserPauseFlag(); |
| 1054 } | 1054 } |
| 1055 | 1055 |
| 1056 void HTMLDocumentParser::resumeParsingAfterPause() { | 1056 void HTMLDocumentParser::resumeParsingAfterPause() { |
| 1057 ASSERT(!isExecutingScript()); | 1057 DCHECK(!isExecutingScript()); |
| 1058 DCHECK(!isPaused()); | 1058 DCHECK(!isPaused()); |
| 1059 | 1059 |
| 1060 checkIfBodyStylesheetAdded(); | 1060 checkIfBodyStylesheetAdded(); |
| 1061 if (isPaused()) | 1061 if (isPaused()) |
| 1062 return; | 1062 return; |
| 1063 | 1063 |
| 1064 if (m_haveBackgroundParser) { | 1064 if (m_haveBackgroundParser) { |
| 1065 if (m_lastChunkBeforePause) { | 1065 if (m_lastChunkBeforePause) { |
| 1066 validateSpeculations(std::move(m_lastChunkBeforePause)); | 1066 validateSpeculations(std::move(m_lastChunkBeforePause)); |
| 1067 DCHECK(!m_lastChunkBeforePause); | 1067 DCHECK(!m_lastChunkBeforePause); |
| 1068 pumpPendingSpeculations(); | 1068 pumpPendingSpeculations(); |
| 1069 } | 1069 } |
| 1070 return; | 1070 return; |
| 1071 } | 1071 } |
| 1072 | 1072 |
| 1073 m_insertionPreloadScanner.reset(); | 1073 m_insertionPreloadScanner.reset(); |
| 1074 if (m_tokenizer) { | 1074 if (m_tokenizer) { |
| 1075 pumpTokenizerIfPossible(); | 1075 pumpTokenizerIfPossible(); |
| 1076 } | 1076 } |
| 1077 endIfDelayed(); | 1077 endIfDelayed(); |
| 1078 } | 1078 } |
| 1079 | 1079 |
| 1080 void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan() { | 1080 void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan() { |
| 1081 ASSERT(m_preloadScanner); | 1081 DCHECK(m_preloadScanner); |
| 1082 m_preloadScanner->appendToEnd(m_input.current()); | 1082 m_preloadScanner->appendToEnd(m_input.current()); |
| 1083 scanAndPreload(m_preloadScanner.get()); | 1083 scanAndPreload(m_preloadScanner.get()); |
| 1084 } | 1084 } |
| 1085 | 1085 |
| 1086 void HTMLDocumentParser::notifyScriptLoaded(PendingScript* pendingScript) { | 1086 void HTMLDocumentParser::notifyScriptLoaded(PendingScript* pendingScript) { |
| 1087 ASSERT(m_scriptRunner); | 1087 DCHECK(m_scriptRunner); |
| 1088 ASSERT(!isExecutingScript()); | 1088 DCHECK(!isExecutingScript()); |
| 1089 | 1089 |
| 1090 if (isStopped()) { | 1090 if (isStopped()) { |
| 1091 return; | 1091 return; |
| 1092 } | 1092 } |
| 1093 | 1093 |
| 1094 if (isStopping()) { | 1094 if (isStopping()) { |
| 1095 attemptToRunDeferredScriptsAndEnd(); | 1095 attemptToRunDeferredScriptsAndEnd(); |
| 1096 return; | 1096 return; |
| 1097 } | 1097 } |
| 1098 | 1098 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1148 ParserContentPolicy parserContentPolicy) { | 1148 ParserContentPolicy parserContentPolicy) { |
| 1149 HTMLDocumentParser* parser = | 1149 HTMLDocumentParser* parser = |
| 1150 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); | 1150 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); |
| 1151 parser->append(source); | 1151 parser->append(source); |
| 1152 parser->finish(); | 1152 parser->finish(); |
| 1153 // Allows ~DocumentParser to assert it was detached before destruction. | 1153 // Allows ~DocumentParser to assert it was detached before destruction. |
| 1154 parser->detach(); | 1154 parser->detach(); |
| 1155 } | 1155 } |
| 1156 | 1156 |
| 1157 void HTMLDocumentParser::suspendScheduledTasks() { | 1157 void HTMLDocumentParser::suspendScheduledTasks() { |
| 1158 ASSERT(!m_tasksWereSuspended); | 1158 DCHECK(!m_tasksWereSuspended); |
| 1159 m_tasksWereSuspended = true; | 1159 m_tasksWereSuspended = true; |
| 1160 if (m_parserScheduler) | 1160 if (m_parserScheduler) |
| 1161 m_parserScheduler->suspend(); | 1161 m_parserScheduler->suspend(); |
| 1162 } | 1162 } |
| 1163 | 1163 |
| 1164 void HTMLDocumentParser::resumeScheduledTasks() { | 1164 void HTMLDocumentParser::resumeScheduledTasks() { |
| 1165 ASSERT(m_tasksWereSuspended); | 1165 DCHECK(m_tasksWereSuspended); |
| 1166 m_tasksWereSuspended = false; | 1166 m_tasksWereSuspended = false; |
| 1167 if (m_parserScheduler) | 1167 if (m_parserScheduler) |
| 1168 m_parserScheduler->resume(); | 1168 m_parserScheduler->resume(); |
| 1169 } | 1169 } |
| 1170 | 1170 |
| 1171 void HTMLDocumentParser::appendBytes(const char* data, size_t length) { | 1171 void HTMLDocumentParser::appendBytes(const char* data, size_t length) { |
| 1172 if (!length || isStopped()) | 1172 if (!length || isStopped()) |
| 1173 return; | 1173 return; |
| 1174 | 1174 |
| 1175 if (shouldUseThreading()) { | 1175 if (shouldUseThreading()) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1213 m_loadingTaskRunner->postTask( | 1213 m_loadingTaskRunner->postTask( |
| 1214 BLINK_FROM_HERE, | 1214 BLINK_FROM_HERE, |
| 1215 WTF::bind(&BackgroundHTMLParser::flush, m_backgroundParser)); | 1215 WTF::bind(&BackgroundHTMLParser::flush, m_backgroundParser)); |
| 1216 } else { | 1216 } else { |
| 1217 DecodedDataDocumentParser::flush(); | 1217 DecodedDataDocumentParser::flush(); |
| 1218 } | 1218 } |
| 1219 } | 1219 } |
| 1220 | 1220 |
| 1221 void HTMLDocumentParser::setDecoder( | 1221 void HTMLDocumentParser::setDecoder( |
| 1222 std::unique_ptr<TextResourceDecoder> decoder) { | 1222 std::unique_ptr<TextResourceDecoder> decoder) { |
| 1223 ASSERT(decoder); | 1223 DCHECK(decoder); |
| 1224 DecodedDataDocumentParser::setDecoder(std::move(decoder)); | 1224 DecodedDataDocumentParser::setDecoder(std::move(decoder)); |
| 1225 | 1225 |
| 1226 if (m_haveBackgroundParser) { | 1226 if (m_haveBackgroundParser) { |
| 1227 m_loadingTaskRunner->postTask( | 1227 m_loadingTaskRunner->postTask( |
| 1228 BLINK_FROM_HERE, | 1228 BLINK_FROM_HERE, |
| 1229 WTF::bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, | 1229 WTF::bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, |
| 1230 WTF::passed(takeDecoder()))); | 1230 WTF::passed(takeDecoder()))); |
| 1231 } | 1231 } |
| 1232 } | 1232 } |
| 1233 | 1233 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1313 successHistogram.count(duration); | 1313 successHistogram.count(duration); |
| 1314 } else { | 1314 } else { |
| 1315 DEFINE_STATIC_LOCAL( | 1315 DEFINE_STATIC_LOCAL( |
| 1316 CustomCountHistogram, failureHistogram, | 1316 CustomCountHistogram, failureHistogram, |
| 1317 ("PreloadScanner.DocumentWrite.ExecutionTime.Failure", 1, 10000, 50)); | 1317 ("PreloadScanner.DocumentWrite.ExecutionTime.Failure", 1, 10000, 50)); |
| 1318 failureHistogram.count(duration); | 1318 failureHistogram.count(duration); |
| 1319 } | 1319 } |
| 1320 } | 1320 } |
| 1321 | 1321 |
| 1322 } // namespace blink | 1322 } // namespace blink |
| OLD | NEW |