Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / html / parser / HTMLDocumentParser.cpp
1 /*
2  * Copyright (C) 2010 Google, Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "core/html/parser/HTMLDocumentParser.h"
28
29 #include "HTMLNames.h"
30 #include "core/css/MediaValuesCached.h"
31 #include "core/dom/DocumentFragment.h"
32 #include "core/dom/Element.h"
33 #include "core/frame/LocalFrame.h"
34 #include "core/html/HTMLDocument.h"
35 #include "core/html/parser/AtomicHTMLToken.h"
36 #include "core/html/parser/BackgroundHTMLParser.h"
37 #include "core/html/parser/HTMLParserScheduler.h"
38 #include "core/html/parser/HTMLParserThread.h"
39 #include "core/html/parser/HTMLScriptRunner.h"
40 #include "core/html/parser/HTMLTreeBuilder.h"
41 #include "core/inspector/InspectorInstrumentation.h"
42 #include "core/inspector/InspectorTraceEvents.h"
43 #include "core/loader/DocumentLoader.h"
44 #include "platform/SharedBuffer.h"
45 #include "platform/TraceEvent.h"
46 #include "public/platform/WebThreadedDataReceiver.h"
47 #include "wtf/Functional.h"
48
49 namespace WebCore {
50
51 using namespace HTMLNames;
52
53 // This is a direct transcription of step 4 from:
54 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case
55 static HTMLTokenizer::State tokenizerStateForContextElement(Element* contextElement, bool reportErrors, const HTMLParserOptions& options)
56 {
57     if (!contextElement)
58         return HTMLTokenizer::DataState;
59
60     const QualifiedName& contextTag = contextElement->tagQName();
61
62     if (contextTag.matches(titleTag) || contextTag.matches(textareaTag))
63         return HTMLTokenizer::RCDATAState;
64     if (contextTag.matches(styleTag)
65         || contextTag.matches(xmpTag)
66         || contextTag.matches(iframeTag)
67         || (contextTag.matches(noembedTag) && options.pluginsEnabled)
68         || (contextTag.matches(noscriptTag) && options.scriptEnabled)
69         || contextTag.matches(noframesTag))
70         return reportErrors ? HTMLTokenizer::RAWTEXTState : HTMLTokenizer::PLAINTEXTState;
71     if (contextTag.matches(scriptTag))
72         return reportErrors ? HTMLTokenizer::ScriptDataState : HTMLTokenizer::PLAINTEXTState;
73     if (contextTag.matches(plaintextTag))
74         return HTMLTokenizer::PLAINTEXTState;
75     return HTMLTokenizer::DataState;
76 }
77
78 class ParserDataReceiver : public blink::WebThreadedDataReceiver {
79 public:
80     explicit ParserDataReceiver(WeakPtr<BackgroundHTMLParser> backgroundParser)
81         : m_backgroundParser(backgroundParser)
82     {
83     }
84
85     // WebThreadedDataReceiver
86     virtual void acceptData(const char* data, int dataLength) OVERRIDE FINAL
87     {
88         ASSERT(backgroundThread()->isCurrentThread());
89         if (m_backgroundParser.get())
90             m_backgroundParser.get()->appendRawBytesFromParserThread(data, dataLength);
91     }
92
93     virtual blink::WebThread* backgroundThread() OVERRIDE FINAL
94     {
95         return &HTMLParserThread::shared()->platformThread();
96     }
97
98 private:
99     WeakPtr<BackgroundHTMLParser> m_backgroundParser;
100 };
101
102 HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors)
103     : ScriptableDocumentParser(document)
104     , m_options(document)
105     , m_token(m_options.useThreading ? nullptr : adoptPtr(new HTMLToken))
106     , m_tokenizer(m_options.useThreading ? nullptr : HTMLTokenizer::create(m_options))
107     , m_scriptRunner(HTMLScriptRunner::create(document, this))
108     , m_treeBuilder(HTMLTreeBuilder::create(this, document, parserContentPolicy(), reportErrors, m_options))
109     , m_parserScheduler(HTMLParserScheduler::create(this))
110     , m_xssAuditorDelegate(document)
111     , m_weakFactory(this)
112     , m_preloader(adoptPtr(new HTMLResourcePreloader(document)))
113     , m_isPinnedToMainThread(false)
114     , m_endWasDelayed(false)
115     , m_haveBackgroundParser(false)
116     , m_pumpSessionNestingLevel(0)
117 {
118     ASSERT(shouldUseThreading() || (m_token && m_tokenizer));
119 }
120
121 // FIXME: Member variables should be grouped into self-initializing structs to
122 // minimize code duplication between these constructors.
123 HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, Element* contextElement, ParserContentPolicy parserContentPolicy)
124     : ScriptableDocumentParser(&fragment->document(), parserContentPolicy)
125     , m_options(&fragment->document())
126     , m_token(adoptPtr(new HTMLToken))
127     , m_tokenizer(HTMLTokenizer::create(m_options))
128     , m_treeBuilder(HTMLTreeBuilder::create(this, fragment, contextElement, this->parserContentPolicy(), m_options))
129     , m_xssAuditorDelegate(&fragment->document())
130     , m_weakFactory(this)
131     , m_isPinnedToMainThread(true)
132     , m_endWasDelayed(false)
133     , m_haveBackgroundParser(false)
134     , m_pumpSessionNestingLevel(0)
135 {
136     ASSERT(!shouldUseThreading());
137     bool reportErrors = false; // For now document fragment parsing never reports errors.
138     m_tokenizer->setState(tokenizerStateForContextElement(contextElement, reportErrors, m_options));
139     m_xssAuditor.initForFragment();
140 }
141
142 HTMLDocumentParser::~HTMLDocumentParser()
143 {
144     ASSERT(!m_parserScheduler);
145     ASSERT(!m_pumpSessionNestingLevel);
146     ASSERT(!m_preloadScanner);
147     ASSERT(!m_insertionPreloadScanner);
148     ASSERT(!m_haveBackgroundParser);
149     // FIXME: We should be able to ASSERT(m_speculations.isEmpty()),
150     // but there are cases where that's not true currently. For example,
151     // we we're told to stop parsing before we've consumed all the input.
152 }
153
154 void HTMLDocumentParser::pinToMainThread()
155 {
156     ASSERT(!m_haveBackgroundParser);
157     ASSERT(!m_isPinnedToMainThread);
158     m_isPinnedToMainThread = true;
159     if (!m_tokenizer) {
160         ASSERT(!m_token);
161         m_token = adoptPtr(new HTMLToken);
162         m_tokenizer = HTMLTokenizer::create(m_options);
163     }
164 }
165
166 void HTMLDocumentParser::detach()
167 {
168     if (m_haveBackgroundParser)
169         stopBackgroundParser();
170     DocumentParser::detach();
171     if (m_scriptRunner)
172         m_scriptRunner->detach();
173     m_treeBuilder->detach();
174     // FIXME: It seems wrong that we would have a preload scanner here.
175     // Yet during fast/dom/HTMLScriptElement/script-load-events.html we do.
176     m_preloadScanner.clear();
177     m_insertionPreloadScanner.clear();
178     m_parserScheduler.clear(); // Deleting the scheduler will clear any timers.
179 }
180
181 void HTMLDocumentParser::stopParsing()
182 {
183     DocumentParser::stopParsing();
184     m_parserScheduler.clear(); // Deleting the scheduler will clear any timers.
185     if (m_haveBackgroundParser)
186         stopBackgroundParser();
187 }
188
189 // This kicks off "Once the user agent stops parsing" as described by:
190 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the-end
191 void HTMLDocumentParser::prepareToStopParsing()
192 {
193     // FIXME: It may not be correct to disable this for the background parser.
194     // That means hasInsertionPoint() may not be correct in some cases.
195     ASSERT(!hasInsertionPoint() || m_haveBackgroundParser);
196
197     // pumpTokenizer can cause this parser to be detached from the Document,
198     // but we need to ensure it isn't deleted yet.
199     RefPtr<HTMLDocumentParser> protect(this);
200
201     // NOTE: This pump should only ever emit buffered character tokens,
202     // so ForceSynchronous vs. AllowYield should be meaningless.
203     if (m_tokenizer) {
204         ASSERT(!m_haveBackgroundParser);
205         pumpTokenizerIfPossible(ForceSynchronous);
206     }
207
208     if (isStopped())
209         return;
210
211     DocumentParser::prepareToStopParsing();
212
213     // We will not have a scriptRunner when parsing a DocumentFragment.
214     if (m_scriptRunner)
215         document()->setReadyState(Document::Interactive);
216
217     // Setting the ready state above can fire mutation event and detach us
218     // from underneath. In that case, just bail out.
219     if (isDetached())
220         return;
221
222     attemptToRunDeferredScriptsAndEnd();
223 }
224
225 bool HTMLDocumentParser::isParsingFragment() const
226 {
227     return m_treeBuilder->isParsingFragment();
228 }
229
230 bool HTMLDocumentParser::processingData() const
231 {
232     return isScheduledForResume() || inPumpSession() || m_haveBackgroundParser;
233 }
234
235 void HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode)
236 {
237     if (isStopped())
238         return;
239     if (isWaitingForScripts())
240         return;
241
242     // Once a resume is scheduled, HTMLParserScheduler controls when we next pump.
243     if (isScheduledForResume()) {
244         ASSERT(mode == AllowYield);
245         return;
246     }
247
248     pumpTokenizer(mode);
249 }
250
251 bool HTMLDocumentParser::isScheduledForResume() const
252 {
253     return m_parserScheduler && m_parserScheduler->isScheduledForResume();
254 }
255
256 // Used by HTMLParserScheduler
257 void HTMLDocumentParser::resumeParsingAfterYield()
258 {
259     ASSERT(!m_isPinnedToMainThread);
260     // pumpTokenizer can cause this parser to be detached from the Document,
261     // but we need to ensure it isn't deleted yet.
262     RefPtr<HTMLDocumentParser> protect(this);
263
264     if (m_haveBackgroundParser) {
265         pumpPendingSpeculations();
266         return;
267     }
268
269     // We should never be here unless we can pump immediately.  Call pumpTokenizer()
270     // directly so that ASSERTS will fire if we're wrong.
271     pumpTokenizer(AllowYield);
272     endIfDelayed();
273 }
274
275 void HTMLDocumentParser::runScriptsForPausedTreeBuilder()
276 {
277     ASSERT(scriptingContentIsAllowed(parserContentPolicy()));
278
279     TextPosition scriptStartPosition = TextPosition::belowRangePosition();
280     RefPtr<Element> scriptElement = m_treeBuilder->takeScriptToProcess(scriptStartPosition);
281     // We will not have a scriptRunner when parsing a DocumentFragment.
282     if (m_scriptRunner)
283         m_scriptRunner->execute(scriptElement.release(), scriptStartPosition);
284 }
285
286 bool HTMLDocumentParser::canTakeNextToken(SynchronousMode mode, PumpSession& session)
287 {
288     if (isStopped())
289         return false;
290
291     ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous);
292
293     if (isWaitingForScripts()) {
294         if (mode == AllowYield)
295             session.didSeeScript = true;
296
297         // If we don't run the script, we cannot allow the next token to be taken.
298         if (session.needsYield)
299             return false;
300
301         // If we're paused waiting for a script, we try to execute scripts before continuing.
302         runScriptsForPausedTreeBuilder();
303         if (isStopped())
304             return false;
305         if (isWaitingForScripts())
306             return false;
307     }
308
309     // FIXME: It's wrong for the HTMLDocumentParser to reach back to the
310     //        LocalFrame, but this approach is how the old parser handled
311     //        stopping when the page assigns window.location.  What really
312     //        should happen is that assigning window.location causes the
313     //        parser to stop parsing cleanly.  The problem is we're not
314     //        perpared to do that at every point where we run JavaScript.
315     if (!isParsingFragment()
316         && document()->frame() && document()->frame()->navigationScheduler().locationChangePending())
317         return false;
318
319     if (mode == AllowYield)
320         m_parserScheduler->checkForYieldBeforeToken(session);
321
322     return true;
323 }
324
325 void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk> chunk)
326 {
327     TRACE_EVENT0("webkit", "HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser");
328
329     // alert(), runModalDialog, and the JavaScript Debugger all run nested event loops
330     // which can cause this method to be re-entered. We detect re-entry using
331     // hasActiveParser(), save the chunk as a speculation, and return.
332     if (isWaitingForScripts() || !m_speculations.isEmpty() || document()->activeParserCount() > 0) {
333         m_preloader->takeAndPreload(chunk->preloads);
334         m_speculations.append(chunk);
335         return;
336     }
337
338     // processParsedChunkFromBackgroundParser can cause this parser to be detached from the Document,
339     // but we need to ensure it isn't deleted yet.
340     RefPtr<HTMLDocumentParser> protect(this);
341
342     ASSERT(m_speculations.isEmpty());
343     chunk->preloads.clear(); // We don't need to preload because we're going to parse immediately.
344     m_speculations.append(chunk);
345     pumpPendingSpeculations();
346 }
347
348 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser(const DocumentEncodingData& data)
349 {
350     document()->setEncodingData(data);
351 }
352
353 void HTMLDocumentParser::validateSpeculations(PassOwnPtr<ParsedChunk> chunk)
354 {
355     ASSERT(chunk);
356     if (isWaitingForScripts()) {
357         // We're waiting on a network script, just save the chunk, we'll get
358         // a second validateSpeculations call after the script completes.
359         // This call should have been made immediately after runScriptsForPausedTreeBuilder
360         // which may have started a network load and left us waiting.
361         ASSERT(!m_lastChunkBeforeScript);
362         m_lastChunkBeforeScript = chunk;
363         return;
364     }
365
366     ASSERT(!m_lastChunkBeforeScript);
367     OwnPtr<HTMLTokenizer> tokenizer = m_tokenizer.release();
368     OwnPtr<HTMLToken> token = m_token.release();
369
370     if (!tokenizer) {
371         // There must not have been any changes to the HTMLTokenizer state on
372         // the main thread, which means the speculation buffer is correct.
373         return;
374     }
375
376     // Currently we're only smart enough to reuse the speculation buffer if the tokenizer
377     // both starts and ends in the DataState. That state is simplest because the HTMLToken
378     // is always in the Uninitialized state. We should consider whether we can reuse the
379     // speculation buffer in other states, but we'd likely need to do something more
380     // sophisticated with the HTMLToken.
381     if (chunk->tokenizerState == HTMLTokenizer::DataState
382         && tokenizer->state() == HTMLTokenizer::DataState
383         && m_input.current().isEmpty()
384         && chunk->treeBuilderState == HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get())) {
385         ASSERT(token->isUninitialized());
386         return;
387     }
388
389     discardSpeculationsAndResumeFrom(chunk, token.release(), tokenizer.release());
390 }
391
392 void HTMLDocumentParser::discardSpeculationsAndResumeFrom(PassOwnPtr<ParsedChunk> lastChunkBeforeScript, PassOwnPtr<HTMLToken> token, PassOwnPtr<HTMLTokenizer> tokenizer)
393 {
394     m_weakFactory.revokeAll();
395     m_speculations.clear();
396
397     OwnPtr<BackgroundHTMLParser::Checkpoint> checkpoint = adoptPtr(new BackgroundHTMLParser::Checkpoint);
398     checkpoint->parser = m_weakFactory.createWeakPtr();
399     checkpoint->token = token;
400     checkpoint->tokenizer = tokenizer;
401     checkpoint->treeBuilderState = HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get());
402     checkpoint->inputCheckpoint = lastChunkBeforeScript->inputCheckpoint;
403     checkpoint->preloadScannerCheckpoint = lastChunkBeforeScript->preloadScannerCheckpoint;
404     checkpoint->unparsedInput = m_input.current().toString().isolatedCopy();
405     m_input.current().clear(); // FIXME: This should be passed in instead of cleared.
406
407     ASSERT(checkpoint->unparsedInput.isSafeToSendToAnotherThread());
408     HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::resumeFrom, m_backgroundParser, checkpoint.release()));
409 }
410
411 void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk> popChunk)
412 {
413     TRACE_EVENT0("webkit", "HTMLDocumentParser::processParsedChunkFromBackgroundParser");
414
415     ASSERT_WITH_SECURITY_IMPLICATION(!document()->activeParserCount());
416     ASSERT(!isParsingFragment());
417     ASSERT(!isWaitingForScripts());
418     ASSERT(!isStopped());
419     // ASSERT that this object is both attached to the Document and protected.
420     ASSERT(refCount() >= 2);
421     ASSERT(shouldUseThreading());
422     ASSERT(!m_tokenizer);
423     ASSERT(!m_token);
424     ASSERT(!m_lastChunkBeforeScript);
425
426     ActiveParserSession session(contextForParsingSession());
427
428     OwnPtr<ParsedChunk> chunk(popChunk);
429     OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release();
430
431     HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::startedChunkWithCheckpoint, m_backgroundParser, chunk->inputCheckpoint));
432
433     for (XSSInfoStream::const_iterator it = chunk->xssInfos.begin(); it != chunk->xssInfos.end(); ++it) {
434         m_textPosition = (*it)->m_textPosition;
435         m_xssAuditorDelegate.didBlockScript(**it);
436         if (isStopped())
437             break;
438     }
439
440     for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); it != tokens->end(); ++it) {
441         ASSERT(!isWaitingForScripts());
442
443         if (document()->frame() && document()->frame()->navigationScheduler().locationChangePending()) {
444
445             // To match main-thread parser behavior (which never checks locationChangePending on the EOF path)
446             // we peek to see if this chunk has an EOF and process it anyway.
447             if (tokens->last().type() == HTMLToken::EndOfFile) {
448                 ASSERT(m_speculations.isEmpty()); // There should never be any chunks after the EOF.
449                 prepareToStopParsing();
450             }
451             break;
452         }
453
454         m_textPosition = it->textPosition();
455
456         constructTreeFromCompactHTMLToken(*it);
457
458         if (isStopped())
459             break;
460
461         if (isWaitingForScripts()) {
462             ASSERT(it + 1 == tokens->end()); // The </script> is assumed to be the last token of this bunch.
463             runScriptsForPausedTreeBuilder();
464             validateSpeculations(chunk.release());
465             break;
466         }
467
468         if (it->type() == HTMLToken::EndOfFile) {
469             ASSERT(it + 1 == tokens->end()); // The EOF is assumed to be the last token of this bunch.
470             ASSERT(m_speculations.isEmpty()); // There should never be any chunks after the EOF.
471             prepareToStopParsing();
472             break;
473         }
474
475         ASSERT(!m_tokenizer);
476         ASSERT(!m_token);
477     }
478
479     // Make sure any pending text nodes are emitted before returning.
480     if (!isStopped())
481         m_treeBuilder->flush();
482 }
483
484 void HTMLDocumentParser::pumpPendingSpeculations()
485 {
486     // FIXME: Share this constant with the parser scheduler.
487     const double parserTimeLimit = 0.500;
488
489     // ASSERT that this object is both attached to the Document and protected.
490     ASSERT(refCount() >= 2);
491     // If this assert fails, you need to call validateSpeculations to make sure
492     // m_tokenizer and m_token don't have state that invalidates m_speculations.
493     ASSERT(!m_tokenizer);
494     ASSERT(!m_token);
495     ASSERT(!m_lastChunkBeforeScript);
496     ASSERT(!isWaitingForScripts());
497     ASSERT(!isStopped());
498
499     // FIXME: Pass in current input length.
500     TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ParseHTML", "beginData", InspectorParseHtmlEvent::beginData(document(), lineNumber().zeroBasedInt()));
501     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
502     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
503     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteHTML(document(), lineNumber().zeroBasedInt());
504
505     double startTime = currentTime();
506
507     while (!m_speculations.isEmpty()) {
508         processParsedChunkFromBackgroundParser(m_speculations.takeFirst());
509
510         // Always check isStopped first as m_document may be null.
511         if (isStopped() || isWaitingForScripts())
512             break;
513
514         if (currentTime() - startTime > parserTimeLimit && !m_speculations.isEmpty()) {
515             m_parserScheduler->scheduleForResume();
516             break;
517         }
518     }
519
520     TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ParseHTML", "endLine", lineNumber().zeroBasedInt());
521     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
522     InspectorInstrumentation::didWriteHTML(cookie, lineNumber().zeroBasedInt());
523     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", "data", InspectorUpdateCountersEvent::data());
524 }
525
526 void HTMLDocumentParser::forcePlaintextForTextDocument()
527 {
528     if (shouldUseThreading()) {
529         // This method is called before any data is appended, so we have to start
530         // the background parser ourselves.
531         if (!m_haveBackgroundParser)
532             startBackgroundParser();
533
534         HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::forcePlaintextForTextDocument, m_backgroundParser));
535     } else
536         m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState);
537 }
538
539 Document* HTMLDocumentParser::contextForParsingSession()
540 {
541     // The parsing session should interact with the document only when parsing
542     // non-fragments. Otherwise, we might delay the load event mistakenly.
543     if (isParsingFragment())
544         return 0;
545     return document();
546 }
547
548 static PassRefPtr<MediaValues> createMediaValues(Document* document)
549 {
550     ASSERT(document);
551     RefPtr<MediaValues> mediaValues = MediaValuesCached::create(*document);
552     ASSERT(mediaValues->isSafeToSendToAnotherThread());
553     return mediaValues;
554 }
555
556 void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
557 {
558     ASSERT(!isStopped());
559     ASSERT(!isScheduledForResume());
560     // ASSERT that this object is both attached to the Document and protected.
561     ASSERT(refCount() >= 2);
562     ASSERT(m_tokenizer);
563     ASSERT(m_token);
564     ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous);
565
566     PumpSession session(m_pumpSessionNestingLevel, contextForParsingSession());
567
568     // We tell the InspectorInstrumentation about every pump, even if we
569     // end up pumping nothing.  It can filter out empty pumps itself.
570     // FIXME: m_input.current().length() is only accurate if we
571     // end up parsing the whole buffer in this pump.  We should pass how
572     // much we parsed as part of didWriteHTML instead of willWriteHTML.
573     TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ParseHTML", "beginData", InspectorParseHtmlEvent::beginData(document(), m_input.current().currentLine().zeroBasedInt()));
574     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
575     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
576     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteHTML(document(), m_input.current().currentLine().zeroBasedInt());
577
578     m_xssAuditor.init(document(), &m_xssAuditorDelegate);
579
580     while (canTakeNextToken(mode, session) && !session.needsYield) {
581         if (!isParsingFragment())
582             m_sourceTracker.start(m_input.current(), m_tokenizer.get(), token());
583
584         if (!m_tokenizer->nextToken(m_input.current(), token()))
585             break;
586
587         if (!isParsingFragment()) {
588             m_sourceTracker.end(m_input.current(), m_tokenizer.get(), token());
589
590             // We do not XSS filter innerHTML, which means we (intentionally) fail
591             // http/tests/security/xssAuditor/dom-write-innerHTML.html
592             if (OwnPtr<XSSInfo> xssInfo = m_xssAuditor.filterToken(FilterTokenRequest(token(), m_sourceTracker, m_tokenizer->shouldAllowCDATA())))
593                 m_xssAuditorDelegate.didBlockScript(*xssInfo);
594         }
595
596         constructTreeFromHTMLToken(token());
597         ASSERT(token().isUninitialized());
598     }
599
600     // Ensure we haven't been totally deref'ed after pumping. Any caller of this
601     // function should be holding a RefPtr to this to ensure we weren't deleted.
602     ASSERT(refCount() >= 1);
603
604     if (isStopped())
605         return;
606
607     // There should only be PendingText left since the tree-builder always flushes
608     // the task queue before returning. In case that ever changes, crash.
609     if (mode == ForceSynchronous)
610         m_treeBuilder->flush();
611     RELEASE_ASSERT(!isStopped());
612
613     if (session.needsYield)
614         m_parserScheduler->scheduleForResume();
615
616     if (isWaitingForScripts()) {
617         ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState);
618         if (!m_preloadScanner) {
619             m_preloadScanner = adoptPtr(new HTMLPreloadScanner(m_options, document()->url(), createMediaValues(document())));
620             m_preloadScanner->appendToEnd(m_input.current());
621         }
622         m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
623     }
624
625     TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ParseHTML", "endLine", m_input.current().currentLine().zeroBasedInt());
626     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
627     InspectorInstrumentation::didWriteHTML(cookie, m_input.current().currentLine().zeroBasedInt());
628 }
629
630 void HTMLDocumentParser::constructTreeFromHTMLToken(HTMLToken& rawToken)
631 {
632     AtomicHTMLToken token(rawToken);
633
634     // We clear the rawToken in case constructTreeFromAtomicToken
635     // synchronously re-enters the parser. We don't clear the token immedately
636     // for Character tokens because the AtomicHTMLToken avoids copying the
637     // characters by keeping a pointer to the underlying buffer in the
638     // HTMLToken. Fortunately, Character tokens can't cause us to re-enter
639     // the parser.
640     //
641     // FIXME: Stop clearing the rawToken once we start running the parser off
642     // the main thread or once we stop allowing synchronous JavaScript
643     // execution from parseAttribute.
644     if (rawToken.type() != HTMLToken::Character)
645         rawToken.clear();
646
647     m_treeBuilder->constructTree(&token);
648
649     if (!rawToken.isUninitialized()) {
650         ASSERT(rawToken.type() == HTMLToken::Character);
651         rawToken.clear();
652     }
653 }
654
655 void HTMLDocumentParser::constructTreeFromCompactHTMLToken(const CompactHTMLToken& compactToken)
656 {
657     AtomicHTMLToken token(compactToken);
658     m_treeBuilder->constructTree(&token);
659 }
660
661 bool HTMLDocumentParser::hasInsertionPoint()
662 {
663     // FIXME: The wasCreatedByScript() branch here might not be fully correct.
664     //        Our model of the EOF character differs slightly from the one in
665     //        the spec because our treatment is uniform between network-sourced
666     //        and script-sourced input streams whereas the spec treats them
667     //        differently.
668     return m_input.hasInsertionPoint() || (wasCreatedByScript() && !m_input.haveSeenEndOfFile());
669 }
670
671 void HTMLDocumentParser::insert(const SegmentedString& source)
672 {
673     if (isStopped())
674         return;
675
676     TRACE_EVENT1("webkit", "HTMLDocumentParser::insert", "source_length", source.length());
677
678     // pumpTokenizer can cause this parser to be detached from the Document,
679     // but we need to ensure it isn't deleted yet.
680     RefPtr<HTMLDocumentParser> protect(this);
681
682     if (!m_tokenizer) {
683         ASSERT(!inPumpSession());
684         ASSERT(m_haveBackgroundParser || wasCreatedByScript());
685         m_token = adoptPtr(new HTMLToken);
686         m_tokenizer = HTMLTokenizer::create(m_options);
687     }
688
689     SegmentedString excludedLineNumberSource(source);
690     excludedLineNumberSource.setExcludeLineNumbers();
691     m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource);
692     pumpTokenizerIfPossible(ForceSynchronous);
693
694     if (isWaitingForScripts()) {
695         // Check the document.write() output with a separate preload scanner as
696         // the main scanner can't deal with insertions.
697         if (!m_insertionPreloadScanner)
698             m_insertionPreloadScanner = adoptPtr(new HTMLPreloadScanner(m_options, document()->url(), createMediaValues(document())));
699
700         m_insertionPreloadScanner->appendToEnd(source);
701         m_insertionPreloadScanner->scan(m_preloader.get(), document()->baseElementURL());
702     }
703
704     endIfDelayed();
705 }
706
707 void HTMLDocumentParser::startBackgroundParser()
708 {
709     ASSERT(!isStopped());
710     ASSERT(shouldUseThreading());
711     ASSERT(!m_haveBackgroundParser);
712     m_haveBackgroundParser = true;
713
714     RefPtr<WeakReference<BackgroundHTMLParser> > reference = WeakReference<BackgroundHTMLParser>::createUnbound();
715     m_backgroundParser = WeakPtr<BackgroundHTMLParser>(reference);
716
717     document()->loader()->attachThreadedDataReceiver(adoptPtr(new ParserDataReceiver(m_backgroundParser)));
718
719     OwnPtr<BackgroundHTMLParser::Configuration> config = adoptPtr(new BackgroundHTMLParser::Configuration);
720     config->options = m_options;
721     config->parser = m_weakFactory.createWeakPtr();
722     config->xssAuditor = adoptPtr(new XSSAuditor);
723     config->xssAuditor->init(document(), &m_xssAuditorDelegate);
724     config->preloadScanner = adoptPtr(new TokenPreloadScanner(document()->url().copy(), createMediaValues(document())));
725     config->decoder = takeDecoder();
726
727     ASSERT(config->xssAuditor->isSafeToSendToAnotherThread());
728     ASSERT(config->preloadScanner->isSafeToSendToAnotherThread());
729     HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::start, reference.release(), config.release()));
730 }
731
732 void HTMLDocumentParser::stopBackgroundParser()
733 {
734     ASSERT(shouldUseThreading());
735     ASSERT(m_haveBackgroundParser);
736     m_haveBackgroundParser = false;
737
738     HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::stop, m_backgroundParser));
739     m_weakFactory.revokeAll();
740 }
741
742 void HTMLDocumentParser::append(PassRefPtr<StringImpl> inputSource)
743 {
744     if (isStopped())
745         return;
746
747     // We should never reach this point if we're using a parser thread,
748     // as appendBytes() will directly ship the data to the thread.
749     ASSERT(!shouldUseThreading());
750
751     // pumpTokenizer can cause this parser to be detached from the Document,
752     // but we need to ensure it isn't deleted yet.
753     RefPtr<HTMLDocumentParser> protect(this);
754     TRACE_EVENT1("net", "HTMLDocumentParser::append", "size", inputSource->length());
755     String source(inputSource);
756
757     if (m_preloadScanner) {
758         if (m_input.current().isEmpty() && !isWaitingForScripts()) {
759             // We have parsed until the end of the current input and so are now moving ahead of the preload scanner.
760             // Clear the scanner so we know to scan starting from the current input point if we block again.
761             m_preloadScanner.clear();
762         } else {
763             m_preloadScanner->appendToEnd(source);
764             if (isWaitingForScripts())
765                 m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
766         }
767     }
768
769     m_input.appendToEnd(source);
770
771     if (inPumpSession()) {
772         // We've gotten data off the network in a nested write.
773         // We don't want to consume any more of the input stream now.  Do
774         // not worry.  We'll consume this data in a less-nested write().
775         return;
776     }
777
778     // A couple pinToMainThread() callers require synchronous parsing, but can't
779     // easily use the insert() method, so we hack append() for them to be synchronous.
780     // javascript: url handling is one such caller.
781     // FIXME: This is gross, and we should separate the concept of synchronous parsing
782     // from insert() so that only document.write() uses insert.
783     if (m_isPinnedToMainThread)
784         pumpTokenizerIfPossible(ForceSynchronous);
785     else
786         pumpTokenizerIfPossible(AllowYield);
787
788     endIfDelayed();
789 }
790
791 void HTMLDocumentParser::end()
792 {
793     ASSERT(!isDetached());
794     ASSERT(!isScheduledForResume());
795
796     if (m_haveBackgroundParser)
797         stopBackgroundParser();
798
799     // Informs the the rest of WebCore that parsing is really finished (and deletes this).
800     m_treeBuilder->finished();
801 }
802
803 void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd()
804 {
805     ASSERT(isStopping());
806     // FIXME: It may not be correct to disable this for the background parser.
807     // That means hasInsertionPoint() may not be correct in some cases.
808     ASSERT(!hasInsertionPoint() || m_haveBackgroundParser);
809     if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing())
810         return;
811     end();
812 }
813
814 void HTMLDocumentParser::attemptToEnd()
815 {
816     // finish() indicates we will not receive any more data. If we are waiting on
817     // an external script to load, we can't finish parsing quite yet.
818
819     if (shouldDelayEnd()) {
820         m_endWasDelayed = true;
821         return;
822     }
823     prepareToStopParsing();
824 }
825
826 void HTMLDocumentParser::endIfDelayed()
827 {
828     // If we've already been detached, don't bother ending.
829     if (isDetached())
830         return;
831
832     if (!m_endWasDelayed || shouldDelayEnd())
833         return;
834
835     m_endWasDelayed = false;
836     prepareToStopParsing();
837 }
838
839 void HTMLDocumentParser::finish()
840 {
841     // FIXME: We should ASSERT(!m_parserStopped) here, since it does not
842     // makes sense to call any methods on DocumentParser once it's been stopped.
843     // However, FrameLoader::stop calls DocumentParser::finish unconditionally.
844
845     // Empty documents never got an append() call, and thus have never started
846     // a background parser. In those cases, we ignore shouldUseThreading()
847     // and fall through to the non-threading case.
848     if (m_haveBackgroundParser) {
849         if (!m_input.haveSeenEndOfFile())
850             m_input.closeWithoutMarkingEndOfFile();
851         HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::finish, m_backgroundParser));
852         return;
853     }
854
855     if (!m_tokenizer) {
856         ASSERT(!m_token);
857         // We're finishing before receiving any data. Rather than booting up
858         // the background parser just to spin it down, we finish parsing
859         // synchronously.
860         m_token = adoptPtr(new HTMLToken);
861         m_tokenizer = HTMLTokenizer::create(m_options);
862     }
863
864     // We're not going to get any more data off the network, so we tell the
865     // input stream we've reached the end of file. finish() can be called more
866     // than once, if the first time does not call end().
867     if (!m_input.haveSeenEndOfFile())
868         m_input.markEndOfFile();
869
870     attemptToEnd();
871 }
872
873 bool HTMLDocumentParser::isExecutingScript() const
874 {
875     if (!m_scriptRunner)
876         return false;
877     return m_scriptRunner->isExecutingScript();
878 }
879
880 OrdinalNumber HTMLDocumentParser::lineNumber() const
881 {
882     if (m_haveBackgroundParser)
883         return m_textPosition.m_line;
884
885     return m_input.current().currentLine();
886 }
887
888 TextPosition HTMLDocumentParser::textPosition() const
889 {
890     if (m_haveBackgroundParser)
891         return m_textPosition;
892
893     const SegmentedString& currentString = m_input.current();
894     OrdinalNumber line = currentString.currentLine();
895     OrdinalNumber column = currentString.currentColumn();
896
897     return TextPosition(line, column);
898 }
899
900 bool HTMLDocumentParser::isWaitingForScripts() const
901 {
902     // When the TreeBuilder encounters a </script> tag, it returns to the HTMLDocumentParser
903     // where the script is transfered from the treebuilder to the script runner.
904     // The script runner will hold the script until its loaded and run. During
905     // any of this time, we want to count ourselves as "waiting for a script" and thus
906     // run the preload scanner, as well as delay completion of parsing.
907     bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript();
908     bool scriptRunnerHasBlockingScript = m_scriptRunner && m_scriptRunner->hasParserBlockingScript();
909     // Since the parser is paused while a script runner has a blocking script, it should
910     // never be possible to end up with both objects holding a blocking script.
911     ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript));
912     // If either object has a blocking script, the parser should be paused.
913     return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript;
914 }
915
916 void HTMLDocumentParser::resumeParsingAfterScriptExecution()
917 {
918     ASSERT(!isExecutingScript());
919     ASSERT(!isWaitingForScripts());
920
921     if (m_haveBackgroundParser) {
922         validateSpeculations(m_lastChunkBeforeScript.release());
923         ASSERT(!m_lastChunkBeforeScript);
924         // processParsedChunkFromBackgroundParser can cause this parser to be detached from the Document,
925         // but we need to ensure it isn't deleted yet.
926         RefPtr<HTMLDocumentParser> protect(this);
927         pumpPendingSpeculations();
928         return;
929     }
930
931     m_insertionPreloadScanner.clear();
932     pumpTokenizerIfPossible(AllowYield);
933     endIfDelayed();
934 }
935
936 void HTMLDocumentParser::watchForLoad(Resource* resource)
937 {
938     ASSERT(!resource->isLoaded());
939     // addClient would call notifyFinished if the load were complete.
940     // Callers do not expect to be re-entered from this call, so they should
941     // not an already-loaded Resource.
942     resource->addClient(this);
943 }
944
945 void HTMLDocumentParser::stopWatchingForLoad(Resource* resource)
946 {
947     resource->removeClient(this);
948 }
949
950 void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan()
951 {
952     ASSERT(m_preloadScanner);
953     m_preloadScanner->appendToEnd(m_input.current());
954     m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
955 }
956
957 void HTMLDocumentParser::notifyFinished(Resource* cachedResource)
958 {
959     // pumpTokenizer can cause this parser to be detached from the Document,
960     // but we need to ensure it isn't deleted yet.
961     RefPtr<HTMLDocumentParser> protect(this);
962
963     ASSERT(m_scriptRunner);
964     ASSERT(!isExecutingScript());
965     if (isStopping()) {
966         attemptToRunDeferredScriptsAndEnd();
967         return;
968     }
969
970     m_scriptRunner->executeScriptsWaitingForLoad(cachedResource);
971     if (!isWaitingForScripts())
972         resumeParsingAfterScriptExecution();
973 }
974
975 void HTMLDocumentParser::executeScriptsWaitingForResources()
976 {
977     // Document only calls this when the Document owns the DocumentParser
978     // so this will not be called in the DocumentFragment case.
979     ASSERT(m_scriptRunner);
980     // Ignore calls unless we have a script blocking the parser waiting on a
981     // stylesheet load.  Otherwise we are currently parsing and this
982     // is a re-entrant call from encountering a </ style> tag.
983     if (!m_scriptRunner->hasScriptsWaitingForResources())
984         return;
985
986     // pumpTokenizer can cause this parser to be detached from the Document,
987     // but we need to ensure it isn't deleted yet.
988     RefPtr<HTMLDocumentParser> protect(this);
989     m_scriptRunner->executeScriptsWaitingForResources();
990     if (!isWaitingForScripts())
991         resumeParsingAfterScriptExecution();
992 }
993
994 void HTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFragment* fragment, Element* contextElement, ParserContentPolicy parserContentPolicy)
995 {
996     RefPtr<HTMLDocumentParser> parser = HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy);
997     parser->insert(source); // Use insert() so that the parser will not yield.
998     parser->finish();
999     ASSERT(!parser->processingData()); // Make sure we're done. <rdar://problem/3963151>
1000     parser->detach(); // Allows ~DocumentParser to assert it was detached before destruction.
1001 }
1002
1003 void HTMLDocumentParser::suspendScheduledTasks()
1004 {
1005     if (m_parserScheduler)
1006         m_parserScheduler->suspend();
1007 }
1008
1009 void HTMLDocumentParser::resumeScheduledTasks()
1010 {
1011     if (m_parserScheduler)
1012         m_parserScheduler->resume();
1013 }
1014
1015 void HTMLDocumentParser::appendBytes(const char* data, size_t length)
1016 {
1017     if (!length || isStopped())
1018         return;
1019
1020     if (shouldUseThreading()) {
1021         if (!m_haveBackgroundParser)
1022             startBackgroundParser();
1023
1024         OwnPtr<Vector<char> > buffer = adoptPtr(new Vector<char>(length));
1025         memcpy(buffer->data(), data, length);
1026         TRACE_EVENT1("net", "HTMLDocumentParser::appendBytes", "size", (unsigned)length);
1027
1028         HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::appendRawBytesFromMainThread, m_backgroundParser, buffer.release()));
1029         return;
1030     }
1031
1032     DecodedDataDocumentParser::appendBytes(data, length);
1033 }
1034
1035 void HTMLDocumentParser::flush()
1036 {
1037     // If we've got no decoder, we never received any data.
1038     if (isDetached() || needsDecoder())
1039         return;
1040
1041     if (m_haveBackgroundParser)
1042         HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::flush, m_backgroundParser));
1043     else
1044         DecodedDataDocumentParser::flush();
1045 }
1046
1047 void HTMLDocumentParser::setDecoder(PassOwnPtr<TextResourceDecoder> decoder)
1048 {
1049     ASSERT(decoder);
1050     DecodedDataDocumentParser::setDecoder(decoder);
1051
1052     if (m_haveBackgroundParser)
1053         HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, takeDecoder()));
1054 }
1055
1056 }