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 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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 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 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 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 (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 Loading... |
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 Loading... |
785 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); | 798 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); |
786 m_token = WTF::wrapUnique(new HTMLToken); | 799 m_token = WTF::wrapUnique(new HTMLToken); |
787 m_tokenizer = HTMLTokenizer::create(m_options); | 800 m_tokenizer = HTMLTokenizer::create(m_options); |
788 } | 801 } |
789 | 802 |
790 SegmentedString excludedLineNumberSource(source); | 803 SegmentedString excludedLineNumberSource(source); |
791 excludedLineNumberSource.setExcludeLineNumbers(); | 804 excludedLineNumberSource.setExcludeLineNumbers(); |
792 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); | 805 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); |
793 pumpTokenizerIfPossible(); | 806 pumpTokenizerIfPossible(); |
794 | 807 |
795 if (isWaitingForScripts()) { | 808 if (isPaused()) { |
796 // Check the document.write() output with a separate preload scanner as | 809 // Check the document.write() output with a separate preload scanner as |
797 // the main scanner can't deal with insertions. | 810 // the main scanner can't deal with insertions. |
798 if (!m_insertionPreloadScanner) | 811 if (!m_insertionPreloadScanner) |
799 m_insertionPreloadScanner = createPreloadScanner(); | 812 m_insertionPreloadScanner = createPreloadScanner(); |
800 m_insertionPreloadScanner->appendToEnd(source); | 813 m_insertionPreloadScanner->appendToEnd(source); |
801 scanAndPreload(m_insertionPreloadScanner.get()); | 814 scanAndPreload(m_insertionPreloadScanner.get()); |
802 } | 815 } |
803 | 816 |
804 endIfDelayed(); | 817 endIfDelayed(); |
805 } | 818 } |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
898 m_preloadScanner = createPreloadScanner(); | 911 m_preloadScanner = createPreloadScanner(); |
899 | 912 |
900 m_preloadScanner->appendToEnd(source); | 913 m_preloadScanner->appendToEnd(source); |
901 scanAndPreload(m_preloadScanner.get()); | 914 scanAndPreload(m_preloadScanner.get()); |
902 | 915 |
903 // Return after the preload scanner, do not actually parse the document. | 916 // Return after the preload scanner, do not actually parse the document. |
904 return; | 917 return; |
905 } | 918 } |
906 | 919 |
907 if (m_preloadScanner) { | 920 if (m_preloadScanner) { |
908 if (m_input.current().isEmpty() && !isWaitingForScripts()) { | 921 if (m_input.current().isEmpty() && !isPaused()) { |
909 // We have parsed until the end of the current input and so are now moving | 922 // We have parsed until the end of the current input and so are now moving |
910 // ahead of the preload scanner. Clear the scanner so we know to scan | 923 // ahead of the preload scanner. Clear the scanner so we know to scan |
911 // starting from the current input point if we block again. | 924 // starting from the current input point if we block again. |
912 m_preloadScanner.reset(); | 925 m_preloadScanner.reset(); |
913 } else { | 926 } else { |
914 m_preloadScanner->appendToEnd(source); | 927 m_preloadScanner->appendToEnd(source); |
915 if (isWaitingForScripts()) | 928 if (isPaused()) |
916 scanAndPreload(m_preloadScanner.get()); | 929 scanAndPreload(m_preloadScanner.get()); |
917 } | 930 } |
918 } | 931 } |
919 | 932 |
920 m_input.appendToEnd(source); | 933 m_input.appendToEnd(source); |
921 | 934 |
922 if (inPumpSession()) { | 935 if (inPumpSession()) { |
923 // We've gotten data off the network in a nested write. We don't want to | 936 // We've gotten data off the network in a nested write. We don't want to |
924 // consume any more of the input stream now. Do not worry. We'll consume | 937 // consume any more of the input stream now. Do not worry. We'll consume |
925 // this data in a less-nested write(). | 938 // this data in a less-nested write(). |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1056 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); | 1069 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); |
1057 // Since the parser is paused while a script runner has a blocking script, it | 1070 // Since the parser is paused while a script runner has a blocking script, it |
1058 // should never be possible to end up with both objects holding a blocking | 1071 // should never be possible to end up with both objects holding a blocking |
1059 // script. | 1072 // script. |
1060 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); | 1073 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); |
1061 // If either object has a blocking script, the parser should be paused. | 1074 // If either object has a blocking script, the parser should be paused. |
1062 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || | 1075 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || |
1063 m_reentryPermit->parserPauseFlag(); | 1076 m_reentryPermit->parserPauseFlag(); |
1064 } | 1077 } |
1065 | 1078 |
1066 void HTMLDocumentParser::resumeParsingAfterScriptExecution() { | 1079 void HTMLDocumentParser::resumeParsingAfterPause() { |
1067 ASSERT(!isExecutingScript()); | 1080 ASSERT(!isExecutingScript()); |
1068 ASSERT(!isWaitingForScripts()); | 1081 DCHECK(!isPaused()); |
| 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 Loading... |
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 Loading... |
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 |
OLD | NEW |