| 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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 , m_haveBackgroundParser(false) | 52 , m_haveBackgroundParser(false) |
| 53 , m_pumpSessionNestingLevel(0) | 53 , m_pumpSessionNestingLevel(0) |
| 54 { | 54 { |
| 55 } | 55 } |
| 56 | 56 |
| 57 HTMLDocumentParser::~HTMLDocumentParser() | 57 HTMLDocumentParser::~HTMLDocumentParser() |
| 58 { | 58 { |
| 59 ASSERT(!m_parserScheduler); | 59 ASSERT(!m_parserScheduler); |
| 60 ASSERT(!m_pumpSessionNestingLevel); | 60 ASSERT(!m_pumpSessionNestingLevel); |
| 61 ASSERT(!m_haveBackgroundParser); | 61 ASSERT(!m_haveBackgroundParser); |
| 62 // FIXME: We should be able to ASSERT(m_speculations.isEmpty()), | 62 // FIXME: We should be able to ASSERT(m_pendingChunks.isEmpty()), |
| 63 // but there are cases where that's not true currently. For example, | 63 // but there are cases where that's not true currently. For example, |
| 64 // we we're told to stop parsing before we've consumed all the input. | 64 // we we're told to stop parsing before we've consumed all the input. |
| 65 } | 65 } |
| 66 | 66 |
| 67 void HTMLDocumentParser::parse(mojo::ScopedDataPipeConsumerHandle source, | 67 void HTMLDocumentParser::parse(mojo::ScopedDataPipeConsumerHandle source, |
| 68 const base::Closure& completionCallback) | 68 const base::Closure& completionCallback) |
| 69 { | 69 { |
| 70 ASSERT(!isStopped()); | 70 ASSERT(!isStopped()); |
| 71 ASSERT(!m_haveBackgroundParser); | 71 ASSERT(!m_haveBackgroundParser); |
| 72 m_haveBackgroundParser = true; | 72 m_haveBackgroundParser = true; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 } | 143 } |
| 144 | 144 |
| 145 // Used by HTMLParserScheduler | 145 // Used by HTMLParserScheduler |
| 146 void HTMLDocumentParser::resumeParsingAfterYield() | 146 void HTMLDocumentParser::resumeParsingAfterYield() |
| 147 { | 147 { |
| 148 // pumpTokenizer can cause this parser to be detached from the Document, | 148 // pumpTokenizer can cause this parser to be detached from the Document, |
| 149 // but we need to ensure it isn't deleted yet. | 149 // but we need to ensure it isn't deleted yet. |
| 150 RefPtr<HTMLDocumentParser> protect(this); | 150 RefPtr<HTMLDocumentParser> protect(this); |
| 151 | 151 |
| 152 ASSERT(m_haveBackgroundParser); | 152 ASSERT(m_haveBackgroundParser); |
| 153 pumpPendingSpeculations(); | 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 m_scriptRunner.runScript(toHTMLScriptElement(scriptToProcess.get()), scriptS
tartPosition); |
| 163 } | 163 } |
| 164 | 164 |
| 165 void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<Pa
rsedChunk> chunk) | 165 void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<Pa
rsedChunk> chunk) |
| 166 { | 166 { |
| 167 TRACE_EVENT0("blink", "HTMLDocumentParser::didReceiveParsedChunkFromBackgrou
ndParser"); | 167 TRACE_EVENT0("blink", "HTMLDocumentParser::didReceiveParsedChunkFromBackgrou
ndParser"); |
| 168 // Sky should not need nested parsers. |
| 169 ASSERT(document()->activeParserCount() == 0); |
| 168 | 170 |
| 169 // alert(), runModalDialog, and the JavaScript Debugger all run nested event
loops | 171 if (isWaitingForScripts() || !m_pendingChunks.isEmpty() || document()->activ
eParserCount() > 0 || !document()->haveImportsLoaded()) { |
| 170 // which can cause this method to be re-entered. We detect re-entry using | 172 m_pendingChunks.append(chunk); |
| 171 // hasActiveParser(), save the chunk as a speculation, and return. | |
| 172 if (isWaitingForScripts() || !m_speculations.isEmpty() || document()->active
ParserCount() > 0) { | |
| 173 m_speculations.append(chunk); | |
| 174 return; | 173 return; |
| 175 } | 174 } |
| 176 | 175 |
| 177 // processParsedChunkFromBackgroundParser can cause this parser to be detach
ed from the Document, | 176 // processParsedChunkFromBackgroundParser can cause this parser to be detach
ed from the Document, |
| 178 // but we need to ensure it isn't deleted yet. | 177 // but we need to ensure it isn't deleted yet. |
| 179 RefPtr<HTMLDocumentParser> protect(this); | 178 RefPtr<HTMLDocumentParser> protect(this); |
| 180 | 179 |
| 181 ASSERT(m_speculations.isEmpty()); | 180 ASSERT(m_pendingChunks.isEmpty()); |
| 182 m_speculations.append(chunk); | 181 m_pendingChunks.append(chunk); |
| 183 pumpPendingSpeculations(); | 182 pumpPendingChunks(); |
| 184 } | 183 } |
| 185 | 184 |
| 186 void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Parse
dChunk> popChunk) | 185 void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Parse
dChunk> popChunk) |
| 187 { | 186 { |
| 187 // TODO(eseidel): Include the token count in the trace event. |
| 188 TRACE_EVENT0("blink", "HTMLDocumentParser::processParsedChunkFromBackgroundP
arser"); | 188 TRACE_EVENT0("blink", "HTMLDocumentParser::processParsedChunkFromBackgroundP
arser"); |
| 189 | 189 |
| 190 ASSERT_WITH_SECURITY_IMPLICATION(!document()->activeParserCount()); | 190 ASSERT_WITH_SECURITY_IMPLICATION(!document()->activeParserCount()); |
| 191 ASSERT(!isParsingFragment()); | 191 ASSERT(!isParsingFragment()); |
| 192 ASSERT(!isWaitingForScripts()); | 192 ASSERT(!isWaitingForScripts()); |
| 193 ASSERT(!isStopped()); | 193 ASSERT(!isStopped()); |
| 194 | 194 |
| 195 // ASSERT that this object is both attached to the Document and protected. | 195 // ASSERT that this object is both attached to the Document and protected. |
| 196 ASSERT(refCount() >= 2); | 196 ASSERT(refCount() >= 2); |
| 197 | 197 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 211 break; | 211 break; |
| 212 | 212 |
| 213 if (isWaitingForScripts()) { | 213 if (isWaitingForScripts()) { |
| 214 ASSERT(it + 1 == tokens->end()); // The </script> is assumed to be t
he last token of this bunch. | 214 ASSERT(it + 1 == tokens->end()); // The </script> is assumed to be t
he last token of this bunch. |
| 215 runScriptsForPausedTreeBuilder(); | 215 runScriptsForPausedTreeBuilder(); |
| 216 break; | 216 break; |
| 217 } | 217 } |
| 218 | 218 |
| 219 if (it->type() == HTMLToken::EndOfFile) { | 219 if (it->type() == HTMLToken::EndOfFile) { |
| 220 ASSERT(it + 1 == tokens->end()); // The EOF is assumed to be the las
t token of this bunch. | 220 ASSERT(it + 1 == tokens->end()); // The EOF is assumed to be the las
t token of this bunch. |
| 221 ASSERT(m_speculations.isEmpty()); // There should never be any chunk
s after the EOF. | 221 ASSERT(m_pendingChunks.isEmpty()); // There should never be any chun
ks after the EOF. |
| 222 prepareToStopParsing(); | 222 prepareToStopParsing(); |
| 223 break; | 223 break; |
| 224 } | 224 } |
| 225 } | 225 } |
| 226 | 226 |
| 227 // Make sure any pending text nodes are emitted before returning. | 227 // Make sure any pending text nodes are emitted before returning. |
| 228 if (!isStopped()) | 228 if (!isStopped()) |
| 229 m_treeBuilder->flush(); | 229 m_treeBuilder->flush(); |
| 230 } | 230 } |
| 231 | 231 |
| 232 void HTMLDocumentParser::pumpPendingSpeculations() | 232 void HTMLDocumentParser::pumpPendingChunks() |
| 233 { | 233 { |
| 234 // FIXME: Share this constant with the parser scheduler. | 234 // FIXME: Share this constant with the parser scheduler. |
| 235 const double parserTimeLimit = 0.500; | 235 const double parserTimeLimit = 0.500; |
| 236 | 236 |
| 237 // ASSERT that this object is both attached to the Document and protected. | 237 // ASSERT that this object is both attached to the Document and protected. |
| 238 ASSERT(refCount() >= 2); | 238 ASSERT(refCount() >= 2); |
| 239 ASSERT(!isWaitingForScripts()); | 239 ASSERT(!isWaitingForScripts()); |
| 240 ASSERT(!isStopped()); | 240 ASSERT(!isStopped()); |
| 241 ASSERT(document()->haveImportsLoaded()); |
| 241 | 242 |
| 242 double startTime = currentTime(); | 243 double startTime = currentTime(); |
| 243 | 244 |
| 244 while (!m_speculations.isEmpty()) { | 245 while (!m_pendingChunks.isEmpty()) { |
| 245 processParsedChunkFromBackgroundParser(m_speculations.takeFirst()); | 246 processParsedChunkFromBackgroundParser(m_pendingChunks.takeFirst()); |
| 246 | 247 |
| 247 // Always check isStopped first as m_document may be null. | 248 // Always check isStopped first as m_document may be null. |
| 248 if (isStopped() || isWaitingForScripts() || !document()->haveImportsLoad
ed()) | 249 if (isStopped() || isWaitingForScripts() || !document()->haveImportsLoad
ed()) |
| 249 break; | 250 break; |
| 250 | 251 |
| 251 if (currentTime() - startTime > parserTimeLimit && !m_speculations.isEmp
ty()) { | 252 if (currentTime() - startTime > parserTimeLimit && !m_pendingChunks.isEm
pty()) { |
| 252 m_parserScheduler->scheduleForResume(); | 253 m_parserScheduler->scheduleForResume(); |
| 253 break; | 254 break; |
| 254 } | 255 } |
| 255 } | 256 } |
| 256 } | 257 } |
| 257 | 258 |
| 258 Document* HTMLDocumentParser::contextForParsingSession() | 259 Document* HTMLDocumentParser::contextForParsingSession() |
| 259 { | 260 { |
| 260 // The parsing session should interact with the document only when parsing | 261 // The parsing session should interact with the document only when parsing |
| 261 // non-fragments. Otherwise, we might delay the load event mistakenly. | 262 // non-fragments. Otherwise, we might delay the load event mistakenly. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 } | 363 } |
| 363 | 364 |
| 364 TextPosition HTMLDocumentParser::textPosition() const | 365 TextPosition HTMLDocumentParser::textPosition() const |
| 365 { | 366 { |
| 366 ASSERT(m_haveBackgroundParser); | 367 ASSERT(m_haveBackgroundParser); |
| 367 return m_textPosition; | 368 return m_textPosition; |
| 368 } | 369 } |
| 369 | 370 |
| 370 bool HTMLDocumentParser::isWaitingForScripts() const | 371 bool HTMLDocumentParser::isWaitingForScripts() const |
| 371 { | 372 { |
| 372 return m_treeBuilder->hasParserBlockingScript() || m_scriptRunner.hasPending
Scripts(); | 373 return m_treeBuilder->hasParserBlockingScript(); |
| 373 } | 374 } |
| 374 | 375 |
| 375 void HTMLDocumentParser::resumeAfterWaitingForImports() | 376 void HTMLDocumentParser::resumeAfterWaitingForImports() |
| 376 { | 377 { |
| 377 RefPtr<HTMLDocumentParser> protect(this); | 378 RefPtr<HTMLDocumentParser> protect(this); |
| 378 if (m_scriptRunner.hasPendingScripts()) | |
| 379 m_scriptRunner.executePendingScripts(); | |
| 380 ASSERT(!isExecutingScript()); | 379 ASSERT(!isExecutingScript()); |
| 381 ASSERT(!isWaitingForScripts()); | 380 ASSERT(!isWaitingForScripts()); |
| 382 if (m_speculations.isEmpty()) | 381 if (m_pendingChunks.isEmpty()) |
| 383 return; | 382 return; |
| 384 ASSERT(m_haveBackgroundParser); | 383 ASSERT(m_haveBackgroundParser); |
| 385 pumpPendingSpeculations(); | 384 pumpPendingChunks(); |
| 386 } | 385 } |
| 387 | 386 |
| 388 } | 387 } |
| OLD | NEW |