Chromium Code Reviews| 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 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 144 m_tokenizedChunkQueue(TokenizedChunkQueue::create()), | 144 m_tokenizedChunkQueue(TokenizedChunkQueue::create()), |
| 145 m_evaluator(DocumentWriteEvaluator::create(document)), | 145 m_evaluator(DocumentWriteEvaluator::create(document)), |
| 146 m_pendingCSPMetaToken(nullptr), | 146 m_pendingCSPMetaToken(nullptr), |
| 147 m_shouldUseThreading(syncPolicy == AllowAsynchronousParsing), | 147 m_shouldUseThreading(syncPolicy == AllowAsynchronousParsing), |
| 148 m_endWasDelayed(false), | 148 m_endWasDelayed(false), |
| 149 m_haveBackgroundParser(false), | 149 m_haveBackgroundParser(false), |
| 150 m_tasksWereSuspended(false), | 150 m_tasksWereSuspended(false), |
| 151 m_pumpSessionNestingLevel(0), | 151 m_pumpSessionNestingLevel(0), |
| 152 m_pumpSpeculationsSessionNestingLevel(0), | 152 m_pumpSpeculationsSessionNestingLevel(0), |
| 153 m_isParsingAtLineNumber(false), | 153 m_isParsingAtLineNumber(false), |
| 154 m_triedLoadingLinkHeaders(false) { | 154 m_triedLoadingLinkHeaders(false), |
| 155 m_addedPendingStylesheetInBody(false), | |
| 156 m_isWaitingForStylesheets(false) { | |
| 155 ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); | 157 ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); |
| 156 // Threading is not allowed in prefetch mode. | 158 // Threading is not allowed in prefetch mode. |
| 157 DCHECK(!document.isPrefetchOnly() || !shouldUseThreading()); | 159 DCHECK(!document.isPrefetchOnly() || !shouldUseThreading()); |
| 158 } | 160 } |
| 159 | 161 |
| 160 HTMLDocumentParser::~HTMLDocumentParser() {} | 162 HTMLDocumentParser::~HTMLDocumentParser() {} |
| 161 | 163 |
| 162 void HTMLDocumentParser::dispose() { | 164 void HTMLDocumentParser::dispose() { |
| 163 // In Oilpan, HTMLDocumentParser can die together with Document, and detach() | 165 // In Oilpan, HTMLDocumentParser can die together with Document, and detach() |
| 164 // is not called in this case. | 166 // is not called in this case. |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 249 return; | 251 return; |
| 250 | 252 |
| 251 attemptToRunDeferredScriptsAndEnd(); | 253 attemptToRunDeferredScriptsAndEnd(); |
| 252 } | 254 } |
| 253 | 255 |
| 254 bool HTMLDocumentParser::isParsingFragment() const { | 256 bool HTMLDocumentParser::isParsingFragment() const { |
| 255 return m_treeBuilder->isParsingFragment(); | 257 return m_treeBuilder->isParsingFragment(); |
| 256 } | 258 } |
| 257 | 259 |
| 258 void HTMLDocumentParser::pumpTokenizerIfPossible() { | 260 void HTMLDocumentParser::pumpTokenizerIfPossible() { |
| 259 if (isStopped() || isWaitingForScripts()) | 261 if (isStopped() || isPaused()) |
| 260 return; | 262 return; |
| 261 | 263 |
| 262 pumpTokenizer(); | 264 pumpTokenizer(); |
| 263 } | 265 } |
| 264 | 266 |
| 265 bool HTMLDocumentParser::isScheduledForResume() const { | 267 bool HTMLDocumentParser::isScheduledForResume() const { |
| 266 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); | 268 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); |
| 267 } | 269 } |
| 268 | 270 |
| 269 // Used by HTMLParserScheduler | 271 // Used by HTMLParserScheduler |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 286 } | 288 } |
| 287 | 289 |
| 288 bool HTMLDocumentParser::canTakeNextToken() { | 290 bool HTMLDocumentParser::canTakeNextToken() { |
| 289 if (isStopped()) | 291 if (isStopped()) |
| 290 return false; | 292 return false; |
| 291 | 293 |
| 292 // If we're paused waiting for a script, we try to execute scripts before | 294 // If we're paused waiting for a script, we try to execute scripts before |
| 293 // continuing. | 295 // continuing. |
| 294 if (m_treeBuilder->hasParserBlockingScript()) | 296 if (m_treeBuilder->hasParserBlockingScript()) |
| 295 runScriptsForPausedTreeBuilder(); | 297 runScriptsForPausedTreeBuilder(); |
| 296 if (isStopped() || isWaitingForScripts()) | 298 if (isStopped() || isPaused()) |
| 297 return false; | 299 return false; |
| 298 | 300 |
| 299 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the | 301 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the |
| 300 // LocalFrame, but this approach is how the old parser handled stopping when | 302 // LocalFrame, but this approach is how the old parser handled stopping when |
| 301 // the page assigns window.location. What really should happen is that | 303 // the page assigns window.location. What really should happen is that |
| 302 // assigning window.location causes the parser to stop parsing cleanly. The | 304 // assigning window.location causes the parser to stop parsing cleanly. The |
| 303 // problem is we're not perpared to do that at every point where we run | 305 // problem is we're not perpared to do that at every point where we run |
| 304 // JavaScript. | 306 // JavaScript. |
| 305 if (!isParsingFragment() && document()->frame() && | 307 if (!isParsingFragment() && document()->frame() && |
| 306 document()->frame()->navigationScheduler().locationChangePending()) | 308 document()->frame()->navigationScheduler().locationChangePending()) |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 374 const CompactHTMLToken& token = chunk->tokens->at(index); | 376 const CompactHTMLToken& token = chunk->tokens->at(index); |
| 375 ASSERT(token.type() == HTMLToken::TokenType::Character); | 377 ASSERT(token.type() == HTMLToken::TokenType::Character); |
| 376 evaluateAndPreloadScriptForDocumentWrite(token.data()); | 378 evaluateAndPreloadScriptForDocumentWrite(token.data()); |
| 377 } | 379 } |
| 378 } | 380 } |
| 379 } | 381 } |
| 380 | 382 |
| 381 for (auto& chunk : pendingChunks) | 383 for (auto& chunk : pendingChunks) |
| 382 m_speculations.append(std::move(chunk)); | 384 m_speculations.append(std::move(chunk)); |
| 383 | 385 |
| 384 if (!isWaitingForScripts() && !isScheduledForResume()) { | 386 if (!isPaused() && !isScheduledForResume()) { |
| 385 if (m_tasksWereSuspended) | 387 if (m_tasksWereSuspended) |
| 386 m_parserScheduler->forceResumeAfterYield(); | 388 m_parserScheduler->forceResumeAfterYield(); |
| 387 else | 389 else |
| 388 m_parserScheduler->scheduleForResume(); | 390 m_parserScheduler->scheduleForResume(); |
| 389 } | 391 } |
| 390 } | 392 } |
| 391 | 393 |
| 392 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( | 394 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( |
| 393 const DocumentEncodingData& data) { | 395 const DocumentEncodingData& data) { |
| 394 document()->setEncodingData(data); | 396 document()->setEncodingData(data); |
| 395 } | 397 } |
| 396 | 398 |
| 397 void HTMLDocumentParser::validateSpeculations( | 399 void HTMLDocumentParser::validateSpeculations( |
| 398 std::unique_ptr<TokenizedChunk> chunk) { | 400 std::unique_ptr<TokenizedChunk> chunk) { |
| 399 ASSERT(chunk); | 401 ASSERT(chunk); |
| 400 // TODO(kouhei): We should simplify codepath here by disallowing | 402 // TODO(kouhei): We should simplify codepath here by disallowing |
| 401 // validateSpeculations | 403 // validateSpeculations |
| 402 // while isWaitingForScripts, and m_lastChunkBeforeScript can simply be | 404 // while isPaused, and m_lastChunkBeforePause can simply be |
| 403 // pushed to m_speculations. | 405 // pushed to m_speculations. |
| 404 if (isWaitingForScripts()) { | 406 if (isPaused()) { |
| 405 // We're waiting on a network script, just save the chunk, we'll get a | 407 // We're waiting on a network script or stylesheet, just save the chunk, |
| 406 // second validateSpeculations call after the script completes. This call | 408 // we'll get a second validateSpeculations call after the script or |
| 407 // should have been made immediately after runScriptsForPausedTreeBuilder | 409 // stylesheet completes. This call should have been made immediately after |
| 408 // which may have started a network load and left us waiting. | 410 // runScriptsForPausedTreeBuilder in the script case which may have started |
| 409 ASSERT(!m_lastChunkBeforeScript); | 411 // a network load and left us waiting. |
| 410 m_lastChunkBeforeScript = std::move(chunk); | 412 DCHECK(!m_lastChunkBeforePause); |
| 413 m_lastChunkBeforePause = std::move(chunk); | |
| 411 return; | 414 return; |
| 412 } | 415 } |
| 413 | 416 |
| 414 ASSERT(!m_lastChunkBeforeScript); | 417 DCHECK(!m_lastChunkBeforePause); |
| 415 std::unique_ptr<HTMLTokenizer> tokenizer = std::move(m_tokenizer); | 418 std::unique_ptr<HTMLTokenizer> tokenizer = std::move(m_tokenizer); |
| 416 std::unique_ptr<HTMLToken> token = std::move(m_token); | 419 std::unique_ptr<HTMLToken> token = std::move(m_token); |
| 417 | 420 |
| 418 if (!tokenizer) { | 421 if (!tokenizer) { |
| 419 // There must not have been any changes to the HTMLTokenizer state on the | 422 // There must not have been any changes to the HTMLTokenizer state on the |
| 420 // main thread, which means the speculation buffer is correct. | 423 // main thread, which means the speculation buffer is correct. |
| 421 return; | 424 return; |
| 422 } | 425 } |
| 423 | 426 |
| 424 // Currently we're only smart enough to reuse the speculation buffer if the | 427 // Currently we're only smart enough to reuse the speculation buffer if the |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 481 std::unique_ptr<TokenizedChunk> popChunk) { | 484 std::unique_ptr<TokenizedChunk> popChunk) { |
| 482 TRACE_EVENT_WITH_FLOW0( | 485 TRACE_EVENT_WITH_FLOW0( |
| 483 "blink,loading", | 486 "blink,loading", |
| 484 "HTMLDocumentParser::processTokenizedChunkFromBackgroundParser", | 487 "HTMLDocumentParser::processTokenizedChunkFromBackgroundParser", |
| 485 popChunk.get(), TRACE_EVENT_FLAG_FLOW_IN); | 488 popChunk.get(), TRACE_EVENT_FLAG_FLOW_IN); |
| 486 AutoReset<bool> hasLineNumber(&m_isParsingAtLineNumber, true); | 489 AutoReset<bool> hasLineNumber(&m_isParsingAtLineNumber, true); |
| 487 | 490 |
| 488 SECURITY_DCHECK(m_pumpSpeculationsSessionNestingLevel == 1); | 491 SECURITY_DCHECK(m_pumpSpeculationsSessionNestingLevel == 1); |
| 489 SECURITY_DCHECK(!inPumpSession()); | 492 SECURITY_DCHECK(!inPumpSession()); |
| 490 ASSERT(!isParsingFragment()); | 493 ASSERT(!isParsingFragment()); |
| 491 ASSERT(!isWaitingForScripts()); | 494 DCHECK(!isPaused()); |
| 492 ASSERT(!isStopped()); | 495 ASSERT(!isStopped()); |
| 493 ASSERT(shouldUseThreading()); | 496 ASSERT(shouldUseThreading()); |
| 494 ASSERT(!m_tokenizer); | 497 ASSERT(!m_tokenizer); |
| 495 ASSERT(!m_token); | 498 ASSERT(!m_token); |
| 496 ASSERT(!m_lastChunkBeforeScript); | 499 DCHECK(!m_lastChunkBeforePause); |
| 497 | 500 |
| 498 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); | 501 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); |
| 499 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); | 502 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); |
| 500 size_t elementTokenCount = 0; | 503 size_t elementTokenCount = 0; |
| 501 | 504 |
| 502 postTaskToLookaheadParser(Asynchronous, | 505 postTaskToLookaheadParser(Asynchronous, |
| 503 &BackgroundHTMLParser::startedChunkWithCheckpoint, | 506 &BackgroundHTMLParser::startedChunkWithCheckpoint, |
| 504 m_backgroundParser, chunk->inputCheckpoint); | 507 m_backgroundParser, chunk->inputCheckpoint); |
| 505 | 508 |
| 506 for (const auto& xssInfo : chunk->xssInfos) { | 509 for (const auto& xssInfo : chunk->xssInfos) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 551 } | 554 } |
| 552 | 555 |
| 553 if (isWaitingForScripts()) { | 556 if (isWaitingForScripts()) { |
| 554 // The </script> is assumed to be the last token of this bunch. | 557 // The </script> is assumed to be the last token of this bunch. |
| 555 ASSERT(it + 1 == tokens->end()); | 558 ASSERT(it + 1 == tokens->end()); |
| 556 runScriptsForPausedTreeBuilder(); | 559 runScriptsForPausedTreeBuilder(); |
| 557 validateSpeculations(std::move(chunk)); | 560 validateSpeculations(std::move(chunk)); |
| 558 break; | 561 break; |
| 559 } | 562 } |
| 560 | 563 |
| 564 if (m_isWaitingForStylesheets && it + 1 == tokens->end()) { | |
|
kouhei (in TOK)
2017/01/12 11:58:13
Can we merge this to the if condition above?
It is
Pat Meenan
2017/01/12 13:26:46
I'm not 100% sure that there aren't any conditions
| |
| 565 validateSpeculations(std::move(chunk)); | |
| 566 break; | |
| 567 } | |
| 568 | |
| 561 if (it->type() == HTMLToken::EndOfFile) { | 569 if (it->type() == HTMLToken::EndOfFile) { |
| 562 // The EOF is assumed to be the last token of this bunch. | 570 // The EOF is assumed to be the last token of this bunch. |
| 563 ASSERT(it + 1 == tokens->end()); | 571 ASSERT(it + 1 == tokens->end()); |
| 564 // There should never be any chunks after the EOF. | 572 // There should never be any chunks after the EOF. |
| 565 ASSERT(m_speculations.isEmpty()); | 573 ASSERT(m_speculations.isEmpty()); |
| 566 prepareToStopParsing(); | 574 prepareToStopParsing(); |
| 567 break; | 575 break; |
| 568 } | 576 } |
| 569 | 577 |
| 570 ASSERT(!m_tokenizer); | 578 ASSERT(!m_tokenizer); |
| 571 ASSERT(!m_token); | 579 ASSERT(!m_token); |
| 572 } | 580 } |
| 573 | 581 |
| 574 // Make sure all required pending text nodes are emitted before returning. | 582 // Make sure all required pending text nodes are emitted before returning. |
| 575 // This leaves "script", "style" and "svg" nodes text nodes intact. | 583 // This leaves "script", "style" and "svg" nodes text nodes intact. |
| 576 if (!isStopped()) | 584 if (!isStopped()) |
| 577 m_treeBuilder->flush(FlushIfAtTextLimit); | 585 m_treeBuilder->flush(FlushIfAtTextLimit); |
| 578 | 586 |
| 579 m_isParsingAtLineNumber = false; | 587 m_isParsingAtLineNumber = false; |
| 580 | 588 |
| 581 return elementTokenCount; | 589 return elementTokenCount; |
| 582 } | 590 } |
| 583 | 591 |
| 584 void HTMLDocumentParser::pumpPendingSpeculations() { | 592 void HTMLDocumentParser::pumpPendingSpeculations() { |
| 585 // If this assert fails, you need to call validateSpeculations to make sure | 593 // If this assert fails, you need to call validateSpeculations to make sure |
| 586 // m_tokenizer and m_token don't have state that invalidates m_speculations. | 594 // m_tokenizer and m_token don't have state that invalidates m_speculations. |
| 587 ASSERT(!m_tokenizer); | 595 ASSERT(!m_tokenizer); |
| 588 ASSERT(!m_token); | 596 ASSERT(!m_token); |
| 589 ASSERT(!m_lastChunkBeforeScript); | 597 DCHECK(!m_lastChunkBeforePause); |
| 590 ASSERT(!isWaitingForScripts()); | 598 DCHECK(!isPaused()); |
| 591 ASSERT(!isStopped()); | 599 ASSERT(!isStopped()); |
| 592 ASSERT(!isScheduledForResume()); | 600 ASSERT(!isScheduledForResume()); |
| 593 ASSERT(!inPumpSession()); | 601 ASSERT(!inPumpSession()); |
| 594 | 602 |
| 595 // FIXME: Here should never be reached when there is a blocking script, | 603 // FIXME: Here should never be reached when there is a blocking script, |
| 596 // but it happens in unknown scenarios. See https://crbug.com/440901 | 604 // but it happens in unknown scenarios. See https://crbug.com/440901 |
| 597 if (isWaitingForScripts()) { | 605 if (isWaitingForScripts()) { |
| 598 m_parserScheduler->scheduleForResume(); | 606 m_parserScheduler->scheduleForResume(); |
| 599 return; | 607 return; |
| 600 } | 608 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 614 while (!m_speculations.isEmpty()) { | 622 while (!m_speculations.isEmpty()) { |
| 615 ASSERT(!isScheduledForResume()); | 623 ASSERT(!isScheduledForResume()); |
| 616 size_t elementTokenCount = | 624 size_t elementTokenCount = |
| 617 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); | 625 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); |
| 618 session.addedElementTokens(elementTokenCount); | 626 session.addedElementTokens(elementTokenCount); |
| 619 | 627 |
| 620 // Always check isParsing first as m_document may be null. Surprisingly, | 628 // Always check isParsing first as m_document may be null. Surprisingly, |
| 621 // isScheduledForResume() may be set here as a result of | 629 // isScheduledForResume() may be set here as a result of |
| 622 // processTokenizedChunkFromBackgroundParser running arbitrary javascript | 630 // processTokenizedChunkFromBackgroundParser running arbitrary javascript |
| 623 // which invokes nested event loops. (e.g. inspector breakpoints) | 631 // which invokes nested event loops. (e.g. inspector breakpoints) |
| 624 if (!isParsing() || isWaitingForScripts() || isScheduledForResume()) | 632 if (!isParsing() || isPaused() || isScheduledForResume()) |
| 625 break; | 633 break; |
| 626 | 634 |
| 627 if (m_speculations.isEmpty() || | 635 if (m_speculations.isEmpty() || |
| 628 m_parserScheduler->yieldIfNeeded( | 636 m_parserScheduler->yieldIfNeeded( |
| 629 session, m_speculations.first()->startingScript)) | 637 session, m_speculations.first()->startingScript)) |
| 630 break; | 638 break; |
| 631 } | 639 } |
| 632 | 640 |
| 633 TRACE_EVENT_END1( | 641 TRACE_EVENT_END1( |
| 634 "devtools.timeline", "ParseHTML", "endData", | 642 "devtools.timeline", "ParseHTML", "endData", |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 702 } | 710 } |
| 703 | 711 |
| 704 if (isStopped()) | 712 if (isStopped()) |
| 705 return; | 713 return; |
| 706 | 714 |
| 707 // There should only be PendingText left since the tree-builder always flushes | 715 // There should only be PendingText left since the tree-builder always flushes |
| 708 // the task queue before returning. In case that ever changes, crash. | 716 // the task queue before returning. In case that ever changes, crash. |
| 709 m_treeBuilder->flush(FlushAlways); | 717 m_treeBuilder->flush(FlushAlways); |
| 710 RELEASE_ASSERT(!isStopped()); | 718 RELEASE_ASSERT(!isStopped()); |
| 711 | 719 |
| 712 if (isWaitingForScripts()) { | 720 if (isPaused()) { |
| 713 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); | 721 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); |
| 714 | 722 |
| 715 ASSERT(m_preloader); | 723 ASSERT(m_preloader); |
| 716 // TODO(kouhei): m_preloader should be always available for synchronous | 724 // TODO(kouhei): m_preloader should be always available for synchronous |
| 717 // parsing case, adding paranoia if for speculative crash fix for | 725 // parsing case, adding paranoia if for speculative crash fix for |
| 718 // crbug.com/465478 | 726 // crbug.com/465478 |
| 719 if (m_preloader) { | 727 if (m_preloader) { |
| 720 if (!m_preloadScanner) { | 728 if (!m_preloadScanner) { |
| 721 m_preloadScanner = createPreloadScanner(); | 729 m_preloadScanner = createPreloadScanner(); |
| 722 m_preloadScanner->appendToEnd(m_input.current()); | 730 m_preloadScanner->appendToEnd(m_input.current()); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 741 // the parser. | 749 // the parser. |
| 742 // | 750 // |
| 743 // FIXME: Stop clearing the m_token once we start running the parser off | 751 // FIXME: Stop clearing the m_token once we start running the parser off |
| 744 // the main thread or once we stop allowing synchronous JavaScript | 752 // the main thread or once we stop allowing synchronous JavaScript |
| 745 // execution from parseAttribute. | 753 // execution from parseAttribute. |
| 746 if (token().type() != HTMLToken::Character) | 754 if (token().type() != HTMLToken::Character) |
| 747 token().clear(); | 755 token().clear(); |
| 748 | 756 |
| 749 m_treeBuilder->constructTree(&atomicToken); | 757 m_treeBuilder->constructTree(&atomicToken); |
| 750 | 758 |
| 759 if (m_addedPendingStylesheetInBody) | |
| 760 m_isWaitingForStylesheets = true; | |
| 761 | |
| 751 // FIXME: constructTree may synchronously cause Document to be detached. | 762 // FIXME: constructTree may synchronously cause Document to be detached. |
| 752 if (!m_token) | 763 if (!m_token) |
| 753 return; | 764 return; |
| 754 | 765 |
| 755 if (!token().isUninitialized()) { | 766 if (!token().isUninitialized()) { |
| 756 ASSERT(token().type() == HTMLToken::Character); | 767 ASSERT(token().type() == HTMLToken::Character); |
| 757 token().clear(); | 768 token().clear(); |
| 758 } | 769 } |
| 759 } | 770 } |
| 760 | 771 |
| 761 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( | 772 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( |
| 762 const CompactHTMLToken& compactToken) { | 773 const CompactHTMLToken& compactToken) { |
| 763 AtomicHTMLToken token(compactToken); | 774 AtomicHTMLToken token(compactToken); |
| 764 m_treeBuilder->constructTree(&token); | 775 m_treeBuilder->constructTree(&token); |
| 776 if (m_addedPendingStylesheetInBody) | |
| 777 m_isWaitingForStylesheets = true; | |
| 765 } | 778 } |
| 766 | 779 |
| 767 bool HTMLDocumentParser::hasInsertionPoint() { | 780 bool HTMLDocumentParser::hasInsertionPoint() { |
| 768 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our | 781 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our |
| 769 // model of the EOF character differs slightly from the one in the spec | 782 // model of the EOF character differs slightly from the one in the spec |
| 770 // because our treatment is uniform between network-sourced and script-sourced | 783 // because our treatment is uniform between network-sourced and script-sourced |
| 771 // input streams whereas the spec treats them differently. | 784 // input streams whereas the spec treats them differently. |
| 772 return m_input.hasInsertionPoint() || | 785 return m_input.hasInsertionPoint() || |
| 773 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); | 786 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); |
| 774 } | 787 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 785 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); | 798 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); |
| 786 m_token = WTF::wrapUnique(new HTMLToken); | 799 m_token = WTF::wrapUnique(new HTMLToken); |
| 787 m_tokenizer = HTMLTokenizer::create(m_options); | 800 m_tokenizer = HTMLTokenizer::create(m_options); |
| 788 } | 801 } |
| 789 | 802 |
| 790 SegmentedString excludedLineNumberSource(source); | 803 SegmentedString excludedLineNumberSource(source); |
| 791 excludedLineNumberSource.setExcludeLineNumbers(); | 804 excludedLineNumberSource.setExcludeLineNumbers(); |
| 792 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); | 805 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); |
| 793 pumpTokenizerIfPossible(); | 806 pumpTokenizerIfPossible(); |
| 794 | 807 |
| 795 if (isWaitingForScripts()) { | 808 if (isPaused()) { |
| 796 // Check the document.write() output with a separate preload scanner as | 809 // Check the document.write() output with a separate preload scanner as |
| 797 // the main scanner can't deal with insertions. | 810 // the main scanner can't deal with insertions. |
| 798 if (!m_insertionPreloadScanner) | 811 if (!m_insertionPreloadScanner) |
| 799 m_insertionPreloadScanner = createPreloadScanner(); | 812 m_insertionPreloadScanner = createPreloadScanner(); |
| 800 m_insertionPreloadScanner->appendToEnd(source); | 813 m_insertionPreloadScanner->appendToEnd(source); |
| 801 scanAndPreload(m_insertionPreloadScanner.get()); | 814 scanAndPreload(m_insertionPreloadScanner.get()); |
| 802 } | 815 } |
| 803 | 816 |
| 804 endIfDelayed(); | 817 endIfDelayed(); |
| 805 } | 818 } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 898 m_preloadScanner = createPreloadScanner(); | 911 m_preloadScanner = createPreloadScanner(); |
| 899 | 912 |
| 900 m_preloadScanner->appendToEnd(source); | 913 m_preloadScanner->appendToEnd(source); |
| 901 scanAndPreload(m_preloadScanner.get()); | 914 scanAndPreload(m_preloadScanner.get()); |
| 902 | 915 |
| 903 // Return after the preload scanner, do not actually parse the document. | 916 // Return after the preload scanner, do not actually parse the document. |
| 904 return; | 917 return; |
| 905 } | 918 } |
| 906 | 919 |
| 907 if (m_preloadScanner) { | 920 if (m_preloadScanner) { |
| 908 if (m_input.current().isEmpty() && !isWaitingForScripts()) { | 921 if (m_input.current().isEmpty() && !isPaused()) { |
| 909 // We have parsed until the end of the current input and so are now moving | 922 // We have parsed until the end of the current input and so are now moving |
| 910 // ahead of the preload scanner. Clear the scanner so we know to scan | 923 // ahead of the preload scanner. Clear the scanner so we know to scan |
| 911 // starting from the current input point if we block again. | 924 // starting from the current input point if we block again. |
| 912 m_preloadScanner.reset(); | 925 m_preloadScanner.reset(); |
| 913 } else { | 926 } else { |
| 914 m_preloadScanner->appendToEnd(source); | 927 m_preloadScanner->appendToEnd(source); |
| 915 if (isWaitingForScripts()) | 928 if (isPaused()) |
| 916 scanAndPreload(m_preloadScanner.get()); | 929 scanAndPreload(m_preloadScanner.get()); |
| 917 } | 930 } |
| 918 } | 931 } |
| 919 | 932 |
| 920 m_input.appendToEnd(source); | 933 m_input.appendToEnd(source); |
| 921 | 934 |
| 922 if (inPumpSession()) { | 935 if (inPumpSession()) { |
| 923 // We've gotten data off the network in a nested write. We don't want to | 936 // We've gotten data off the network in a nested write. We don't want to |
| 924 // consume any more of the input stream now. Do not worry. We'll consume | 937 // consume any more of the input stream now. Do not worry. We'll consume |
| 925 // this data in a less-nested write(). | 938 // this data in a less-nested write(). |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1056 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); | 1069 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); |
| 1057 // Since the parser is paused while a script runner has a blocking script, it | 1070 // Since the parser is paused while a script runner has a blocking script, it |
| 1058 // should never be possible to end up with both objects holding a blocking | 1071 // should never be possible to end up with both objects holding a blocking |
| 1059 // script. | 1072 // script. |
| 1060 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); | 1073 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); |
| 1061 // If either object has a blocking script, the parser should be paused. | 1074 // If either object has a blocking script, the parser should be paused. |
| 1062 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || | 1075 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || |
| 1063 m_reentryPermit->parserPauseFlag(); | 1076 m_reentryPermit->parserPauseFlag(); |
| 1064 } | 1077 } |
| 1065 | 1078 |
| 1066 void HTMLDocumentParser::resumeParsingAfterScriptExecution() { | 1079 void HTMLDocumentParser::resumeParsingAfterPause() { |
| 1067 ASSERT(!isExecutingScript()); | 1080 ASSERT(!isExecutingScript()); |
| 1068 ASSERT(!isWaitingForScripts()); | 1081 DCHECK(!isPaused()); |
| 1069 | 1082 |
| 1070 if (m_haveBackgroundParser) { | 1083 if (m_haveBackgroundParser) { |
| 1071 if (m_lastChunkBeforeScript) { | 1084 if (m_lastChunkBeforePause) { |
| 1072 validateSpeculations(std::move(m_lastChunkBeforeScript)); | 1085 validateSpeculations(std::move(m_lastChunkBeforePause)); |
| 1073 DCHECK(!m_lastChunkBeforeScript); | 1086 DCHECK(!m_lastChunkBeforePause); |
| 1074 pumpPendingSpeculations(); | 1087 pumpPendingSpeculations(); |
| 1075 } | 1088 } |
| 1076 return; | 1089 return; |
| 1077 } | 1090 } |
| 1078 | 1091 |
| 1079 m_insertionPreloadScanner.reset(); | 1092 m_insertionPreloadScanner.reset(); |
| 1080 if (m_tokenizer) { | 1093 if (m_tokenizer) { |
| 1081 pumpTokenizerIfPossible(); | 1094 pumpTokenizerIfPossible(); |
| 1082 } | 1095 } |
| 1083 endIfDelayed(); | 1096 endIfDelayed(); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1096 if (isStopped()) { | 1109 if (isStopped()) { |
| 1097 return; | 1110 return; |
| 1098 } | 1111 } |
| 1099 | 1112 |
| 1100 if (isStopping()) { | 1113 if (isStopping()) { |
| 1101 attemptToRunDeferredScriptsAndEnd(); | 1114 attemptToRunDeferredScriptsAndEnd(); |
| 1102 return; | 1115 return; |
| 1103 } | 1116 } |
| 1104 | 1117 |
| 1105 m_scriptRunner->executeScriptsWaitingForLoad(pendingScript); | 1118 m_scriptRunner->executeScriptsWaitingForLoad(pendingScript); |
| 1106 if (!isWaitingForScripts()) | 1119 if (!isPaused()) |
| 1107 resumeParsingAfterScriptExecution(); | 1120 resumeParsingAfterPause(); |
| 1108 } | 1121 } |
| 1109 | 1122 |
| 1110 void HTMLDocumentParser::executeScriptsWaitingForResources() { | 1123 void HTMLDocumentParser::executeScriptsWaitingForResources() { |
| 1111 DCHECK(document()->isScriptExecutionReady()); | 1124 DCHECK(document()->isScriptExecutionReady()); |
| 1112 | 1125 |
| 1126 if (m_isWaitingForStylesheets) | |
| 1127 m_isWaitingForStylesheets = false; | |
| 1128 | |
| 1113 // Document only calls this when the Document owns the DocumentParser so this | 1129 // Document only calls this when the Document owns the DocumentParser so this |
| 1114 // will not be called in the DocumentFragment case. | 1130 // will not be called in the DocumentFragment case. |
| 1115 DCHECK(m_scriptRunner); | 1131 DCHECK(m_scriptRunner); |
| 1116 m_scriptRunner->executeScriptsWaitingForResources(); | 1132 m_scriptRunner->executeScriptsWaitingForResources(); |
| 1117 if (!isWaitingForScripts()) | 1133 if (!isPaused()) |
| 1118 resumeParsingAfterScriptExecution(); | 1134 resumeParsingAfterPause(); |
| 1135 } | |
| 1136 | |
| 1137 void HTMLDocumentParser::didAddPendingStylesheetInBody() { | |
| 1138 // When in-body CSS doesn't block painting, the parser needs to pause so that | |
| 1139 // the DOM doesn't include any elements that may depend on the CSS for style. | |
| 1140 // The stylesheet can be added and removed during the parsing of a single | |
| 1141 // token so don't actually set the bit to block parsing here, just track | |
| 1142 // the state of the added sheet in case it does persist beyond a single | |
| 1143 // token. | |
| 1144 if (RuntimeEnabledFeatures::cssInBodyDoesNotBlockPaintEnabled()) | |
| 1145 m_addedPendingStylesheetInBody = true; | |
| 1146 } | |
| 1147 | |
| 1148 void HTMLDocumentParser::didLoadAllStylesheets() { | |
| 1149 // Just toggle the stylesheet flag here (mostly for synchronous sheets). | |
| 1150 // The document will also call into executeScriptsWaitingForResources | |
| 1151 // which is when the parser will re-start, otherwise it will attempt to | |
| 1152 // resume twice which could cause state machine issues. | |
| 1153 m_addedPendingStylesheetInBody = false; | |
| 1119 } | 1154 } |
| 1120 | 1155 |
| 1121 void HTMLDocumentParser::parseDocumentFragment( | 1156 void HTMLDocumentParser::parseDocumentFragment( |
| 1122 const String& source, | 1157 const String& source, |
| 1123 DocumentFragment* fragment, | 1158 DocumentFragment* fragment, |
| 1124 Element* contextElement, | 1159 Element* contextElement, |
| 1125 ParserContentPolicy parserContentPolicy) { | 1160 ParserContentPolicy parserContentPolicy) { |
| 1126 HTMLDocumentParser* parser = | 1161 HTMLDocumentParser* parser = |
| 1127 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); | 1162 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); |
| 1128 parser->append(source); | 1163 parser->append(source); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1316 case Asynchronous: | 1351 case Asynchronous: |
| 1317 m_loadingTaskRunner->postTask( | 1352 m_loadingTaskRunner->postTask( |
| 1318 BLINK_FROM_HERE, | 1353 BLINK_FROM_HERE, |
| 1319 WTF::bind(function, std::forward<Ps>(parameters)...)); | 1354 WTF::bind(function, std::forward<Ps>(parameters)...)); |
| 1320 return; | 1355 return; |
| 1321 } | 1356 } |
| 1322 NOTREACHED(); | 1357 NOTREACHED(); |
| 1323 } | 1358 } |
| 1324 | 1359 |
| 1325 } // namespace blink | 1360 } // namespace blink |
| OLD | NEW |