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 |