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() || isWaitingForScripts() || m_isWaitingForStylesheets) |
|
kouhei (in TOK)
2017/01/06 03:32:43
Would you mind cleaning up the HTMLDocumentParser
Pat Meenan
2017/01/09 16:37:05
For Option B, the state is currently tracked in th
| |
| 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() || isWaitingForScripts() || m_isWaitingForStylesheets) |
| 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 (!isWaitingForScripts() && !isScheduledForResume() && |
| 387 !m_isWaitingForStylesheets) { | |
| 385 if (m_tasksWereSuspended) | 388 if (m_tasksWereSuspended) |
| 386 m_parserScheduler->forceResumeAfterYield(); | 389 m_parserScheduler->forceResumeAfterYield(); |
| 387 else | 390 else |
| 388 m_parserScheduler->scheduleForResume(); | 391 m_parserScheduler->scheduleForResume(); |
| 389 } | 392 } |
| 390 } | 393 } |
| 391 | 394 |
| 392 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( | 395 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( |
| 393 const DocumentEncodingData& data) { | 396 const DocumentEncodingData& data) { |
| 394 document()->setEncodingData(data); | 397 document()->setEncodingData(data); |
| 395 } | 398 } |
| 396 | 399 |
| 397 void HTMLDocumentParser::validateSpeculations( | 400 void HTMLDocumentParser::validateSpeculations( |
| 398 std::unique_ptr<TokenizedChunk> chunk) { | 401 std::unique_ptr<TokenizedChunk> chunk) { |
| 399 ASSERT(chunk); | 402 ASSERT(chunk); |
| 400 // TODO(kouhei): We should simplify codepath here by disallowing | 403 // TODO(kouhei): We should simplify codepath here by disallowing |
| 401 // validateSpeculations | 404 // validateSpeculations |
| 402 // while isWaitingForScripts, and m_lastChunkBeforeScript can simply be | 405 // while isWaitingForScripts, and m_lastChunkBeforePause can simply be |
| 403 // pushed to m_speculations. | 406 // pushed to m_speculations. |
| 404 if (isWaitingForScripts()) { | 407 if (isWaitingForScripts() || m_isWaitingForStylesheets) { |
| 405 // We're waiting on a network script, just save the chunk, we'll get a | 408 // We're waiting on a network script, just save the chunk, we'll get a |
| 406 // second validateSpeculations call after the script completes. This call | 409 // second validateSpeculations call after the script completes. This call |
| 407 // should have been made immediately after runScriptsForPausedTreeBuilder | 410 // should have been made immediately after runScriptsForPausedTreeBuilder |
| 408 // which may have started a network load and left us waiting. | 411 // which may have started a network load and left us waiting. |
| 409 ASSERT(!m_lastChunkBeforeScript); | 412 DCHECK(!m_lastChunkBeforePause); |
| 410 m_lastChunkBeforeScript = std::move(chunk); | 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 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 ASSERT(!isWaitingForScripts()); |
| 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); |
| 500 DCHECK(!m_isWaitingForStylesheets); | |
| 497 | 501 |
| 498 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); | 502 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); |
| 499 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); | 503 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); |
| 500 size_t elementTokenCount = 0; | 504 size_t elementTokenCount = 0; |
| 501 | 505 |
| 502 postTaskToLookaheadParser(Asynchronous, | 506 postTaskToLookaheadParser(Asynchronous, |
| 503 &BackgroundHTMLParser::startedChunkWithCheckpoint, | 507 &BackgroundHTMLParser::startedChunkWithCheckpoint, |
| 504 m_backgroundParser, chunk->inputCheckpoint); | 508 m_backgroundParser, chunk->inputCheckpoint); |
| 505 | 509 |
| 506 for (const auto& xssInfo : chunk->xssInfos) { | 510 for (const auto& xssInfo : chunk->xssInfos) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 551 } | 555 } |
| 552 | 556 |
| 553 if (isWaitingForScripts()) { | 557 if (isWaitingForScripts()) { |
| 554 // The </script> is assumed to be the last token of this bunch. | 558 // The </script> is assumed to be the last token of this bunch. |
| 555 ASSERT(it + 1 == tokens->end()); | 559 ASSERT(it + 1 == tokens->end()); |
| 556 runScriptsForPausedTreeBuilder(); | 560 runScriptsForPausedTreeBuilder(); |
| 557 validateSpeculations(std::move(chunk)); | 561 validateSpeculations(std::move(chunk)); |
| 558 break; | 562 break; |
| 559 } | 563 } |
| 560 | 564 |
| 565 if (m_isWaitingForStylesheets && it + 1 == tokens->end()) { | |
| 566 validateSpeculations(std::move(chunk)); | |
| 567 break; | |
| 568 } | |
| 569 | |
| 561 if (it->type() == HTMLToken::EndOfFile) { | 570 if (it->type() == HTMLToken::EndOfFile) { |
| 562 // The EOF is assumed to be the last token of this bunch. | 571 // The EOF is assumed to be the last token of this bunch. |
| 563 ASSERT(it + 1 == tokens->end()); | 572 ASSERT(it + 1 == tokens->end()); |
| 564 // There should never be any chunks after the EOF. | 573 // There should never be any chunks after the EOF. |
| 565 ASSERT(m_speculations.isEmpty()); | 574 ASSERT(m_speculations.isEmpty()); |
| 566 prepareToStopParsing(); | 575 prepareToStopParsing(); |
| 567 break; | 576 break; |
| 568 } | 577 } |
| 569 | 578 |
| 570 ASSERT(!m_tokenizer); | 579 ASSERT(!m_tokenizer); |
| 571 ASSERT(!m_token); | 580 ASSERT(!m_token); |
| 572 } | 581 } |
| 573 | 582 |
| 574 // Make sure all required pending text nodes are emitted before returning. | 583 // Make sure all required pending text nodes are emitted before returning. |
| 575 // This leaves "script", "style" and "svg" nodes text nodes intact. | 584 // This leaves "script", "style" and "svg" nodes text nodes intact. |
| 576 if (!isStopped()) | 585 if (!isStopped()) |
| 577 m_treeBuilder->flush(FlushIfAtTextLimit); | 586 m_treeBuilder->flush(FlushIfAtTextLimit); |
| 578 | 587 |
| 579 m_isParsingAtLineNumber = false; | 588 m_isParsingAtLineNumber = false; |
| 580 | 589 |
| 581 return elementTokenCount; | 590 return elementTokenCount; |
| 582 } | 591 } |
| 583 | 592 |
| 584 void HTMLDocumentParser::pumpPendingSpeculations() { | 593 void HTMLDocumentParser::pumpPendingSpeculations() { |
| 585 // If this assert fails, you need to call validateSpeculations to make sure | 594 // 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. | 595 // m_tokenizer and m_token don't have state that invalidates m_speculations. |
| 587 ASSERT(!m_tokenizer); | 596 ASSERT(!m_tokenizer); |
| 588 ASSERT(!m_token); | 597 ASSERT(!m_token); |
| 589 ASSERT(!m_lastChunkBeforeScript); | 598 DCHECK(!m_lastChunkBeforePause); |
| 590 ASSERT(!isWaitingForScripts()); | 599 ASSERT(!isWaitingForScripts()); |
| 591 ASSERT(!isStopped()); | 600 ASSERT(!isStopped()); |
| 592 ASSERT(!isScheduledForResume()); | 601 ASSERT(!isScheduledForResume()); |
| 593 ASSERT(!inPumpSession()); | 602 ASSERT(!inPumpSession()); |
| 603 DCHECK(!m_isWaitingForStylesheets); | |
| 594 | 604 |
| 595 // FIXME: Here should never be reached when there is a blocking script, | 605 // FIXME: Here should never be reached when there is a blocking script, |
| 596 // but it happens in unknown scenarios. See https://crbug.com/440901 | 606 // but it happens in unknown scenarios. See https://crbug.com/440901 |
| 597 if (isWaitingForScripts()) { | 607 if (isWaitingForScripts()) { |
| 598 m_parserScheduler->scheduleForResume(); | 608 m_parserScheduler->scheduleForResume(); |
| 599 return; | 609 return; |
| 600 } | 610 } |
| 601 | 611 |
| 602 // Do not allow pumping speculations in nested event loops. | 612 // Do not allow pumping speculations in nested event loops. |
| 603 if (m_pumpSpeculationsSessionNestingLevel) { | 613 if (m_pumpSpeculationsSessionNestingLevel) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 614 while (!m_speculations.isEmpty()) { | 624 while (!m_speculations.isEmpty()) { |
| 615 ASSERT(!isScheduledForResume()); | 625 ASSERT(!isScheduledForResume()); |
| 616 size_t elementTokenCount = | 626 size_t elementTokenCount = |
| 617 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); | 627 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); |
| 618 session.addedElementTokens(elementTokenCount); | 628 session.addedElementTokens(elementTokenCount); |
| 619 | 629 |
| 620 // Always check isParsing first as m_document may be null. Surprisingly, | 630 // Always check isParsing first as m_document may be null. Surprisingly, |
| 621 // isScheduledForResume() may be set here as a result of | 631 // isScheduledForResume() may be set here as a result of |
| 622 // processTokenizedChunkFromBackgroundParser running arbitrary javascript | 632 // processTokenizedChunkFromBackgroundParser running arbitrary javascript |
| 623 // which invokes nested event loops. (e.g. inspector breakpoints) | 633 // which invokes nested event loops. (e.g. inspector breakpoints) |
| 624 if (!isParsing() || isWaitingForScripts() || isScheduledForResume()) | 634 if (!isParsing() || isWaitingForScripts() || isScheduledForResume() || |
| 635 m_isWaitingForStylesheets) | |
| 625 break; | 636 break; |
| 626 | 637 |
| 627 if (m_speculations.isEmpty() || | 638 if (m_speculations.isEmpty() || |
| 628 m_parserScheduler->yieldIfNeeded( | 639 m_parserScheduler->yieldIfNeeded( |
| 629 session, m_speculations.first()->startingScript)) | 640 session, m_speculations.first()->startingScript)) |
| 630 break; | 641 break; |
| 631 } | 642 } |
| 632 | 643 |
| 633 TRACE_EVENT_END1( | 644 TRACE_EVENT_END1( |
| 634 "devtools.timeline", "ParseHTML", "endData", | 645 "devtools.timeline", "ParseHTML", "endData", |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 702 } | 713 } |
| 703 | 714 |
| 704 if (isStopped()) | 715 if (isStopped()) |
| 705 return; | 716 return; |
| 706 | 717 |
| 707 // There should only be PendingText left since the tree-builder always flushes | 718 // There should only be PendingText left since the tree-builder always flushes |
| 708 // the task queue before returning. In case that ever changes, crash. | 719 // the task queue before returning. In case that ever changes, crash. |
| 709 m_treeBuilder->flush(FlushAlways); | 720 m_treeBuilder->flush(FlushAlways); |
| 710 RELEASE_ASSERT(!isStopped()); | 721 RELEASE_ASSERT(!isStopped()); |
| 711 | 722 |
| 712 if (isWaitingForScripts()) { | 723 if (isWaitingForScripts() || m_isWaitingForStylesheets) { |
| 713 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); | 724 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); |
| 714 | 725 |
| 715 ASSERT(m_preloader); | 726 ASSERT(m_preloader); |
| 716 // TODO(kouhei): m_preloader should be always available for synchronous | 727 // TODO(kouhei): m_preloader should be always available for synchronous |
| 717 // parsing case, adding paranoia if for speculative crash fix for | 728 // parsing case, adding paranoia if for speculative crash fix for |
| 718 // crbug.com/465478 | 729 // crbug.com/465478 |
| 719 if (m_preloader) { | 730 if (m_preloader && document()->url().isValid()) { |
| 720 if (!m_preloadScanner) { | 731 if (!m_preloadScanner) { |
| 721 m_preloadScanner = createPreloadScanner(); | 732 m_preloadScanner = createPreloadScanner(); |
| 722 m_preloadScanner->appendToEnd(m_input.current()); | 733 m_preloadScanner->appendToEnd(m_input.current()); |
| 723 } | 734 } |
| 724 scanAndPreload(m_preloadScanner.get()); | 735 scanAndPreload(m_preloadScanner.get()); |
| 725 } | 736 } |
| 726 } | 737 } |
| 727 | 738 |
| 728 TRACE_EVENT_END1("devtools.timeline", "ParseHTML", "endData", | 739 TRACE_EVENT_END1("devtools.timeline", "ParseHTML", "endData", |
| 729 InspectorParseHtmlEvent::endData( | 740 InspectorParseHtmlEvent::endData( |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 741 // the parser. | 752 // the parser. |
| 742 // | 753 // |
| 743 // FIXME: Stop clearing the m_token once we start running the parser off | 754 // FIXME: Stop clearing the m_token once we start running the parser off |
| 744 // the main thread or once we stop allowing synchronous JavaScript | 755 // the main thread or once we stop allowing synchronous JavaScript |
| 745 // execution from parseAttribute. | 756 // execution from parseAttribute. |
| 746 if (token().type() != HTMLToken::Character) | 757 if (token().type() != HTMLToken::Character) |
| 747 token().clear(); | 758 token().clear(); |
| 748 | 759 |
| 749 m_treeBuilder->constructTree(&atomicToken); | 760 m_treeBuilder->constructTree(&atomicToken); |
| 750 | 761 |
| 762 if (m_addedPendingStylesheetInBody) | |
| 763 m_isWaitingForStylesheets = true; | |
| 764 | |
| 751 // FIXME: constructTree may synchronously cause Document to be detached. | 765 // FIXME: constructTree may synchronously cause Document to be detached. |
| 752 if (!m_token) | 766 if (!m_token) |
| 753 return; | 767 return; |
| 754 | 768 |
| 755 if (!token().isUninitialized()) { | 769 if (!token().isUninitialized()) { |
| 756 ASSERT(token().type() == HTMLToken::Character); | 770 ASSERT(token().type() == HTMLToken::Character); |
| 757 token().clear(); | 771 token().clear(); |
| 758 } | 772 } |
| 759 } | 773 } |
| 760 | 774 |
| 761 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( | 775 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( |
| 762 const CompactHTMLToken& compactToken) { | 776 const CompactHTMLToken& compactToken) { |
| 763 AtomicHTMLToken token(compactToken); | 777 AtomicHTMLToken token(compactToken); |
| 764 m_treeBuilder->constructTree(&token); | 778 m_treeBuilder->constructTree(&token); |
| 779 if (m_addedPendingStylesheetInBody) | |
| 780 m_isWaitingForStylesheets = true; | |
| 765 } | 781 } |
| 766 | 782 |
| 767 bool HTMLDocumentParser::hasInsertionPoint() { | 783 bool HTMLDocumentParser::hasInsertionPoint() { |
| 768 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our | 784 // 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 | 785 // 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 | 786 // because our treatment is uniform between network-sourced and script-sourced |
| 771 // input streams whereas the spec treats them differently. | 787 // input streams whereas the spec treats them differently. |
| 772 return m_input.hasInsertionPoint() || | 788 return m_input.hasInsertionPoint() || |
| 773 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); | 789 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); |
| 774 } | 790 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 785 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); | 801 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); |
| 786 m_token = WTF::wrapUnique(new HTMLToken); | 802 m_token = WTF::wrapUnique(new HTMLToken); |
| 787 m_tokenizer = HTMLTokenizer::create(m_options); | 803 m_tokenizer = HTMLTokenizer::create(m_options); |
| 788 } | 804 } |
| 789 | 805 |
| 790 SegmentedString excludedLineNumberSource(source); | 806 SegmentedString excludedLineNumberSource(source); |
| 791 excludedLineNumberSource.setExcludeLineNumbers(); | 807 excludedLineNumberSource.setExcludeLineNumbers(); |
| 792 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); | 808 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); |
| 793 pumpTokenizerIfPossible(); | 809 pumpTokenizerIfPossible(); |
| 794 | 810 |
| 795 if (isWaitingForScripts()) { | 811 if (isWaitingForScripts() || m_isWaitingForStylesheets) { |
| 796 // Check the document.write() output with a separate preload scanner as | 812 if (document()->url().isValid()) { |
| 797 // the main scanner can't deal with insertions. | 813 // Check the document.write() output with a separate preload scanner as |
| 798 if (!m_insertionPreloadScanner) | 814 // the main scanner can't deal with insertions. |
| 799 m_insertionPreloadScanner = createPreloadScanner(); | 815 if (!m_insertionPreloadScanner) |
| 800 m_insertionPreloadScanner->appendToEnd(source); | 816 m_insertionPreloadScanner = createPreloadScanner(); |
| 801 scanAndPreload(m_insertionPreloadScanner.get()); | 817 m_insertionPreloadScanner->appendToEnd(source); |
| 818 scanAndPreload(m_insertionPreloadScanner.get()); | |
| 819 } | |
| 802 } | 820 } |
| 803 | 821 |
| 804 endIfDelayed(); | 822 endIfDelayed(); |
| 805 } | 823 } |
| 806 | 824 |
| 807 void HTMLDocumentParser::startBackgroundParser() { | 825 void HTMLDocumentParser::startBackgroundParser() { |
| 808 ASSERT(!isStopped()); | 826 ASSERT(!isStopped()); |
| 809 ASSERT(shouldUseThreading()); | 827 ASSERT(shouldUseThreading()); |
| 810 ASSERT(!m_haveBackgroundParser); | 828 ASSERT(!m_haveBackgroundParser); |
| 811 ASSERT(document()); | 829 ASSERT(document()); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 881 | 899 |
| 882 // We should never reach this point if we're using a parser thread, as | 900 // We should never reach this point if we're using a parser thread, as |
| 883 // appendBytes() will directly ship the data to the thread. | 901 // appendBytes() will directly ship the data to the thread. |
| 884 ASSERT(!shouldUseThreading()); | 902 ASSERT(!shouldUseThreading()); |
| 885 | 903 |
| 886 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), | 904 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), |
| 887 "HTMLDocumentParser::append", "size", inputSource.length()); | 905 "HTMLDocumentParser::append", "size", inputSource.length()); |
| 888 const SegmentedString source(inputSource); | 906 const SegmentedString source(inputSource); |
| 889 | 907 |
| 890 if (document()->isPrefetchOnly()) { | 908 if (document()->isPrefetchOnly()) { |
| 891 if (!m_preloadScanner) | 909 if (document()->url().isValid()) { |
| 892 m_preloadScanner = createPreloadScanner(); | 910 if (!m_preloadScanner) |
| 911 m_preloadScanner = createPreloadScanner(); | |
| 893 | 912 |
| 894 m_preloadScanner->appendToEnd(source); | 913 m_preloadScanner->appendToEnd(source); |
| 895 scanAndPreload(m_preloadScanner.get()); | 914 scanAndPreload(m_preloadScanner.get()); |
| 915 } | |
| 896 | 916 |
| 897 // Return after the preload scanner, do not actually parse the document. | 917 // Return after the preload scanner, do not actually parse the document. |
| 898 return; | 918 return; |
| 899 } | 919 } |
| 900 | 920 |
| 901 if (m_preloadScanner) { | 921 if (m_preloadScanner) { |
| 902 if (m_input.current().isEmpty() && !isWaitingForScripts()) { | 922 if (m_input.current().isEmpty() && !isWaitingForScripts() && |
| 923 !m_isWaitingForStylesheets) { | |
| 903 // We have parsed until the end of the current input and so are now moving | 924 // We have parsed until the end of the current input and so are now moving |
| 904 // ahead of the preload scanner. Clear the scanner so we know to scan | 925 // ahead of the preload scanner. Clear the scanner so we know to scan |
| 905 // starting from the current input point if we block again. | 926 // starting from the current input point if we block again. |
| 906 m_preloadScanner.reset(); | 927 m_preloadScanner.reset(); |
| 907 } else { | 928 } else { |
| 908 m_preloadScanner->appendToEnd(source); | 929 m_preloadScanner->appendToEnd(source); |
| 909 if (isWaitingForScripts()) | 930 if (isWaitingForScripts() || m_isWaitingForStylesheets) |
| 910 scanAndPreload(m_preloadScanner.get()); | 931 scanAndPreload(m_preloadScanner.get()); |
| 911 } | 932 } |
| 912 } | 933 } |
| 913 | 934 |
| 914 m_input.appendToEnd(source); | 935 m_input.appendToEnd(source); |
| 915 | 936 |
| 916 if (inPumpSession()) { | 937 if (inPumpSession()) { |
| 917 // We've gotten data off the network in a nested write. We don't want to | 938 // We've gotten data off the network in a nested write. We don't want to |
| 918 // consume any more of the input stream now. Do not worry. We'll consume | 939 // consume any more of the input stream now. Do not worry. We'll consume |
| 919 // this data in a less-nested write(). | 940 // this data in a less-nested write(). |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1050 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); | 1071 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); |
| 1051 // Since the parser is paused while a script runner has a blocking script, it | 1072 // Since the parser is paused while a script runner has a blocking script, it |
| 1052 // should never be possible to end up with both objects holding a blocking | 1073 // should never be possible to end up with both objects holding a blocking |
| 1053 // script. | 1074 // script. |
| 1054 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); | 1075 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); |
| 1055 // If either object has a blocking script, the parser should be paused. | 1076 // If either object has a blocking script, the parser should be paused. |
| 1056 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || | 1077 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || |
| 1057 m_reentryPermit->parserPauseFlag(); | 1078 m_reentryPermit->parserPauseFlag(); |
| 1058 } | 1079 } |
| 1059 | 1080 |
| 1060 void HTMLDocumentParser::resumeParsingAfterScriptExecution() { | 1081 void HTMLDocumentParser::resumeParsingAfterPause() { |
| 1061 ASSERT(!isExecutingScript()); | 1082 ASSERT(!isExecutingScript()); |
| 1062 ASSERT(!isWaitingForScripts()); | 1083 ASSERT(!isWaitingForScripts()); |
| 1084 DCHECK(!m_isWaitingForStylesheets); | |
| 1063 | 1085 |
| 1064 if (m_haveBackgroundParser) { | 1086 if (m_haveBackgroundParser) { |
| 1065 if (m_lastChunkBeforeScript) { | 1087 if (m_lastChunkBeforePause) { |
| 1066 validateSpeculations(std::move(m_lastChunkBeforeScript)); | 1088 validateSpeculations(std::move(m_lastChunkBeforePause)); |
| 1067 DCHECK(!m_lastChunkBeforeScript); | 1089 DCHECK(!m_lastChunkBeforePause); |
| 1068 pumpPendingSpeculations(); | 1090 pumpPendingSpeculations(); |
| 1069 } | 1091 } |
| 1070 return; | 1092 return; |
| 1071 } | 1093 } |
| 1072 | 1094 |
| 1073 m_insertionPreloadScanner.reset(); | 1095 m_insertionPreloadScanner.reset(); |
| 1074 if (m_tokenizer) { | 1096 if (m_tokenizer) { |
| 1075 pumpTokenizerIfPossible(); | 1097 pumpTokenizerIfPossible(); |
| 1076 } | 1098 } |
| 1077 endIfDelayed(); | 1099 endIfDelayed(); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1090 if (isStopped()) { | 1112 if (isStopped()) { |
| 1091 return; | 1113 return; |
| 1092 } | 1114 } |
| 1093 | 1115 |
| 1094 if (isStopping()) { | 1116 if (isStopping()) { |
| 1095 attemptToRunDeferredScriptsAndEnd(); | 1117 attemptToRunDeferredScriptsAndEnd(); |
| 1096 return; | 1118 return; |
| 1097 } | 1119 } |
| 1098 | 1120 |
| 1099 m_scriptRunner->executeScriptsWaitingForLoad(pendingScript); | 1121 m_scriptRunner->executeScriptsWaitingForLoad(pendingScript); |
| 1100 if (!isWaitingForScripts()) | 1122 if (!isWaitingForScripts() && !m_isWaitingForStylesheets) |
| 1101 resumeParsingAfterScriptExecution(); | 1123 resumeParsingAfterPause(); |
| 1102 } | 1124 } |
| 1103 | 1125 |
| 1104 void HTMLDocumentParser::executeScriptsWaitingForResources() { | 1126 void HTMLDocumentParser::executeScriptsWaitingForResources() { |
| 1105 DCHECK(document()->isScriptExecutionReady()); | 1127 DCHECK(document()->isScriptExecutionReady()); |
| 1106 | 1128 |
| 1107 // 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 |
| 1108 // will not be called in the DocumentFragment case. | 1130 // will not be called in the DocumentFragment case. |
| 1109 DCHECK(m_scriptRunner); | 1131 DCHECK(m_scriptRunner); |
| 1110 m_scriptRunner->executeScriptsWaitingForResources(); | 1132 m_scriptRunner->executeScriptsWaitingForResources(); |
| 1111 if (!isWaitingForScripts()) | 1133 if (!isWaitingForScripts() && !m_isWaitingForStylesheets) |
| 1112 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 m_addedPendingStylesheetInBody = false; | |
| 1150 if (m_isWaitingForStylesheets) { | |
| 1151 m_isWaitingForStylesheets = false; | |
| 1152 if (!isWaitingForScripts()) { | |
| 1153 // Post an async task to resume parsing since this can (and often is) | |
| 1154 // called while already parsing. | |
| 1155 m_resumeParsingTaskHandle = | |
| 1156 TaskRunnerHelper::get(TaskType::Networking, document()) | |
| 1157 ->postCancellableTask( | |
| 1158 BLINK_FROM_HERE, | |
| 1159 WTF::bind(&HTMLDocumentParser::resumeParsingAfterPause, | |
| 1160 wrapWeakPersistent(this))); | |
| 1161 } | |
| 1162 } | |
| 1113 } | 1163 } |
| 1114 | 1164 |
| 1115 void HTMLDocumentParser::parseDocumentFragment( | 1165 void HTMLDocumentParser::parseDocumentFragment( |
| 1116 const String& source, | 1166 const String& source, |
| 1117 DocumentFragment* fragment, | 1167 DocumentFragment* fragment, |
| 1118 Element* contextElement, | 1168 Element* contextElement, |
| 1119 ParserContentPolicy parserContentPolicy) { | 1169 ParserContentPolicy parserContentPolicy) { |
| 1120 HTMLDocumentParser* parser = | 1170 HTMLDocumentParser* parser = |
| 1121 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); | 1171 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); |
| 1122 parser->append(source); | 1172 parser->append(source); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1250 bool neededInitialization = m_evaluator->ensureEvaluationContext(); | 1300 bool neededInitialization = m_evaluator->ensureEvaluationContext(); |
| 1251 double initializationDuration = | 1301 double initializationDuration = |
| 1252 monotonicallyIncreasingTimeMS() - initializeStartTime; | 1302 monotonicallyIncreasingTimeMS() - initializeStartTime; |
| 1253 | 1303 |
| 1254 double startTime = monotonicallyIncreasingTimeMS(); | 1304 double startTime = monotonicallyIncreasingTimeMS(); |
| 1255 String writtenSource = m_evaluator->evaluateAndEmitWrittenSource(source); | 1305 String writtenSource = m_evaluator->evaluateAndEmitWrittenSource(source); |
| 1256 double duration = monotonicallyIncreasingTimeMS() - startTime; | 1306 double duration = monotonicallyIncreasingTimeMS() - startTime; |
| 1257 | 1307 |
| 1258 int currentPreloadCount = document()->loader()->fetcher()->countPreloads(); | 1308 int currentPreloadCount = document()->loader()->fetcher()->countPreloads(); |
| 1259 | 1309 |
| 1260 std::unique_ptr<HTMLPreloadScanner> scanner = createPreloadScanner(); | 1310 if (document()->url().isValid()) { |
|
kouhei (in TOK)
2017/01/06 03:32:43
Would you describe your change here?
Pat Meenan
2017/01/09 16:37:05
Sorry, left-over from some earlier iterations and
| |
| 1261 scanner->appendToEnd(SegmentedString(writtenSource)); | 1311 std::unique_ptr<HTMLPreloadScanner> scanner = createPreloadScanner(); |
| 1262 scanAndPreload(scanner.get()); | 1312 scanner->appendToEnd(SegmentedString(writtenSource)); |
| 1313 scanAndPreload(scanner.get()); | |
| 1314 } | |
| 1263 | 1315 |
| 1264 int numPreloads = | 1316 int numPreloads = |
| 1265 document()->loader()->fetcher()->countPreloads() - currentPreloadCount; | 1317 document()->loader()->fetcher()->countPreloads() - currentPreloadCount; |
| 1266 | 1318 |
| 1267 TRACE_EVENT_INSTANT2( | 1319 TRACE_EVENT_INSTANT2( |
| 1268 "blink", | 1320 "blink", |
| 1269 "HTMLDocumentParser::evaluateAndPreloadScriptForDocumentWrite.data", | 1321 "HTMLDocumentParser::evaluateAndPreloadScriptForDocumentWrite.data", |
| 1270 TRACE_EVENT_SCOPE_THREAD, "numPreloads", numPreloads, "scriptLength", | 1322 TRACE_EVENT_SCOPE_THREAD, "numPreloads", numPreloads, "scriptLength", |
| 1271 source.length()); | 1323 source.length()); |
| 1272 | 1324 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1310 case Asynchronous: | 1362 case Asynchronous: |
| 1311 m_loadingTaskRunner->postTask( | 1363 m_loadingTaskRunner->postTask( |
| 1312 BLINK_FROM_HERE, | 1364 BLINK_FROM_HERE, |
| 1313 WTF::bind(function, std::forward<Ps>(parameters)...)); | 1365 WTF::bind(function, std::forward<Ps>(parameters)...)); |
| 1314 return; | 1366 return; |
| 1315 } | 1367 } |
| 1316 NOTREACHED(); | 1368 NOTREACHED(); |
| 1317 } | 1369 } |
| 1318 | 1370 |
| 1319 } // namespace blink | 1371 } // namespace blink |
| OLD | NEW |