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