Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(366)

Side by Side Diff: sky/engine/core/html/parser/HTMLDocumentParser.cpp

Issue 664573004: Live the dream (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: DEPS Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 30 matching lines...) Expand all
41 #include "core/inspector/InspectorTraceEvents.h" 41 #include "core/inspector/InspectorTraceEvents.h"
42 #include "platform/SharedBuffer.h" 42 #include "platform/SharedBuffer.h"
43 #include "platform/TraceEvent.h" 43 #include "platform/TraceEvent.h"
44 #include "wtf/Functional.h" 44 #include "wtf/Functional.h"
45 45
46 namespace blink { 46 namespace blink {
47 47
48 HTMLDocumentParser::HTMLDocumentParser(HTMLDocument& document, bool reportErrors ) 48 HTMLDocumentParser::HTMLDocumentParser(HTMLDocument& document, bool reportErrors )
49 : DecodedDataDocumentParser(document) 49 : DecodedDataDocumentParser(document)
50 , m_options(&document) 50 , m_options(&document)
51 , m_token(m_options.useThreading ? nullptr : adoptPtr(new HTMLToken))
52 , m_tokenizer(m_options.useThreading ? nullptr : HTMLTokenizer::create(m_opt ions))
53 , m_treeBuilder(HTMLTreeBuilder::create(this, &document, reportErrors, m_opt ions)) 51 , m_treeBuilder(HTMLTreeBuilder::create(this, &document, reportErrors, m_opt ions))
54 , m_parserScheduler(HTMLParserScheduler::create(this)) 52 , m_parserScheduler(HTMLParserScheduler::create(this))
55 , m_weakFactory(this) 53 , m_weakFactory(this)
56 , m_isFragment(false) 54 , m_isFragment(false)
57 , m_endWasDelayed(false) 55 , m_endWasDelayed(false)
58 , m_haveBackgroundParser(false) 56 , m_haveBackgroundParser(false)
59 , m_pumpSessionNestingLevel(0) 57 , m_pumpSessionNestingLevel(0)
60 { 58 {
61 ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); 59 ASSERT(shouldUseThreading());
62 } 60 }
63 61
64 HTMLDocumentParser::~HTMLDocumentParser() 62 HTMLDocumentParser::~HTMLDocumentParser()
65 { 63 {
66 #if ENABLE(OILPAN) 64 #if ENABLE(OILPAN)
67 if (m_haveBackgroundParser) 65 if (m_haveBackgroundParser)
68 stopBackgroundParser(); 66 stopBackgroundParser();
69 // In Oilpan, HTMLDocumentParser can die together with Document, and 67 // In Oilpan, HTMLDocumentParser can die together with Document, and
70 // detach() is not called in this case. 68 // detach() is not called in this case.
71 #else 69 #else
72 ASSERT(!m_parserScheduler); 70 ASSERT(!m_parserScheduler);
73 ASSERT(!m_pumpSessionNestingLevel); 71 ASSERT(!m_pumpSessionNestingLevel);
74 ASSERT(!m_haveBackgroundParser); 72 ASSERT(!m_haveBackgroundParser);
75 // FIXME: We should be able to ASSERT(m_speculations.isEmpty()), 73 // FIXME: We should be able to ASSERT(m_speculations.isEmpty()),
76 // but there are cases where that's not true currently. For example, 74 // but there are cases where that's not true currently. For example,
77 // we we're told to stop parsing before we've consumed all the input. 75 // we we're told to stop parsing before we've consumed all the input.
78 #endif 76 #endif
79 } 77 }
80 78
81 void HTMLDocumentParser::trace(Visitor* visitor) 79 void HTMLDocumentParser::trace(Visitor* visitor)
82 { 80 {
83 visitor->trace(m_treeBuilder); 81 visitor->trace(m_treeBuilder);
84 DecodedDataDocumentParser::trace(visitor); 82 DecodedDataDocumentParser::trace(visitor);
85 } 83 }
86 84
85 void HTMLDocumentParser::parse(mojo::ScopedDataPipeConsumerHandle source)
86 {
87 ASSERT(!isStopped());
88 ASSERT(shouldUseThreading());
89 ASSERT(!m_haveBackgroundParser);
90 m_haveBackgroundParser = true;
91
92 OwnPtr<BackgroundHTMLParser::Configuration> config = adoptPtr(new Background HTMLParser::Configuration);
93 config->options = m_options;
94 config->source = source.Pass();
95 config->parser = m_weakFactory.createWeakPtr();
96
97 m_backgroundParser = BackgroundHTMLParser::create(config.release());
98 HTMLParserThread::taskRunner()->PostTask(FROM_HERE,
99 base::Bind(&BackgroundHTMLParser::start, m_backgroundParser));
100 }
101
87 void HTMLDocumentParser::detach() 102 void HTMLDocumentParser::detach()
88 { 103 {
89 if (m_haveBackgroundParser) 104 if (m_haveBackgroundParser)
90 stopBackgroundParser(); 105 stopBackgroundParser();
91 DocumentParser::detach(); 106 DocumentParser::detach();
92 m_treeBuilder->detach(); 107 m_treeBuilder->detach();
93 // FIXME: It seems wrong that we would have a preload scanner here. 108 // FIXME: It seems wrong that we would have a preload scanner here.
94 // Yet during fast/dom/HTMLScriptElement/script-load-events.html we do. 109 // Yet during fast/dom/HTMLScriptElement/script-load-events.html we do.
95 m_parserScheduler.clear(); // Deleting the scheduler will clear any timers. 110 m_parserScheduler.clear(); // Deleting the scheduler will clear any timers.
96 } 111 }
(...skipping 11 matching lines...) Expand all
108 void HTMLDocumentParser::prepareToStopParsing() 123 void HTMLDocumentParser::prepareToStopParsing()
109 { 124 {
110 // FIXME: It may not be correct to disable this for the background parser. 125 // FIXME: It may not be correct to disable this for the background parser.
111 // That means hasInsertionPoint() may not be correct in some cases. 126 // That means hasInsertionPoint() may not be correct in some cases.
112 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); 127 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser);
113 128
114 // pumpTokenizer can cause this parser to be detached from the Document, 129 // pumpTokenizer can cause this parser to be detached from the Document,
115 // but we need to ensure it isn't deleted yet. 130 // but we need to ensure it isn't deleted yet.
116 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); 131 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this);
117 132
118 // NOTE: This pump should only ever emit buffered character tokens,
119 // so ForceSynchronous vs. AllowYield should be meaningless.
120 if (m_tokenizer) {
121 ASSERT(!m_haveBackgroundParser);
122 pumpTokenizerIfPossible(ForceSynchronous);
123 }
124
125 if (isStopped()) 133 if (isStopped())
126 return; 134 return;
127 135
128 DocumentParser::prepareToStopParsing(); 136 DocumentParser::prepareToStopParsing();
129 137
130 // We will not have a scriptRunner when parsing a DocumentFragment. 138 // We will not have a scriptRunner when parsing a DocumentFragment.
131 if (!m_isFragment) 139 if (!m_isFragment)
132 document()->setReadyState(Document::Interactive); 140 document()->setReadyState(Document::Interactive);
133 141
134 // Setting the ready state above can fire mutation event and detach us 142 // Setting the ready state above can fire mutation event and detach us
135 // from underneath. In that case, just bail out. 143 // from underneath. In that case, just bail out.
136 if (isDetached()) 144 if (isDetached())
137 return; 145 return;
138 146
139 ASSERT(isStopping()); 147 ASSERT(isStopping());
140 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); 148 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser);
141 end(); 149 end();
142 } 150 }
143 151
144 bool HTMLDocumentParser::isParsingFragment() const 152 bool HTMLDocumentParser::isParsingFragment() const
145 { 153 {
146 return m_treeBuilder->isParsingFragment(); 154 return m_treeBuilder->isParsingFragment();
147 } 155 }
148 156
149 bool HTMLDocumentParser::processingData() const 157 bool HTMLDocumentParser::processingData() const
150 { 158 {
151 return isScheduledForResume() || inPumpSession() || m_haveBackgroundParser; 159 return isScheduledForResume() || inPumpSession() || m_haveBackgroundParser;
152 } 160 }
153 161
154 void HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode)
155 {
156 if (isStopped())
157 return;
158 if (isWaitingForScripts())
159 return;
160
161 // Once a resume is scheduled, HTMLParserScheduler controls when we next pum p.
162 if (isScheduledForResume()) {
163 ASSERT(mode == AllowYield);
164 return;
165 }
166
167 pumpTokenizer(mode);
168 }
169
170 bool HTMLDocumentParser::isScheduledForResume() const 162 bool HTMLDocumentParser::isScheduledForResume() const
171 { 163 {
172 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); 164 return m_parserScheduler && m_parserScheduler->isScheduledForResume();
173 } 165 }
174 166
175 // Used by HTMLParserScheduler 167 // Used by HTMLParserScheduler
176 void HTMLDocumentParser::resumeParsingAfterYield() 168 void HTMLDocumentParser::resumeParsingAfterYield()
177 { 169 {
178 // pumpTokenizer can cause this parser to be detached from the Document, 170 // pumpTokenizer can cause this parser to be detached from the Document,
179 // but we need to ensure it isn't deleted yet. 171 // but we need to ensure it isn't deleted yet.
180 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); 172 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this);
181 173
182 if (m_haveBackgroundParser) { 174 ASSERT(m_haveBackgroundParser);
183 pumpPendingSpeculations(); 175 pumpPendingSpeculations();
184 return;
185 }
186
187 // We should never be here unless we can pump immediately. Call pumpTokeniz er()
188 // directly so that ASSERTS will fire if we're wrong.
189 pumpTokenizer(AllowYield);
190 endIfDelayed();
191 } 176 }
192 177
193 void HTMLDocumentParser::runScriptsForPausedTreeBuilder() 178 void HTMLDocumentParser::runScriptsForPausedTreeBuilder()
194 { 179 {
195 if (m_isFragment) 180 if (m_isFragment)
196 return; 181 return;
197 TextPosition scriptStartPosition = TextPosition::belowRangePosition(); 182 TextPosition scriptStartPosition = TextPosition::belowRangePosition();
198 RefPtrWillBeRawPtr<Element> scriptToProcess = m_treeBuilder->takeScriptToPro cess(scriptStartPosition); 183 RefPtrWillBeRawPtr<Element> scriptToProcess = m_treeBuilder->takeScriptToPro cess(scriptStartPosition);
199 m_scriptRunner.runScript(toHTMLScriptElement(scriptToProcess.get()), scriptS tartPosition); 184 m_scriptRunner.runScript(toHTMLScriptElement(scriptToProcess.get()), scriptS tartPosition);
200 } 185 }
201 186
202 bool HTMLDocumentParser::canTakeNextToken(SynchronousMode mode, PumpSession& ses sion)
203 {
204 if (isStopped())
205 return false;
206
207 ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous);
208
209 if (isWaitingForScripts()) {
210 if (mode == AllowYield)
211 session.didSeeScript = true;
212
213 // If we don't run the script, we cannot allow the next token to be take n.
214 if (session.needsYield)
215 return false;
216
217 // If we're paused waiting for a script, we try to execute scripts befor e continuing.
218 runScriptsForPausedTreeBuilder();
219 if (isStopped())
220 return false;
221 if (isWaitingForScripts())
222 return false;
223 }
224
225 if (mode == AllowYield)
226 m_parserScheduler->checkForYieldBeforeToken(session);
227
228 return true;
229 }
230
231 void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<Pa rsedChunk> chunk) 187 void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<Pa rsedChunk> chunk)
232 { 188 {
233 TRACE_EVENT0("blink", "HTMLDocumentParser::didReceiveParsedChunkFromBackgrou ndParser"); 189 TRACE_EVENT0("blink", "HTMLDocumentParser::didReceiveParsedChunkFromBackgrou ndParser");
234 190
235 // alert(), runModalDialog, and the JavaScript Debugger all run nested event loops 191 // alert(), runModalDialog, and the JavaScript Debugger all run nested event loops
236 // which can cause this method to be re-entered. We detect re-entry using 192 // which can cause this method to be re-entered. We detect re-entry using
237 // hasActiveParser(), save the chunk as a speculation, and return. 193 // hasActiveParser(), save the chunk as a speculation, and return.
238 if (isWaitingForScripts() || !m_speculations.isEmpty() || document()->active ParserCount() > 0) { 194 if (isWaitingForScripts() || !m_speculations.isEmpty() || document()->active ParserCount() > 0) {
239 m_speculations.append(chunk); 195 m_speculations.append(chunk);
240 return; 196 return;
(...skipping 28 matching lines...) Expand all
269 225
270 ASSERT_WITH_SECURITY_IMPLICATION(!document()->activeParserCount()); 226 ASSERT_WITH_SECURITY_IMPLICATION(!document()->activeParserCount());
271 ASSERT(!isParsingFragment()); 227 ASSERT(!isParsingFragment());
272 ASSERT(!isWaitingForScripts()); 228 ASSERT(!isWaitingForScripts());
273 ASSERT(!isStopped()); 229 ASSERT(!isStopped());
274 #if !ENABLE(OILPAN) 230 #if !ENABLE(OILPAN)
275 // ASSERT that this object is both attached to the Document and protected. 231 // ASSERT that this object is both attached to the Document and protected.
276 ASSERT(refCount() >= 2); 232 ASSERT(refCount() >= 2);
277 #endif 233 #endif
278 ASSERT(shouldUseThreading()); 234 ASSERT(shouldUseThreading());
279 ASSERT(!m_tokenizer);
280 ASSERT(!m_token);
281 ASSERT(!m_lastChunkBeforeScript); 235 ASSERT(!m_lastChunkBeforeScript);
282 236
283 ActiveParserSession session(contextForParsingSession()); 237 ActiveParserSession session(contextForParsingSession());
284 238
285 OwnPtr<ParsedChunk> chunk(popChunk); 239 OwnPtr<ParsedChunk> chunk(popChunk);
286 OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release(); 240 OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release();
287 241
288 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); it != to kens->end(); ++it) { 242 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); it != to kens->end(); ++it) {
289 ASSERT(!isWaitingForScripts()); 243 ASSERT(!isWaitingForScripts());
290 244
(...skipping 10 matching lines...) Expand all
301 validateSpeculations(chunk.release()); 255 validateSpeculations(chunk.release());
302 break; 256 break;
303 } 257 }
304 258
305 if (it->type() == HTMLToken::EndOfFile) { 259 if (it->type() == HTMLToken::EndOfFile) {
306 ASSERT(it + 1 == tokens->end()); // The EOF is assumed to be the las t token of this bunch. 260 ASSERT(it + 1 == tokens->end()); // The EOF is assumed to be the las t token of this bunch.
307 ASSERT(m_speculations.isEmpty()); // There should never be any chunk s after the EOF. 261 ASSERT(m_speculations.isEmpty()); // There should never be any chunk s after the EOF.
308 prepareToStopParsing(); 262 prepareToStopParsing();
309 break; 263 break;
310 } 264 }
311
312 ASSERT(!m_tokenizer);
313 ASSERT(!m_token);
314 } 265 }
315 266
316 // Make sure any pending text nodes are emitted before returning. 267 // Make sure any pending text nodes are emitted before returning.
317 if (!isStopped()) 268 if (!isStopped())
318 m_treeBuilder->flush(); 269 m_treeBuilder->flush();
319 } 270 }
320 271
321 void HTMLDocumentParser::pumpPendingSpeculations() 272 void HTMLDocumentParser::pumpPendingSpeculations()
322 { 273 {
323 // FIXME: Share this constant with the parser scheduler. 274 // FIXME: Share this constant with the parser scheduler.
324 const double parserTimeLimit = 0.500; 275 const double parserTimeLimit = 0.500;
325 276
326 #if !ENABLE(OILPAN) 277 #if !ENABLE(OILPAN)
327 // ASSERT that this object is both attached to the Document and protected. 278 // ASSERT that this object is both attached to the Document and protected.
328 ASSERT(refCount() >= 2); 279 ASSERT(refCount() >= 2);
329 #endif 280 #endif
330 // If this assert fails, you need to call validateSpeculations to make sure
331 // m_tokenizer and m_token don't have state that invalidates m_speculations.
332 ASSERT(!m_tokenizer);
333 ASSERT(!m_token);
334 ASSERT(!m_lastChunkBeforeScript); 281 ASSERT(!m_lastChunkBeforeScript);
335 ASSERT(!isWaitingForScripts()); 282 ASSERT(!isWaitingForScripts());
336 ASSERT(!isStopped()); 283 ASSERT(!isStopped());
337 284
338 // FIXME: Pass in current input length. 285 // FIXME: Pass in current input length.
339 TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ParseHTM L", "beginData", InspectorParseHtmlEvent::beginData(document(), lineNumber().zer oBasedInt())); 286 TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ParseHTM L", "beginData", InspectorParseHtmlEvent::beginData(document(), lineNumber().zer oBasedInt()));
340 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), " CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 287 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), " CallStack", "stack", InspectorCallStackEvent::currentCallStack());
341 288
342 double startTime = currentTime(); 289 double startTime = currentTime();
343 290
(...skipping 16 matching lines...) Expand all
360 307
361 Document* HTMLDocumentParser::contextForParsingSession() 308 Document* HTMLDocumentParser::contextForParsingSession()
362 { 309 {
363 // The parsing session should interact with the document only when parsing 310 // The parsing session should interact with the document only when parsing
364 // non-fragments. Otherwise, we might delay the load event mistakenly. 311 // non-fragments. Otherwise, we might delay the load event mistakenly.
365 if (isParsingFragment()) 312 if (isParsingFragment())
366 return 0; 313 return 0;
367 return document(); 314 return document();
368 } 315 }
369 316
370 void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
371 {
372 ASSERT(!isStopped());
373 ASSERT(!isScheduledForResume());
374 #if !ENABLE(OILPAN)
375 // ASSERT that this object is both attached to the Document and protected.
376 ASSERT(refCount() >= 2);
377 #endif
378 ASSERT(m_tokenizer);
379 ASSERT(m_token);
380 ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous);
381
382 PumpSession session(m_pumpSessionNestingLevel, contextForParsingSession());
383
384 TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ParseHTM L", "beginData", InspectorParseHtmlEvent::beginData(document(), m_input.current( ).currentLine().zeroBasedInt()));
385 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), " CallStack", "stack", InspectorCallStackEvent::currentCallStack());
386
387 while (canTakeNextToken(mode, session) && !session.needsYield) {
388 if (!m_tokenizer->nextToken(m_input.current(), token()))
389 break;
390
391 constructTreeFromHTMLToken(token());
392 ASSERT(token().isUninitialized());
393 }
394
395 #if !ENABLE(OILPAN)
396 // Ensure we haven't been totally deref'ed after pumping. Any caller of this
397 // function should be holding a RefPtr to this to ensure we weren't deleted.
398 ASSERT(refCount() >= 1);
399 #endif
400
401 if (isStopped())
402 return;
403
404 // There should only be PendingText left since the tree-builder always flush es
405 // the task queue before returning. In case that ever changes, crash.
406 if (mode == ForceSynchronous)
407 m_treeBuilder->flush();
408 RELEASE_ASSERT(!isStopped());
409
410 if (session.needsYield)
411 m_parserScheduler->scheduleForResume();
412
413 TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ParseHTML" , "endLine", m_input.current().currentLine().zeroBasedInt());
414 }
415
416 void HTMLDocumentParser::constructTreeFromHTMLToken(HTMLToken& rawToken) 317 void HTMLDocumentParser::constructTreeFromHTMLToken(HTMLToken& rawToken)
417 { 318 {
418 AtomicHTMLToken token(rawToken); 319 AtomicHTMLToken token(rawToken);
419 320
420 // We clear the rawToken in case constructTreeFromAtomicToken 321 // We clear the rawToken in case constructTreeFromAtomicToken
421 // synchronously re-enters the parser. We don't clear the token immedately 322 // synchronously re-enters the parser. We don't clear the token immedately
422 // for Character tokens because the AtomicHTMLToken avoids copying the 323 // for Character tokens because the AtomicHTMLToken avoids copying the
423 // characters by keeping a pointer to the underlying buffer in the 324 // characters by keeping a pointer to the underlying buffer in the
424 // HTMLToken. Fortunately, Character tokens can't cause us to re-enter 325 // HTMLToken. Fortunately, Character tokens can't cause us to re-enter
425 // the parser. 326 // the parser.
(...skipping 13 matching lines...) Expand all
439 } 340 }
440 341
441 void HTMLDocumentParser::constructTreeFromCompactHTMLToken(const CompactHTMLToke n& compactToken) 342 void HTMLDocumentParser::constructTreeFromCompactHTMLToken(const CompactHTMLToke n& compactToken)
442 { 343 {
443 AtomicHTMLToken token(compactToken); 344 AtomicHTMLToken token(compactToken);
444 m_treeBuilder->constructTree(&token); 345 m_treeBuilder->constructTree(&token);
445 } 346 }
446 347
447 bool HTMLDocumentParser::hasInsertionPoint() 348 bool HTMLDocumentParser::hasInsertionPoint()
448 { 349 {
449 return m_input.hasInsertionPoint(); 350 return false;
450 }
451
452 void HTMLDocumentParser::insert(const SegmentedString& source)
453 {
454 if (isStopped())
455 return;
456
457 TRACE_EVENT1("blink", "HTMLDocumentParser::insert", "source_length", source. length());
458
459 // pumpTokenizer can cause this parser to be detached from the Document,
460 // but we need to ensure it isn't deleted yet.
461 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this);
462
463 if (!m_tokenizer) {
464 ASSERT(!inPumpSession());
465 ASSERT(m_haveBackgroundParser);
466 m_token = adoptPtr(new HTMLToken);
467 m_tokenizer = HTMLTokenizer::create(m_options);
468 }
469
470 SegmentedString excludedLineNumberSource(source);
471 excludedLineNumberSource.setExcludeLineNumbers();
472 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource);
473 pumpTokenizerIfPossible(ForceSynchronous);
474
475 endIfDelayed();
476 } 351 }
477 352
478 void HTMLDocumentParser::startBackgroundParser() 353 void HTMLDocumentParser::startBackgroundParser()
479 { 354 {
480 ASSERT(!isStopped());
481 ASSERT(shouldUseThreading());
482 ASSERT(!m_haveBackgroundParser);
483 m_haveBackgroundParser = true;
484
485 OwnPtr<BackgroundHTMLParser::Configuration> config = adoptPtr(new Background HTMLParser::Configuration);
486 config->options = m_options;
487 config->parser = m_weakFactory.createWeakPtr();
488
489 m_backgroundParser = BackgroundHTMLParser::create(config.release());
490 } 355 }
491 356
492 void HTMLDocumentParser::stopBackgroundParser() 357 void HTMLDocumentParser::stopBackgroundParser()
493 { 358 {
494 ASSERT(shouldUseThreading()); 359 ASSERT(shouldUseThreading());
495 ASSERT(m_haveBackgroundParser); 360 ASSERT(m_haveBackgroundParser);
496 m_haveBackgroundParser = false; 361 m_haveBackgroundParser = false;
497 362
498 HTMLParserThread::taskRunner()->PostTask(FROM_HERE, 363 HTMLParserThread::taskRunner()->PostTask(FROM_HERE,
499 base::Bind(&BackgroundHTMLParser::stop, m_backgroundParser)); 364 base::Bind(&BackgroundHTMLParser::stop, m_backgroundParser));
500 m_weakFactory.revokeAll(); 365 m_weakFactory.revokeAll();
501 } 366 }
502 367
503 void HTMLDocumentParser::append(PassRefPtr<StringImpl> inputSource)
504 {
505 if (isStopped())
506 return;
507
508 // We should never reach this point if we're using a parser thread,
509 // as appendBytes() will directly ship the data to the thread.
510 ASSERT(!shouldUseThreading());
511
512 // pumpTokenizer can cause this parser to be detached from the Document,
513 // but we need to ensure it isn't deleted yet.
514 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this);
515 TRACE_EVENT1("net", "HTMLDocumentParser::append", "size", inputSource->lengt h());
516 String source(inputSource);
517
518 m_input.appendToEnd(source);
519
520 if (inPumpSession()) {
521 // We've gotten data off the network in a nested write.
522 // We don't want to consume any more of the input stream now. Do
523 // not worry. We'll consume this data in a less-nested write().
524 return;
525 }
526
527 pumpTokenizerIfPossible(AllowYield);
528
529 endIfDelayed();
530 }
531
532 void HTMLDocumentParser::end() 368 void HTMLDocumentParser::end()
533 { 369 {
534 ASSERT(!isDetached()); 370 ASSERT(!isDetached());
535 ASSERT(!isScheduledForResume()); 371 ASSERT(!isScheduledForResume());
536 372
537 if (m_haveBackgroundParser) 373 if (m_haveBackgroundParser)
538 stopBackgroundParser(); 374 stopBackgroundParser();
539 375
540 // Informs the the rest of WebCore that parsing is really finished (and dele tes this). 376 // Informs the the rest of WebCore that parsing is really finished (and dele tes this).
541 m_treeBuilder->finished(); 377 m_treeBuilder->finished();
542 } 378 }
543 379
544 void HTMLDocumentParser::attemptToEnd() 380 void HTMLDocumentParser::attemptToEnd()
545 { 381 {
546 // finish() indicates we will not receive any more data. If we are waiting o n
547 // an external script to load, we can't finish parsing quite yet.
548
549 if (shouldDelayEnd()) { 382 if (shouldDelayEnd()) {
550 m_endWasDelayed = true; 383 m_endWasDelayed = true;
551 return; 384 return;
552 } 385 }
553 prepareToStopParsing(); 386 prepareToStopParsing();
554 } 387 }
555 388
556 void HTMLDocumentParser::endIfDelayed() 389 void HTMLDocumentParser::endIfDelayed()
557 { 390 {
558 // If we've already been detached, don't bother ending. 391 // If we've already been detached, don't bother ending.
559 if (isDetached()) 392 if (isDetached())
560 return; 393 return;
561 394
562 if (!m_endWasDelayed || shouldDelayEnd()) 395 if (!m_endWasDelayed || shouldDelayEnd())
563 return; 396 return;
564 397
565 m_endWasDelayed = false; 398 m_endWasDelayed = false;
566 prepareToStopParsing(); 399 prepareToStopParsing();
567 } 400 }
568 401
569 void HTMLDocumentParser::finish()
570 {
571 // FIXME: We should ASSERT(!m_parserStopped) here, since it does not
572 // makes sense to call any methods on DocumentParser once it's been stopped.
573 // However, FrameLoader::stop calls DocumentParser::finish unconditionally.
574
575 // flush may ending up executing arbitrary script, and possibly detach the p arser.
576 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this);
577 flush();
578 if (isDetached())
579 return;
580
581 // Empty documents never got an append() call, and thus have never started
582 // a background parser. In those cases, we ignore shouldUseThreading()
583 // and fall through to the non-threading case.
584 if (m_haveBackgroundParser) {
585 if (!m_input.haveSeenEndOfFile())
586 m_input.closeWithoutMarkingEndOfFile();
587 HTMLParserThread::taskRunner()->PostTask(FROM_HERE,
588 base::Bind(&BackgroundHTMLParser::finish, m_backgroundParser));
589 return;
590 }
591
592 if (!m_tokenizer) {
593 ASSERT(!m_token);
594 // We're finishing before receiving any data. Rather than booting up
595 // the background parser just to spin it down, we finish parsing
596 // synchronously.
597 m_token = adoptPtr(new HTMLToken);
598 m_tokenizer = HTMLTokenizer::create(m_options);
599 }
600
601 // We're not going to get any more data off the network, so we tell the
602 // input stream we've reached the end of file. finish() can be called more
603 // than once, if the first time does not call end().
604 if (!m_input.haveSeenEndOfFile())
605 m_input.markEndOfFile();
606
607 attemptToEnd();
608 }
609
610 bool HTMLDocumentParser::isExecutingScript() const 402 bool HTMLDocumentParser::isExecutingScript() const
611 { 403 {
612 return m_scriptRunner.isExecutingScript(); 404 return m_scriptRunner.isExecutingScript();
613 } 405 }
614 406
615 OrdinalNumber HTMLDocumentParser::lineNumber() const 407 OrdinalNumber HTMLDocumentParser::lineNumber() const
616 { 408 {
617 if (m_haveBackgroundParser) 409 ASSERT(m_haveBackgroundParser);
618 return m_textPosition.m_line; 410 return m_textPosition.m_line;
619
620 return m_input.current().currentLine();
621 } 411 }
622 412
623 TextPosition HTMLDocumentParser::textPosition() const 413 TextPosition HTMLDocumentParser::textPosition() const
624 { 414 {
625 if (m_haveBackgroundParser) 415 ASSERT(m_haveBackgroundParser);
626 return m_textPosition; 416 return m_textPosition;
627
628 const SegmentedString& currentString = m_input.current();
629 OrdinalNumber line = currentString.currentLine();
630 OrdinalNumber column = currentString.currentColumn();
631
632 return TextPosition(line, column);
633 } 417 }
634 418
635 bool HTMLDocumentParser::isWaitingForScripts() const 419 bool HTMLDocumentParser::isWaitingForScripts() const
636 { 420 {
637 return m_treeBuilder->hasParserBlockingScript() || m_scriptRunner.hasPending Scripts(); 421 return m_treeBuilder->hasParserBlockingScript() || m_scriptRunner.hasPending Scripts();
638 } 422 }
639 423
640 void HTMLDocumentParser::resumeParsingAfterScriptExecution() 424 void HTMLDocumentParser::resumeParsingAfterScriptExecution()
641 { 425 {
642 ASSERT(!isExecutingScript()); 426 ASSERT(!isExecutingScript());
643 ASSERT(!isWaitingForScripts()); 427 ASSERT(!isWaitingForScripts());
428 ASSERT(m_haveBackgroundParser);
644 429
645 if (m_haveBackgroundParser) { 430 validateSpeculations(m_lastChunkBeforeScript.release());
646 validateSpeculations(m_lastChunkBeforeScript.release()); 431 ASSERT(!m_lastChunkBeforeScript);
647 ASSERT(!m_lastChunkBeforeScript); 432 // processParsedChunkFromBackgroundParser can cause this parser to be detach ed from the Document,
648 // processParsedChunkFromBackgroundParser can cause this parser to be de tached from the Document, 433 // but we need to ensure it isn't deleted yet.
649 // but we need to ensure it isn't deleted yet. 434 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this);
650 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); 435 pumpPendingSpeculations();
651 pumpPendingSpeculations();
652 return;
653 }
654
655 pumpTokenizerIfPossible(AllowYield);
656 endIfDelayed();
657 } 436 }
658 437
659 void HTMLDocumentParser::executeScriptsWaitingForResources() 438 void HTMLDocumentParser::executeScriptsWaitingForResources()
660 { 439 {
661 if (!m_scriptRunner.hasPendingScripts()) 440 if (!m_scriptRunner.hasPendingScripts())
662 return; 441 return;
663 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this); 442 RefPtrWillBeRawPtr<HTMLDocumentParser> protect(this);
664 m_scriptRunner.executePendingScripts(); 443 m_scriptRunner.executePendingScripts();
665 if (!isWaitingForScripts()) 444 if (!isWaitingForScripts())
666 resumeParsingAfterScriptExecution(); 445 resumeParsingAfterScriptExecution();
667 } 446 }
668 447
669 void HTMLDocumentParser::appendBytes(const char* data, size_t length)
670 {
671 if (!length || isStopped())
672 return;
673
674 if (shouldUseThreading()) {
675 if (!m_haveBackgroundParser)
676 startBackgroundParser();
677
678 OwnPtr<Vector<char> > buffer = adoptPtr(new Vector<char>(length));
679 memcpy(buffer->data(), data, length);
680 TRACE_EVENT1("net", "HTMLDocumentParser::appendBytes", "size", (unsigned )length);
681
682 HTMLParserThread::taskRunner()->PostTask(FROM_HERE,
683 base::Bind(&BackgroundHTMLParser::appendRawBytesFromMainThread, m_ba ckgroundParser, buffer.release()));
684 return;
685 }
686
687 DecodedDataDocumentParser::appendBytes(data, length);
688 } 448 }
689
690 void HTMLDocumentParser::flush()
691 {
692 // If we've got no decoder, we never received any data.
693 if (isDetached())
694 return;
695
696 if (m_haveBackgroundParser) {
697 HTMLParserThread::taskRunner()->PostTask(FROM_HERE,
698 base::Bind(&BackgroundHTMLParser::flush, m_backgroundParser));
699 } else {
700 DecodedDataDocumentParser::flush();
701 }
702 }
703
704 }
OLDNEW
« no previous file with comments | « sky/engine/core/html/parser/HTMLDocumentParser.h ('k') | sky/engine/core/html/parser/HTMLParserOptions.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698