Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp

Issue 2614663004: Pause HTML parser for external stylesheets in the body (Closed)
Patch Set: merge to trunk Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698