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 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, | 105 HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, |
106 Element* contextElement, | 106 Element* contextElement, |
107 ParserContentPolicy parserContentPolicy) | 107 ParserContentPolicy parserContentPolicy) |
108 : HTMLDocumentParser(fragment->document(), | 108 : HTMLDocumentParser(fragment->document(), |
109 parserContentPolicy, | 109 parserContentPolicy, |
110 ForceSynchronousParsing) { | 110 ForceSynchronousParsing) { |
111 // No m_scriptRunner in fragment parser. | 111 // No m_scriptRunner in fragment parser. |
112 m_treeBuilder = HTMLTreeBuilder::create(this, fragment, contextElement, | 112 m_treeBuilder = HTMLTreeBuilder::create(this, fragment, contextElement, |
113 parserContentPolicy, m_options); | 113 parserContentPolicy, m_options); |
114 | 114 |
115 bool reportErrors = | 115 // For now document fragment parsing never reports errors. |
116 false; // For now document fragment parsing never reports errors. | 116 bool reportErrors = false; |
117 m_tokenizer->setState( | 117 m_tokenizer->setState( |
118 tokenizerStateForContextElement(contextElement, reportErrors, m_options)); | 118 tokenizerStateForContextElement(contextElement, reportErrors, m_options)); |
119 m_xssAuditor.initForFragment(); | 119 m_xssAuditor.initForFragment(); |
120 } | 120 } |
121 | 121 |
122 HTMLDocumentParser::HTMLDocumentParser(Document& document, | 122 HTMLDocumentParser::HTMLDocumentParser(Document& document, |
123 ParserContentPolicy contentPolicy, | 123 ParserContentPolicy contentPolicy, |
124 ParserSynchronizationPolicy syncPolicy) | 124 ParserSynchronizationPolicy syncPolicy) |
125 : ScriptableDocumentParser(document, contentPolicy), | 125 : ScriptableDocumentParser(document, contentPolicy), |
126 m_options(&document), | 126 m_options(&document), |
(...skipping 26 matching lines...) Expand all Loading... |
153 ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); | 153 ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); |
154 // Threading is not allowed in prefetch mode. | 154 // Threading is not allowed in prefetch mode. |
155 DCHECK(!document.isPrefetchOnly() || !shouldUseThreading()); | 155 DCHECK(!document.isPrefetchOnly() || !shouldUseThreading()); |
156 | 156 |
157 ThreadState::current()->registerPreFinalizer(this); | 157 ThreadState::current()->registerPreFinalizer(this); |
158 } | 158 } |
159 | 159 |
160 HTMLDocumentParser::~HTMLDocumentParser() {} | 160 HTMLDocumentParser::~HTMLDocumentParser() {} |
161 | 161 |
162 void HTMLDocumentParser::dispose() { | 162 void HTMLDocumentParser::dispose() { |
163 // In Oilpan, HTMLDocumentParser can die together with Document, and | 163 // In Oilpan, HTMLDocumentParser can die together with Document, and detach() |
164 // detach() is not called in this case. | 164 // is not called in this case. |
165 if (m_haveBackgroundParser) | 165 if (m_haveBackgroundParser) |
166 stopBackgroundParser(); | 166 stopBackgroundParser(); |
167 } | 167 } |
168 | 168 |
169 DEFINE_TRACE(HTMLDocumentParser) { | 169 DEFINE_TRACE(HTMLDocumentParser) { |
170 visitor->trace(m_treeBuilder); | 170 visitor->trace(m_treeBuilder); |
171 visitor->trace(m_parserScheduler); | 171 visitor->trace(m_parserScheduler); |
172 visitor->trace(m_xssAuditorDelegate); | 172 visitor->trace(m_xssAuditorDelegate); |
173 visitor->trace(m_scriptRunner); | 173 visitor->trace(m_scriptRunner); |
174 visitor->trace(m_preloader); | 174 visitor->trace(m_preloader); |
(...skipping 13 matching lines...) Expand all Loading... |
188 peakPendingTokenHistogram.count( | 188 peakPendingTokenHistogram.count( |
189 m_tokenizedChunkQueue->peakPendingTokenCount()); | 189 m_tokenizedChunkQueue->peakPendingTokenCount()); |
190 } | 190 } |
191 | 191 |
192 if (m_haveBackgroundParser) | 192 if (m_haveBackgroundParser) |
193 stopBackgroundParser(); | 193 stopBackgroundParser(); |
194 DocumentParser::detach(); | 194 DocumentParser::detach(); |
195 if (m_scriptRunner) | 195 if (m_scriptRunner) |
196 m_scriptRunner->detach(); | 196 m_scriptRunner->detach(); |
197 m_treeBuilder->detach(); | 197 m_treeBuilder->detach(); |
198 // FIXME: It seems wrong that we would have a preload scanner here. | 198 // FIXME: It seems wrong that we would have a preload scanner here. Yet during |
199 // Yet during fast/dom/HTMLScriptElement/script-load-events.html we do. | 199 // fast/dom/HTMLScriptElement/script-load-events.html we do. |
200 m_preloadScanner.reset(); | 200 m_preloadScanner.reset(); |
201 m_insertionPreloadScanner.reset(); | 201 m_insertionPreloadScanner.reset(); |
202 if (m_parserScheduler) { | 202 if (m_parserScheduler) { |
203 m_parserScheduler->detach(); | 203 m_parserScheduler->detach(); |
204 m_parserScheduler.clear(); | 204 m_parserScheduler.clear(); |
205 } | 205 } |
206 // Oilpan: It is important to clear m_token to deallocate backing memory of | 206 // Oilpan: It is important to clear m_token to deallocate backing memory of |
207 // HTMLToken::m_data and let the allocator reuse the memory for | 207 // HTMLToken::m_data and let the allocator reuse the memory for |
208 // HTMLToken::m_data of a next HTMLDocumentParser. We need to clear | 208 // HTMLToken::m_data of a next HTMLDocumentParser. We need to clear |
209 // m_tokenizer first because m_tokenizer has a raw pointer to m_token. | 209 // m_tokenizer first because m_tokenizer has a raw pointer to m_token. |
(...skipping 26 matching lines...) Expand all Loading... |
236 | 236 |
237 if (isStopped()) | 237 if (isStopped()) |
238 return; | 238 return; |
239 | 239 |
240 DocumentParser::prepareToStopParsing(); | 240 DocumentParser::prepareToStopParsing(); |
241 | 241 |
242 // We will not have a scriptRunner when parsing a DocumentFragment. | 242 // We will not have a scriptRunner when parsing a DocumentFragment. |
243 if (m_scriptRunner) | 243 if (m_scriptRunner) |
244 document()->setReadyState(Document::Interactive); | 244 document()->setReadyState(Document::Interactive); |
245 | 245 |
246 // Setting the ready state above can fire mutation event and detach us | 246 // Setting the ready state above can fire mutation event and detach us from |
247 // from underneath. In that case, just bail out. | 247 // underneath. In that case, just bail out. |
248 if (isDetached()) | 248 if (isDetached()) |
249 return; | 249 return; |
250 | 250 |
251 attemptToRunDeferredScriptsAndEnd(); | 251 attemptToRunDeferredScriptsAndEnd(); |
252 } | 252 } |
253 | 253 |
254 bool HTMLDocumentParser::isParsingFragment() const { | 254 bool HTMLDocumentParser::isParsingFragment() const { |
255 return m_treeBuilder->isParsingFragment(); | 255 return m_treeBuilder->isParsingFragment(); |
256 } | 256 } |
257 | 257 |
(...skipping 24 matching lines...) Expand all Loading... |
282 m_treeBuilder->takeScriptToProcess(scriptStartPosition); | 282 m_treeBuilder->takeScriptToProcess(scriptStartPosition); |
283 // We will not have a scriptRunner when parsing a DocumentFragment. | 283 // We will not have a scriptRunner when parsing a DocumentFragment. |
284 if (m_scriptRunner) | 284 if (m_scriptRunner) |
285 m_scriptRunner->execute(scriptElement, scriptStartPosition); | 285 m_scriptRunner->execute(scriptElement, scriptStartPosition); |
286 } | 286 } |
287 | 287 |
288 bool HTMLDocumentParser::canTakeNextToken() { | 288 bool HTMLDocumentParser::canTakeNextToken() { |
289 if (isStopped()) | 289 if (isStopped()) |
290 return false; | 290 return false; |
291 | 291 |
292 // If we're paused waiting for a script, we try to execute scripts before cont
inuing. | 292 // If we're paused waiting for a script, we try to execute scripts before |
| 293 // continuing. |
293 if (m_treeBuilder->hasParserBlockingScript()) | 294 if (m_treeBuilder->hasParserBlockingScript()) |
294 runScriptsForPausedTreeBuilder(); | 295 runScriptsForPausedTreeBuilder(); |
295 if (isStopped() || isWaitingForScripts()) | 296 if (isStopped() || isWaitingForScripts()) |
296 return false; | 297 return false; |
297 | 298 |
298 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the | 299 // FIXME: It's wrong for the HTMLDocumentParser to reach back to the |
299 // LocalFrame, but this approach is how the old parser handled | 300 // LocalFrame, but this approach is how the old parser handled stopping when |
300 // stopping when the page assigns window.location. What really | 301 // the page assigns window.location. What really should happen is that |
301 // should happen is that assigning window.location causes the | 302 // assigning window.location causes the parser to stop parsing cleanly. The |
302 // parser to stop parsing cleanly. The problem is we're not | 303 // problem is we're not perpared to do that at every point where we run |
303 // perpared to do that at every point where we run JavaScript. | 304 // JavaScript. |
304 if (!isParsingFragment() && document()->frame() && | 305 if (!isParsingFragment() && document()->frame() && |
305 document()->frame()->navigationScheduler().locationChangePending()) | 306 document()->frame()->navigationScheduler().locationChangePending()) |
306 return false; | 307 return false; |
307 | 308 |
308 return true; | 309 return true; |
309 } | 310 } |
310 | 311 |
311 void HTMLDocumentParser::notifyPendingTokenizedChunks() { | 312 void HTMLDocumentParser::notifyPendingTokenizedChunks() { |
312 TRACE_EVENT0("blink", "HTMLDocumentParser::notifyPendingTokenizedChunks"); | 313 TRACE_EVENT0("blink", "HTMLDocumentParser::notifyPendingTokenizedChunks"); |
313 DCHECK(m_tokenizedChunkQueue); | 314 DCHECK(m_tokenizedChunkQueue); |
314 | 315 |
315 Vector<std::unique_ptr<TokenizedChunk>> pendingChunks; | 316 Vector<std::unique_ptr<TokenizedChunk>> pendingChunks; |
316 m_tokenizedChunkQueue->takeAll(pendingChunks); | 317 m_tokenizedChunkQueue->takeAll(pendingChunks); |
317 | 318 |
318 if (!isParsing()) | 319 if (!isParsing()) |
319 return; | 320 return; |
320 | 321 |
321 // ApplicationCache needs to be initialized before issuing preloads. | 322 // ApplicationCache needs to be initialized before issuing preloads. We |
322 // We suspend preload until HTMLHTMLElement is inserted and | 323 // suspend preload until HTMLHTMLElement is inserted and ApplicationCache is |
323 // ApplicationCache is initialized. Note: link rel preloads don't follow | 324 // initialized. Note: link rel preloads don't follow this policy per the spec. |
324 // this policy per the spec. These directives should initiate a fetch as | 325 // These directives should initiate a fetch as fast as possible. |
325 // fast as possible. | |
326 if (!m_triedLoadingLinkHeaders && document()->loader() && | 326 if (!m_triedLoadingLinkHeaders && document()->loader() && |
327 !pendingChunks.isEmpty()) { | 327 !pendingChunks.isEmpty()) { |
328 // Note that on commit, the loader dispatched preloads for all the | 328 // Note that on commit, the loader dispatched preloads for all the non-media |
329 // non-media links. | 329 // links. |
330 document()->loader()->dispatchLinkHeaderPreloads( | 330 document()->loader()->dispatchLinkHeaderPreloads( |
331 &pendingChunks.first()->viewport, LinkLoader::OnlyLoadMedia); | 331 &pendingChunks.first()->viewport, LinkLoader::OnlyLoadMedia); |
332 m_triedLoadingLinkHeaders = true; | 332 m_triedLoadingLinkHeaders = true; |
333 } | 333 } |
334 | 334 |
335 // Defer preloads if any of the chunks contains a <meta> csp tag. | 335 // Defer preloads if any of the chunks contains a <meta> csp tag. |
336 for (auto& chunk : pendingChunks) { | 336 for (auto& chunk : pendingChunks) { |
337 if (chunk->pendingCSPMetaTokenIndex != TokenizedChunk::noPendingToken) { | 337 if (chunk->pendingCSPMetaTokenIndex != TokenizedChunk::noPendingToken) { |
338 m_pendingCSPMetaToken = | 338 m_pendingCSPMetaToken = |
339 &chunk->tokens->at(chunk->pendingCSPMetaTokenIndex); | 339 &chunk->tokens->at(chunk->pendingCSPMetaTokenIndex); |
(...skipping 12 matching lines...) Expand all Loading... |
352 m_queuedPreloads.append(std::move(request)); | 352 m_queuedPreloads.append(std::move(request)); |
353 } | 353 } |
354 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { | 354 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { |
355 const CompactHTMLToken& token = chunk->tokens->at(index); | 355 const CompactHTMLToken& token = chunk->tokens->at(index); |
356 ASSERT(token.type() == HTMLToken::TokenType::Character); | 356 ASSERT(token.type() == HTMLToken::TokenType::Character); |
357 m_queuedDocumentWriteScripts.append(token.data()); | 357 m_queuedDocumentWriteScripts.append(token.data()); |
358 } | 358 } |
359 } | 359 } |
360 m_preloader->takeAndPreload(linkRelPreloads); | 360 m_preloader->takeAndPreload(linkRelPreloads); |
361 } else { | 361 } else { |
362 // We can safely assume that there are no queued preloads request after | 362 // We can safely assume that there are no queued preloads request after the |
363 // the document element is available, as we empty the queue immediately | 363 // document element is available, as we empty the queue immediately after |
364 // after the document element is created in documentElementAvailable(). | 364 // the document element is created in documentElementAvailable(). |
365 ASSERT(m_queuedPreloads.isEmpty()); | 365 ASSERT(m_queuedPreloads.isEmpty()); |
366 ASSERT(m_queuedDocumentWriteScripts.isEmpty()); | 366 ASSERT(m_queuedDocumentWriteScripts.isEmpty()); |
367 // Loop through the chunks to generate preloads before any | 367 // Loop through the chunks to generate preloads before any document.write |
368 // document.write script evaluation takes place. Preloading these | 368 // script evaluation takes place. Preloading these scripts is valuable and |
369 // scripts is valuable and comparably cheap, while evaluating JS can be | 369 // comparably cheap, while evaluating JS can be expensive. |
370 // expensive. | |
371 for (auto& chunk : pendingChunks) { | 370 for (auto& chunk : pendingChunks) { |
372 m_preloader->takeAndPreload(chunk->preloads); | 371 m_preloader->takeAndPreload(chunk->preloads); |
373 } | 372 } |
374 for (auto& chunk : pendingChunks) { | 373 for (auto& chunk : pendingChunks) { |
375 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { | 374 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { |
376 const CompactHTMLToken& token = chunk->tokens->at(index); | 375 const CompactHTMLToken& token = chunk->tokens->at(index); |
377 ASSERT(token.type() == HTMLToken::TokenType::Character); | 376 ASSERT(token.type() == HTMLToken::TokenType::Character); |
378 evaluateAndPreloadScriptForDocumentWrite(token.data()); | 377 evaluateAndPreloadScriptForDocumentWrite(token.data()); |
379 } | 378 } |
380 } | 379 } |
(...skipping 12 matching lines...) Expand all Loading... |
393 | 392 |
394 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( | 393 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( |
395 const DocumentEncodingData& data) { | 394 const DocumentEncodingData& data) { |
396 document()->setEncodingData(data); | 395 document()->setEncodingData(data); |
397 } | 396 } |
398 | 397 |
399 void HTMLDocumentParser::validateSpeculations( | 398 void HTMLDocumentParser::validateSpeculations( |
400 std::unique_ptr<TokenizedChunk> chunk) { | 399 std::unique_ptr<TokenizedChunk> chunk) { |
401 ASSERT(chunk); | 400 ASSERT(chunk); |
402 if (isWaitingForScripts()) { | 401 if (isWaitingForScripts()) { |
403 // We're waiting on a network script, just save the chunk, we'll get | 402 // We're waiting on a network script, just save the chunk, we'll get a |
404 // a second validateSpeculations call after the script completes. | 403 // second validateSpeculations call after the script completes. This call |
405 // This call should have been made immediately after runScriptsForPausedTree
Builder | 404 // should have been made immediately after runScriptsForPausedTreeBuilder |
406 // which may have started a network load and left us waiting. | 405 // which may have started a network load and left us waiting. |
407 ASSERT(!m_lastChunkBeforeScript); | 406 ASSERT(!m_lastChunkBeforeScript); |
408 m_lastChunkBeforeScript = std::move(chunk); | 407 m_lastChunkBeforeScript = std::move(chunk); |
409 return; | 408 return; |
410 } | 409 } |
411 | 410 |
412 ASSERT(!m_lastChunkBeforeScript); | 411 ASSERT(!m_lastChunkBeforeScript); |
413 std::unique_ptr<HTMLTokenizer> tokenizer = std::move(m_tokenizer); | 412 std::unique_ptr<HTMLTokenizer> tokenizer = std::move(m_tokenizer); |
414 std::unique_ptr<HTMLToken> token = std::move(m_token); | 413 std::unique_ptr<HTMLToken> token = std::move(m_token); |
415 | 414 |
416 if (!tokenizer) { | 415 if (!tokenizer) { |
417 // There must not have been any changes to the HTMLTokenizer state on | 416 // There must not have been any changes to the HTMLTokenizer state on the |
418 // the main thread, which means the speculation buffer is correct. | 417 // main thread, which means the speculation buffer is correct. |
419 return; | 418 return; |
420 } | 419 } |
421 | 420 |
422 // Currently we're only smart enough to reuse the speculation buffer if the to
kenizer | 421 // Currently we're only smart enough to reuse the speculation buffer if the |
423 // both starts and ends in the DataState. That state is simplest because the H
TMLToken | 422 // tokenizer both starts and ends in the DataState. That state is simplest |
424 // is always in the Uninitialized state. We should consider whether we can reu
se the | 423 // because the HTMLToken is always in the Uninitialized state. We should |
425 // speculation buffer in other states, but we'd likely need to do something mo
re | 424 // consider whether we can reuse the speculation buffer in other states, but |
426 // sophisticated with the HTMLToken. | 425 // we'd likely need to do something more sophisticated with the HTMLToken. |
427 if (chunk->tokenizerState == HTMLTokenizer::DataState && | 426 if (chunk->tokenizerState == HTMLTokenizer::DataState && |
428 tokenizer->getState() == HTMLTokenizer::DataState && | 427 tokenizer->getState() == HTMLTokenizer::DataState && |
429 m_input.current().isEmpty() && | 428 m_input.current().isEmpty() && |
430 chunk->treeBuilderState == | 429 chunk->treeBuilderState == |
431 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get())) { | 430 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get())) { |
432 ASSERT(token->isUninitialized()); | 431 ASSERT(token->isUninitialized()); |
433 return; | 432 return; |
434 } | 433 } |
435 | 434 |
436 discardSpeculationsAndResumeFrom(std::move(chunk), std::move(token), | 435 discardSpeculationsAndResumeFrom(std::move(chunk), std::move(token), |
(...skipping 22 matching lines...) Expand all Loading... |
459 wrapUnique(new BackgroundHTMLParser::Checkpoint); | 458 wrapUnique(new BackgroundHTMLParser::Checkpoint); |
460 checkpoint->parser = m_weakFactory.createWeakPtr(); | 459 checkpoint->parser = m_weakFactory.createWeakPtr(); |
461 checkpoint->token = std::move(token); | 460 checkpoint->token = std::move(token); |
462 checkpoint->tokenizer = std::move(tokenizer); | 461 checkpoint->tokenizer = std::move(tokenizer); |
463 checkpoint->treeBuilderState = | 462 checkpoint->treeBuilderState = |
464 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get()); | 463 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get()); |
465 checkpoint->inputCheckpoint = lastChunkBeforeScript->inputCheckpoint; | 464 checkpoint->inputCheckpoint = lastChunkBeforeScript->inputCheckpoint; |
466 checkpoint->preloadScannerCheckpoint = | 465 checkpoint->preloadScannerCheckpoint = |
467 lastChunkBeforeScript->preloadScannerCheckpoint; | 466 lastChunkBeforeScript->preloadScannerCheckpoint; |
468 checkpoint->unparsedInput = m_input.current().toString().isolatedCopy(); | 467 checkpoint->unparsedInput = m_input.current().toString().isolatedCopy(); |
469 m_input.current() | 468 // FIXME: This should be passed in instead of cleared. |
470 .clear(); // FIXME: This should be passed in instead of cleared. | 469 m_input.current().clear(); |
471 | 470 |
472 ASSERT(checkpoint->unparsedInput.isSafeToSendToAnotherThread()); | 471 ASSERT(checkpoint->unparsedInput.isSafeToSendToAnotherThread()); |
473 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::resumeFrom, | 472 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::resumeFrom, |
474 m_backgroundParser, passed(std::move(checkpoint))); | 473 m_backgroundParser, passed(std::move(checkpoint))); |
475 } | 474 } |
476 | 475 |
477 size_t HTMLDocumentParser::processTokenizedChunkFromBackgroundParser( | 476 size_t HTMLDocumentParser::processTokenizedChunkFromBackgroundParser( |
478 std::unique_ptr<TokenizedChunk> popChunk) { | 477 std::unique_ptr<TokenizedChunk> popChunk) { |
479 TRACE_EVENT_WITH_FLOW0( | 478 TRACE_EVENT_WITH_FLOW0( |
480 "blink,loading", | 479 "blink,loading", |
(...skipping 18 matching lines...) Expand all Loading... |
499 postTaskToLookaheadParser(Asynchronous, | 498 postTaskToLookaheadParser(Asynchronous, |
500 &BackgroundHTMLParser::startedChunkWithCheckpoint, | 499 &BackgroundHTMLParser::startedChunkWithCheckpoint, |
501 m_backgroundParser, chunk->inputCheckpoint); | 500 m_backgroundParser, chunk->inputCheckpoint); |
502 | 501 |
503 for (const auto& xssInfo : chunk->xssInfos) { | 502 for (const auto& xssInfo : chunk->xssInfos) { |
504 m_textPosition = xssInfo->m_textPosition; | 503 m_textPosition = xssInfo->m_textPosition; |
505 m_xssAuditorDelegate.didBlockScript(*xssInfo); | 504 m_xssAuditorDelegate.didBlockScript(*xssInfo); |
506 if (isStopped()) | 505 if (isStopped()) |
507 break; | 506 break; |
508 } | 507 } |
509 // XSSAuditorDelegate can detach the parser if it decides to block the entire
current document. | 508 // XSSAuditorDelegate can detach the parser if it decides to block the entire |
| 509 // current document. |
510 if (isDetached()) | 510 if (isDetached()) |
511 return elementTokenCount; | 511 return elementTokenCount; |
512 | 512 |
513 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); | 513 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); |
514 it != tokens->end(); ++it) { | 514 it != tokens->end(); ++it) { |
515 ASSERT(!isWaitingForScripts()); | 515 ASSERT(!isWaitingForScripts()); |
516 | 516 |
517 if (!chunk->startingScript && | 517 if (!chunk->startingScript && |
518 (it->type() == HTMLToken::StartTag || it->type() == HTMLToken::EndTag)) | 518 (it->type() == HTMLToken::StartTag || it->type() == HTMLToken::EndTag)) |
519 elementTokenCount++; | 519 elementTokenCount++; |
520 | 520 |
521 if (document()->frame() && | 521 if (document()->frame() && |
522 document()->frame()->navigationScheduler().locationChangePending()) { | 522 document()->frame()->navigationScheduler().locationChangePending()) { |
523 // To match main-thread parser behavior (which never checks locationChange
Pending on the EOF path) | 523 // To match main-thread parser behavior (which never checks |
524 // we peek to see if this chunk has an EOF and process it anyway. | 524 // locationChangePending on the EOF path) we peek to see if this chunk has |
| 525 // an EOF and process it anyway. |
525 if (tokens->last().type() == HTMLToken::EndOfFile) { | 526 if (tokens->last().type() == HTMLToken::EndOfFile) { |
526 ASSERT( | 527 ASSERT( |
527 m_speculations | 528 m_speculations |
528 .isEmpty()); // There should never be any chunks after the EOF. | 529 .isEmpty()); // There should never be any chunks after the EOF. |
529 prepareToStopParsing(); | 530 prepareToStopParsing(); |
530 } | 531 } |
531 break; | 532 break; |
532 } | 533 } |
533 | 534 |
534 m_textPosition = it->textPosition(); | 535 m_textPosition = it->textPosition(); |
535 | 536 |
536 constructTreeFromCompactHTMLToken(*it); | 537 constructTreeFromCompactHTMLToken(*it); |
537 | 538 |
538 if (isStopped()) | 539 if (isStopped()) |
539 break; | 540 break; |
540 | 541 |
541 // Preloads were queued if there was a <meta> csp token in a tokenized | 542 // Preloads were queued if there was a <meta> csp token in a tokenized |
542 // chunk. | 543 // chunk. |
543 if (m_pendingCSPMetaToken && it == m_pendingCSPMetaToken) { | 544 if (m_pendingCSPMetaToken && it == m_pendingCSPMetaToken) { |
544 m_pendingCSPMetaToken = nullptr; | 545 m_pendingCSPMetaToken = nullptr; |
545 fetchQueuedPreloads(); | 546 fetchQueuedPreloads(); |
546 } | 547 } |
547 | 548 |
548 if (isWaitingForScripts()) { | 549 if (isWaitingForScripts()) { |
549 ASSERT( | 550 // The </script> is assumed to be the last token of this bunch. |
550 it + 1 == | 551 ASSERT(it + 1 == tokens->end()); |
551 tokens | |
552 ->end()); // The </script> is assumed to be the last token of thi
s bunch. | |
553 runScriptsForPausedTreeBuilder(); | 552 runScriptsForPausedTreeBuilder(); |
554 validateSpeculations(std::move(chunk)); | 553 validateSpeculations(std::move(chunk)); |
555 break; | 554 break; |
556 } | 555 } |
557 | 556 |
558 if (it->type() == HTMLToken::EndOfFile) { | 557 if (it->type() == HTMLToken::EndOfFile) { |
559 ASSERT( | 558 // The EOF is assumed to be the last token of this bunch. |
560 it + 1 == | 559 ASSERT(it + 1 == tokens->end()); |
561 tokens | 560 // There should never be any chunks after the EOF. |
562 ->end()); // The EOF is assumed to be the last token of this bunc
h. | 561 ASSERT(m_speculations.isEmpty()); |
563 ASSERT( | |
564 m_speculations | |
565 .isEmpty()); // There should never be any chunks after the EOF. | |
566 prepareToStopParsing(); | 562 prepareToStopParsing(); |
567 break; | 563 break; |
568 } | 564 } |
569 | 565 |
570 ASSERT(!m_tokenizer); | 566 ASSERT(!m_tokenizer); |
571 ASSERT(!m_token); | 567 ASSERT(!m_token); |
572 } | 568 } |
573 | 569 |
574 // Make sure all required pending text nodes are emitted before returning. | 570 // Make sure all required pending text nodes are emitted before returning. |
575 // This leaves "script", "style" and "svg" nodes text nodes intact. | 571 // This leaves "script", "style" and "svg" nodes text nodes intact. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
610 InspectorParseHtmlEvent::beginData( | 606 InspectorParseHtmlEvent::beginData( |
611 document(), lineNumber().zeroBasedInt())); | 607 document(), lineNumber().zeroBasedInt())); |
612 | 608 |
613 SpeculationsPumpSession session(m_pumpSpeculationsSessionNestingLevel); | 609 SpeculationsPumpSession session(m_pumpSpeculationsSessionNestingLevel); |
614 while (!m_speculations.isEmpty()) { | 610 while (!m_speculations.isEmpty()) { |
615 ASSERT(!isScheduledForResume()); | 611 ASSERT(!isScheduledForResume()); |
616 size_t elementTokenCount = | 612 size_t elementTokenCount = |
617 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); | 613 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); |
618 session.addedElementTokens(elementTokenCount); | 614 session.addedElementTokens(elementTokenCount); |
619 | 615 |
620 // Always check isParsing first as m_document may be null. | 616 // Always check isParsing first as m_document may be null. Surprisingly, |
621 // Surprisingly, isScheduledForResume() may be set here as a result of | 617 // isScheduledForResume() may be set here as a result of |
622 // processTokenizedChunkFromBackgroundParser running arbitrary javascript | 618 // processTokenizedChunkFromBackgroundParser running arbitrary javascript |
623 // which invokes nested event loops. (e.g. inspector breakpoints) | 619 // which invokes nested event loops. (e.g. inspector breakpoints) |
624 if (!isParsing() || isWaitingForScripts() || isScheduledForResume()) | 620 if (!isParsing() || isWaitingForScripts() || isScheduledForResume()) |
625 break; | 621 break; |
626 | 622 |
627 if (m_speculations.isEmpty() || | 623 if (m_speculations.isEmpty() || |
628 m_parserScheduler->yieldIfNeeded( | 624 m_parserScheduler->yieldIfNeeded( |
629 session, m_speculations.first()->startingScript)) | 625 session, m_speculations.first()->startingScript)) |
630 break; | 626 break; |
631 } | 627 } |
(...skipping 22 matching lines...) Expand all Loading... |
654 m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); | 650 m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); |
655 } | 651 } |
656 | 652 |
657 void HTMLDocumentParser::pumpTokenizer() { | 653 void HTMLDocumentParser::pumpTokenizer() { |
658 ASSERT(!isStopped()); | 654 ASSERT(!isStopped()); |
659 ASSERT(m_tokenizer); | 655 ASSERT(m_tokenizer); |
660 ASSERT(m_token); | 656 ASSERT(m_token); |
661 | 657 |
662 PumpSession session(m_pumpSessionNestingLevel); | 658 PumpSession session(m_pumpSessionNestingLevel); |
663 | 659 |
664 // We tell the InspectorInstrumentation about every pump, even if we | 660 // We tell the InspectorInstrumentation about every pump, even if we end up |
665 // end up pumping nothing. It can filter out empty pumps itself. | 661 // pumping nothing. It can filter out empty pumps itself. |
666 // FIXME: m_input.current().length() is only accurate if we | 662 // FIXME: m_input.current().length() is only accurate if we end up parsing the |
667 // end up parsing the whole buffer in this pump. We should pass how | 663 // whole buffer in this pump. We should pass how much we parsed as part of |
668 // much we parsed as part of didWriteHTML instead of willWriteHTML. | 664 // didWriteHTML instead of willWriteHTML. |
669 TRACE_EVENT_BEGIN1( | 665 TRACE_EVENT_BEGIN1( |
670 "devtools.timeline", "ParseHTML", "beginData", | 666 "devtools.timeline", "ParseHTML", "beginData", |
671 InspectorParseHtmlEvent::beginData( | 667 InspectorParseHtmlEvent::beginData( |
672 document(), m_input.current().currentLine().zeroBasedInt())); | 668 document(), m_input.current().currentLine().zeroBasedInt())); |
673 | 669 |
674 if (!isParsingFragment()) | 670 if (!isParsingFragment()) |
675 m_xssAuditor.init(document(), &m_xssAuditorDelegate); | 671 m_xssAuditor.init(document(), &m_xssAuditorDelegate); |
676 | 672 |
677 while (canTakeNextToken()) { | 673 while (canTakeNextToken()) { |
678 if (m_xssAuditor.isEnabled()) | 674 if (m_xssAuditor.isEnabled()) |
(...skipping 22 matching lines...) Expand all Loading... |
701 | 697 |
702 // There should only be PendingText left since the tree-builder always flushes | 698 // There should only be PendingText left since the tree-builder always flushes |
703 // the task queue before returning. In case that ever changes, crash. | 699 // the task queue before returning. In case that ever changes, crash. |
704 m_treeBuilder->flush(FlushAlways); | 700 m_treeBuilder->flush(FlushAlways); |
705 RELEASE_ASSERT(!isStopped()); | 701 RELEASE_ASSERT(!isStopped()); |
706 | 702 |
707 if (isWaitingForScripts()) { | 703 if (isWaitingForScripts()) { |
708 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); | 704 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); |
709 | 705 |
710 ASSERT(m_preloader); | 706 ASSERT(m_preloader); |
711 // TODO(kouhei): m_preloader should be always available for synchronous pars
ing case, | 707 // TODO(kouhei): m_preloader should be always available for synchronous |
712 // adding paranoia if for speculative crash fix for crbug.com/465478 | 708 // parsing case, adding paranoia if for speculative crash fix for |
| 709 // crbug.com/465478 |
713 if (m_preloader) { | 710 if (m_preloader) { |
714 if (!m_preloadScanner) { | 711 if (!m_preloadScanner) { |
715 m_preloadScanner = createPreloadScanner(); | 712 m_preloadScanner = createPreloadScanner(); |
716 m_preloadScanner->appendToEnd(m_input.current()); | 713 m_preloadScanner->appendToEnd(m_input.current()); |
717 } | 714 } |
718 m_preloadScanner->scanAndPreload( | 715 m_preloadScanner->scanAndPreload( |
719 m_preloader.get(), document()->validBaseElementURL(), nullptr); | 716 m_preloader.get(), document()->validBaseElementURL(), nullptr); |
720 } | 717 } |
721 } | 718 } |
722 | 719 |
(...skipping 30 matching lines...) Expand all Loading... |
753 } | 750 } |
754 } | 751 } |
755 | 752 |
756 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( | 753 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( |
757 const CompactHTMLToken& compactToken) { | 754 const CompactHTMLToken& compactToken) { |
758 AtomicHTMLToken token(compactToken); | 755 AtomicHTMLToken token(compactToken); |
759 m_treeBuilder->constructTree(&token); | 756 m_treeBuilder->constructTree(&token); |
760 } | 757 } |
761 | 758 |
762 bool HTMLDocumentParser::hasInsertionPoint() { | 759 bool HTMLDocumentParser::hasInsertionPoint() { |
763 // FIXME: The wasCreatedByScript() branch here might not be fully correct. | 760 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our |
764 // Our model of the EOF character differs slightly from the one in | 761 // model of the EOF character differs slightly from the one in the spec |
765 // the spec because our treatment is uniform between network-sourced | 762 // because our treatment is uniform between network-sourced and script-sourced |
766 // and script-sourced input streams whereas the spec treats them | 763 // input streams whereas the spec treats them differently. |
767 // differently. | |
768 return m_input.hasInsertionPoint() || | 764 return m_input.hasInsertionPoint() || |
769 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); | 765 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); |
770 } | 766 } |
771 | 767 |
772 void HTMLDocumentParser::insert(const SegmentedString& source) { | 768 void HTMLDocumentParser::insert(const SegmentedString& source) { |
773 if (isStopped()) | 769 if (isStopped()) |
774 return; | 770 return; |
775 | 771 |
776 TRACE_EVENT1("blink", "HTMLDocumentParser::insert", "source_length", | 772 TRACE_EVENT1("blink", "HTMLDocumentParser::insert", "source_length", |
777 source.length()); | 773 source.length()); |
(...skipping 23 matching lines...) Expand all Loading... |
801 endIfDelayed(); | 797 endIfDelayed(); |
802 } | 798 } |
803 | 799 |
804 void HTMLDocumentParser::startBackgroundParser() { | 800 void HTMLDocumentParser::startBackgroundParser() { |
805 ASSERT(!isStopped()); | 801 ASSERT(!isStopped()); |
806 ASSERT(shouldUseThreading()); | 802 ASSERT(shouldUseThreading()); |
807 ASSERT(!m_haveBackgroundParser); | 803 ASSERT(!m_haveBackgroundParser); |
808 ASSERT(document()); | 804 ASSERT(document()); |
809 m_haveBackgroundParser = true; | 805 m_haveBackgroundParser = true; |
810 | 806 |
811 // TODO(alexclarke): Remove WebFrameScheduler::setDocumentParsingInBackground
when background parser goes away. | 807 // TODO(alexclarke): Remove WebFrameScheduler::setDocumentParsingInBackground |
| 808 // when background parser goes away. |
812 if (document()->frame() && document()->frame()->frameScheduler()) | 809 if (document()->frame() && document()->frame()->frameScheduler()) |
813 document()->frame()->frameScheduler()->setDocumentParsingInBackground(true); | 810 document()->frame()->frameScheduler()->setDocumentParsingInBackground(true); |
814 | 811 |
815 // Make sure that a resolver is set up, so that the correct viewport dimension
s will be fed to the background parser and preload scanner. | 812 // Make sure that a resolver is set up, so that the correct viewport |
| 813 // dimensions will be fed to the background parser and preload scanner. |
816 if (document()->loader()) | 814 if (document()->loader()) |
817 document()->ensureStyleResolver(); | 815 document()->ensureStyleResolver(); |
818 | 816 |
819 std::unique_ptr<BackgroundHTMLParser::Configuration> config = | 817 std::unique_ptr<BackgroundHTMLParser::Configuration> config = |
820 wrapUnique(new BackgroundHTMLParser::Configuration); | 818 wrapUnique(new BackgroundHTMLParser::Configuration); |
821 config->options = m_options; | 819 config->options = m_options; |
822 config->parser = m_weakFactory.createWeakPtr(); | 820 config->parser = m_weakFactory.createWeakPtr(); |
823 config->xssAuditor = wrapUnique(new XSSAuditor); | 821 config->xssAuditor = wrapUnique(new XSSAuditor); |
824 config->xssAuditor->init(document(), &m_xssAuditorDelegate); | 822 config->xssAuditor->init(document(), &m_xssAuditorDelegate); |
825 | 823 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
866 // ParseHTMLOnMainThread lands (the lookahead parser will be a member). | 864 // ParseHTMLOnMainThread lands (the lookahead parser will be a member). |
867 postTaskToLookaheadParser(Synchronous, &BackgroundHTMLParser::stop, | 865 postTaskToLookaheadParser(Synchronous, &BackgroundHTMLParser::stop, |
868 m_backgroundParser); | 866 m_backgroundParser); |
869 m_weakFactory.revokeAll(); | 867 m_weakFactory.revokeAll(); |
870 } | 868 } |
871 | 869 |
872 void HTMLDocumentParser::append(const String& inputSource) { | 870 void HTMLDocumentParser::append(const String& inputSource) { |
873 if (isStopped()) | 871 if (isStopped()) |
874 return; | 872 return; |
875 | 873 |
876 // We should never reach this point if we're using a parser thread, | 874 // We should never reach this point if we're using a parser thread, as |
877 // as appendBytes() will directly ship the data to the thread. | 875 // appendBytes() will directly ship the data to the thread. |
878 ASSERT(!shouldUseThreading()); | 876 ASSERT(!shouldUseThreading()); |
879 | 877 |
880 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), | 878 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), |
881 "HTMLDocumentParser::append", "size", inputSource.length()); | 879 "HTMLDocumentParser::append", "size", inputSource.length()); |
882 const SegmentedString source(inputSource); | 880 const SegmentedString source(inputSource); |
883 | 881 |
884 if (document()->isPrefetchOnly()) { | 882 if (document()->isPrefetchOnly()) { |
885 if (!m_preloadScanner) | 883 if (!m_preloadScanner) |
886 m_preloadScanner = createPreloadScanner(); | 884 m_preloadScanner = createPreloadScanner(); |
887 | 885 |
888 m_preloadScanner->appendToEnd(source); | 886 m_preloadScanner->appendToEnd(source); |
889 m_preloadScanner->scanAndPreload( | 887 m_preloadScanner->scanAndPreload( |
890 m_preloader.get(), document()->validBaseElementURL(), nullptr); | 888 m_preloader.get(), document()->validBaseElementURL(), nullptr); |
891 | 889 |
892 // Return after the preload scanner, do not actually parse the document. | 890 // Return after the preload scanner, do not actually parse the document. |
893 return; | 891 return; |
894 } | 892 } |
895 | 893 |
896 if (m_preloadScanner) { | 894 if (m_preloadScanner) { |
897 if (m_input.current().isEmpty() && !isWaitingForScripts()) { | 895 if (m_input.current().isEmpty() && !isWaitingForScripts()) { |
898 // We have parsed until the end of the current input and so are now moving
ahead of the preload scanner. | 896 // We have parsed until the end of the current input and so are now moving |
899 // Clear the scanner so we know to scan starting from the current input po
int if we block again. | 897 // ahead of the preload scanner. Clear the scanner so we know to scan |
| 898 // starting from the current input point if we block again. |
900 m_preloadScanner.reset(); | 899 m_preloadScanner.reset(); |
901 } else { | 900 } else { |
902 m_preloadScanner->appendToEnd(source); | 901 m_preloadScanner->appendToEnd(source); |
903 if (isWaitingForScripts()) | 902 if (isWaitingForScripts()) |
904 m_preloadScanner->scanAndPreload( | 903 m_preloadScanner->scanAndPreload( |
905 m_preloader.get(), document()->validBaseElementURL(), nullptr); | 904 m_preloader.get(), document()->validBaseElementURL(), nullptr); |
906 } | 905 } |
907 } | 906 } |
908 | 907 |
909 m_input.appendToEnd(source); | 908 m_input.appendToEnd(source); |
910 | 909 |
911 if (inPumpSession()) { | 910 if (inPumpSession()) { |
912 // We've gotten data off the network in a nested write. | 911 // We've gotten data off the network in a nested write. We don't want to |
913 // We don't want to consume any more of the input stream now. Do | 912 // consume any more of the input stream now. Do not worry. We'll consume |
914 // not worry. We'll consume this data in a less-nested write(). | 913 // this data in a less-nested write(). |
915 return; | 914 return; |
916 } | 915 } |
917 | 916 |
918 pumpTokenizerIfPossible(); | 917 pumpTokenizerIfPossible(); |
919 | 918 |
920 endIfDelayed(); | 919 endIfDelayed(); |
921 } | 920 } |
922 | 921 |
923 void HTMLDocumentParser::end() { | 922 void HTMLDocumentParser::end() { |
924 ASSERT(!isDetached()); | 923 ASSERT(!isDetached()); |
925 ASSERT(!isScheduledForResume()); | 924 ASSERT(!isScheduledForResume()); |
926 | 925 |
927 if (m_haveBackgroundParser) | 926 if (m_haveBackgroundParser) |
928 stopBackgroundParser(); | 927 stopBackgroundParser(); |
929 | 928 |
930 // Informs the the rest of WebCore that parsing is really finished (and delete
s this). | 929 // Informs the the rest of WebCore that parsing is really finished (and |
| 930 // deletes this). |
931 m_treeBuilder->finished(); | 931 m_treeBuilder->finished(); |
932 | 932 |
933 DocumentParser::stopParsing(); | 933 DocumentParser::stopParsing(); |
934 } | 934 } |
935 | 935 |
936 void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd() { | 936 void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd() { |
937 ASSERT(isStopping()); | 937 ASSERT(isStopping()); |
938 // FIXME: It may not be correct to disable this for the background parser. | 938 // FIXME: It may not be correct to disable this for the background parser. |
939 // That means hasInsertionPoint() may not be correct in some cases. | 939 // That means hasInsertionPoint() may not be correct in some cases. |
940 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); | 940 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); |
(...skipping 19 matching lines...) Expand all Loading... |
960 return; | 960 return; |
961 | 961 |
962 if (!m_endWasDelayed || shouldDelayEnd()) | 962 if (!m_endWasDelayed || shouldDelayEnd()) |
963 return; | 963 return; |
964 | 964 |
965 m_endWasDelayed = false; | 965 m_endWasDelayed = false; |
966 prepareToStopParsing(); | 966 prepareToStopParsing(); |
967 } | 967 } |
968 | 968 |
969 void HTMLDocumentParser::finish() { | 969 void HTMLDocumentParser::finish() { |
970 // FIXME: We should ASSERT(!m_parserStopped) here, since it does not | 970 // FIXME: We should ASSERT(!m_parserStopped) here, since it does not makes |
971 // makes sense to call any methods on DocumentParser once it's been stopped. | 971 // sense to call any methods on DocumentParser once it's been stopped. |
972 // However, FrameLoader::stop calls DocumentParser::finish unconditionally. | 972 // However, FrameLoader::stop calls DocumentParser::finish unconditionally. |
973 | 973 |
974 flush(); | 974 flush(); |
975 if (isDetached()) | 975 if (isDetached()) |
976 return; | 976 return; |
977 | 977 |
978 // Empty documents never got an append() call, and thus have never started | 978 // Empty documents never got an append() call, and thus have never started a |
979 // a background parser. In those cases, we ignore shouldUseThreading() | 979 // background parser. In those cases, we ignore shouldUseThreading() and fall |
980 // and fall through to the non-threading case. | 980 // through to the non-threading case. |
981 if (m_haveBackgroundParser) { | 981 if (m_haveBackgroundParser) { |
982 if (!m_input.haveSeenEndOfFile()) | 982 if (!m_input.haveSeenEndOfFile()) |
983 m_input.closeWithoutMarkingEndOfFile(); | 983 m_input.closeWithoutMarkingEndOfFile(); |
984 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::finish, | 984 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::finish, |
985 m_backgroundParser); | 985 m_backgroundParser); |
986 return; | 986 return; |
987 } | 987 } |
988 | 988 |
989 if (!m_tokenizer) { | 989 if (!m_tokenizer) { |
990 ASSERT(!m_token); | 990 ASSERT(!m_token); |
991 // We're finishing before receiving any data. Rather than booting up | 991 // We're finishing before receiving any data. Rather than booting up the |
992 // the background parser just to spin it down, we finish parsing | 992 // background parser just to spin it down, we finish parsing synchronously. |
993 // synchronously. | |
994 m_token = wrapUnique(new HTMLToken); | 993 m_token = wrapUnique(new HTMLToken); |
995 m_tokenizer = HTMLTokenizer::create(m_options); | 994 m_tokenizer = HTMLTokenizer::create(m_options); |
996 } | 995 } |
997 | 996 |
998 // We're not going to get any more data off the network, so we tell the | 997 // We're not going to get any more data off the network, so we tell the input |
999 // input stream we've reached the end of file. finish() can be called more | 998 // stream we've reached the end of file. finish() can be called more than |
1000 // than once, if the first time does not call end(). | 999 // once, if the first time does not call end(). |
1001 if (!m_input.haveSeenEndOfFile()) | 1000 if (!m_input.haveSeenEndOfFile()) |
1002 m_input.markEndOfFile(); | 1001 m_input.markEndOfFile(); |
1003 | 1002 |
1004 attemptToEnd(); | 1003 attemptToEnd(); |
1005 } | 1004 } |
1006 | 1005 |
1007 bool HTMLDocumentParser::isExecutingScript() const { | 1006 bool HTMLDocumentParser::isExecutingScript() const { |
1008 if (!m_scriptRunner) | 1007 if (!m_scriptRunner) |
1009 return false; | 1008 return false; |
1010 return m_scriptRunner->isExecutingScript(); | 1009 return m_scriptRunner->isExecutingScript(); |
(...skipping 16 matching lines...) Expand all Loading... |
1027 return m_textPosition; | 1026 return m_textPosition; |
1028 | 1027 |
1029 const SegmentedString& currentString = m_input.current(); | 1028 const SegmentedString& currentString = m_input.current(); |
1030 OrdinalNumber line = currentString.currentLine(); | 1029 OrdinalNumber line = currentString.currentLine(); |
1031 OrdinalNumber column = currentString.currentColumn(); | 1030 OrdinalNumber column = currentString.currentColumn(); |
1032 | 1031 |
1033 return TextPosition(line, column); | 1032 return TextPosition(line, column); |
1034 } | 1033 } |
1035 | 1034 |
1036 bool HTMLDocumentParser::isWaitingForScripts() const { | 1035 bool HTMLDocumentParser::isWaitingForScripts() const { |
1037 // When the TreeBuilder encounters a </script> tag, it returns to the HTMLDocu
mentParser | 1036 // When the TreeBuilder encounters a </script> tag, it returns to the |
1038 // where the script is transfered from the treebuilder to the script runner. | 1037 // HTMLDocumentParser where the script is transfered from the treebuilder to |
1039 // The script runner will hold the script until its loaded and run. During | 1038 // the script runner. The script runner will hold the script until its loaded |
1040 // any of this time, we want to count ourselves as "waiting for a script" and
thus | 1039 // and run. During any of this time, we want to count ourselves as "waiting |
1041 // run the preload scanner, as well as delay completion of parsing. | 1040 // for a script" and thus run the preload scanner, as well as delay completion |
| 1041 // of parsing. |
1042 bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript(); | 1042 bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript(); |
1043 bool scriptRunnerHasBlockingScript = | 1043 bool scriptRunnerHasBlockingScript = |
1044 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); | 1044 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); |
1045 // Since the parser is paused while a script runner has a blocking script, it
should | 1045 // Since the parser is paused while a script runner has a blocking script, it |
1046 // never be possible to end up with both objects holding a blocking script. | 1046 // should never be possible to end up with both objects holding a blocking |
| 1047 // script. |
1047 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); | 1048 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); |
1048 // If either object has a blocking script, the parser should be paused. | 1049 // If either object has a blocking script, the parser should be paused. |
1049 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || | 1050 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || |
1050 m_reentryPermit->parserPauseFlag(); | 1051 m_reentryPermit->parserPauseFlag(); |
1051 } | 1052 } |
1052 | 1053 |
1053 void HTMLDocumentParser::resumeParsingAfterScriptExecution() { | 1054 void HTMLDocumentParser::resumeParsingAfterScriptExecution() { |
1054 ASSERT(!isExecutingScript()); | 1055 ASSERT(!isExecutingScript()); |
1055 ASSERT(!isWaitingForScripts()); | 1056 ASSERT(!isWaitingForScripts()); |
1056 | 1057 |
(...skipping 28 matching lines...) Expand all Loading... |
1085 attemptToRunDeferredScriptsAndEnd(); | 1086 attemptToRunDeferredScriptsAndEnd(); |
1086 return; | 1087 return; |
1087 } | 1088 } |
1088 | 1089 |
1089 m_scriptRunner->executeScriptsWaitingForLoad(cachedResource); | 1090 m_scriptRunner->executeScriptsWaitingForLoad(cachedResource); |
1090 if (!isWaitingForScripts()) | 1091 if (!isWaitingForScripts()) |
1091 resumeParsingAfterScriptExecution(); | 1092 resumeParsingAfterScriptExecution(); |
1092 } | 1093 } |
1093 | 1094 |
1094 void HTMLDocumentParser::executeScriptsWaitingForResources() { | 1095 void HTMLDocumentParser::executeScriptsWaitingForResources() { |
1095 // Document only calls this when the Document owns the DocumentParser | 1096 // Document only calls this when the Document owns the DocumentParser so this |
1096 // so this will not be called in the DocumentFragment case. | 1097 // will not be called in the DocumentFragment case. |
1097 ASSERT(m_scriptRunner); | 1098 ASSERT(m_scriptRunner); |
1098 // Ignore calls unless we have a script blocking the parser waiting on a | 1099 // Ignore calls unless we have a script blocking the parser waiting on a |
1099 // stylesheet load. Otherwise we are currently parsing and this | 1100 // stylesheet load. Otherwise we are currently parsing and this is a |
1100 // is a re-entrant call from encountering a </ style> tag. | 1101 // re-entrant call from encountering a </ style> tag. |
1101 if (!m_scriptRunner->hasScriptsWaitingForResources()) | 1102 if (!m_scriptRunner->hasScriptsWaitingForResources()) |
1102 return; | 1103 return; |
1103 m_scriptRunner->executeScriptsWaitingForResources(); | 1104 m_scriptRunner->executeScriptsWaitingForResources(); |
1104 if (!isWaitingForScripts()) | 1105 if (!isWaitingForScripts()) |
1105 resumeParsingAfterScriptExecution(); | 1106 resumeParsingAfterScriptExecution(); |
1106 } | 1107 } |
1107 | 1108 |
1108 void HTMLDocumentParser::parseDocumentFragment( | 1109 void HTMLDocumentParser::parseDocumentFragment( |
1109 const String& source, | 1110 const String& source, |
1110 DocumentFragment* fragment, | 1111 DocumentFragment* fragment, |
1111 Element* contextElement, | 1112 Element* contextElement, |
1112 ParserContentPolicy parserContentPolicy) { | 1113 ParserContentPolicy parserContentPolicy) { |
1113 HTMLDocumentParser* parser = | 1114 HTMLDocumentParser* parser = |
1114 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); | 1115 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); |
1115 parser->append(source); | 1116 parser->append(source); |
1116 parser->finish(); | 1117 parser->finish(); |
1117 parser | 1118 // Allows ~DocumentParser to assert it was detached before destruction. |
1118 ->detach(); // Allows ~DocumentParser to assert it was detached before de
struction. | 1119 parser->detach(); |
1119 } | 1120 } |
1120 | 1121 |
1121 void HTMLDocumentParser::suspendScheduledTasks() { | 1122 void HTMLDocumentParser::suspendScheduledTasks() { |
1122 ASSERT(!m_tasksWereSuspended); | 1123 ASSERT(!m_tasksWereSuspended); |
1123 m_tasksWereSuspended = true; | 1124 m_tasksWereSuspended = true; |
1124 if (m_parserScheduler) | 1125 if (m_parserScheduler) |
1125 m_parserScheduler->suspend(); | 1126 m_parserScheduler->suspend(); |
1126 } | 1127 } |
1127 | 1128 |
1128 void HTMLDocumentParser::resumeScheduledTasks() { | 1129 void HTMLDocumentParser::resumeScheduledTasks() { |
(...skipping 30 matching lines...) Expand all Loading... |
1159 | 1160 |
1160 DecodedDataDocumentParser::appendBytes(data, length); | 1161 DecodedDataDocumentParser::appendBytes(data, length); |
1161 } | 1162 } |
1162 | 1163 |
1163 void HTMLDocumentParser::flush() { | 1164 void HTMLDocumentParser::flush() { |
1164 // If we've got no decoder, we never received any data. | 1165 // If we've got no decoder, we never received any data. |
1165 if (isDetached() || needsDecoder()) | 1166 if (isDetached() || needsDecoder()) |
1166 return; | 1167 return; |
1167 | 1168 |
1168 if (shouldUseThreading()) { | 1169 if (shouldUseThreading()) { |
1169 // In some cases, flush() is called without any invocation of | 1170 // In some cases, flush() is called without any invocation of appendBytes. |
1170 // appendBytes. Fallback to synchronous parsing in that case. | 1171 // Fallback to synchronous parsing in that case. |
1171 if (!m_haveBackgroundParser) { | 1172 if (!m_haveBackgroundParser) { |
1172 m_shouldUseThreading = false; | 1173 m_shouldUseThreading = false; |
1173 m_token = wrapUnique(new HTMLToken); | 1174 m_token = wrapUnique(new HTMLToken); |
1174 m_tokenizer = HTMLTokenizer::create(m_options); | 1175 m_tokenizer = HTMLTokenizer::create(m_options); |
1175 DecodedDataDocumentParser::flush(); | 1176 DecodedDataDocumentParser::flush(); |
1176 return; | 1177 return; |
1177 } | 1178 } |
1178 | 1179 |
1179 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::flush, | 1180 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::flush, |
1180 m_backgroundParser); | 1181 m_backgroundParser); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1294 case Asynchronous: | 1295 case Asynchronous: |
1295 m_loadingTaskRunner->postTask( | 1296 m_loadingTaskRunner->postTask( |
1296 BLINK_FROM_HERE, | 1297 BLINK_FROM_HERE, |
1297 WTF::bind(function, std::forward<Ps>(parameters)...)); | 1298 WTF::bind(function, std::forward<Ps>(parameters)...)); |
1298 return; | 1299 return; |
1299 } | 1300 } |
1300 NOTREACHED(); | 1301 NOTREACHED(); |
1301 } | 1302 } |
1302 | 1303 |
1303 } // namespace blink | 1304 } // namespace blink |
OLD | NEW |