| 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 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 ASSERT(m_haveBackgroundParser); | 152 ASSERT(m_haveBackgroundParser); |
| 153 pumpPendingChunks(); | 153 pumpPendingChunks(); |
| 154 } | 154 } |
| 155 | 155 |
| 156 void HTMLDocumentParser::runScriptsForPausedTreeBuilder() | 156 void HTMLDocumentParser::runScriptsForPausedTreeBuilder() |
| 157 { | 157 { |
| 158 if (m_isFragment) | 158 if (m_isFragment) |
| 159 return; | 159 return; |
| 160 TextPosition scriptStartPosition = TextPosition::belowRangePosition(); | 160 TextPosition scriptStartPosition = TextPosition::belowRangePosition(); |
| 161 RefPtr<Element> scriptToProcess = m_treeBuilder->takeScriptToProcess(scriptS
tartPosition); | 161 RefPtr<Element> scriptToProcess = m_treeBuilder->takeScriptToProcess(scriptS
tartPosition); |
| 162 m_scriptRunner.runScript(toHTMLScriptElement(scriptToProcess.get()), scriptS
tartPosition); | 162 |
| 163 // Sending the script to dart may find additional 'import' declarations |
| 164 // which need to load before the script can execute. HTMLScriptRunner |
| 165 // always calls scriptExecutionCompleted regardless of success/failure. |
| 166 m_scriptRunner = HTMLScriptRunner::createForScript( |
| 167 toHTMLScriptElement(scriptToProcess.get()), scriptStartPosition, this); |
| 168 m_scriptRunner->start(); |
| 163 } | 169 } |
| 164 | 170 |
| 165 void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<Pa
rsedChunk> chunk) | 171 void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<Pa
rsedChunk> chunk) |
| 166 { | 172 { |
| 167 TRACE_EVENT0("blink", "HTMLDocumentParser::didReceiveParsedChunkFromBackgrou
ndParser"); | 173 TRACE_EVENT0("blink", "HTMLDocumentParser::didReceiveParsedChunkFromBackgrou
ndParser"); |
| 168 // Sky should not need nested parsers. | 174 // Sky should not need nested parsers. |
| 169 ASSERT(document()->activeParserCount() == 0); | 175 ASSERT(document()->activeParserCount() == 0); |
| 170 | 176 |
| 171 if (isWaitingForScripts() || !m_pendingChunks.isEmpty() || document()->activ
eParserCount() > 0 || !document()->haveImportsLoaded()) { | 177 if (isWaitingForScripts() || !m_pendingChunks.isEmpty() || |
| 178 document()->activeParserCount() > 0) { |
| 172 m_pendingChunks.append(chunk); | 179 m_pendingChunks.append(chunk); |
| 173 return; | 180 return; |
| 174 } | 181 } |
| 175 | 182 |
| 176 // processParsedChunkFromBackgroundParser can cause this parser to be detach
ed from the Document, | 183 // processParsedChunkFromBackgroundParser can cause this parser to be detach
ed from the Document, |
| 177 // but we need to ensure it isn't deleted yet. | 184 // but we need to ensure it isn't deleted yet. |
| 178 RefPtr<HTMLDocumentParser> protect(this); | 185 RefPtr<HTMLDocumentParser> protect(this); |
| 179 | 186 |
| 180 ASSERT(m_pendingChunks.isEmpty()); | 187 ASSERT(m_pendingChunks.isEmpty()); |
| 181 m_pendingChunks.append(chunk); | 188 m_pendingChunks.append(chunk); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 193 ASSERT(!isStopped()); | 200 ASSERT(!isStopped()); |
| 194 | 201 |
| 195 // ASSERT that this object is both attached to the Document and protected. | 202 // ASSERT that this object is both attached to the Document and protected. |
| 196 ASSERT(refCount() >= 2); | 203 ASSERT(refCount() >= 2); |
| 197 | 204 |
| 198 ActiveParserSession session(contextForParsingSession()); | 205 ActiveParserSession session(contextForParsingSession()); |
| 199 | 206 |
| 200 OwnPtr<ParsedChunk> chunk(popChunk); | 207 OwnPtr<ParsedChunk> chunk(popChunk); |
| 201 OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release(); | 208 OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release(); |
| 202 | 209 |
| 203 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); it != to
kens->end(); ++it) { | 210 Vector<CompactHTMLToken>::const_iterator it; |
| 204 ASSERT(!isWaitingForScripts()); | 211 for (it = tokens->begin(); it != tokens->end(); ++it) { |
| 212 // A chunk can issue import loads causing us to be isWaitingForScripts |
| 213 // but we don't stop processing in that case. |
| 214 ASSERT(!m_treeBuilder->hasParserBlockingScript()); |
| 215 ASSERT(!m_scriptRunner); |
| 205 | 216 |
| 206 m_textPosition = it->textPosition(); | 217 m_textPosition = it->textPosition(); |
| 207 | 218 |
| 208 constructTreeFromCompactHTMLToken(*it); | 219 constructTreeFromCompactHTMLToken(*it); |
| 209 | 220 |
| 210 if (isStopped()) | 221 if (isStopped()) |
| 211 break; | 222 break; |
| 212 | 223 |
| 213 if (isWaitingForScripts()) { | 224 if (m_treeBuilder->hasParserBlockingScript()) { |
| 214 ASSERT(it + 1 == tokens->end()); // The </script> is assumed to be t
he last token of this bunch. | 225 ++it; // Make it == end() during non-stopped termination. |
| 226 ASSERT(it == tokens->end()); // The </script> is assumed to be the |
| 227 // last token of this bunch. |
| 215 runScriptsForPausedTreeBuilder(); | 228 runScriptsForPausedTreeBuilder(); |
| 216 break; | 229 break; |
| 217 } | 230 } |
| 218 | 231 |
| 219 if (it->type() == HTMLToken::EndOfFile) { | 232 if (it->type() == HTMLToken::EndOfFile) { |
| 220 ASSERT(it + 1 == tokens->end()); // The EOF is assumed to be the las
t token of this bunch. | 233 ++it; // Make it == end() during non-stopped termination. |
| 234 ASSERT(it == tokens->end()); // The EOF is assumed to be the |
| 235 // last token of this bunch. |
| 221 ASSERT(m_pendingChunks.isEmpty()); // There should never be any chun
ks after the EOF. | 236 ASSERT(m_pendingChunks.isEmpty()); // There should never be any chun
ks after the EOF. |
| 222 prepareToStopParsing(); | 237 prepareToStopParsing(); |
| 223 break; | 238 break; |
| 224 } | 239 } |
| 225 } | 240 } |
| 226 | 241 |
| 242 // Either we aborted due to stopping or we processed all tokens. |
| 243 ASSERT(isStopped() || it == tokens->end()); |
| 244 |
| 227 // Make sure any pending text nodes are emitted before returning. | 245 // Make sure any pending text nodes are emitted before returning. |
| 228 if (!isStopped()) | 246 if (!isStopped()) |
| 229 m_treeBuilder->flush(); | 247 m_treeBuilder->flush(); |
| 230 } | 248 } |
| 231 | 249 |
| 232 void HTMLDocumentParser::pumpPendingChunks() | 250 void HTMLDocumentParser::pumpPendingChunks() |
| 233 { | 251 { |
| 234 // FIXME: Share this constant with the parser scheduler. | 252 // FIXME: Share this constant with the parser scheduler. |
| 235 const double parserTimeLimit = 0.500; | 253 const double parserTimeLimit = 0.500; |
| 236 | 254 |
| 237 // ASSERT that this object is both attached to the Document and protected. | 255 // ASSERT that this object is both attached to the Document and protected. |
| 238 ASSERT(refCount() >= 2); | 256 ASSERT(refCount() >= 2); |
| 239 ASSERT(!isWaitingForScripts()); | 257 ASSERT(!isWaitingForScripts()); |
| 240 ASSERT(!isStopped()); | 258 ASSERT(!isStopped()); |
| 241 ASSERT(document()->haveImportsLoaded()); | |
| 242 | 259 |
| 243 double startTime = currentTime(); | 260 double startTime = currentTime(); |
| 244 | 261 |
| 245 while (!m_pendingChunks.isEmpty()) { | 262 while (!m_pendingChunks.isEmpty()) { |
| 246 processParsedChunkFromBackgroundParser(m_pendingChunks.takeFirst()); | 263 processParsedChunkFromBackgroundParser(m_pendingChunks.takeFirst()); |
| 247 | 264 |
| 248 // Always check isStopped first as m_document may be null. | 265 // Always check isStopped first as m_document may be null. |
| 249 if (isStopped() || isWaitingForScripts() || !document()->haveImportsLoad
ed()) | 266 if (isStopped() || isWaitingForScripts()) |
| 250 break; | 267 break; |
| 251 | 268 |
| 252 if (currentTime() - startTime > parserTimeLimit && !m_pendingChunks.isEm
pty()) { | 269 if (currentTime() - startTime > parserTimeLimit && !m_pendingChunks.isEm
pty()) { |
| 253 m_parserScheduler->scheduleForResume(); | 270 m_parserScheduler->scheduleForResume(); |
| 254 break; | 271 break; |
| 255 } | 272 } |
| 256 } | 273 } |
| 257 } | 274 } |
| 258 | 275 |
| 259 Document* HTMLDocumentParser::contextForParsingSession() | 276 Document* HTMLDocumentParser::contextForParsingSession() |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 | 363 |
| 347 if (!m_endWasDelayed || shouldDelayEnd()) | 364 if (!m_endWasDelayed || shouldDelayEnd()) |
| 348 return; | 365 return; |
| 349 | 366 |
| 350 m_endWasDelayed = false; | 367 m_endWasDelayed = false; |
| 351 prepareToStopParsing(); | 368 prepareToStopParsing(); |
| 352 } | 369 } |
| 353 | 370 |
| 354 bool HTMLDocumentParser::isExecutingScript() const | 371 bool HTMLDocumentParser::isExecutingScript() const |
| 355 { | 372 { |
| 356 return m_scriptRunner.isExecutingScript(); | 373 // TODO(eseidel): Callers may need updates now that scripts can be async. |
| 374 return m_scriptRunner && m_scriptRunner->isExecutingScript(); |
| 357 } | 375 } |
| 358 | 376 |
| 359 OrdinalNumber HTMLDocumentParser::lineNumber() const | 377 OrdinalNumber HTMLDocumentParser::lineNumber() const |
| 360 { | 378 { |
| 361 ASSERT(m_haveBackgroundParser); | 379 ASSERT(m_haveBackgroundParser); |
| 362 return m_textPosition.m_line; | 380 return m_textPosition.m_line; |
| 363 } | 381 } |
| 364 | 382 |
| 365 TextPosition HTMLDocumentParser::textPosition() const | 383 TextPosition HTMLDocumentParser::textPosition() const |
| 366 { | 384 { |
| 367 ASSERT(m_haveBackgroundParser); | 385 ASSERT(m_haveBackgroundParser); |
| 368 return m_textPosition; | 386 return m_textPosition; |
| 369 } | 387 } |
| 370 | 388 |
| 371 bool HTMLDocumentParser::isWaitingForScripts() const | 389 bool HTMLDocumentParser::isWaitingForScripts() const |
| 372 { | 390 { |
| 373 return m_treeBuilder->hasParserBlockingScript(); | 391 return m_treeBuilder->hasParserBlockingScript() || m_scriptRunner || |
| 392 !document()->haveImportsLoaded(); |
| 374 } | 393 } |
| 375 | 394 |
| 376 void HTMLDocumentParser::resumeAfterWaitingForImports() | 395 void HTMLDocumentParser::resumeAfterWaitingForImports() |
| 377 { | 396 { |
| 378 RefPtr<HTMLDocumentParser> protect(this); | 397 RefPtr<HTMLDocumentParser> protect(this); |
| 379 ASSERT(!isExecutingScript()); | |
| 380 ASSERT(!isWaitingForScripts()); | 398 ASSERT(!isWaitingForScripts()); |
| 381 if (m_pendingChunks.isEmpty()) | 399 if (m_pendingChunks.isEmpty()) |
| 382 return; | 400 return; |
| 383 ASSERT(m_haveBackgroundParser); | 401 ASSERT(m_haveBackgroundParser); |
| 384 pumpPendingChunks(); | 402 pumpPendingChunks(); |
| 385 } | 403 } |
| 386 | 404 |
| 405 // HTMLScriptRunner has finished executing a script. |
| 406 // Just call resumeAfterWaitingForImports since it happens to do what we need. |
| 407 void HTMLDocumentParser::scriptExecutionCompleted() { |
| 408 ASSERT(m_scriptRunner); |
| 409 m_scriptRunner.clear(); |
| 410 // To avoid re-entering the parser for synchronous scripts, we use a postTask. |
| 411 base::MessageLoop::current()->PostTask( |
| 412 FROM_HERE, base::Bind(&HTMLDocumentParser::resumeAfterWaitingForImports, |
| 413 m_weakFactory.GetWeakPtr())); |
| 387 } | 414 } |
| 415 } |
| OLD | NEW |