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

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: Paramaterized test cases 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 checkIfBodyStlyesheetAdded();
262 if (isStopped() || isPaused())
260 return; 263 return;
261 264
262 pumpTokenizer(); 265 pumpTokenizer();
263 } 266 }
264 267
265 bool HTMLDocumentParser::isScheduledForResume() const { 268 bool HTMLDocumentParser::isScheduledForResume() const {
266 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); 269 return m_parserScheduler && m_parserScheduler->isScheduledForResume();
267 } 270 }
268 271
269 // Used by HTMLParserScheduler 272 // Used by HTMLParserScheduler
270 void HTMLDocumentParser::resumeParsingAfterYield() { 273 void HTMLDocumentParser::resumeParsingAfterYield() {
271 ASSERT(shouldUseThreading()); 274 ASSERT(shouldUseThreading());
272 ASSERT(m_haveBackgroundParser); 275 ASSERT(m_haveBackgroundParser);
273 276
277 checkIfBodyStlyesheetAdded();
278 if (isStopped() || isPaused())
279 return;
280
274 pumpPendingSpeculations(); 281 pumpPendingSpeculations();
275 } 282 }
276 283
277 void HTMLDocumentParser::runScriptsForPausedTreeBuilder() { 284 void HTMLDocumentParser::runScriptsForPausedTreeBuilder() {
278 ASSERT(scriptingContentIsAllowed(getParserContentPolicy())); 285 ASSERT(scriptingContentIsAllowed(getParserContentPolicy()));
279 286
280 TextPosition scriptStartPosition = TextPosition::belowRangePosition(); 287 TextPosition scriptStartPosition = TextPosition::belowRangePosition();
281 Element* scriptElement = 288 Element* scriptElement =
282 m_treeBuilder->takeScriptToProcess(scriptStartPosition); 289 m_treeBuilder->takeScriptToProcess(scriptStartPosition);
283 // We will not have a scriptRunner when parsing a DocumentFragment. 290 // We will not have a scriptRunner when parsing a DocumentFragment.
284 if (m_scriptRunner) 291 if (m_scriptRunner)
285 m_scriptRunner->processScriptElement(scriptElement, scriptStartPosition); 292 m_scriptRunner->processScriptElement(scriptElement, scriptStartPosition);
293 checkIfBodyStlyesheetAdded();
286 } 294 }
287 295
288 bool HTMLDocumentParser::canTakeNextToken() { 296 bool HTMLDocumentParser::canTakeNextToken() {
289 if (isStopped()) 297 if (isStopped())
290 return false; 298 return false;
291 299
292 // If we're paused waiting for a script, we try to execute scripts before 300 // If we're paused waiting for a script, we try to execute scripts before
293 // continuing. 301 // continuing.
294 if (m_treeBuilder->hasParserBlockingScript()) 302 if (m_treeBuilder->hasParserBlockingScript())
295 runScriptsForPausedTreeBuilder(); 303 runScriptsForPausedTreeBuilder();
296 if (isStopped() || isWaitingForScripts()) 304 if (isStopped() || isPaused())
297 return false; 305 return false;
298 306
299 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the 307 // 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 308 // LocalFrame, but this approach is how the old parser handled stopping when
301 // the page assigns window.location. What really should happen is that 309 // the page assigns window.location. What really should happen is that
302 // assigning window.location causes the parser to stop parsing cleanly. The 310 // 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 311 // problem is we're not perpared to do that at every point where we run
304 // JavaScript. 312 // JavaScript.
305 if (!isParsingFragment() && document()->frame() && 313 if (!isParsingFragment() && document()->frame() &&
306 document()->frame()->navigationScheduler().locationChangePending()) 314 document()->frame()->navigationScheduler().locationChangePending())
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 const CompactHTMLToken& token = chunk->tokens->at(index); 382 const CompactHTMLToken& token = chunk->tokens->at(index);
375 ASSERT(token.type() == HTMLToken::TokenType::Character); 383 ASSERT(token.type() == HTMLToken::TokenType::Character);
376 evaluateAndPreloadScriptForDocumentWrite(token.data()); 384 evaluateAndPreloadScriptForDocumentWrite(token.data());
377 } 385 }
378 } 386 }
379 } 387 }
380 388
381 for (auto& chunk : pendingChunks) 389 for (auto& chunk : pendingChunks)
382 m_speculations.append(std::move(chunk)); 390 m_speculations.append(std::move(chunk));
383 391
384 if (!isWaitingForScripts() && !isScheduledForResume()) { 392 if (!isPaused() && !isScheduledForResume()) {
385 if (m_tasksWereSuspended) 393 if (m_tasksWereSuspended)
386 m_parserScheduler->forceResumeAfterYield(); 394 m_parserScheduler->forceResumeAfterYield();
387 else 395 else
388 m_parserScheduler->scheduleForResume(); 396 m_parserScheduler->scheduleForResume();
389 } 397 }
390 } 398 }
391 399
392 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( 400 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser(
393 const DocumentEncodingData& data) { 401 const DocumentEncodingData& data) {
394 document()->setEncodingData(data); 402 document()->setEncodingData(data);
395 } 403 }
396 404
397 void HTMLDocumentParser::validateSpeculations( 405 void HTMLDocumentParser::validateSpeculations(
398 std::unique_ptr<TokenizedChunk> chunk) { 406 std::unique_ptr<TokenizedChunk> chunk) {
399 ASSERT(chunk); 407 ASSERT(chunk);
400 // TODO(kouhei): We should simplify codepath here by disallowing 408 // TODO(kouhei): We should simplify codepath here by disallowing
401 // validateSpeculations 409 // validateSpeculations
402 // while isWaitingForScripts, and m_lastChunkBeforeScript can simply be 410 // while isPaused, and m_lastChunkBeforePause can simply be
403 // pushed to m_speculations. 411 // pushed to m_speculations.
404 if (isWaitingForScripts()) { 412 if (isPaused()) {
405 // We're waiting on a network script, just save the chunk, we'll get a 413 // We're waiting on a network script or stylesheet, just save the chunk,
406 // second validateSpeculations call after the script completes. This call 414 // we'll get a second validateSpeculations call after the script or
407 // should have been made immediately after runScriptsForPausedTreeBuilder 415 // stylesheet completes. This call should have been made immediately after
408 // which may have started a network load and left us waiting. 416 // runScriptsForPausedTreeBuilder in the script case which may have started
409 ASSERT(!m_lastChunkBeforeScript); 417 // a network load and left us waiting.
410 m_lastChunkBeforeScript = std::move(chunk); 418 DCHECK(!m_lastChunkBeforePause);
419 m_lastChunkBeforePause = std::move(chunk);
411 return; 420 return;
412 } 421 }
413 422
414 ASSERT(!m_lastChunkBeforeScript); 423 DCHECK(!m_lastChunkBeforePause);
415 std::unique_ptr<HTMLTokenizer> tokenizer = std::move(m_tokenizer); 424 std::unique_ptr<HTMLTokenizer> tokenizer = std::move(m_tokenizer);
416 std::unique_ptr<HTMLToken> token = std::move(m_token); 425 std::unique_ptr<HTMLToken> token = std::move(m_token);
417 426
418 if (!tokenizer) { 427 if (!tokenizer) {
419 // There must not have been any changes to the HTMLTokenizer state on the 428 // There must not have been any changes to the HTMLTokenizer state on the
420 // main thread, which means the speculation buffer is correct. 429 // main thread, which means the speculation buffer is correct.
421 return; 430 return;
422 } 431 }
423 432
424 // Currently we're only smart enough to reuse the speculation buffer if the 433 // 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) { 490 std::unique_ptr<TokenizedChunk> popChunk) {
482 TRACE_EVENT_WITH_FLOW0( 491 TRACE_EVENT_WITH_FLOW0(
483 "blink,loading", 492 "blink,loading",
484 "HTMLDocumentParser::processTokenizedChunkFromBackgroundParser", 493 "HTMLDocumentParser::processTokenizedChunkFromBackgroundParser",
485 popChunk.get(), TRACE_EVENT_FLAG_FLOW_IN); 494 popChunk.get(), TRACE_EVENT_FLAG_FLOW_IN);
486 AutoReset<bool> hasLineNumber(&m_isParsingAtLineNumber, true); 495 AutoReset<bool> hasLineNumber(&m_isParsingAtLineNumber, true);
487 496
488 SECURITY_DCHECK(m_pumpSpeculationsSessionNestingLevel == 1); 497 SECURITY_DCHECK(m_pumpSpeculationsSessionNestingLevel == 1);
489 SECURITY_DCHECK(!inPumpSession()); 498 SECURITY_DCHECK(!inPumpSession());
490 ASSERT(!isParsingFragment()); 499 ASSERT(!isParsingFragment());
491 ASSERT(!isWaitingForScripts()); 500 DCHECK(!isPaused());
492 ASSERT(!isStopped()); 501 ASSERT(!isStopped());
493 ASSERT(shouldUseThreading()); 502 ASSERT(shouldUseThreading());
494 ASSERT(!m_tokenizer); 503 ASSERT(!m_tokenizer);
495 ASSERT(!m_token); 504 ASSERT(!m_token);
496 ASSERT(!m_lastChunkBeforeScript); 505 DCHECK(!m_lastChunkBeforePause);
497 506
498 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); 507 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk));
499 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); 508 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens);
500 size_t elementTokenCount = 0; 509 size_t elementTokenCount = 0;
501 510
502 postTaskToLookaheadParser(Asynchronous, 511 postTaskToLookaheadParser(Asynchronous,
503 &BackgroundHTMLParser::startedChunkWithCheckpoint, 512 &BackgroundHTMLParser::startedChunkWithCheckpoint,
504 m_backgroundParser, chunk->inputCheckpoint); 513 m_backgroundParser, chunk->inputCheckpoint);
505 514
506 for (const auto& xssInfo : chunk->xssInfos) { 515 for (const auto& xssInfo : chunk->xssInfos) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
543 if (isStopped()) 552 if (isStopped())
544 break; 553 break;
545 554
546 // Preloads were queued if there was a <meta> csp token in a tokenized 555 // Preloads were queued if there was a <meta> csp token in a tokenized
547 // chunk. 556 // chunk.
548 if (m_pendingCSPMetaToken && it == m_pendingCSPMetaToken) { 557 if (m_pendingCSPMetaToken && it == m_pendingCSPMetaToken) {
549 m_pendingCSPMetaToken = nullptr; 558 m_pendingCSPMetaToken = nullptr;
550 fetchQueuedPreloads(); 559 fetchQueuedPreloads();
551 } 560 }
552 561
553 if (isWaitingForScripts()) { 562 if (isPaused()) {
554 // The </script> is assumed to be the last token of this bunch. 563 // The script or stylesheet should be the last token of this bunch.
555 ASSERT(it + 1 == tokens->end()); 564 ASSERT(it + 1 == tokens->end());
556 runScriptsForPausedTreeBuilder(); 565 if (isWaitingForScripts())
566 runScriptsForPausedTreeBuilder();
557 validateSpeculations(std::move(chunk)); 567 validateSpeculations(std::move(chunk));
558 break; 568 break;
559 } 569 }
560 570
561 if (it->type() == HTMLToken::EndOfFile) { 571 if (it->type() == HTMLToken::EndOfFile) {
562 // The EOF is assumed to be the last token of this bunch. 572 // The EOF is assumed to be the last token of this bunch.
563 ASSERT(it + 1 == tokens->end()); 573 ASSERT(it + 1 == tokens->end());
564 // There should never be any chunks after the EOF. 574 // There should never be any chunks after the EOF.
565 ASSERT(m_speculations.isEmpty()); 575 ASSERT(m_speculations.isEmpty());
566 prepareToStopParsing(); 576 prepareToStopParsing();
(...skipping 12 matching lines...) Expand all
579 m_isParsingAtLineNumber = false; 589 m_isParsingAtLineNumber = false;
580 590
581 return elementTokenCount; 591 return elementTokenCount;
582 } 592 }
583 593
584 void HTMLDocumentParser::pumpPendingSpeculations() { 594 void HTMLDocumentParser::pumpPendingSpeculations() {
585 // If this assert fails, you need to call validateSpeculations to make sure 595 // 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. 596 // m_tokenizer and m_token don't have state that invalidates m_speculations.
587 ASSERT(!m_tokenizer); 597 ASSERT(!m_tokenizer);
588 ASSERT(!m_token); 598 ASSERT(!m_token);
589 ASSERT(!m_lastChunkBeforeScript); 599 DCHECK(!m_lastChunkBeforePause);
590 ASSERT(!isWaitingForScripts()); 600 DCHECK(!isPaused());
591 ASSERT(!isStopped()); 601 ASSERT(!isStopped());
592 ASSERT(!isScheduledForResume()); 602 ASSERT(!isScheduledForResume());
593 ASSERT(!inPumpSession()); 603 ASSERT(!inPumpSession());
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 }
(...skipping 13 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 checkIfBodyStlyesheetAdded();
635 if (!isParsing() || isPaused() || isScheduledForResume())
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 (isPaused()) {
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) {
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());
(...skipping 17 matching lines...) Expand all
740 // HTMLToken. Fortunately, Character tokens can't cause us to re-enter 751 // HTMLToken. Fortunately, Character tokens can't cause us to re-enter
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);
761 checkIfBodyStlyesheetAdded();
750 762
751 // FIXME: constructTree may synchronously cause Document to be detached. 763 // FIXME: constructTree may synchronously cause Document to be detached.
752 if (!m_token) 764 if (!m_token)
753 return; 765 return;
754 766
755 if (!token().isUninitialized()) { 767 if (!token().isUninitialized()) {
756 ASSERT(token().type() == HTMLToken::Character); 768 ASSERT(token().type() == HTMLToken::Character);
757 token().clear(); 769 token().clear();
758 } 770 }
759 } 771 }
760 772
761 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( 773 void HTMLDocumentParser::constructTreeFromCompactHTMLToken(
762 const CompactHTMLToken& compactToken) { 774 const CompactHTMLToken& compactToken) {
763 AtomicHTMLToken token(compactToken); 775 AtomicHTMLToken token(compactToken);
764 m_treeBuilder->constructTree(&token); 776 m_treeBuilder->constructTree(&token);
777 checkIfBodyStlyesheetAdded();
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());
1082
1083 checkIfBodyStlyesheetAdded();
1084 if (isPaused())
1085 return;
1069 1086
1070 if (m_haveBackgroundParser) { 1087 if (m_haveBackgroundParser) {
1071 if (m_lastChunkBeforeScript) { 1088 if (m_lastChunkBeforePause) {
1072 validateSpeculations(std::move(m_lastChunkBeforeScript)); 1089 validateSpeculations(std::move(m_lastChunkBeforePause));
1073 DCHECK(!m_lastChunkBeforeScript); 1090 DCHECK(!m_lastChunkBeforePause);
1074 pumpPendingSpeculations(); 1091 pumpPendingSpeculations();
1075 } 1092 }
1076 return; 1093 return;
1077 } 1094 }
1078 1095
1079 m_insertionPreloadScanner.reset(); 1096 m_insertionPreloadScanner.reset();
1080 if (m_tokenizer) { 1097 if (m_tokenizer) {
1081 pumpTokenizerIfPossible(); 1098 pumpTokenizerIfPossible();
1082 } 1099 }
1083 endIfDelayed(); 1100 endIfDelayed();
(...skipping 12 matching lines...) Expand all
1096 if (isStopped()) { 1113 if (isStopped()) {
1097 return; 1114 return;
1098 } 1115 }
1099 1116
1100 if (isStopping()) { 1117 if (isStopping()) {
1101 attemptToRunDeferredScriptsAndEnd(); 1118 attemptToRunDeferredScriptsAndEnd();
1102 return; 1119 return;
1103 } 1120 }
1104 1121
1105 m_scriptRunner->executeScriptsWaitingForLoad(pendingScript); 1122 m_scriptRunner->executeScriptsWaitingForLoad(pendingScript);
1106 if (!isWaitingForScripts()) 1123 if (!isPaused())
1107 resumeParsingAfterScriptExecution(); 1124 resumeParsingAfterPause();
1108 } 1125 }
1109 1126
1110 void HTMLDocumentParser::executeScriptsWaitingForResources() { 1127 void HTMLDocumentParser::executeScriptsWaitingForResources() {
1111 DCHECK(document()->isScriptExecutionReady()); 1128 DCHECK(document()->isScriptExecutionReady());
1112 1129
1130 if (m_isWaitingForStylesheets)
1131 m_isWaitingForStylesheets = false;
1132
1113 // Document only calls this when the Document owns the DocumentParser so this 1133 // Document only calls this when the Document owns the DocumentParser so this
1114 // will not be called in the DocumentFragment case. 1134 // will not be called in the DocumentFragment case.
1115 DCHECK(m_scriptRunner); 1135 DCHECK(m_scriptRunner);
1116 m_scriptRunner->executeScriptsWaitingForResources(); 1136 m_scriptRunner->executeScriptsWaitingForResources();
1117 if (!isWaitingForScripts()) 1137 if (!isPaused())
1118 resumeParsingAfterScriptExecution(); 1138 resumeParsingAfterPause();
1139 }
1140
1141 void HTMLDocumentParser::didAddPendingStylesheetInBody() {
1142 // When in-body CSS doesn't block painting, the parser needs to pause so that
1143 // the DOM doesn't include any elements that may depend on the CSS for style.
1144 // The stylesheet can be added and removed during the parsing of a single
1145 // token so don't actually set the bit to block parsing here, just track
1146 // the state of the added sheet in case it does persist beyond a single
1147 // token.
1148 if (RuntimeEnabledFeatures::cssInBodyDoesNotBlockPaintEnabled())
1149 m_addedPendingStylesheetInBody = true;
1150 }
1151
1152 void HTMLDocumentParser::didLoadAllBodyStylesheets() {
1153 // Just toggle the stylesheet flag here (mostly for synchronous sheets).
1154 // The document will also call into executeScriptsWaitingForResources
1155 // which is when the parser will re-start, otherwise it will attempt to
1156 // resume twice which could cause state machine issues.
1157 m_addedPendingStylesheetInBody = false;
1158 }
1159
1160 void HTMLDocumentParser::checkIfBodyStlyesheetAdded() {
1161 if (m_addedPendingStylesheetInBody) {
1162 m_addedPendingStylesheetInBody = false;
1163 m_isWaitingForStylesheets = true;
1164 }
1119 } 1165 }
1120 1166
1121 void HTMLDocumentParser::parseDocumentFragment( 1167 void HTMLDocumentParser::parseDocumentFragment(
1122 const String& source, 1168 const String& source,
1123 DocumentFragment* fragment, 1169 DocumentFragment* fragment,
1124 Element* contextElement, 1170 Element* contextElement,
1125 ParserContentPolicy parserContentPolicy) { 1171 ParserContentPolicy parserContentPolicy) {
1126 HTMLDocumentParser* parser = 1172 HTMLDocumentParser* parser =
1127 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); 1173 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy);
1128 parser->append(source); 1174 parser->append(source);
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
1316 case Asynchronous: 1362 case Asynchronous:
1317 m_loadingTaskRunner->postTask( 1363 m_loadingTaskRunner->postTask(
1318 BLINK_FROM_HERE, 1364 BLINK_FROM_HERE,
1319 WTF::bind(function, std::forward<Ps>(parameters)...)); 1365 WTF::bind(function, std::forward<Ps>(parameters)...));
1320 return; 1366 return;
1321 } 1367 }
1322 NOTREACHED(); 1368 NOTREACHED();
1323 } 1369 }
1324 1370
1325 } // namespace blink 1371 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698