1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=2 et tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsHtml5Parser.h"
9 #include "mozilla/AutoRestore.h"
11 #include "nsContentUtils.h" // for kLoadAsData
12 #include "nsHtml5AtomTable.h"
13 #include "nsHtml5DependentUTF16Buffer.h"
14 #include "nsHtml5Tokenizer.h"
15 #include "nsHtml5TreeBuilder.h"
16 #include "nsNetUtil.h"
18 NS_INTERFACE_TABLE_HEAD(nsHtml5Parser
)
19 NS_INTERFACE_TABLE(nsHtml5Parser
, nsIParser
, nsISupportsWeakReference
)
20 NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsHtml5Parser
)
23 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHtml5Parser
)
24 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHtml5Parser
)
26 NS_IMPL_CYCLE_COLLECTION_CLASS(nsHtml5Parser
)
28 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsHtml5Parser
)
29 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExecutor
)
30 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(GetStreamParser())
31 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
33 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsHtml5Parser
)
34 NS_IMPL_CYCLE_COLLECTION_UNLINK(mExecutor
)
35 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
36 tmp
->DropStreamParser();
37 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
39 nsHtml5Parser::nsHtml5Parser()
41 mDocWriteSpeculativeLastWasCR(false),
43 mDocWriteSpeculatorActive(false),
44 mScriptNestingLevel(0),
45 mDocumentClosed(false),
46 mInDocumentWrite(false),
47 mInsertionPointPermanentlyUndefined(false),
48 mFirstBuffer(new nsHtml5OwningUTF16Buffer((void*)nullptr)),
49 mLastBuffer(mFirstBuffer
),
50 mExecutor(new nsHtml5TreeOpExecutor()),
51 mTreeBuilder(new nsHtml5TreeBuilder(mExecutor
, nullptr)),
52 mTokenizer(new nsHtml5Tokenizer(mTreeBuilder
.get(), false)),
53 mRootContextLineNumber(1),
54 mReturnToStreamParserPermitted(false) {
55 mTokenizer
->setInterner(&mAtomTable
);
58 nsHtml5Parser::~nsHtml5Parser() {
60 if (mDocWriteSpeculativeTokenizer
) {
61 mDocWriteSpeculativeTokenizer
->end();
66 nsHtml5Parser::SetContentSink(nsIContentSink
* aSink
) {
67 NS_ASSERTION(aSink
== static_cast<nsIContentSink
*>(mExecutor
),
68 "Attempt to set a foreign sink.");
71 NS_IMETHODIMP_(nsIContentSink
*)
72 nsHtml5Parser::GetContentSink() {
73 return static_cast<nsIContentSink
*>(mExecutor
);
77 nsHtml5Parser::GetCommand(nsCString
& aCommand
) {
78 aCommand
.AssignLiteral("view");
82 nsHtml5Parser::SetCommand(const char* aCommand
) {
83 NS_ASSERTION(!strcmp(aCommand
, "view") || !strcmp(aCommand
, "view-source") ||
84 !strcmp(aCommand
, "external-resource") ||
85 !strcmp(aCommand
, "import") ||
86 !strcmp(aCommand
, kLoadAsData
),
87 "Unsupported parser command");
91 nsHtml5Parser::SetCommand(eParserCommands aParserCommand
) {
92 NS_ASSERTION(aParserCommand
== eViewNormal
,
93 "Parser command was not eViewNormal.");
96 void nsHtml5Parser::SetDocumentCharset(NotNull
<const Encoding
*> aEncoding
,
97 int32_t aCharsetSource
,
98 bool aForceAutoDetection
) {
99 MOZ_ASSERT(!mExecutor
->HasStarted(), "Document charset set too late.");
100 MOZ_ASSERT(GetStreamParser(), "Setting charset on a script-only parser.");
101 GetStreamParser()->SetDocumentCharset(aEncoding
, aCharsetSource
,
102 aForceAutoDetection
);
103 mExecutor
->SetDocumentCharsetAndSource(aEncoding
, aCharsetSource
);
107 nsHtml5Parser::GetChannel(nsIChannel
** aChannel
) {
108 if (GetStreamParser()) {
109 return GetStreamParser()->GetChannel(aChannel
);
111 return NS_ERROR_NOT_AVAILABLE
;
116 nsHtml5Parser::GetDTD(nsIDTD
** aDTD
) {
121 nsIStreamListener
* nsHtml5Parser::GetStreamListener() {
122 return mStreamListener
;
126 nsHtml5Parser::ContinueInterruptedParsing() {
127 MOZ_ASSERT_UNREACHABLE("Don't call. For interface compat only.");
128 return NS_ERROR_NOT_IMPLEMENTED
;
132 nsHtml5Parser::BlockParser() { mBlocked
++; }
135 nsHtml5Parser::UnblockParser() {
136 MOZ_DIAGNOSTIC_ASSERT(mBlocked
> 0);
137 if (MOZ_LIKELY(mBlocked
> 0)) {
140 if (MOZ_LIKELY(mBlocked
== 0) && mExecutor
) {
141 mExecutor
->ContinueInterruptedParsingAsync();
146 nsHtml5Parser::ContinueInterruptedParsingAsync() {
148 mExecutor
->ContinueInterruptedParsingAsync();
153 nsHtml5Parser::IsParserEnabled() { return !mBlocked
; }
156 nsHtml5Parser::IsComplete() { return mExecutor
->IsComplete(); }
159 nsHtml5Parser::Parse(nsIURI
* aURL
, void* /* legacy; ignored */) {
161 * Do NOT cause WillBuildModel to be called synchronously from here!
162 * The document won't be ready for it until OnStartRequest!
164 MOZ_ASSERT(!mExecutor
->HasStarted(),
165 "Tried to start parse without initializing the parser.");
166 MOZ_ASSERT(GetStreamParser(),
167 "Can't call this Parse() variant on script-created parser");
169 GetStreamParser()->SetViewSourceTitle(aURL
); // In case we're viewing source
170 mExecutor
->SetStreamParser(GetStreamParser());
171 mExecutor
->SetParser(this);
175 nsresult
nsHtml5Parser::Parse(const nsAString
& aSourceBuffer
, void* aKey
,
178 if (NS_FAILED(rv
= mExecutor
->IsBroken())) {
181 if (aSourceBuffer
.Length() > INT32_MAX
) {
182 return mExecutor
->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY
);
185 // Maintain a reference to ourselves so we don't go away
186 // till we're completely done. The old parser grips itself in this method.
187 nsCOMPtr
<nsIParser
> kungFuDeathGrip(this);
189 // Gripping the other objects just in case, since the other old grip
190 // required grips to these, too.
191 RefPtr
<nsHtml5StreamParser
> streamKungFuDeathGrip(GetStreamParser());
192 mozilla::Unused
<< streamKungFuDeathGrip
; // Not used within function
193 RefPtr
<nsHtml5TreeOpExecutor
> executor(mExecutor
);
195 MOZ_RELEASE_ASSERT(executor
->HasStarted());
197 // Return early if the parser has processed EOF
198 if (executor
->IsComplete()) {
202 if (aLastCall
&& aSourceBuffer
.IsEmpty() && !aKey
) {
204 NS_ASSERTION(!GetStreamParser(),
205 "Had stream parser but got document.close().");
206 if (mDocumentClosed
) {
210 mDocumentClosed
= true;
211 if (!mBlocked
&& !mInDocumentWrite
) {
212 return ParseUntilBlocked();
217 // If we got this far, we are dealing with a document.write or
218 // document.writeln call--not document.close().
221 IsInsertionPointDefined(),
222 "Doc.write reached parser with undefined insertion point.");
224 MOZ_RELEASE_ASSERT(!(GetStreamParser() && !aKey
),
225 "Got a null key in a non-script-created parser");
227 // XXX is this optimization bogus?
228 if (aSourceBuffer
.IsEmpty()) {
232 // This guard is here to prevent document.close from tokenizing synchronously
233 // while a document.write (that wrote the script that called document.close!)
234 // is still on the call stack.
235 mozilla::AutoRestore
<bool> guard(mInDocumentWrite
);
236 mInDocumentWrite
= true;
238 // The script is identified by aKey. If there's nothing in the buffer
239 // chain for that key, we'll insert at the head of the queue.
240 // When the script leaves something in the queue, a zero-length
241 // key-holder "buffer" is inserted in the queue. If the same script
242 // leaves something in the chain again, it will be inserted immediately
243 // before the old key holder belonging to the same script.
245 // We don't do the actual data insertion yet in the hope that the data gets
246 // tokenized and there no data or less data to copy to the heap after
247 // tokenization. Also, this way, we avoid inserting one empty data buffer
248 // per document.write, which matters for performance when the parser isn't
249 // blocked and a badly-authored script calls document.write() once per
250 // input character. (As seen in a benchmark!)
252 // The insertion into the input stream happens conceptually before anything
253 // gets tokenized. To make sure multi-level document.write works right,
254 // it's necessary to establish the location of our parser key up front
255 // in case this is the first write with this key.
257 // In a document.open() case, the first write level has a null key, so that
258 // case is handled separately, because normal buffers containing data
261 // These don't need to be owning references, because they always point to
262 // the buffer queue and buffers can't be removed from the buffer queue
263 // before document.write() returns. The buffer queue clean-up happens the
264 // next time ParseUntilBlocked() is called.
265 // However, they are made owning just in case the reasoning above is flawed
266 // and a flaw would lead to worse problems with plain pointers. If this
267 // turns out to be a perf problem, it's worthwhile to consider making
268 // prevSearchbuf a plain pointer again.
269 RefPtr
<nsHtml5OwningUTF16Buffer
> prevSearchBuf
;
270 RefPtr
<nsHtml5OwningUTF16Buffer
> firstLevelMarker
;
273 if (mFirstBuffer
== mLastBuffer
) {
274 nsHtml5OwningUTF16Buffer
* keyHolder
= new nsHtml5OwningUTF16Buffer(aKey
);
275 keyHolder
->next
= mLastBuffer
;
276 mFirstBuffer
= keyHolder
;
277 } else if (mFirstBuffer
->key
!= aKey
) {
278 prevSearchBuf
= mFirstBuffer
;
280 if (prevSearchBuf
->next
== mLastBuffer
) {
282 nsHtml5OwningUTF16Buffer
* keyHolder
=
283 new nsHtml5OwningUTF16Buffer(aKey
);
284 keyHolder
->next
= mFirstBuffer
;
285 mFirstBuffer
= keyHolder
;
286 prevSearchBuf
= nullptr;
289 if (prevSearchBuf
->next
->key
== aKey
) {
290 // found a key holder
293 prevSearchBuf
= prevSearchBuf
->next
;
295 } // else mFirstBuffer is the keyholder
297 // prevSearchBuf is the previous buffer before the keyholder or null if
300 // We have a first-level write in the document.open() case. We insert before
301 // mLastBuffer, effectively, by making mLastBuffer be a new sentinel object
302 // and redesignating the previous mLastBuffer as our firstLevelMarker. We
303 // need to put a marker there, because otherwise additional document.writes
304 // from nested event loops would insert in the wrong place. Sigh.
305 mLastBuffer
->next
= new nsHtml5OwningUTF16Buffer((void*)nullptr);
306 firstLevelMarker
= mLastBuffer
;
307 mLastBuffer
= mLastBuffer
->next
;
310 nsHtml5DependentUTF16Buffer
stackBuffer(aSourceBuffer
);
312 while (!mBlocked
&& stackBuffer
.hasMore()) {
313 stackBuffer
.adjust(mLastWasCR
);
315 if (stackBuffer
.hasMore()) {
316 int32_t lineNumberSave
;
317 bool inRootContext
= (!GetStreamParser() && !aKey
);
319 mTokenizer
->setLineNumber(mRootContextLineNumber
);
321 // we aren't the root context, so save the line number on the
322 // *stack* so that we can restore it.
323 lineNumberSave
= mTokenizer
->getLineNumber();
326 if (!mTokenizer
->EnsureBufferSpace(stackBuffer
.getLength())) {
327 return executor
->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY
);
329 mLastWasCR
= mTokenizer
->tokenizeBuffer(&stackBuffer
);
330 if (NS_FAILED((rv
= mTreeBuilder
->IsBroken()))) {
331 return executor
->MarkAsBroken(rv
);
335 mRootContextLineNumber
= mTokenizer
->getLineNumber();
337 mTokenizer
->setLineNumber(lineNumberSave
);
340 if (mTreeBuilder
->HasScript()) {
341 mTreeBuilder
->Flush(); // Move ops to the executor
342 rv
= executor
->FlushDocumentWrite(); // run the ops
343 NS_ENSURE_SUCCESS(rv
, rv
);
344 // Flushing tree ops can cause all sorts of things.
345 // Return early if the parser got terminated.
346 if (executor
->IsComplete()) {
350 // Ignore suspension requests
354 RefPtr
<nsHtml5OwningUTF16Buffer
> heapBuffer
;
355 if (stackBuffer
.hasMore()) {
356 // The buffer wasn't tokenized to completion. Create a copy of the tail
358 heapBuffer
= stackBuffer
.FalliblyCopyAsOwningBuffer();
360 // Allocation failed. The parser is now broken.
361 return executor
->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY
);
366 // We have something to insert before the keyholder holding in the non-null
367 // aKey case and we have something to swap into firstLevelMarker in the
370 NS_ASSERTION(mFirstBuffer
!= mLastBuffer
, "Where's the keyholder?");
371 // the key holder is still somewhere further down the list from
372 // prevSearchBuf (which may be null)
373 if (mFirstBuffer
->key
== aKey
) {
376 "Non-null prevSearchBuf when mFirstBuffer is the key holder?");
377 heapBuffer
->next
= mFirstBuffer
;
378 mFirstBuffer
= heapBuffer
;
380 if (!prevSearchBuf
) {
381 prevSearchBuf
= mFirstBuffer
;
383 // We created a key holder earlier, so we will find it without walking
384 // past the end of the list.
385 while (prevSearchBuf
->next
->key
!= aKey
) {
386 prevSearchBuf
= prevSearchBuf
->next
;
388 heapBuffer
->next
= prevSearchBuf
->next
;
389 prevSearchBuf
->next
= heapBuffer
;
392 NS_ASSERTION(firstLevelMarker
, "How come we don't have a marker.");
393 firstLevelMarker
->Swap(heapBuffer
);
397 if (!mBlocked
) { // buffer was tokenized to completion
398 NS_ASSERTION(!stackBuffer
.hasMore(),
399 "Buffer wasn't tokenized to completion?");
400 // Scripting semantics require a forced tree builder flush here
401 mTreeBuilder
->Flush(); // Move ops to the executor
402 rv
= executor
->FlushDocumentWrite(); // run the ops
403 NS_ENSURE_SUCCESS(rv
, rv
);
404 } else if (stackBuffer
.hasMore()) {
405 // The buffer wasn't tokenized to completion. Tokenize the untokenized
406 // content in order to preload stuff. This content will be retokenized
407 // later for normal parsing.
408 if (!mDocWriteSpeculatorActive
) {
409 mDocWriteSpeculatorActive
= true;
410 if (!mDocWriteSpeculativeTreeBuilder
) {
411 // Lazily initialize if uninitialized
412 mDocWriteSpeculativeTreeBuilder
=
413 MakeUnique
<nsHtml5TreeBuilder
>(nullptr, executor
->GetStage());
414 mDocWriteSpeculativeTreeBuilder
->setScriptingEnabled(
415 mTreeBuilder
->isScriptingEnabled());
416 mDocWriteSpeculativeTokenizer
= MakeUnique
<nsHtml5Tokenizer
>(
417 mDocWriteSpeculativeTreeBuilder
.get(), false);
418 mDocWriteSpeculativeTokenizer
->setInterner(&mAtomTable
);
419 mDocWriteSpeculativeTokenizer
->start();
421 mDocWriteSpeculativeTokenizer
->resetToDataState();
422 mDocWriteSpeculativeTreeBuilder
->loadState(mTreeBuilder
.get());
423 mDocWriteSpeculativeLastWasCR
= false;
426 // Note that with multilevel document.write if we didn't just activate the
427 // speculator, it's possible that the speculator is now in the wrong state.
428 // That's OK for the sake of simplicity. The worst that can happen is
429 // that the speculative loads aren't exactly right. The content will be
430 // reparsed anyway for non-preload purposes.
432 // The buffer position for subsequent non-speculative parsing now lives
433 // in heapBuffer, so it's ok to let the buffer position of stackBuffer
434 // to be overwritten and not restored below.
435 while (stackBuffer
.hasMore()) {
436 stackBuffer
.adjust(mDocWriteSpeculativeLastWasCR
);
437 if (stackBuffer
.hasMore()) {
438 if (!mDocWriteSpeculativeTokenizer
->EnsureBufferSpace(
439 stackBuffer
.getLength())) {
440 return executor
->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY
);
442 mDocWriteSpeculativeLastWasCR
=
443 mDocWriteSpeculativeTokenizer
->tokenizeBuffer(&stackBuffer
);
445 if (NS_FAILED((rv
= mDocWriteSpeculativeTreeBuilder
->IsBroken()))) {
446 return executor
->MarkAsBroken(rv
);
451 mDocWriteSpeculativeTreeBuilder
->Flush();
452 mDocWriteSpeculativeTreeBuilder
->DropHandles();
453 executor
->FlushSpeculativeLoads();
460 nsHtml5Parser::Terminate() {
461 // Prevent a second call to DidBuildModel via document.close()
462 mDocumentClosed
= true;
463 // We should only call DidBuildModel once, so don't do anything if this is
464 // the second time that Terminate has been called.
465 if (mExecutor
->IsComplete()) {
468 // XXX - [ until we figure out a way to break parser-sink circularity ]
469 // Hack - Hold a reference until we are completely done...
470 nsCOMPtr
<nsIParser
> kungFuDeathGrip(this);
471 RefPtr
<nsHtml5StreamParser
> streamParser(GetStreamParser());
472 RefPtr
<nsHtml5TreeOpExecutor
> executor(mExecutor
);
474 streamParser
->Terminate();
476 return executor
->DidBuildModel(true);
480 nsHtml5Parser::ParseFragment(const nsAString
& aSourceBuffer
,
481 nsTArray
<nsString
>& aTagStack
) {
482 return NS_ERROR_NOT_IMPLEMENTED
;
486 nsHtml5Parser::BuildModel() {
487 MOZ_ASSERT_UNREACHABLE("Don't call this!");
488 return NS_ERROR_NOT_IMPLEMENTED
;
492 nsHtml5Parser::CancelParsingEvents() {
493 MOZ_ASSERT_UNREACHABLE("Don't call this!");
494 return NS_ERROR_NOT_IMPLEMENTED
;
497 void nsHtml5Parser::Reset() { MOZ_ASSERT_UNREACHABLE("Don't call this!"); }
499 bool nsHtml5Parser::IsInsertionPointDefined() {
500 return !mExecutor
->IsFlushing() && !mInsertionPointPermanentlyUndefined
&&
501 (!GetStreamParser() || mScriptNestingLevel
!= 0);
504 void nsHtml5Parser::IncrementScriptNestingLevel() { ++mScriptNestingLevel
; }
506 void nsHtml5Parser::DecrementScriptNestingLevel() { --mScriptNestingLevel
; }
508 bool nsHtml5Parser::HasNonzeroScriptNestingLevel() const {
509 return mScriptNestingLevel
!= 0;
512 void nsHtml5Parser::MarkAsNotScriptCreated(const char* aCommand
) {
513 MOZ_ASSERT(!mStreamListener
, "Must not call this twice.");
514 eParserMode mode
= NORMAL
;
515 if (!nsCRT::strcmp(aCommand
, "view-source")) {
516 mode
= VIEW_SOURCE_HTML
;
517 } else if (!nsCRT::strcmp(aCommand
, "view-source-xml")) {
518 mode
= VIEW_SOURCE_XML
;
519 } else if (!nsCRT::strcmp(aCommand
, "view-source-plain")) {
520 mode
= VIEW_SOURCE_PLAIN
;
521 } else if (!nsCRT::strcmp(aCommand
, "plain-text")) {
523 } else if (!nsCRT::strcmp(aCommand
, kLoadAsData
)) {
528 NS_ASSERTION(!nsCRT::strcmp(aCommand
, "view") ||
529 !nsCRT::strcmp(aCommand
, "external-resource") ||
530 !nsCRT::strcmp(aCommand
, "import"),
531 "Unsupported parser command!");
535 new nsHtml5StreamListener(new nsHtml5StreamParser(mExecutor
, this, mode
));
538 bool nsHtml5Parser::IsScriptCreated() { return !GetStreamParser(); }
542 // not from interface
543 nsresult
nsHtml5Parser::ParseUntilBlocked() {
544 nsresult rv
= mExecutor
->IsBroken();
545 NS_ENSURE_SUCCESS(rv
, rv
);
546 if (mBlocked
|| mInsertionPointPermanentlyUndefined
||
547 mExecutor
->IsComplete()) {
550 NS_ASSERTION(mExecutor
->HasStarted(), "Bad life cycle.");
551 NS_ASSERTION(!mInDocumentWrite
,
552 "ParseUntilBlocked entered while in doc.write!");
554 mDocWriteSpeculatorActive
= false;
557 if (!mFirstBuffer
->hasMore()) {
558 if (mFirstBuffer
== mLastBuffer
) {
559 if (mExecutor
->IsComplete()) {
560 // something like cache manisfests stopped the parse in mid-flight
563 if (mDocumentClosed
) {
564 PermanentlyUndefineInsertionPoint();
568 "This should only happen with script-created parser.");
569 if (NS_SUCCEEDED((rv
= mExecutor
->IsBroken()))) {
571 if (NS_FAILED((rv
= mTreeBuilder
->IsBroken()))) {
572 mExecutor
->MarkAsBroken(rv
);
574 mTreeBuilder
->StreamEnded();
577 mTreeBuilder
->Flush();
578 mExecutor
->FlushDocumentWrite();
579 // The below call does memory cleanup, so call it even if the
580 // parser has been marked as broken.
584 // never release the last buffer.
585 NS_ASSERTION(!mLastBuffer
->getStart() && !mLastBuffer
->getEnd(),
586 "Sentinel buffer had its indeces changed.");
587 if (GetStreamParser()) {
588 if (mReturnToStreamParserPermitted
&&
589 !mExecutor
->IsScriptExecuting()) {
590 mTreeBuilder
->Flush();
591 mReturnToStreamParserPermitted
= false;
592 GetStreamParser()->ContinueAfterScripts(
593 mTokenizer
.get(), mTreeBuilder
.get(), mLastWasCR
);
596 // Script-created parser
597 mTreeBuilder
->Flush();
598 // No need to flush the executor, because the executor is already
600 NS_ASSERTION(mExecutor
->IsInFlushLoop(),
601 "How did we come here without being in the flush loop?");
603 return NS_OK
; // no more data for now but expecting more
605 mFirstBuffer
= mFirstBuffer
->next
;
609 if (mBlocked
|| mExecutor
->IsComplete()) {
613 // now we have a non-empty buffer
614 mFirstBuffer
->adjust(mLastWasCR
);
616 if (mFirstBuffer
->hasMore()) {
617 bool inRootContext
= (!GetStreamParser() && !mFirstBuffer
->key
);
619 mTokenizer
->setLineNumber(mRootContextLineNumber
);
621 if (!mTokenizer
->EnsureBufferSpace(mFirstBuffer
->getLength())) {
622 return mExecutor
->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY
);
624 mLastWasCR
= mTokenizer
->tokenizeBuffer(mFirstBuffer
);
626 if (NS_FAILED((rv
= mTreeBuilder
->IsBroken()))) {
627 return mExecutor
->MarkAsBroken(rv
);
630 mRootContextLineNumber
= mTokenizer
->getLineNumber();
632 if (mTreeBuilder
->HasScript()) {
633 mTreeBuilder
->Flush();
634 rv
= mExecutor
->FlushDocumentWrite();
635 NS_ENSURE_SUCCESS(rv
, rv
);
644 nsresult
nsHtml5Parser::StartExecutor() {
645 MOZ_ASSERT(!GetStreamParser(),
646 "Had stream parser but document.write started life cycle.");
647 // This is part of the setup document.open() does.
648 RefPtr
<nsHtml5TreeOpExecutor
> executor(mExecutor
);
649 executor
->SetParser(this);
650 mTreeBuilder
->setScriptingEnabled(executor
->IsScriptEnabled());
652 mTreeBuilder
->setIsSrcdocDocument(false);
658 * We know we're in document.open(), so our document must already
659 * have a script global andthe WillBuildModel call is safe.
661 return executor
->WillBuildModel(eDTDMode_unknown
);
664 nsresult
nsHtml5Parser::Initialize(mozilla::dom::Document
* aDoc
, nsIURI
* aURI
,
665 nsISupports
* aContainer
,
666 nsIChannel
* aChannel
) {
667 return mExecutor
->Init(aDoc
, aURI
, aContainer
, aChannel
);
670 void nsHtml5Parser::StartTokenizer(bool aScriptingEnabled
) {
671 bool isSrcdoc
= false;
672 nsCOMPtr
<nsIChannel
> channel
;
673 nsresult rv
= GetChannel(getter_AddRefs(channel
));
674 if (NS_SUCCEEDED(rv
)) {
675 isSrcdoc
= NS_IsSrcdocChannel(channel
);
677 mTreeBuilder
->setIsSrcdocDocument(isSrcdoc
);
679 mTreeBuilder
->SetPreventScriptExecution(!aScriptingEnabled
);
680 mTreeBuilder
->setScriptingEnabled(aScriptingEnabled
);
684 void nsHtml5Parser::InitializeDocWriteParserState(
685 nsAHtml5TreeBuilderState
* aState
, int32_t aLine
) {
686 mTokenizer
->resetToDataState();
687 mTokenizer
->setLineNumber(aLine
);
688 mTreeBuilder
->loadState(aState
);
690 mReturnToStreamParserPermitted
= true;
693 void nsHtml5Parser::ContinueAfterFailedCharsetSwitch() {
696 "Tried to continue after failed charset switch without a stream parser");
697 GetStreamParser()->ContinueAfterFailedCharsetSwitch();