OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. | 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
144 m_tokenizedChunkQueue(TokenizedChunkQueue::create()), | 144 m_tokenizedChunkQueue(TokenizedChunkQueue::create()), |
145 m_evaluator(DocumentWriteEvaluator::create(document)), | 145 m_evaluator(DocumentWriteEvaluator::create(document)), |
146 m_pendingCSPMetaToken(nullptr), | 146 m_pendingCSPMetaToken(nullptr), |
147 m_shouldUseThreading(syncPolicy == AllowAsynchronousParsing), | 147 m_shouldUseThreading(syncPolicy == AllowAsynchronousParsing), |
148 m_endWasDelayed(false), | 148 m_endWasDelayed(false), |
149 m_haveBackgroundParser(false), | 149 m_haveBackgroundParser(false), |
150 m_tasksWereSuspended(false), | 150 m_tasksWereSuspended(false), |
151 m_pumpSessionNestingLevel(0), | 151 m_pumpSessionNestingLevel(0), |
152 m_pumpSpeculationsSessionNestingLevel(0), | 152 m_pumpSpeculationsSessionNestingLevel(0), |
153 m_isParsingAtLineNumber(false), | 153 m_isParsingAtLineNumber(false), |
154 m_triedLoadingLinkHeaders(false) { | 154 m_triedLoadingLinkHeaders(false), |
155 m_addedPendingStylesheetInBody(false), | |
156 m_isWaitingForStylesheets(false) { | |
155 ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); | 157 ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); |
156 // Threading is not allowed in prefetch mode. | 158 // Threading is not allowed in prefetch mode. |
157 DCHECK(!document.isPrefetchOnly() || !shouldUseThreading()); | 159 DCHECK(!document.isPrefetchOnly() || !shouldUseThreading()); |
158 } | 160 } |
159 | 161 |
160 HTMLDocumentParser::~HTMLDocumentParser() {} | 162 HTMLDocumentParser::~HTMLDocumentParser() {} |
161 | 163 |
162 void HTMLDocumentParser::dispose() { | 164 void HTMLDocumentParser::dispose() { |
163 // In Oilpan, HTMLDocumentParser can die together with Document, and detach() | 165 // In Oilpan, HTMLDocumentParser can die together with Document, and detach() |
164 // is not called in this case. | 166 // is not called in this case. |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
249 return; | 251 return; |
250 | 252 |
251 attemptToRunDeferredScriptsAndEnd(); | 253 attemptToRunDeferredScriptsAndEnd(); |
252 } | 254 } |
253 | 255 |
254 bool HTMLDocumentParser::isParsingFragment() const { | 256 bool HTMLDocumentParser::isParsingFragment() const { |
255 return m_treeBuilder->isParsingFragment(); | 257 return m_treeBuilder->isParsingFragment(); |
256 } | 258 } |
257 | 259 |
258 void HTMLDocumentParser::pumpTokenizerIfPossible() { | 260 void HTMLDocumentParser::pumpTokenizerIfPossible() { |
259 if (isStopped() || isWaitingForScripts()) | 261 if (isStopped() || isWaitingForScripts() || m_isWaitingForStylesheets) |
kouhei (in TOK)
2017/01/06 03:32:43
Would you mind cleaning up the HTMLDocumentParser
Pat Meenan
2017/01/09 16:37:05
For Option B, the state is currently tracked in th
| |
260 return; | 262 return; |
261 | 263 |
262 pumpTokenizer(); | 264 pumpTokenizer(); |
263 } | 265 } |
264 | 266 |
265 bool HTMLDocumentParser::isScheduledForResume() const { | 267 bool HTMLDocumentParser::isScheduledForResume() const { |
266 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); | 268 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); |
267 } | 269 } |
268 | 270 |
269 // Used by HTMLParserScheduler | 271 // Used by HTMLParserScheduler |
(...skipping 16 matching lines...) Expand all Loading... | |
286 } | 288 } |
287 | 289 |
288 bool HTMLDocumentParser::canTakeNextToken() { | 290 bool HTMLDocumentParser::canTakeNextToken() { |
289 if (isStopped()) | 291 if (isStopped()) |
290 return false; | 292 return false; |
291 | 293 |
292 // If we're paused waiting for a script, we try to execute scripts before | 294 // If we're paused waiting for a script, we try to execute scripts before |
293 // continuing. | 295 // continuing. |
294 if (m_treeBuilder->hasParserBlockingScript()) | 296 if (m_treeBuilder->hasParserBlockingScript()) |
295 runScriptsForPausedTreeBuilder(); | 297 runScriptsForPausedTreeBuilder(); |
296 if (isStopped() || isWaitingForScripts()) | 298 if (isStopped() || isWaitingForScripts() || m_isWaitingForStylesheets) |
297 return false; | 299 return false; |
298 | 300 |
299 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the | 301 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the |
300 // LocalFrame, but this approach is how the old parser handled stopping when | 302 // LocalFrame, but this approach is how the old parser handled stopping when |
301 // the page assigns window.location. What really should happen is that | 303 // the page assigns window.location. What really should happen is that |
302 // assigning window.location causes the parser to stop parsing cleanly. The | 304 // assigning window.location causes the parser to stop parsing cleanly. The |
303 // problem is we're not perpared to do that at every point where we run | 305 // problem is we're not perpared to do that at every point where we run |
304 // JavaScript. | 306 // JavaScript. |
305 if (!isParsingFragment() && document()->frame() && | 307 if (!isParsingFragment() && document()->frame() && |
306 document()->frame()->navigationScheduler().locationChangePending()) | 308 document()->frame()->navigationScheduler().locationChangePending()) |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
374 const CompactHTMLToken& token = chunk->tokens->at(index); | 376 const CompactHTMLToken& token = chunk->tokens->at(index); |
375 ASSERT(token.type() == HTMLToken::TokenType::Character); | 377 ASSERT(token.type() == HTMLToken::TokenType::Character); |
376 evaluateAndPreloadScriptForDocumentWrite(token.data()); | 378 evaluateAndPreloadScriptForDocumentWrite(token.data()); |
377 } | 379 } |
378 } | 380 } |
379 } | 381 } |
380 | 382 |
381 for (auto& chunk : pendingChunks) | 383 for (auto& chunk : pendingChunks) |
382 m_speculations.append(std::move(chunk)); | 384 m_speculations.append(std::move(chunk)); |
383 | 385 |
384 if (!isWaitingForScripts() && !isScheduledForResume()) { | 386 if (!isWaitingForScripts() && !isScheduledForResume() && |
387 !m_isWaitingForStylesheets) { | |
385 if (m_tasksWereSuspended) | 388 if (m_tasksWereSuspended) |
386 m_parserScheduler->forceResumeAfterYield(); | 389 m_parserScheduler->forceResumeAfterYield(); |
387 else | 390 else |
388 m_parserScheduler->scheduleForResume(); | 391 m_parserScheduler->scheduleForResume(); |
389 } | 392 } |
390 } | 393 } |
391 | 394 |
392 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( | 395 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( |
393 const DocumentEncodingData& data) { | 396 const DocumentEncodingData& data) { |
394 document()->setEncodingData(data); | 397 document()->setEncodingData(data); |
395 } | 398 } |
396 | 399 |
397 void HTMLDocumentParser::validateSpeculations( | 400 void HTMLDocumentParser::validateSpeculations( |
398 std::unique_ptr<TokenizedChunk> chunk) { | 401 std::unique_ptr<TokenizedChunk> chunk) { |
399 ASSERT(chunk); | 402 ASSERT(chunk); |
400 // TODO(kouhei): We should simplify codepath here by disallowing | 403 // TODO(kouhei): We should simplify codepath here by disallowing |
401 // validateSpeculations | 404 // validateSpeculations |
402 // while isWaitingForScripts, and m_lastChunkBeforeScript can simply be | 405 // while isWaitingForScripts, and m_lastChunkBeforePause can simply be |
403 // pushed to m_speculations. | 406 // pushed to m_speculations. |
404 if (isWaitingForScripts()) { | 407 if (isWaitingForScripts() || m_isWaitingForStylesheets) { |
405 // We're waiting on a network script, just save the chunk, we'll get a | 408 // We're waiting on a network script, just save the chunk, we'll get a |
406 // second validateSpeculations call after the script completes. This call | 409 // second validateSpeculations call after the script completes. This call |
407 // should have been made immediately after runScriptsForPausedTreeBuilder | 410 // should have been made immediately after runScriptsForPausedTreeBuilder |
408 // which may have started a network load and left us waiting. | 411 // which may have started a network load and left us waiting. |
409 ASSERT(!m_lastChunkBeforeScript); | 412 DCHECK(!m_lastChunkBeforePause); |
410 m_lastChunkBeforeScript = std::move(chunk); | 413 m_lastChunkBeforePause = std::move(chunk); |
411 return; | 414 return; |
412 } | 415 } |
413 | 416 |
414 ASSERT(!m_lastChunkBeforeScript); | 417 DCHECK(!m_lastChunkBeforePause); |
415 std::unique_ptr<HTMLTokenizer> tokenizer = std::move(m_tokenizer); | 418 std::unique_ptr<HTMLTokenizer> tokenizer = std::move(m_tokenizer); |
416 std::unique_ptr<HTMLToken> token = std::move(m_token); | 419 std::unique_ptr<HTMLToken> token = std::move(m_token); |
417 | 420 |
418 if (!tokenizer) { | 421 if (!tokenizer) { |
419 // There must not have been any changes to the HTMLTokenizer state on the | 422 // There must not have been any changes to the HTMLTokenizer state on the |
420 // main thread, which means the speculation buffer is correct. | 423 // main thread, which means the speculation buffer is correct. |
421 return; | 424 return; |
422 } | 425 } |
423 | 426 |
424 // Currently we're only smart enough to reuse the speculation buffer if the | 427 // Currently we're only smart enough to reuse the speculation buffer if the |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
486 AutoReset<bool> hasLineNumber(&m_isParsingAtLineNumber, true); | 489 AutoReset<bool> hasLineNumber(&m_isParsingAtLineNumber, true); |
487 | 490 |
488 SECURITY_DCHECK(m_pumpSpeculationsSessionNestingLevel == 1); | 491 SECURITY_DCHECK(m_pumpSpeculationsSessionNestingLevel == 1); |
489 SECURITY_DCHECK(!inPumpSession()); | 492 SECURITY_DCHECK(!inPumpSession()); |
490 ASSERT(!isParsingFragment()); | 493 ASSERT(!isParsingFragment()); |
491 ASSERT(!isWaitingForScripts()); | 494 ASSERT(!isWaitingForScripts()); |
492 ASSERT(!isStopped()); | 495 ASSERT(!isStopped()); |
493 ASSERT(shouldUseThreading()); | 496 ASSERT(shouldUseThreading()); |
494 ASSERT(!m_tokenizer); | 497 ASSERT(!m_tokenizer); |
495 ASSERT(!m_token); | 498 ASSERT(!m_token); |
496 ASSERT(!m_lastChunkBeforeScript); | 499 DCHECK(!m_lastChunkBeforePause); |
500 DCHECK(!m_isWaitingForStylesheets); | |
497 | 501 |
498 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); | 502 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); |
499 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); | 503 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); |
500 size_t elementTokenCount = 0; | 504 size_t elementTokenCount = 0; |
501 | 505 |
502 postTaskToLookaheadParser(Asynchronous, | 506 postTaskToLookaheadParser(Asynchronous, |
503 &BackgroundHTMLParser::startedChunkWithCheckpoint, | 507 &BackgroundHTMLParser::startedChunkWithCheckpoint, |
504 m_backgroundParser, chunk->inputCheckpoint); | 508 m_backgroundParser, chunk->inputCheckpoint); |
505 | 509 |
506 for (const auto& xssInfo : chunk->xssInfos) { | 510 for (const auto& xssInfo : chunk->xssInfos) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
551 } | 555 } |
552 | 556 |
553 if (isWaitingForScripts()) { | 557 if (isWaitingForScripts()) { |
554 // The </script> is assumed to be the last token of this bunch. | 558 // The </script> is assumed to be the last token of this bunch. |
555 ASSERT(it + 1 == tokens->end()); | 559 ASSERT(it + 1 == tokens->end()); |
556 runScriptsForPausedTreeBuilder(); | 560 runScriptsForPausedTreeBuilder(); |
557 validateSpeculations(std::move(chunk)); | 561 validateSpeculations(std::move(chunk)); |
558 break; | 562 break; |
559 } | 563 } |
560 | 564 |
565 if (m_isWaitingForStylesheets && it + 1 == tokens->end()) { | |
566 validateSpeculations(std::move(chunk)); | |
567 break; | |
568 } | |
569 | |
561 if (it->type() == HTMLToken::EndOfFile) { | 570 if (it->type() == HTMLToken::EndOfFile) { |
562 // The EOF is assumed to be the last token of this bunch. | 571 // The EOF is assumed to be the last token of this bunch. |
563 ASSERT(it + 1 == tokens->end()); | 572 ASSERT(it + 1 == tokens->end()); |
564 // There should never be any chunks after the EOF. | 573 // There should never be any chunks after the EOF. |
565 ASSERT(m_speculations.isEmpty()); | 574 ASSERT(m_speculations.isEmpty()); |
566 prepareToStopParsing(); | 575 prepareToStopParsing(); |
567 break; | 576 break; |
568 } | 577 } |
569 | 578 |
570 ASSERT(!m_tokenizer); | 579 ASSERT(!m_tokenizer); |
571 ASSERT(!m_token); | 580 ASSERT(!m_token); |
572 } | 581 } |
573 | 582 |
574 // Make sure all required pending text nodes are emitted before returning. | 583 // Make sure all required pending text nodes are emitted before returning. |
575 // This leaves "script", "style" and "svg" nodes text nodes intact. | 584 // This leaves "script", "style" and "svg" nodes text nodes intact. |
576 if (!isStopped()) | 585 if (!isStopped()) |
577 m_treeBuilder->flush(FlushIfAtTextLimit); | 586 m_treeBuilder->flush(FlushIfAtTextLimit); |
578 | 587 |
579 m_isParsingAtLineNumber = false; | 588 m_isParsingAtLineNumber = false; |
580 | 589 |
581 return elementTokenCount; | 590 return elementTokenCount; |
582 } | 591 } |
583 | 592 |
584 void HTMLDocumentParser::pumpPendingSpeculations() { | 593 void HTMLDocumentParser::pumpPendingSpeculations() { |
585 // If this assert fails, you need to call validateSpeculations to make sure | 594 // If this assert fails, you need to call validateSpeculations to make sure |
586 // m_tokenizer and m_token don't have state that invalidates m_speculations. | 595 // m_tokenizer and m_token don't have state that invalidates m_speculations. |
587 ASSERT(!m_tokenizer); | 596 ASSERT(!m_tokenizer); |
588 ASSERT(!m_token); | 597 ASSERT(!m_token); |
589 ASSERT(!m_lastChunkBeforeScript); | 598 DCHECK(!m_lastChunkBeforePause); |
590 ASSERT(!isWaitingForScripts()); | 599 ASSERT(!isWaitingForScripts()); |
591 ASSERT(!isStopped()); | 600 ASSERT(!isStopped()); |
592 ASSERT(!isScheduledForResume()); | 601 ASSERT(!isScheduledForResume()); |
593 ASSERT(!inPumpSession()); | 602 ASSERT(!inPumpSession()); |
603 DCHECK(!m_isWaitingForStylesheets); | |
594 | 604 |
595 // FIXME: Here should never be reached when there is a blocking script, | 605 // FIXME: Here should never be reached when there is a blocking script, |
596 // but it happens in unknown scenarios. See https://crbug.com/440901 | 606 // but it happens in unknown scenarios. See https://crbug.com/440901 |
597 if (isWaitingForScripts()) { | 607 if (isWaitingForScripts()) { |
598 m_parserScheduler->scheduleForResume(); | 608 m_parserScheduler->scheduleForResume(); |
599 return; | 609 return; |
600 } | 610 } |
601 | 611 |
602 // Do not allow pumping speculations in nested event loops. | 612 // Do not allow pumping speculations in nested event loops. |
603 if (m_pumpSpeculationsSessionNestingLevel) { | 613 if (m_pumpSpeculationsSessionNestingLevel) { |
(...skipping 10 matching lines...) Expand all Loading... | |
614 while (!m_speculations.isEmpty()) { | 624 while (!m_speculations.isEmpty()) { |
615 ASSERT(!isScheduledForResume()); | 625 ASSERT(!isScheduledForResume()); |
616 size_t elementTokenCount = | 626 size_t elementTokenCount = |
617 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); | 627 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); |
618 session.addedElementTokens(elementTokenCount); | 628 session.addedElementTokens(elementTokenCount); |
619 | 629 |
620 // Always check isParsing first as m_document may be null. Surprisingly, | 630 // Always check isParsing first as m_document may be null. Surprisingly, |
621 // isScheduledForResume() may be set here as a result of | 631 // isScheduledForResume() may be set here as a result of |
622 // processTokenizedChunkFromBackgroundParser running arbitrary javascript | 632 // processTokenizedChunkFromBackgroundParser running arbitrary javascript |
623 // which invokes nested event loops. (e.g. inspector breakpoints) | 633 // which invokes nested event loops. (e.g. inspector breakpoints) |
624 if (!isParsing() || isWaitingForScripts() || isScheduledForResume()) | 634 if (!isParsing() || isWaitingForScripts() || isScheduledForResume() || |
635 m_isWaitingForStylesheets) | |
625 break; | 636 break; |
626 | 637 |
627 if (m_speculations.isEmpty() || | 638 if (m_speculations.isEmpty() || |
628 m_parserScheduler->yieldIfNeeded( | 639 m_parserScheduler->yieldIfNeeded( |
629 session, m_speculations.first()->startingScript)) | 640 session, m_speculations.first()->startingScript)) |
630 break; | 641 break; |
631 } | 642 } |
632 | 643 |
633 TRACE_EVENT_END1( | 644 TRACE_EVENT_END1( |
634 "devtools.timeline", "ParseHTML", "endData", | 645 "devtools.timeline", "ParseHTML", "endData", |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
702 } | 713 } |
703 | 714 |
704 if (isStopped()) | 715 if (isStopped()) |
705 return; | 716 return; |
706 | 717 |
707 // There should only be PendingText left since the tree-builder always flushes | 718 // There should only be PendingText left since the tree-builder always flushes |
708 // the task queue before returning. In case that ever changes, crash. | 719 // the task queue before returning. In case that ever changes, crash. |
709 m_treeBuilder->flush(FlushAlways); | 720 m_treeBuilder->flush(FlushAlways); |
710 RELEASE_ASSERT(!isStopped()); | 721 RELEASE_ASSERT(!isStopped()); |
711 | 722 |
712 if (isWaitingForScripts()) { | 723 if (isWaitingForScripts() || m_isWaitingForStylesheets) { |
713 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); | 724 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); |
714 | 725 |
715 ASSERT(m_preloader); | 726 ASSERT(m_preloader); |
716 // TODO(kouhei): m_preloader should be always available for synchronous | 727 // TODO(kouhei): m_preloader should be always available for synchronous |
717 // parsing case, adding paranoia if for speculative crash fix for | 728 // parsing case, adding paranoia if for speculative crash fix for |
718 // crbug.com/465478 | 729 // crbug.com/465478 |
719 if (m_preloader) { | 730 if (m_preloader && document()->url().isValid()) { |
720 if (!m_preloadScanner) { | 731 if (!m_preloadScanner) { |
721 m_preloadScanner = createPreloadScanner(); | 732 m_preloadScanner = createPreloadScanner(); |
722 m_preloadScanner->appendToEnd(m_input.current()); | 733 m_preloadScanner->appendToEnd(m_input.current()); |
723 } | 734 } |
724 scanAndPreload(m_preloadScanner.get()); | 735 scanAndPreload(m_preloadScanner.get()); |
725 } | 736 } |
726 } | 737 } |
727 | 738 |
728 TRACE_EVENT_END1("devtools.timeline", "ParseHTML", "endData", | 739 TRACE_EVENT_END1("devtools.timeline", "ParseHTML", "endData", |
729 InspectorParseHtmlEvent::endData( | 740 InspectorParseHtmlEvent::endData( |
(...skipping 11 matching lines...) Expand all Loading... | |
741 // the parser. | 752 // the parser. |
742 // | 753 // |
743 // FIXME: Stop clearing the m_token once we start running the parser off | 754 // FIXME: Stop clearing the m_token once we start running the parser off |
744 // the main thread or once we stop allowing synchronous JavaScript | 755 // the main thread or once we stop allowing synchronous JavaScript |
745 // execution from parseAttribute. | 756 // execution from parseAttribute. |
746 if (token().type() != HTMLToken::Character) | 757 if (token().type() != HTMLToken::Character) |
747 token().clear(); | 758 token().clear(); |
748 | 759 |
749 m_treeBuilder->constructTree(&atomicToken); | 760 m_treeBuilder->constructTree(&atomicToken); |
750 | 761 |
762 if (m_addedPendingStylesheetInBody) | |
763 m_isWaitingForStylesheets = true; | |
764 | |
751 // FIXME: constructTree may synchronously cause Document to be detached. | 765 // FIXME: constructTree may synchronously cause Document to be detached. |
752 if (!m_token) | 766 if (!m_token) |
753 return; | 767 return; |
754 | 768 |
755 if (!token().isUninitialized()) { | 769 if (!token().isUninitialized()) { |
756 ASSERT(token().type() == HTMLToken::Character); | 770 ASSERT(token().type() == HTMLToken::Character); |
757 token().clear(); | 771 token().clear(); |
758 } | 772 } |
759 } | 773 } |
760 | 774 |
761 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( | 775 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( |
762 const CompactHTMLToken& compactToken) { | 776 const CompactHTMLToken& compactToken) { |
763 AtomicHTMLToken token(compactToken); | 777 AtomicHTMLToken token(compactToken); |
764 m_treeBuilder->constructTree(&token); | 778 m_treeBuilder->constructTree(&token); |
779 if (m_addedPendingStylesheetInBody) | |
780 m_isWaitingForStylesheets = true; | |
765 } | 781 } |
766 | 782 |
767 bool HTMLDocumentParser::hasInsertionPoint() { | 783 bool HTMLDocumentParser::hasInsertionPoint() { |
768 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our | 784 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our |
769 // model of the EOF character differs slightly from the one in the spec | 785 // model of the EOF character differs slightly from the one in the spec |
770 // because our treatment is uniform between network-sourced and script-sourced | 786 // because our treatment is uniform between network-sourced and script-sourced |
771 // input streams whereas the spec treats them differently. | 787 // input streams whereas the spec treats them differently. |
772 return m_input.hasInsertionPoint() || | 788 return m_input.hasInsertionPoint() || |
773 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); | 789 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); |
774 } | 790 } |
(...skipping 10 matching lines...) Expand all Loading... | |
785 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); | 801 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); |
786 m_token = WTF::wrapUnique(new HTMLToken); | 802 m_token = WTF::wrapUnique(new HTMLToken); |
787 m_tokenizer = HTMLTokenizer::create(m_options); | 803 m_tokenizer = HTMLTokenizer::create(m_options); |
788 } | 804 } |
789 | 805 |
790 SegmentedString excludedLineNumberSource(source); | 806 SegmentedString excludedLineNumberSource(source); |
791 excludedLineNumberSource.setExcludeLineNumbers(); | 807 excludedLineNumberSource.setExcludeLineNumbers(); |
792 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); | 808 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); |
793 pumpTokenizerIfPossible(); | 809 pumpTokenizerIfPossible(); |
794 | 810 |
795 if (isWaitingForScripts()) { | 811 if (isWaitingForScripts() || m_isWaitingForStylesheets) { |
796 // Check the document.write() output with a separate preload scanner as | 812 if (document()->url().isValid()) { |
797 // the main scanner can't deal with insertions. | 813 // Check the document.write() output with a separate preload scanner as |
798 if (!m_insertionPreloadScanner) | 814 // the main scanner can't deal with insertions. |
799 m_insertionPreloadScanner = createPreloadScanner(); | 815 if (!m_insertionPreloadScanner) |
800 m_insertionPreloadScanner->appendToEnd(source); | 816 m_insertionPreloadScanner = createPreloadScanner(); |
801 scanAndPreload(m_insertionPreloadScanner.get()); | 817 m_insertionPreloadScanner->appendToEnd(source); |
818 scanAndPreload(m_insertionPreloadScanner.get()); | |
819 } | |
802 } | 820 } |
803 | 821 |
804 endIfDelayed(); | 822 endIfDelayed(); |
805 } | 823 } |
806 | 824 |
807 void HTMLDocumentParser::startBackgroundParser() { | 825 void HTMLDocumentParser::startBackgroundParser() { |
808 ASSERT(!isStopped()); | 826 ASSERT(!isStopped()); |
809 ASSERT(shouldUseThreading()); | 827 ASSERT(shouldUseThreading()); |
810 ASSERT(!m_haveBackgroundParser); | 828 ASSERT(!m_haveBackgroundParser); |
811 ASSERT(document()); | 829 ASSERT(document()); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
881 | 899 |
882 // We should never reach this point if we're using a parser thread, as | 900 // We should never reach this point if we're using a parser thread, as |
883 // appendBytes() will directly ship the data to the thread. | 901 // appendBytes() will directly ship the data to the thread. |
884 ASSERT(!shouldUseThreading()); | 902 ASSERT(!shouldUseThreading()); |
885 | 903 |
886 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), | 904 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), |
887 "HTMLDocumentParser::append", "size", inputSource.length()); | 905 "HTMLDocumentParser::append", "size", inputSource.length()); |
888 const SegmentedString source(inputSource); | 906 const SegmentedString source(inputSource); |
889 | 907 |
890 if (document()->isPrefetchOnly()) { | 908 if (document()->isPrefetchOnly()) { |
891 if (!m_preloadScanner) | 909 if (document()->url().isValid()) { |
892 m_preloadScanner = createPreloadScanner(); | 910 if (!m_preloadScanner) |
911 m_preloadScanner = createPreloadScanner(); | |
893 | 912 |
894 m_preloadScanner->appendToEnd(source); | 913 m_preloadScanner->appendToEnd(source); |
895 scanAndPreload(m_preloadScanner.get()); | 914 scanAndPreload(m_preloadScanner.get()); |
915 } | |
896 | 916 |
897 // Return after the preload scanner, do not actually parse the document. | 917 // Return after the preload scanner, do not actually parse the document. |
898 return; | 918 return; |
899 } | 919 } |
900 | 920 |
901 if (m_preloadScanner) { | 921 if (m_preloadScanner) { |
902 if (m_input.current().isEmpty() && !isWaitingForScripts()) { | 922 if (m_input.current().isEmpty() && !isWaitingForScripts() && |
923 !m_isWaitingForStylesheets) { | |
903 // We have parsed until the end of the current input and so are now moving | 924 // We have parsed until the end of the current input and so are now moving |
904 // ahead of the preload scanner. Clear the scanner so we know to scan | 925 // ahead of the preload scanner. Clear the scanner so we know to scan |
905 // starting from the current input point if we block again. | 926 // starting from the current input point if we block again. |
906 m_preloadScanner.reset(); | 927 m_preloadScanner.reset(); |
907 } else { | 928 } else { |
908 m_preloadScanner->appendToEnd(source); | 929 m_preloadScanner->appendToEnd(source); |
909 if (isWaitingForScripts()) | 930 if (isWaitingForScripts() || m_isWaitingForStylesheets) |
910 scanAndPreload(m_preloadScanner.get()); | 931 scanAndPreload(m_preloadScanner.get()); |
911 } | 932 } |
912 } | 933 } |
913 | 934 |
914 m_input.appendToEnd(source); | 935 m_input.appendToEnd(source); |
915 | 936 |
916 if (inPumpSession()) { | 937 if (inPumpSession()) { |
917 // We've gotten data off the network in a nested write. We don't want to | 938 // We've gotten data off the network in a nested write. We don't want to |
918 // consume any more of the input stream now. Do not worry. We'll consume | 939 // consume any more of the input stream now. Do not worry. We'll consume |
919 // this data in a less-nested write(). | 940 // this data in a less-nested write(). |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1050 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); | 1071 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); |
1051 // Since the parser is paused while a script runner has a blocking script, it | 1072 // Since the parser is paused while a script runner has a blocking script, it |
1052 // should never be possible to end up with both objects holding a blocking | 1073 // should never be possible to end up with both objects holding a blocking |
1053 // script. | 1074 // script. |
1054 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); | 1075 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); |
1055 // If either object has a blocking script, the parser should be paused. | 1076 // If either object has a blocking script, the parser should be paused. |
1056 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || | 1077 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || |
1057 m_reentryPermit->parserPauseFlag(); | 1078 m_reentryPermit->parserPauseFlag(); |
1058 } | 1079 } |
1059 | 1080 |
1060 void HTMLDocumentParser::resumeParsingAfterScriptExecution() { | 1081 void HTMLDocumentParser::resumeParsingAfterPause() { |
1061 ASSERT(!isExecutingScript()); | 1082 ASSERT(!isExecutingScript()); |
1062 ASSERT(!isWaitingForScripts()); | 1083 ASSERT(!isWaitingForScripts()); |
1084 DCHECK(!m_isWaitingForStylesheets); | |
1063 | 1085 |
1064 if (m_haveBackgroundParser) { | 1086 if (m_haveBackgroundParser) { |
1065 if (m_lastChunkBeforeScript) { | 1087 if (m_lastChunkBeforePause) { |
1066 validateSpeculations(std::move(m_lastChunkBeforeScript)); | 1088 validateSpeculations(std::move(m_lastChunkBeforePause)); |
1067 DCHECK(!m_lastChunkBeforeScript); | 1089 DCHECK(!m_lastChunkBeforePause); |
1068 pumpPendingSpeculations(); | 1090 pumpPendingSpeculations(); |
1069 } | 1091 } |
1070 return; | 1092 return; |
1071 } | 1093 } |
1072 | 1094 |
1073 m_insertionPreloadScanner.reset(); | 1095 m_insertionPreloadScanner.reset(); |
1074 if (m_tokenizer) { | 1096 if (m_tokenizer) { |
1075 pumpTokenizerIfPossible(); | 1097 pumpTokenizerIfPossible(); |
1076 } | 1098 } |
1077 endIfDelayed(); | 1099 endIfDelayed(); |
(...skipping 12 matching lines...) Expand all Loading... | |
1090 if (isStopped()) { | 1112 if (isStopped()) { |
1091 return; | 1113 return; |
1092 } | 1114 } |
1093 | 1115 |
1094 if (isStopping()) { | 1116 if (isStopping()) { |
1095 attemptToRunDeferredScriptsAndEnd(); | 1117 attemptToRunDeferredScriptsAndEnd(); |
1096 return; | 1118 return; |
1097 } | 1119 } |
1098 | 1120 |
1099 m_scriptRunner->executeScriptsWaitingForLoad(pendingScript); | 1121 m_scriptRunner->executeScriptsWaitingForLoad(pendingScript); |
1100 if (!isWaitingForScripts()) | 1122 if (!isWaitingForScripts() && !m_isWaitingForStylesheets) |
1101 resumeParsingAfterScriptExecution(); | 1123 resumeParsingAfterPause(); |
1102 } | 1124 } |
1103 | 1125 |
1104 void HTMLDocumentParser::executeScriptsWaitingForResources() { | 1126 void HTMLDocumentParser::executeScriptsWaitingForResources() { |
1105 DCHECK(document()->isScriptExecutionReady()); | 1127 DCHECK(document()->isScriptExecutionReady()); |
1106 | 1128 |
1107 // Document only calls this when the Document owns the DocumentParser so this | 1129 // Document only calls this when the Document owns the DocumentParser so this |
1108 // will not be called in the DocumentFragment case. | 1130 // will not be called in the DocumentFragment case. |
1109 DCHECK(m_scriptRunner); | 1131 DCHECK(m_scriptRunner); |
1110 m_scriptRunner->executeScriptsWaitingForResources(); | 1132 m_scriptRunner->executeScriptsWaitingForResources(); |
1111 if (!isWaitingForScripts()) | 1133 if (!isWaitingForScripts() && !m_isWaitingForStylesheets) |
1112 resumeParsingAfterScriptExecution(); | 1134 resumeParsingAfterPause(); |
1135 } | |
1136 | |
1137 void HTMLDocumentParser::didAddPendingStylesheetInBody() { | |
1138 // When in-body CSS doesn't block painting, the parser needs to pause so that | |
1139 // the DOM doesn't include any elements that may depend on the CSS for style. | |
1140 // The stylesheet can be added and removed during the parsing of a single | |
1141 // token so don't actually set the bit to block parsing here, just track | |
1142 // the state of the added sheet in case it does persist beyond a single | |
1143 // token. | |
1144 if (RuntimeEnabledFeatures::cssInBodyDoesNotBlockPaintEnabled()) | |
1145 m_addedPendingStylesheetInBody = true; | |
1146 } | |
1147 | |
1148 void HTMLDocumentParser::didLoadAllStylesheets() { | |
1149 m_addedPendingStylesheetInBody = false; | |
1150 if (m_isWaitingForStylesheets) { | |
1151 m_isWaitingForStylesheets = false; | |
1152 if (!isWaitingForScripts()) { | |
1153 // Post an async task to resume parsing since this can (and often is) | |
1154 // called while already parsing. | |
1155 m_resumeParsingTaskHandle = | |
1156 TaskRunnerHelper::get(TaskType::Networking, document()) | |
1157 ->postCancellableTask( | |
1158 BLINK_FROM_HERE, | |
1159 WTF::bind(&HTMLDocumentParser::resumeParsingAfterPause, | |
1160 wrapWeakPersistent(this))); | |
1161 } | |
1162 } | |
1113 } | 1163 } |
1114 | 1164 |
1115 void HTMLDocumentParser::parseDocumentFragment( | 1165 void HTMLDocumentParser::parseDocumentFragment( |
1116 const String& source, | 1166 const String& source, |
1117 DocumentFragment* fragment, | 1167 DocumentFragment* fragment, |
1118 Element* contextElement, | 1168 Element* contextElement, |
1119 ParserContentPolicy parserContentPolicy) { | 1169 ParserContentPolicy parserContentPolicy) { |
1120 HTMLDocumentParser* parser = | 1170 HTMLDocumentParser* parser = |
1121 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); | 1171 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); |
1122 parser->append(source); | 1172 parser->append(source); |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1250 bool neededInitialization = m_evaluator->ensureEvaluationContext(); | 1300 bool neededInitialization = m_evaluator->ensureEvaluationContext(); |
1251 double initializationDuration = | 1301 double initializationDuration = |
1252 monotonicallyIncreasingTimeMS() - initializeStartTime; | 1302 monotonicallyIncreasingTimeMS() - initializeStartTime; |
1253 | 1303 |
1254 double startTime = monotonicallyIncreasingTimeMS(); | 1304 double startTime = monotonicallyIncreasingTimeMS(); |
1255 String writtenSource = m_evaluator->evaluateAndEmitWrittenSource(source); | 1305 String writtenSource = m_evaluator->evaluateAndEmitWrittenSource(source); |
1256 double duration = monotonicallyIncreasingTimeMS() - startTime; | 1306 double duration = monotonicallyIncreasingTimeMS() - startTime; |
1257 | 1307 |
1258 int currentPreloadCount = document()->loader()->fetcher()->countPreloads(); | 1308 int currentPreloadCount = document()->loader()->fetcher()->countPreloads(); |
1259 | 1309 |
1260 std::unique_ptr<HTMLPreloadScanner> scanner = createPreloadScanner(); | 1310 if (document()->url().isValid()) { |
kouhei (in TOK)
2017/01/06 03:32:43
Would you describe your change here?
Pat Meenan
2017/01/09 16:37:05
Sorry, left-over from some earlier iterations and
| |
1261 scanner->appendToEnd(SegmentedString(writtenSource)); | 1311 std::unique_ptr<HTMLPreloadScanner> scanner = createPreloadScanner(); |
1262 scanAndPreload(scanner.get()); | 1312 scanner->appendToEnd(SegmentedString(writtenSource)); |
1313 scanAndPreload(scanner.get()); | |
1314 } | |
1263 | 1315 |
1264 int numPreloads = | 1316 int numPreloads = |
1265 document()->loader()->fetcher()->countPreloads() - currentPreloadCount; | 1317 document()->loader()->fetcher()->countPreloads() - currentPreloadCount; |
1266 | 1318 |
1267 TRACE_EVENT_INSTANT2( | 1319 TRACE_EVENT_INSTANT2( |
1268 "blink", | 1320 "blink", |
1269 "HTMLDocumentParser::evaluateAndPreloadScriptForDocumentWrite.data", | 1321 "HTMLDocumentParser::evaluateAndPreloadScriptForDocumentWrite.data", |
1270 TRACE_EVENT_SCOPE_THREAD, "numPreloads", numPreloads, "scriptLength", | 1322 TRACE_EVENT_SCOPE_THREAD, "numPreloads", numPreloads, "scriptLength", |
1271 source.length()); | 1323 source.length()); |
1272 | 1324 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1310 case Asynchronous: | 1362 case Asynchronous: |
1311 m_loadingTaskRunner->postTask( | 1363 m_loadingTaskRunner->postTask( |
1312 BLINK_FROM_HERE, | 1364 BLINK_FROM_HERE, |
1313 WTF::bind(function, std::forward<Ps>(parameters)...)); | 1365 WTF::bind(function, std::forward<Ps>(parameters)...)); |
1314 return; | 1366 return; |
1315 } | 1367 } |
1316 NOTREACHED(); | 1368 NOTREACHED(); |
1317 } | 1369 } |
1318 | 1370 |
1319 } // namespace blink | 1371 } // namespace blink |
OLD | NEW |