| 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 13 matching lines...) Expand all Loading... |
| 24 */ | 24 */ |
| 25 | 25 |
| 26 #include "core/html/parser/HTMLDocumentParser.h" | 26 #include "core/html/parser/HTMLDocumentParser.h" |
| 27 | 27 |
| 28 #include "core/HTMLNames.h" | 28 #include "core/HTMLNames.h" |
| 29 #include "core/css/MediaValuesCached.h" | 29 #include "core/css/MediaValuesCached.h" |
| 30 #include "core/css/resolver/StyleResolver.h" | 30 #include "core/css/resolver/StyleResolver.h" |
| 31 #include "core/dom/DocumentFragment.h" | 31 #include "core/dom/DocumentFragment.h" |
| 32 #include "core/dom/DocumentLifecycleObserver.h" | 32 #include "core/dom/DocumentLifecycleObserver.h" |
| 33 #include "core/dom/Element.h" | 33 #include "core/dom/Element.h" |
| 34 #include "core/dom/StyleEngine.h" |
| 34 #include "core/frame/LocalFrame.h" | 35 #include "core/frame/LocalFrame.h" |
| 35 #include "core/frame/Settings.h" | 36 #include "core/frame/Settings.h" |
| 36 #include "core/html/HTMLDocument.h" | 37 #include "core/html/HTMLDocument.h" |
| 37 #include "core/html/parser/AtomicHTMLToken.h" | 38 #include "core/html/parser/AtomicHTMLToken.h" |
| 38 #include "core/html/parser/BackgroundHTMLParser.h" | 39 #include "core/html/parser/BackgroundHTMLParser.h" |
| 39 #include "core/html/parser/HTMLParserScheduler.h" | 40 #include "core/html/parser/HTMLParserScheduler.h" |
| 40 #include "core/html/parser/HTMLParserThread.h" | 41 #include "core/html/parser/HTMLParserThread.h" |
| 41 #include "core/html/parser/HTMLScriptRunner.h" | 42 #include "core/html/parser/HTMLScriptRunner.h" |
| 42 #include "core/html/parser/HTMLTreeBuilder.h" | 43 #include "core/html/parser/HTMLTreeBuilder.h" |
| 43 #include "core/inspector/InspectorInstrumentation.h" | 44 #include "core/inspector/InspectorInstrumentation.h" |
| 44 #include "core/inspector/InspectorTraceEvents.h" | 45 #include "core/inspector/InspectorTraceEvents.h" |
| 45 #include "core/loader/DocumentLoader.h" | 46 #include "core/loader/DocumentLoader.h" |
| 46 #include "core/loader/NavigationScheduler.h" | 47 #include "core/loader/NavigationScheduler.h" |
| 48 #include "platform/RuntimeEnabledFeatures.h" |
| 47 #include "platform/SharedBuffer.h" | 49 #include "platform/SharedBuffer.h" |
| 48 #include "platform/ThreadSafeFunctional.h" | 50 #include "platform/ThreadSafeFunctional.h" |
| 49 #include "platform/TraceEvent.h" | 51 #include "platform/TraceEvent.h" |
| 50 #include "platform/heap/Handle.h" | 52 #include "platform/heap/Handle.h" |
| 51 #include "public/platform/Platform.h" | 53 #include "public/platform/Platform.h" |
| 52 #include "public/platform/WebFrameScheduler.h" | 54 #include "public/platform/WebFrameScheduler.h" |
| 53 #include "public/platform/WebScheduler.h" | 55 #include "public/platform/WebScheduler.h" |
| 54 #include "public/platform/WebThread.h" | 56 #include "public/platform/WebThread.h" |
| 55 #include "wtf/RefCounted.h" | 57 #include "wtf/RefCounted.h" |
| 56 #include "wtf/TemporaryChange.h" | 58 #include "wtf/TemporaryChange.h" |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 return m_treeBuilder->isParsingFragment(); | 261 return m_treeBuilder->isParsingFragment(); |
| 260 } | 262 } |
| 261 | 263 |
| 262 bool HTMLDocumentParser::processingData() const | 264 bool HTMLDocumentParser::processingData() const |
| 263 { | 265 { |
| 264 return isScheduledForResume() || inPumpSession() || m_haveBackgroundParser; | 266 return isScheduledForResume() || inPumpSession() || m_haveBackgroundParser; |
| 265 } | 267 } |
| 266 | 268 |
| 267 void HTMLDocumentParser::pumpTokenizerIfPossible() | 269 void HTMLDocumentParser::pumpTokenizerIfPossible() |
| 268 { | 270 { |
| 269 if (isStopped() || isWaitingForScripts()) | 271 if (isStopped() || isWaitingForBlockingResource()) |
| 270 return; | 272 return; |
| 271 | 273 |
| 272 pumpTokenizer(); | 274 pumpTokenizer(); |
| 273 } | 275 } |
| 274 | 276 |
| 275 bool HTMLDocumentParser::isScheduledForResume() const | 277 bool HTMLDocumentParser::isScheduledForResume() const |
| 276 { | 278 { |
| 277 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); | 279 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); |
| 278 } | 280 } |
| 279 | 281 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 307 | 309 |
| 308 if (isWaitingForScripts()) { | 310 if (isWaitingForScripts()) { |
| 309 // If we're paused waiting for a script, we try to execute scripts befor
e continuing. | 311 // If we're paused waiting for a script, we try to execute scripts befor
e continuing. |
| 310 runScriptsForPausedTreeBuilder(); | 312 runScriptsForPausedTreeBuilder(); |
| 311 if (isStopped()) | 313 if (isStopped()) |
| 312 return false; | 314 return false; |
| 313 if (isWaitingForScripts()) | 315 if (isWaitingForScripts()) |
| 314 return false; | 316 return false; |
| 315 } | 317 } |
| 316 | 318 |
| 319 if (isWaitingForStyles() || isWaitingForImports()) |
| 320 return false; |
| 321 |
| 317 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the | 322 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the |
| 318 // LocalFrame, but this approach is how the old parser handled | 323 // LocalFrame, but this approach is how the old parser handled |
| 319 // stopping when the page assigns window.location. What really | 324 // stopping when the page assigns window.location. What really |
| 320 // should happen is that assigning window.location causes the | 325 // should happen is that assigning window.location causes the |
| 321 // parser to stop parsing cleanly. The problem is we're not | 326 // parser to stop parsing cleanly. The problem is we're not |
| 322 // perpared to do that at every point where we run JavaScript. | 327 // perpared to do that at every point where we run JavaScript. |
| 323 if (!isParsingFragment() | 328 if (!isParsingFragment() |
| 324 && document()->frame() && document()->frame()->navigationScheduler().loc
ationChangePending()) | 329 && document()->frame() && document()->frame()->navigationScheduler().loc
ationChangePending()) |
| 325 return false; | 330 return false; |
| 326 | 331 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 351 // the document element is available, as we empty the queue immediately | 356 // the document element is available, as we empty the queue immediately |
| 352 // after the document element is created in pumpPendingSpeculations(). | 357 // after the document element is created in pumpPendingSpeculations(). |
| 353 ASSERT(m_queuedPreloads.isEmpty()); | 358 ASSERT(m_queuedPreloads.isEmpty()); |
| 354 for (auto& chunk : pendingChunks) | 359 for (auto& chunk : pendingChunks) |
| 355 m_preloader->takeAndPreload(chunk->preloads); | 360 m_preloader->takeAndPreload(chunk->preloads); |
| 356 } | 361 } |
| 357 | 362 |
| 358 for (auto& chunk : pendingChunks) | 363 for (auto& chunk : pendingChunks) |
| 359 m_speculations.append(chunk.release()); | 364 m_speculations.append(chunk.release()); |
| 360 | 365 |
| 361 if (!isWaitingForScripts() && !isScheduledForResume()) { | 366 if (!isWaitingForBlockingResource() && !isScheduledForResume()) { |
| 362 if (m_tasksWereSuspended) | 367 if (m_tasksWereSuspended) |
| 363 m_parserScheduler->forceResumeAfterYield(); | 368 m_parserScheduler->forceResumeAfterYield(); |
| 364 else | 369 else |
| 365 m_parserScheduler->scheduleForResume(); | 370 m_parserScheduler->scheduleForResume(); |
| 366 } | 371 } |
| 367 } | 372 } |
| 368 | 373 |
| 369 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser(const Docume
ntEncodingData& data) | 374 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser(const Docume
ntEncodingData& data) |
| 370 { | 375 { |
| 371 document()->setEncodingData(data); | 376 document()->setEncodingData(data); |
| 372 } | 377 } |
| 373 | 378 |
| 374 void HTMLDocumentParser::validateSpeculations(PassOwnPtr<ParsedChunk> chunk) | 379 void HTMLDocumentParser::validateSpeculations(PassOwnPtr<ParsedChunk> chunk) |
| 375 { | 380 { |
| 376 ASSERT(chunk); | 381 ASSERT(chunk); |
| 377 if (isWaitingForScripts()) { | 382 if (isWaitingForBlockingResource()) { |
| 378 // We're waiting on a network script, just save the chunk, we'll get | 383 // We're waiting on a blocking resource, just save the chunk, we'll get |
| 379 // a second validateSpeculations call after the script completes. | 384 // a second validateSpeculations call after the resource completes. |
| 380 // This call should have been made immediately after runScriptsForPaused
TreeBuilder | 385 // This call should have been made immediately after runScriptsForPaused
TreeBuilder |
| 381 // which may have started a network load and left us waiting. | 386 // in the case of a script which may have started a network load and lef
t us waiting. |
| 382 ASSERT(!m_lastChunkBeforeScript); | 387 ASSERT(!m_lastChunkBeforeBlockingResource); |
| 383 m_lastChunkBeforeScript = chunk; | 388 m_lastChunkBeforeBlockingResource = chunk; |
| 384 return; | 389 return; |
| 385 } | 390 } |
| 386 | 391 |
| 387 ASSERT(!m_lastChunkBeforeScript); | 392 ASSERT(!m_lastChunkBeforeBlockingResource); |
| 388 OwnPtr<HTMLTokenizer> tokenizer = m_tokenizer.release(); | 393 OwnPtr<HTMLTokenizer> tokenizer = m_tokenizer.release(); |
| 389 OwnPtr<HTMLToken> token = m_token.release(); | 394 OwnPtr<HTMLToken> token = m_token.release(); |
| 390 | 395 |
| 391 if (!tokenizer) { | 396 if (!tokenizer) { |
| 392 // There must not have been any changes to the HTMLTokenizer state on | 397 // There must not have been any changes to the HTMLTokenizer state on |
| 393 // the main thread, which means the speculation buffer is correct. | 398 // the main thread, which means the speculation buffer is correct. |
| 394 return; | 399 return; |
| 395 } | 400 } |
| 396 | 401 |
| 397 // Currently we're only smart enough to reuse the speculation buffer if the
tokenizer | 402 // Currently we're only smart enough to reuse the speculation buffer if the
tokenizer |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 HTMLParserThread::shared()->postTask(threadSafeBind(&BackgroundHTMLParser::r
esumeFrom, AllowCrossThreadAccess(m_backgroundParser), checkpoint.release())); | 434 HTMLParserThread::shared()->postTask(threadSafeBind(&BackgroundHTMLParser::r
esumeFrom, AllowCrossThreadAccess(m_backgroundParser), checkpoint.release())); |
| 430 } | 435 } |
| 431 | 436 |
| 432 size_t HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Par
sedChunk> popChunk) | 437 size_t HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Par
sedChunk> popChunk) |
| 433 { | 438 { |
| 434 TRACE_EVENT0("blink", "HTMLDocumentParser::processParsedChunkFromBackgroundP
arser"); | 439 TRACE_EVENT0("blink", "HTMLDocumentParser::processParsedChunkFromBackgroundP
arser"); |
| 435 TemporaryChange<bool> hasLineNumber(m_isParsingAtLineNumber, true); | 440 TemporaryChange<bool> hasLineNumber(m_isParsingAtLineNumber, true); |
| 436 | 441 |
| 437 ASSERT_WITH_SECURITY_IMPLICATION(document()->activeParserCount() == 1); | 442 ASSERT_WITH_SECURITY_IMPLICATION(document()->activeParserCount() == 1); |
| 438 ASSERT(!isParsingFragment()); | 443 ASSERT(!isParsingFragment()); |
| 439 ASSERT(!isWaitingForScripts()); | 444 ASSERT(!isWaitingForBlockingResource()); |
| 440 ASSERT(!isStopped()); | 445 ASSERT(!isStopped()); |
| 441 #if !ENABLE(OILPAN) | 446 #if !ENABLE(OILPAN) |
| 442 // ASSERT that this object is both attached to the Document and protected. | 447 // ASSERT that this object is both attached to the Document and protected. |
| 443 ASSERT(refCount() >= 2); | 448 ASSERT(refCount() >= 2); |
| 444 #endif | 449 #endif |
| 445 ASSERT(shouldUseThreading()); | 450 ASSERT(shouldUseThreading()); |
| 446 ASSERT(!m_tokenizer); | 451 ASSERT(!m_tokenizer); |
| 447 ASSERT(!m_token); | 452 ASSERT(!m_token); |
| 448 ASSERT(!m_lastChunkBeforeScript); | 453 ASSERT(!m_lastChunkBeforeBlockingResource); |
| 449 | 454 |
| 450 OwnPtr<ParsedChunk> chunk(popChunk); | 455 OwnPtr<ParsedChunk> chunk(popChunk); |
| 451 OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release(); | 456 OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release(); |
| 452 size_t elementTokenCount = 0; | 457 size_t elementTokenCount = 0; |
| 453 | 458 |
| 454 HTMLParserThread::shared()->postTask(threadSafeBind(&BackgroundHTMLParser::s
tartedChunkWithCheckpoint, AllowCrossThreadAccess(m_backgroundParser), chunk->in
putCheckpoint)); | 459 HTMLParserThread::shared()->postTask(threadSafeBind(&BackgroundHTMLParser::s
tartedChunkWithCheckpoint, AllowCrossThreadAccess(m_backgroundParser), chunk->in
putCheckpoint)); |
| 455 | 460 |
| 456 for (const auto& xssInfo : chunk->xssInfos) { | 461 for (const auto& xssInfo : chunk->xssInfos) { |
| 457 m_textPosition = xssInfo->m_textPosition; | 462 m_textPosition = xssInfo->m_textPosition; |
| 458 m_xssAuditorDelegate.didBlockScript(*xssInfo); | 463 m_xssAuditorDelegate.didBlockScript(*xssInfo); |
| 459 if (isStopped()) | 464 if (isStopped()) |
| 460 break; | 465 break; |
| 461 } | 466 } |
| 462 // XSSAuditorDelegate can detach the parser if it decides to block the entir
e current document. | 467 // XSSAuditorDelegate can detach the parser if it decides to block the entir
e current document. |
| 463 if (isDetached()) | 468 if (isDetached()) |
| 464 return elementTokenCount; | 469 return elementTokenCount; |
| 465 | 470 |
| 466 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); it != to
kens->end(); ++it) { | 471 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); it != to
kens->end(); ++it) { |
| 467 ASSERT(!isWaitingForScripts()); | 472 ASSERT(!isWaitingForBlockingResource()); |
| 468 | 473 |
| 469 if (!chunk->startingScript && (it->type() == HTMLToken::StartTag || it->
type() == HTMLToken::EndTag)) | 474 if (!chunk->startingScript && (it->type() == HTMLToken::StartTag || it->
type() == HTMLToken::EndTag)) |
| 470 elementTokenCount++; | 475 elementTokenCount++; |
| 471 | 476 |
| 472 if (document()->frame() && document()->frame()->navigationScheduler().lo
cationChangePending()) { | 477 if (document()->frame() && document()->frame()->navigationScheduler().lo
cationChangePending()) { |
| 473 | 478 |
| 474 // To match main-thread parser behavior (which never checks location
ChangePending on the EOF path) | 479 // To match main-thread parser behavior (which never checks location
ChangePending on the EOF path) |
| 475 // we peek to see if this chunk has an EOF and process it anyway. | 480 // we peek to see if this chunk has an EOF and process it anyway. |
| 476 if (tokens->last().type() == HTMLToken::EndOfFile) { | 481 if (tokens->last().type() == HTMLToken::EndOfFile) { |
| 477 ASSERT(m_speculations.isEmpty()); // There should never be any c
hunks after the EOF. | 482 ASSERT(m_speculations.isEmpty()); // There should never be any c
hunks after the EOF. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 490 if (!m_queuedPreloads.isEmpty() && document()->documentElement()) | 495 if (!m_queuedPreloads.isEmpty() && document()->documentElement()) |
| 491 m_preloader->takeAndPreload(m_queuedPreloads); | 496 m_preloader->takeAndPreload(m_queuedPreloads); |
| 492 | 497 |
| 493 if (isWaitingForScripts()) { | 498 if (isWaitingForScripts()) { |
| 494 ASSERT(it + 1 == tokens->end()); // The </script> is assumed to be t
he last token of this bunch. | 499 ASSERT(it + 1 == tokens->end()); // The </script> is assumed to be t
he last token of this bunch. |
| 495 runScriptsForPausedTreeBuilder(); | 500 runScriptsForPausedTreeBuilder(); |
| 496 validateSpeculations(chunk.release()); | 501 validateSpeculations(chunk.release()); |
| 497 break; | 502 break; |
| 498 } | 503 } |
| 499 | 504 |
| 505 if (isWaitingForStyles() || isWaitingForImports()) { |
| 506 ASSERT(it + 1 == tokens->end()); // The token is assumed to be the l
ast token of this bunch. |
| 507 validateSpeculations(chunk.release()); |
| 508 break; |
| 509 } |
| 510 |
| 500 if (it->type() == HTMLToken::EndOfFile) { | 511 if (it->type() == HTMLToken::EndOfFile) { |
| 501 ASSERT(it + 1 == tokens->end()); // The EOF is assumed to be the las
t token of this bunch. | 512 ASSERT(it + 1 == tokens->end()); // The EOF is assumed to be the las
t token of this bunch. |
| 502 ASSERT(m_speculations.isEmpty()); // There should never be any chunk
s after the EOF. | 513 ASSERT(m_speculations.isEmpty()); // There should never be any chunk
s after the EOF. |
| 503 prepareToStopParsing(); | 514 prepareToStopParsing(); |
| 504 break; | 515 break; |
| 505 } | 516 } |
| 506 | 517 |
| 507 ASSERT(!m_tokenizer); | 518 ASSERT(!m_tokenizer); |
| 508 ASSERT(!m_token); | 519 ASSERT(!m_token); |
| 509 } | 520 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 521 void HTMLDocumentParser::pumpPendingSpeculations() | 532 void HTMLDocumentParser::pumpPendingSpeculations() |
| 522 { | 533 { |
| 523 #if !ENABLE(OILPAN) | 534 #if !ENABLE(OILPAN) |
| 524 // ASSERT that this object is both attached to the Document and protected. | 535 // ASSERT that this object is both attached to the Document and protected. |
| 525 ASSERT(refCount() >= 2); | 536 ASSERT(refCount() >= 2); |
| 526 #endif | 537 #endif |
| 527 // If this assert fails, you need to call validateSpeculations to make sure | 538 // If this assert fails, you need to call validateSpeculations to make sure |
| 528 // m_tokenizer and m_token don't have state that invalidates m_speculations. | 539 // m_tokenizer and m_token don't have state that invalidates m_speculations. |
| 529 ASSERT(!m_tokenizer); | 540 ASSERT(!m_tokenizer); |
| 530 ASSERT(!m_token); | 541 ASSERT(!m_token); |
| 531 ASSERT(!m_lastChunkBeforeScript); | 542 ASSERT(!m_lastChunkBeforeBlockingResource); |
| 532 ASSERT(!isWaitingForScripts()); | 543 ASSERT(!isWaitingForBlockingResource()); |
| 533 ASSERT(!isStopped()); | 544 ASSERT(!isStopped()); |
| 534 ASSERT(!isScheduledForResume()); | 545 ASSERT(!isScheduledForResume()); |
| 535 ASSERT(!inPumpSession()); | 546 ASSERT(!inPumpSession()); |
| 536 | 547 |
| 537 // FIXME: Here should never be reached when there is a blocking script, | 548 // FIXME: Here should never be reached when there is a blocking script, |
| 538 // but it happens in unknown scenarios. See https://crbug.com/440901 | 549 // but it happens in unknown scenarios. See https://crbug.com/440901 |
| 539 if (isWaitingForScripts()) { | 550 if (isWaitingForBlockingResource()) { |
| 540 m_parserScheduler->scheduleForResume(); | 551 m_parserScheduler->scheduleForResume(); |
| 541 return; | 552 return; |
| 542 } | 553 } |
| 543 | 554 |
| 544 // Do not allow pumping speculations in nested event loops. | 555 // Do not allow pumping speculations in nested event loops. |
| 545 if (m_pumpSpeculationsSessionNestingLevel) { | 556 if (m_pumpSpeculationsSessionNestingLevel) { |
| 546 m_parserScheduler->scheduleForResume(); | 557 m_parserScheduler->scheduleForResume(); |
| 547 return; | 558 return; |
| 548 } | 559 } |
| 549 | 560 |
| 550 // FIXME: Pass in current input length. | 561 // FIXME: Pass in current input length. |
| 551 TRACE_EVENT_BEGIN1("devtools.timeline", "ParseHTML", "beginData", InspectorP
arseHtmlEvent::beginData(document(), lineNumber().zeroBasedInt())); | 562 TRACE_EVENT_BEGIN1("devtools.timeline", "ParseHTML", "beginData", InspectorP
arseHtmlEvent::beginData(document(), lineNumber().zeroBasedInt())); |
| 552 | 563 |
| 553 SpeculationsPumpSession session(m_pumpSpeculationsSessionNestingLevel, conte
xtForParsingSession()); | 564 SpeculationsPumpSession session(m_pumpSpeculationsSessionNestingLevel, conte
xtForParsingSession()); |
| 554 while (!m_speculations.isEmpty()) { | 565 while (!m_speculations.isEmpty()) { |
| 555 ASSERT(!isScheduledForResume()); | 566 ASSERT(!isScheduledForResume()); |
| 556 size_t elementTokenCount = processParsedChunkFromBackgroundParser(m_spec
ulations.takeFirst().release()); | 567 size_t elementTokenCount = processParsedChunkFromBackgroundParser(m_spec
ulations.takeFirst().release()); |
| 557 session.addedElementTokens(elementTokenCount); | 568 session.addedElementTokens(elementTokenCount); |
| 558 | 569 |
| 559 // Always check isParsing first as m_document may be null. | 570 // Always check isParsing first as m_document may be null. |
| 560 // Surprisingly, isScheduledForResume() may be set here as a result of | 571 // Surprisingly, isScheduledForResume() may be set here as a result of |
| 561 // processParsedChunkFromBackgroundParser running arbitrary javascript | 572 // processParsedChunkFromBackgroundParser running arbitrary javascript |
| 562 // which invokes nested event loops. (e.g. inspector breakpoints) | 573 // which invokes nested event loops. (e.g. inspector breakpoints) |
| 563 if (!isParsing() || isWaitingForScripts() || isScheduledForResume()) | 574 if (!isParsing() || isWaitingForBlockingResource() || isScheduledForResu
me()) |
| 564 break; | 575 break; |
| 565 | 576 |
| 566 if (m_speculations.isEmpty() || m_parserScheduler->yieldIfNeeded(session
, m_speculations.first()->startingScript)) | 577 if (m_speculations.isEmpty() || m_parserScheduler->yieldIfNeeded(session
, m_speculations.first()->startingScript)) |
| 567 break; | 578 break; |
| 568 } | 579 } |
| 569 | 580 |
| 570 TRACE_EVENT_END1("devtools.timeline", "ParseHTML", "endData", InspectorParse
HtmlEvent::endData(lineNumber().zeroBasedInt() - 1)); | 581 TRACE_EVENT_END1("devtools.timeline", "ParseHTML", "endData", InspectorParse
HtmlEvent::endData(lineNumber().zeroBasedInt() - 1)); |
| 571 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Update
Counters", TRACE_EVENT_SCOPE_THREAD, "data", InspectorUpdateCountersEvent::data(
)); | 582 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Update
Counters", TRACE_EVENT_SCOPE_THREAD, "data", InspectorUpdateCountersEvent::data(
)); |
| 572 } | 583 } |
| 573 | 584 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 642 #endif | 653 #endif |
| 643 | 654 |
| 644 if (isStopped()) | 655 if (isStopped()) |
| 645 return; | 656 return; |
| 646 | 657 |
| 647 // There should only be PendingText left since the tree-builder always flush
es | 658 // There should only be PendingText left since the tree-builder always flush
es |
| 648 // the task queue before returning. In case that ever changes, crash. | 659 // the task queue before returning. In case that ever changes, crash. |
| 649 m_treeBuilder->flush(FlushAlways); | 660 m_treeBuilder->flush(FlushAlways); |
| 650 RELEASE_ASSERT(!isStopped()); | 661 RELEASE_ASSERT(!isStopped()); |
| 651 | 662 |
| 652 if (isWaitingForScripts()) { | 663 if (isWaitingForBlockingResource()) { |
| 653 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); | 664 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); |
| 654 | 665 |
| 655 ASSERT(m_preloader); | 666 ASSERT(m_preloader); |
| 656 // TODO(kouhei): m_preloader should be always available for synchronous
parsing case, | 667 // TODO(kouhei): m_preloader should be always available for synchronous
parsing case, |
| 657 // adding paranoia if for speculative crash fix for crbug.com/465478 | 668 // adding paranoia if for speculative crash fix for crbug.com/465478 |
| 658 if (m_preloader) { | 669 if (m_preloader) { |
| 659 if (!m_preloadScanner) { | 670 if (!m_preloadScanner) { |
| 660 m_preloadScanner = HTMLPreloadScanner::create( | 671 m_preloadScanner = HTMLPreloadScanner::create( |
| 661 m_options, | 672 m_options, |
| 662 document()->url(), | 673 document()->url(), |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 732 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); | 743 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); |
| 733 m_token = adoptPtr(new HTMLToken); | 744 m_token = adoptPtr(new HTMLToken); |
| 734 m_tokenizer = HTMLTokenizer::create(m_options); | 745 m_tokenizer = HTMLTokenizer::create(m_options); |
| 735 } | 746 } |
| 736 | 747 |
| 737 SegmentedString excludedLineNumberSource(source); | 748 SegmentedString excludedLineNumberSource(source); |
| 738 excludedLineNumberSource.setExcludeLineNumbers(); | 749 excludedLineNumberSource.setExcludeLineNumbers(); |
| 739 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); | 750 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); |
| 740 pumpTokenizerIfPossible(); | 751 pumpTokenizerIfPossible(); |
| 741 | 752 |
| 742 if (isWaitingForScripts()) { | 753 if (isWaitingForBlockingResource()) { |
| 743 // Check the document.write() output with a separate preload scanner as | 754 // Check the document.write() output with a separate preload scanner as |
| 744 // the main scanner can't deal with insertions. | 755 // the main scanner can't deal with insertions. |
| 745 if (!m_insertionPreloadScanner) { | 756 if (!m_insertionPreloadScanner) { |
| 746 m_insertionPreloadScanner = HTMLPreloadScanner::create( | 757 m_insertionPreloadScanner = HTMLPreloadScanner::create( |
| 747 m_options, | 758 m_options, |
| 748 document()->url(), | 759 document()->url(), |
| 749 CachedDocumentParameters::create(document()), | 760 CachedDocumentParameters::create(document()), |
| 750 MediaValuesCached::MediaValuesCachedData(*document())); | 761 MediaValuesCached::MediaValuesCachedData(*document())); |
| 751 } | 762 } |
| 752 | 763 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 817 // as appendBytes() will directly ship the data to the thread. | 828 // as appendBytes() will directly ship the data to the thread. |
| 818 ASSERT(!shouldUseThreading()); | 829 ASSERT(!shouldUseThreading()); |
| 819 | 830 |
| 820 // pumpTokenizer can cause this parser to be detached from the Document, | 831 // pumpTokenizer can cause this parser to be detached from the Document, |
| 821 // but we need to ensure it isn't deleted yet. | 832 // but we need to ensure it isn't deleted yet. |
| 822 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); | 833 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); |
| 823 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), "HTMLDocumentParser::
append", "size", inputSource.length()); | 834 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), "HTMLDocumentParser::
append", "size", inputSource.length()); |
| 824 const SegmentedString source(inputSource); | 835 const SegmentedString source(inputSource); |
| 825 | 836 |
| 826 if (m_preloadScanner) { | 837 if (m_preloadScanner) { |
| 827 if (m_input.current().isEmpty() && !isWaitingForScripts()) { | 838 if (m_input.current().isEmpty() && !isWaitingForBlockingResource()) { |
| 828 // We have parsed until the end of the current input and so are now
moving ahead of the preload scanner. | 839 // We have parsed until the end of the current input and so are now
moving ahead of the preload scanner. |
| 829 // Clear the scanner so we know to scan starting from the current in
put point if we block again. | 840 // Clear the scanner so we know to scan starting from the current in
put point if we block again. |
| 830 m_preloadScanner.clear(); | 841 m_preloadScanner.clear(); |
| 831 } else { | 842 } else { |
| 832 m_preloadScanner->appendToEnd(source); | 843 m_preloadScanner->appendToEnd(source); |
| 833 if (isWaitingForScripts()) | 844 if (isWaitingForBlockingResource()) |
| 834 m_preloadScanner->scan(m_preloader.get(), document()->baseElemen
tURL()); | 845 m_preloadScanner->scan(m_preloader.get(), document()->baseElemen
tURL()); |
| 835 } | 846 } |
| 836 } | 847 } |
| 837 | 848 |
| 838 m_input.appendToEnd(source); | 849 m_input.appendToEnd(source); |
| 839 | 850 |
| 840 if (inPumpSession()) { | 851 if (inPumpSession()) { |
| 841 // We've gotten data off the network in a nested write. | 852 // We've gotten data off the network in a nested write. |
| 842 // We don't want to consume any more of the input stream now. Do | 853 // We don't want to consume any more of the input stream now. Do |
| 843 // not worry. We'll consume this data in a less-nested write(). | 854 // not worry. We'll consume this data in a less-nested write(). |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 980 // run the preload scanner, as well as delay completion of parsing. | 991 // run the preload scanner, as well as delay completion of parsing. |
| 981 bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript()
; | 992 bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript()
; |
| 982 bool scriptRunnerHasBlockingScript = m_scriptRunner && m_scriptRunner->hasPa
rserBlockingScript(); | 993 bool scriptRunnerHasBlockingScript = m_scriptRunner && m_scriptRunner->hasPa
rserBlockingScript(); |
| 983 // Since the parser is paused while a script runner has a blocking script, i
t should | 994 // Since the parser is paused while a script runner has a blocking script, i
t should |
| 984 // never be possible to end up with both objects holding a blocking script. | 995 // never be possible to end up with both objects holding a blocking script. |
| 985 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); | 996 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); |
| 986 // If either object has a blocking script, the parser should be paused. | 997 // If either object has a blocking script, the parser should be paused. |
| 987 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript; | 998 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript; |
| 988 } | 999 } |
| 989 | 1000 |
| 990 void HTMLDocumentParser::resumeParsingAfterScriptExecution() | 1001 bool HTMLDocumentParser::isWaitingForStyles() const |
| 1002 { |
| 1003 return RuntimeEnabledFeatures::htmlParserBlocksOnCSSEnabled() && document()
&& document()->styleEngine().hasPendingSheets(); |
| 1004 } |
| 1005 |
| 1006 bool HTMLDocumentParser::isWaitingForImports() const |
| 1007 { |
| 1008 return RuntimeEnabledFeatures::htmlParserBlocksOnCSSEnabled() && document()
&& !document()->haveImportsLoaded(); |
| 1009 } |
| 1010 |
| 1011 bool HTMLDocumentParser::isWaitingForBlockingResource() const |
| 1012 { |
| 1013 return isWaitingForScripts() || isWaitingForStyles() || isWaitingForImports(
); |
| 1014 } |
| 1015 |
| 1016 void HTMLDocumentParser::resumeParsingAfterBlock() |
| 991 { | 1017 { |
| 992 ASSERT(!isExecutingScript()); | 1018 ASSERT(!isExecutingScript()); |
| 993 ASSERT(!isWaitingForScripts()); | 1019 ASSERT(!isWaitingForBlockingResource()); |
| 994 | 1020 |
| 995 if (m_haveBackgroundParser) { | 1021 if (m_haveBackgroundParser) { |
| 996 validateSpeculations(m_lastChunkBeforeScript.release()); | 1022 validateSpeculations(m_lastChunkBeforeBlockingResource.release()); |
| 997 ASSERT(!m_lastChunkBeforeScript); | 1023 ASSERT(!m_lastChunkBeforeBlockingResource); |
| 998 // processParsedChunkFromBackgroundParser can cause this parser to be de
tached from the Document, | 1024 // processParsedChunkFromBackgroundParser can cause this parser to be de
tached from the Document, |
| 999 // but we need to ensure it isn't deleted yet. | 1025 // but we need to ensure it isn't deleted yet. |
| 1000 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); | 1026 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); |
| 1001 pumpPendingSpeculations(); | 1027 pumpPendingSpeculations(); |
| 1002 return; | 1028 return; |
| 1003 } | 1029 } |
| 1004 | 1030 |
| 1005 m_insertionPreloadScanner.clear(); | 1031 m_insertionPreloadScanner.clear(); |
| 1006 pumpTokenizerIfPossible(); | 1032 pumpTokenizerIfPossible(); |
| 1007 endIfDelayed(); | 1033 endIfDelayed(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1026 if (isStopped()) { | 1052 if (isStopped()) { |
| 1027 return; | 1053 return; |
| 1028 } | 1054 } |
| 1029 | 1055 |
| 1030 if (isStopping()) { | 1056 if (isStopping()) { |
| 1031 attemptToRunDeferredScriptsAndEnd(); | 1057 attemptToRunDeferredScriptsAndEnd(); |
| 1032 return; | 1058 return; |
| 1033 } | 1059 } |
| 1034 | 1060 |
| 1035 m_scriptRunner->executeScriptsWaitingForLoad(cachedResource); | 1061 m_scriptRunner->executeScriptsWaitingForLoad(cachedResource); |
| 1036 if (!isWaitingForScripts()) | 1062 if (!isWaitingForBlockingResource()) |
| 1037 resumeParsingAfterScriptExecution(); | 1063 resumeParsingAfterBlock(); |
| 1038 } | 1064 } |
| 1039 | 1065 |
| 1040 void HTMLDocumentParser::executeScriptsWaitingForResources() | 1066 void HTMLDocumentParser::executeScriptsWaitingForResources() |
| 1041 { | 1067 { |
| 1042 // Document only calls this when the Document owns the DocumentParser | 1068 // Document only calls this when the Document owns the DocumentParser |
| 1043 // so this will not be called in the DocumentFragment case. | 1069 // so this will not be called in the DocumentFragment case. |
| 1044 ASSERT(m_scriptRunner); | 1070 ASSERT(m_scriptRunner); |
| 1045 // Ignore calls unless we have a script blocking the parser waiting on a | |
| 1046 // stylesheet load. Otherwise we are currently parsing and this | |
| 1047 // is a re-entrant call from encountering a </ style> tag. | |
| 1048 if (!m_scriptRunner->hasScriptsWaitingForResources()) | |
| 1049 return; | |
| 1050 | 1071 |
| 1051 // pumpTokenizer can cause this parser to be detached from the Document, | 1072 if (m_scriptRunner->hasScriptsWaitingForResources()) { |
| 1052 // but we need to ensure it isn't deleted yet. | 1073 // pumpTokenizer can cause this parser to be detached from the Document, |
| 1053 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); | 1074 // but we need to ensure it isn't deleted yet. |
| 1054 m_scriptRunner->executeScriptsWaitingForResources(); | 1075 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); |
| 1055 if (!isWaitingForScripts()) | 1076 m_scriptRunner->executeScriptsWaitingForResources(); |
| 1056 resumeParsingAfterScriptExecution(); | 1077 if (!isWaitingForBlockingResource()) |
| 1078 resumeParsingAfterBlock(); |
| 1079 } else if (RuntimeEnabledFeatures::htmlParserBlocksOnCSSEnabled() && !inPump
Session() && !isWaitingForBlockingResource()) { |
| 1080 resumeParsingAfterBlock(); |
| 1081 } |
| 1057 } | 1082 } |
| 1058 | 1083 |
| 1059 void HTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFra
gment* fragment, Element* contextElement, ParserContentPolicy parserContentPolic
y) | 1084 void HTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFra
gment* fragment, Element* contextElement, ParserContentPolicy parserContentPolic
y) |
| 1060 { | 1085 { |
| 1061 RefPtrWillBeRawPtr<HTMLDocumentParser> parser = HTMLDocumentParser::create(f
ragment, contextElement, parserContentPolicy); | 1086 RefPtrWillBeRawPtr<HTMLDocumentParser> parser = HTMLDocumentParser::create(f
ragment, contextElement, parserContentPolicy); |
| 1062 parser->append(source); | 1087 parser->append(source); |
| 1063 parser->finish(); | 1088 parser->finish(); |
| 1064 ASSERT(!parser->processingData()); // Make sure we're done. <rdar://problem/
3963151> | 1089 ASSERT(!parser->processingData()); // Make sure we're done. <rdar://problem/
3963151> |
| 1065 parser->detach(); // Allows ~DocumentParser to assert it was detached before
destruction. | 1090 parser->detach(); // Allows ~DocumentParser to assert it was detached before
destruction. |
| 1066 } | 1091 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1127 void HTMLDocumentParser::setDecoder(PassOwnPtr<TextResourceDecoder> decoder) | 1152 void HTMLDocumentParser::setDecoder(PassOwnPtr<TextResourceDecoder> decoder) |
| 1128 { | 1153 { |
| 1129 ASSERT(decoder); | 1154 ASSERT(decoder); |
| 1130 DecodedDataDocumentParser::setDecoder(decoder); | 1155 DecodedDataDocumentParser::setDecoder(decoder); |
| 1131 | 1156 |
| 1132 if (m_haveBackgroundParser) | 1157 if (m_haveBackgroundParser) |
| 1133 HTMLParserThread::shared()->postTask(threadSafeBind(&BackgroundHTMLParse
r::setDecoder, AllowCrossThreadAccess(m_backgroundParser), takeDecoder())); | 1158 HTMLParserThread::shared()->postTask(threadSafeBind(&BackgroundHTMLParse
r::setDecoder, AllowCrossThreadAccess(m_backgroundParser), takeDecoder())); |
| 1134 } | 1159 } |
| 1135 | 1160 |
| 1136 } // namespace blink | 1161 } // namespace blink |
| OLD | NEW |