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 |