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

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: Fixed interaction with imports 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() || 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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698