1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 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/. */
8 * This file is near-OBSOLETE. It is used for about:blank only and for the
9 * HTML element factory.
10 * Don't bother adding new stuff in this file.
13 #include "mozilla/ArrayUtils.h"
15 #include "nsContentSink.h"
17 #include "nsHTMLTags.h"
18 #include "nsReadableUtils.h"
19 #include "nsUnicharUtils.h"
20 #include "nsIHTMLContentSink.h"
21 #include "nsIInterfaceRequestor.h"
22 #include "nsIInterfaceRequestorUtils.h"
24 #include "mozilla/dom/NodeInfo.h"
25 #include "mozilla/dom/ScriptLoader.h"
28 #include "mozilla/Logging.h"
29 #include "nsIContent.h"
30 #include "mozilla/dom/CustomElementRegistry.h"
31 #include "mozilla/dom/Element.h"
32 #include "mozilla/dom/MutationObservers.h"
33 #include "mozilla/Preferences.h"
35 #include "nsGenericHTMLElement.h"
37 #include "nsIScriptElement.h"
39 #include "nsDocElementCreatedNotificationRunner.h"
40 #include "nsGkAtoms.h"
41 #include "nsContentUtils.h"
42 #include "nsIChannel.h"
43 #include "mozilla/dom/Document.h"
44 #include "nsStubDocumentObserver.h"
45 #include "nsHTMLDocument.h"
47 #include "nsTextFragment.h"
48 #include "nsIScriptGlobalObject.h"
49 #include "nsNameSpaceManager.h"
52 #include "nsContentPolicyUtils.h"
53 #include "nsIDocShell.h"
54 #include "nsIScriptContext.h"
57 #include "nsNodeInfoManager.h"
58 #include "nsContentCreatorFunctions.h"
59 #include "mozAutoDocUpdate.h"
60 #include "nsTextNode.h"
62 using namespace mozilla
;
63 using namespace mozilla::dom
;
65 //----------------------------------------------------------------------
67 nsGenericHTMLElement
* NS_NewHTMLNOTUSEDElement(
68 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
,
69 FromParser aFromParser
) {
70 MOZ_ASSERT_UNREACHABLE("The element ctor should never be called");
74 #define HTML_TAG(_tag, _classname, _interfacename) \
75 NS_NewHTML##_classname##Element,
76 #define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement,
77 static const HTMLContentCreatorFunction sHTMLContentCreatorFunctions
[] = {
78 NS_NewHTMLUnknownElement
,
79 #include "nsHTMLTagList.h"
82 NS_NewHTMLUnknownElement
};
85 class HTMLContentSink
;
88 * This class is near-OBSOLETE. It is used for about:blank only.
89 * Don't bother adding new stuff in this file.
91 class HTMLContentSink
: public nsContentSink
, public nsIHTMLContentSink
{
93 friend class SinkContext
;
97 nsresult
Init(Document
* aDoc
, nsIURI
* aURI
, nsISupports
* aContainer
,
98 nsIChannel
* aChannel
);
101 NS_DECL_ISUPPORTS_INHERITED
102 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLContentSink
, nsContentSink
)
105 NS_IMETHOD
WillParse(void) override
;
106 NS_IMETHOD
WillBuildModel(nsDTDMode aDTDMode
) override
;
107 NS_IMETHOD
DidBuildModel(bool aTerminated
) override
;
108 NS_IMETHOD
WillInterrupt(void) override
;
109 void WillResume() override
;
110 NS_IMETHOD
SetParser(nsParserBase
* aParser
) override
;
111 virtual void FlushPendingNotifications(FlushType aType
) override
;
112 virtual void SetDocumentCharset(NotNull
<const Encoding
*> aEncoding
) override
;
113 virtual nsISupports
* GetTarget() override
;
114 virtual bool IsScriptExecuting() override
;
115 virtual bool WaitForPendingSheets() override
;
116 virtual void ContinueInterruptedParsingAsync() override
;
118 // nsIHTMLContentSink
119 NS_IMETHOD
OpenContainer(ElementType aNodeType
) override
;
120 NS_IMETHOD
CloseContainer(ElementType aTag
) override
;
123 virtual ~HTMLContentSink();
125 RefPtr
<nsHTMLDocument
> mHTMLDocument
;
127 // The maximum length of a text run
130 RefPtr
<nsGenericHTMLElement
> mRoot
;
131 RefPtr
<nsGenericHTMLElement
> mBody
;
132 RefPtr
<nsGenericHTMLElement
> mHead
;
134 AutoTArray
<SinkContext
*, 8> mContextStack
;
135 SinkContext
* mCurrentContext
;
136 SinkContext
* mHeadContext
;
138 // Boolean indicating whether we've seen a <head> tag that might have had
139 // attributes once already.
142 // Boolean indicating whether we've notified insertion of our root content
143 // yet. We want to make sure to only do this once.
144 bool mNotifiedRootInsertion
;
146 nsresult
FlushTags() override
;
148 // Routines for tags that require special handling
149 nsresult
CloseHTML();
151 nsresult
CloseBody();
153 void CloseHeadContext();
155 // nsContentSink overrides
156 void UpdateChildCounts() override
;
158 void NotifyInsert(nsIContent
* aContent
, nsIContent
* aChildContent
);
159 void NotifyRootInsertion();
162 void ContinueInterruptedParsingIfEnabled();
167 explicit SinkContext(HTMLContentSink
* aSink
);
170 nsresult
Begin(nsHTMLTag aNodeType
, nsGenericHTMLElement
* aRoot
,
171 uint32_t aNumFlushed
, int32_t aInsertionPoint
);
173 nsresult
CloseBody();
176 nsresult
GrowStack();
177 nsresult
FlushTags();
179 bool IsCurrentContainer(nsHTMLTag aTag
) const;
181 void DidAddContent(nsIContent
* aContent
);
182 void UpdateChildCounts();
185 // Function to check whether we've notified for the current content.
186 // What this actually does is check whether we've notified for all
187 // of the parent's kids.
188 bool HaveNotifiedForCurrentContent() const;
191 HTMLContentSink
* mSink
;
192 int32_t mNotifyLevel
;
196 nsGenericHTMLElement
* mContent
;
197 uint32_t mNumFlushed
;
198 int32_t mInsertionPoint
;
200 nsIContent
* Add(nsIContent
* child
);
208 nsresult
NS_NewHTMLElement(Element
** aResult
,
209 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
,
210 FromParser aFromParser
, nsAtom
* aIsAtom
,
211 mozilla::dom::CustomElementDefinition
* aDefinition
) {
212 RefPtr
<mozilla::dom::NodeInfo
> nodeInfo
= aNodeInfo
;
215 nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
),
216 "Trying to create HTML elements that don't have the XHTML namespace");
218 return nsContentUtils::NewXULOrHTMLElement(aResult
, nodeInfo
, aFromParser
,
219 aIsAtom
, aDefinition
);
222 already_AddRefed
<nsGenericHTMLElement
> CreateHTMLElement(
223 uint32_t aNodeType
, already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
,
224 FromParser aFromParser
) {
226 aNodeType
<= NS_HTML_TAG_MAX
|| aNodeType
== eHTMLTag_userdefined
,
227 "aNodeType is out of bounds");
229 HTMLContentCreatorFunction cb
= sHTMLContentCreatorFunctions
[aNodeType
];
231 NS_ASSERTION(cb
!= NS_NewHTMLNOTUSEDElement
,
232 "Don't know how to construct tag element!");
234 RefPtr
<nsGenericHTMLElement
> result
= cb(std::move(aNodeInfo
), aFromParser
);
236 return result
.forget();
239 //----------------------------------------------------------------------
241 SinkContext::SinkContext(HTMLContentSink
* aSink
)
247 MOZ_COUNT_CTOR(SinkContext
);
250 SinkContext::~SinkContext() {
251 MOZ_COUNT_DTOR(SinkContext
);
254 for (int32_t i
= 0; i
< mStackPos
; i
++) {
255 NS_RELEASE(mStack
[i
].mContent
);
261 nsresult
SinkContext::Begin(nsHTMLTag aNodeType
, nsGenericHTMLElement
* aRoot
,
262 uint32_t aNumFlushed
, int32_t aInsertionPoint
) {
263 if (mStackSize
< 1) {
264 nsresult rv
= GrowStack();
270 mStack
[0].mType
= aNodeType
;
271 mStack
[0].mContent
= aRoot
;
272 mStack
[0].mNumFlushed
= aNumFlushed
;
273 mStack
[0].mInsertionPoint
= aInsertionPoint
;
280 bool SinkContext::IsCurrentContainer(nsHTMLTag aTag
) const {
281 return aTag
== mStack
[mStackPos
- 1].mType
;
284 void SinkContext::DidAddContent(nsIContent
* aContent
) {
285 if ((mStackPos
== 2) && (mSink
->mBody
== mStack
[1].mContent
)) {
286 // We just finished adding something to the body
290 // If we just added content to a node for which
291 // an insertion happen, we need to do an immediate
292 // notification for that insertion.
293 if (0 < mStackPos
&& mStack
[mStackPos
- 1].mInsertionPoint
!= -1 &&
294 mStack
[mStackPos
- 1].mNumFlushed
<
295 mStack
[mStackPos
- 1].mContent
->GetChildCount()) {
296 nsIContent
* parent
= mStack
[mStackPos
- 1].mContent
;
297 mSink
->NotifyInsert(parent
, aContent
);
298 mStack
[mStackPos
- 1].mNumFlushed
= parent
->GetChildCount();
299 } else if (mSink
->IsTimeToNotify()) {
304 nsresult
SinkContext::OpenBody() {
305 if (mStackPos
<= 0) {
306 NS_ERROR("container w/o parent");
308 return NS_ERROR_FAILURE
;
312 if (mStackPos
+ 1 > mStackSize
) {
319 RefPtr
<mozilla::dom::NodeInfo
> nodeInfo
=
320 mSink
->mNodeInfoManager
->GetNodeInfo(
321 nsGkAtoms::body
, nullptr, kNameSpaceID_XHTML
, nsINode::ELEMENT_NODE
);
322 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_UNEXPECTED
);
324 // Make the content object
325 RefPtr
<nsGenericHTMLElement
> body
=
326 NS_NewHTMLBodyElement(nodeInfo
.forget(), FROM_PARSER_NETWORK
);
328 return NS_ERROR_OUT_OF_MEMORY
;
331 mStack
[mStackPos
].mType
= eHTMLTag_body
;
332 body
.forget(&mStack
[mStackPos
].mContent
);
333 mStack
[mStackPos
].mNumFlushed
= 0;
334 mStack
[mStackPos
].mInsertionPoint
= -1;
336 mStack
[mStackPos
- 2].Add(mStack
[mStackPos
- 1].mContent
);
341 bool SinkContext::HaveNotifiedForCurrentContent() const {
343 nsIContent
* parent
= mStack
[mStackPos
- 1].mContent
;
344 return mStack
[mStackPos
- 1].mNumFlushed
== parent
->GetChildCount();
350 nsIContent
* SinkContext::Node::Add(nsIContent
* child
) {
351 NS_ASSERTION(mContent
, "No parent to insert/append into!");
352 if (mInsertionPoint
!= -1) {
353 NS_ASSERTION(mNumFlushed
== mContent
->GetChildCount(),
354 "Inserting multiple children without flushing.");
355 nsCOMPtr
<nsIContent
> nodeToInsertBefore
=
356 mContent
->GetChildAt_Deprecated(mInsertionPoint
++);
357 mContent
->InsertChildBefore(child
, nodeToInsertBefore
, false,
360 mContent
->AppendChildTo(child
, false, IgnoreErrors());
365 nsresult
SinkContext::CloseBody() {
366 NS_ASSERTION(mStackPos
> 0, "stack out of bounds. wrong context probably!");
368 if (mStackPos
<= 0) {
369 return NS_OK
; // Fix crash - Ref. bug 45975 or 45007
373 NS_ASSERTION(mStack
[mStackPos
].mType
== eHTMLTag_body
,
374 "Tag mismatch. Closing tag on wrong context or something?");
376 nsGenericHTMLElement
* content
= mStack
[mStackPos
].mContent
;
380 // If we're in a state where we do append notifications as
381 // we go up the tree, and we're at the level where the next
382 // notification needs to be done, do the notification.
383 if (mNotifyLevel
>= mStackPos
) {
384 // Check to see if new content has been added after our last
387 if (mStack
[mStackPos
].mNumFlushed
< content
->GetChildCount()) {
388 mSink
->NotifyAppend(content
, mStack
[mStackPos
].mNumFlushed
);
389 mStack
[mStackPos
].mNumFlushed
= content
->GetChildCount();
392 // Indicate that notification has now happened at this level
393 mNotifyLevel
= mStackPos
- 1;
396 DidAddContent(content
);
397 NS_IF_RELEASE(content
);
402 nsresult
SinkContext::End() {
403 for (int32_t i
= 0; i
< mStackPos
; i
++) {
404 NS_RELEASE(mStack
[i
].mContent
);
412 nsresult
SinkContext::GrowStack() {
413 int32_t newSize
= mStackSize
* 2;
418 Node
* stack
= new Node
[newSize
];
420 if (mStackPos
!= 0) {
421 memcpy(stack
, mStack
, sizeof(Node
) * mStackPos
);
426 mStackSize
= newSize
;
432 * NOTE!! Forked into nsXMLContentSink. Please keep in sync.
434 * Flush all elements that have been seen so far such that
435 * they are visible in the tree. Specifically, make sure
436 * that they are all added to their respective parents.
437 * Also, do notification at the top for all content that
438 * has been newly added so that the frame tree is complete.
440 nsresult
SinkContext::FlushTags() {
441 mSink
->mDeferredFlushTags
= false;
442 uint32_t oldUpdates
= mSink
->mUpdatesInNotification
;
444 ++(mSink
->mInNotification
);
445 mSink
->mUpdatesInNotification
= 0;
447 // Scope so we call EndUpdate before we decrease mInNotification
448 mozAutoDocUpdate
updateBatch(mSink
->mDocument
, true);
450 // Start from the base of the stack (growing downward) and do
451 // a notification from the node that is closest to the root of
452 // tree for any content that has been added.
454 // Note that we can start at stackPos == 0 here, because it's the caller's
455 // responsibility to handle flushing interactions between contexts (see
456 // HTMLContentSink::BeginContext).
457 int32_t stackPos
= 0;
458 bool flushed
= false;
460 nsGenericHTMLElement
* content
;
462 while (stackPos
< mStackPos
) {
463 content
= mStack
[stackPos
].mContent
;
464 childCount
= content
->GetChildCount();
466 if (!flushed
&& (mStack
[stackPos
].mNumFlushed
< childCount
)) {
467 if (mStack
[stackPos
].mInsertionPoint
!= -1) {
468 // We might have popped the child off our stack already
469 // but not notified on it yet, which is why we have to get it
470 // directly from its parent node.
472 int32_t childIndex
= mStack
[stackPos
].mInsertionPoint
- 1;
473 nsIContent
* child
= content
->GetChildAt_Deprecated(childIndex
);
474 // Child not on stack anymore; can't assert it's correct
475 NS_ASSERTION(!(mStackPos
> (stackPos
+ 1)) ||
476 (child
== mStack
[stackPos
+ 1].mContent
),
477 "Flushing the wrong child.");
478 mSink
->NotifyInsert(content
, child
);
480 mSink
->NotifyAppend(content
, mStack
[stackPos
].mNumFlushed
);
486 mStack
[stackPos
].mNumFlushed
= childCount
;
489 mNotifyLevel
= mStackPos
- 1;
491 --(mSink
->mInNotification
);
493 if (mSink
->mUpdatesInNotification
> 1) {
497 mSink
->mUpdatesInNotification
= oldUpdates
;
503 * NOTE!! Forked into nsXMLContentSink. Please keep in sync.
505 void SinkContext::UpdateChildCounts() {
506 // Start from the top of the stack (growing upwards) and see if any
507 // new content has been appended. If so, we recognize that reflows
508 // have been generated for it and we should make sure that no
509 // further reflows occur. Note that we have to include stackPos == 0
510 // to properly notify on kids of <html>.
511 int32_t stackPos
= mStackPos
- 1;
512 while (stackPos
>= 0) {
513 Node
& node
= mStack
[stackPos
];
514 node
.mNumFlushed
= node
.mContent
->GetChildCount();
519 mNotifyLevel
= mStackPos
- 1;
522 nsresult
NS_NewHTMLContentSink(nsIHTMLContentSink
** aResult
, Document
* aDoc
,
523 nsIURI
* aURI
, nsISupports
* aContainer
,
524 nsIChannel
* aChannel
) {
525 NS_ENSURE_ARG_POINTER(aResult
);
527 RefPtr
<HTMLContentSink
> it
= new HTMLContentSink();
529 nsresult rv
= it
->Init(aDoc
, aURI
, aContainer
, aChannel
);
531 NS_ENSURE_SUCCESS(rv
, rv
);
539 HTMLContentSink::HTMLContentSink()
541 mCurrentContext(nullptr),
542 mHeadContext(nullptr),
543 mHaveSeenHead(false),
544 mNotifiedRootInsertion(false) {}
546 HTMLContentSink::~HTMLContentSink() {
547 if (mNotificationTimer
) {
548 mNotificationTimer
->Cancel();
551 if (mCurrentContext
== mHeadContext
&& !mContextStack
.IsEmpty()) {
552 // Pop off the second html context if it's not done earlier
553 mContextStack
.RemoveLastElement();
556 for (int32_t i
= 0, numContexts
= mContextStack
.Length(); i
< numContexts
;
558 SinkContext
* sc
= mContextStack
.ElementAt(i
);
561 if (sc
== mCurrentContext
) {
562 mCurrentContext
= nullptr;
569 if (mCurrentContext
== mHeadContext
) {
570 mCurrentContext
= nullptr;
573 delete mCurrentContext
;
578 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLContentSink
, nsContentSink
,
579 mHTMLDocument
, mRoot
, mBody
, mHead
)
581 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLContentSink
, nsContentSink
,
582 nsIContentSink
, nsIHTMLContentSink
)
584 nsresult
HTMLContentSink::Init(Document
* aDoc
, nsIURI
* aURI
,
585 nsISupports
* aContainer
, nsIChannel
* aChannel
) {
586 NS_ENSURE_TRUE(aContainer
, NS_ERROR_NULL_POINTER
);
588 nsresult rv
= nsContentSink::Init(aDoc
, aURI
, aContainer
, aChannel
);
593 aDoc
->AddObserver(this);
594 mIsDocumentObserver
= true;
595 mHTMLDocument
= aDoc
->AsHTMLDocument();
597 NS_ASSERTION(mDocShell
, "oops no docshell!");
599 // Changed from 8192 to greatly improve page loading performance on
600 // large pages. See bugzilla bug 77540.
601 mMaxTextRun
= Preferences::GetInt("content.maxtextrun", 8191);
603 RefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
604 nodeInfo
= mNodeInfoManager
->GetNodeInfo(
605 nsGkAtoms::html
, nullptr, kNameSpaceID_XHTML
, nsINode::ELEMENT_NODE
);
608 mRoot
= NS_NewHTMLHtmlElement(nodeInfo
.forget());
610 return NS_ERROR_OUT_OF_MEMORY
;
613 NS_ASSERTION(mDocument
->GetChildCount() == 0,
614 "Document should have no kids here!");
616 mDocument
->AppendChildTo(mRoot
, false, error
);
617 if (error
.Failed()) {
618 return error
.StealNSResult();
622 nodeInfo
= mNodeInfoManager
->GetNodeInfo(
623 nsGkAtoms::head
, nullptr, kNameSpaceID_XHTML
, nsINode::ELEMENT_NODE
);
625 mHead
= NS_NewHTMLHeadElement(nodeInfo
.forget());
627 return NS_ERROR_OUT_OF_MEMORY
;
630 mRoot
->AppendChildTo(mHead
, false, IgnoreErrors());
632 mCurrentContext
= new SinkContext(this);
633 mCurrentContext
->Begin(eHTMLTag_html
, mRoot
, 0, -1);
634 mContextStack
.AppendElement(mCurrentContext
);
640 HTMLContentSink::WillParse(void) { return WillParseImpl(); }
643 HTMLContentSink::WillBuildModel(nsDTDMode aDTDMode
) {
644 WillBuildModelImpl();
646 mDocument
->SetCompatibilityMode(aDTDMode
== eDTDMode_full_standards
647 ? eCompatibility_FullStandards
648 : eCompatibility_NavQuirks
);
650 // Notify document that the load is beginning
651 mDocument
->BeginLoad();
657 HTMLContentSink::DidBuildModel(bool aTerminated
) {
658 DidBuildModelImpl(aTerminated
);
660 // Reflow the last batch of content
662 mCurrentContext
->FlushTags();
663 } else if (!mLayoutStarted
) {
664 // We never saw the body, and layout never got started. Force
665 // layout *now*, to get an initial reflow.
666 // NOTE: only force the layout if we are NOT destroying the
667 // docshell. If we are destroying it, then starting layout will
668 // likely cause us to crash, or at best waste a lot of time as we
669 // are just going to tear it down anyway.
670 bool bDestroying
= true;
672 mDocShell
->IsBeingDestroyed(&bDestroying
);
682 // Make sure we no longer respond to document mutations. We've flushed all
683 // our notifications out, so there's no need to do anything else here.
685 // XXXbz I wonder whether we could End() our contexts here too, or something,
686 // just to make sure we no longer notify... Or is the mIsDocumentObserver
688 mDocument
->RemoveObserver(this);
689 mIsDocumentObserver
= false;
691 mDocument
->EndLoad();
693 DropParserAndPerfHint();
699 HTMLContentSink::SetParser(nsParserBase
* aParser
) {
700 MOZ_ASSERT(aParser
, "Should have a parser here!");
705 nsresult
HTMLContentSink::CloseHTML() {
707 if (mCurrentContext
== mHeadContext
) {
708 // Pop off the second html context if it's not done earlier
709 mCurrentContext
= mContextStack
.PopLastElement();
715 mHeadContext
= nullptr;
721 nsresult
HTMLContentSink::OpenBody() {
722 CloseHeadContext(); // do this just in case if the HEAD was left open!
724 // if we already have a body we're done
729 nsresult rv
= mCurrentContext
->OpenBody();
735 mBody
= mCurrentContext
->mStack
[mCurrentContext
->mStackPos
- 1].mContent
;
737 if (mCurrentContext
->mStackPos
> 1) {
738 int32_t parentIndex
= mCurrentContext
->mStackPos
- 2;
739 nsGenericHTMLElement
* parent
=
740 mCurrentContext
->mStack
[parentIndex
].mContent
;
741 int32_t numFlushed
= mCurrentContext
->mStack
[parentIndex
].mNumFlushed
;
742 int32_t childCount
= parent
->GetChildCount();
743 NS_ASSERTION(numFlushed
< childCount
, "Already notified on the body?");
745 int32_t insertionPoint
=
746 mCurrentContext
->mStack
[parentIndex
].mInsertionPoint
;
748 // XXX: I have yet to see a case where numFlushed is non-zero and
749 // insertionPoint is not -1, but this code will try to handle
752 uint32_t oldUpdates
= mUpdatesInNotification
;
753 mUpdatesInNotification
= 0;
754 if (insertionPoint
!= -1) {
755 NotifyInsert(parent
, mBody
);
757 NotifyAppend(parent
, numFlushed
);
759 mCurrentContext
->mStack
[parentIndex
].mNumFlushed
= childCount
;
760 if (mUpdatesInNotification
> 1) {
763 mUpdatesInNotification
= oldUpdates
;
771 nsresult
HTMLContentSink::CloseBody() {
772 // Flush out anything that's left
773 mCurrentContext
->FlushTags();
774 mCurrentContext
->CloseBody();
780 HTMLContentSink::OpenContainer(ElementType aElementType
) {
783 switch (aElementType
) {
789 // If we've already hit this code once, then we're done
790 if (!mNotifiedRootInsertion
) {
791 NotifyRootInsertion();
801 HTMLContentSink::CloseContainer(const ElementType aTag
) {
817 HTMLContentSink::WillInterrupt() { return WillInterruptImpl(); }
819 void HTMLContentSink::WillResume() { WillResumeImpl(); }
821 void HTMLContentSink::CloseHeadContext() {
822 if (mCurrentContext
) {
823 if (!mCurrentContext
->IsCurrentContainer(eHTMLTag_head
)) return;
825 mCurrentContext
->FlushTags();
828 if (!mContextStack
.IsEmpty()) {
829 mCurrentContext
= mContextStack
.PopLastElement();
833 void HTMLContentSink::NotifyInsert(nsIContent
* aContent
,
834 nsIContent
* aChildContent
) {
838 // Scope so we call EndUpdate before we decrease mInNotification
839 // Note that aContent->OwnerDoc() may be different to mDocument already.
840 MOZ_AUTO_DOC_UPDATE(aContent
? aContent
->OwnerDoc() : mDocument
.get(),
842 MutationObservers::NotifyContentInserted(NODE_FROM(aContent
, mDocument
),
844 mLastNotificationTime
= PR_Now();
850 void HTMLContentSink::NotifyRootInsertion() {
851 MOZ_ASSERT(!mNotifiedRootInsertion
, "Double-notifying on root?");
852 NS_ASSERTION(!mLayoutStarted
,
853 "How did we start layout without notifying on root?");
854 // Now make sure to notify that we have now inserted our root. If
855 // there has been no initial reflow yet it'll be a no-op, but if
856 // there has been one we need this to get its frames constructed.
857 // Note that if mNotifiedRootInsertion is true we don't notify here,
858 // since that just means there are multiple <html> tags in the
859 // document; in those cases we just want to put all the attrs on one
861 mNotifiedRootInsertion
= true;
862 NotifyInsert(nullptr, mRoot
);
864 // Now update the notification information in all our
865 // contexts, since we just inserted the root and notified on
869 nsContentUtils::AddScriptRunner(
870 new nsDocElementCreatedNotificationRunner(mDocument
));
873 void HTMLContentSink::UpdateChildCounts() {
874 uint32_t numContexts
= mContextStack
.Length();
875 for (uint32_t i
= 0; i
< numContexts
; i
++) {
876 SinkContext
* sc
= mContextStack
.ElementAt(i
);
878 sc
->UpdateChildCounts();
881 mCurrentContext
->UpdateChildCounts();
884 void HTMLContentSink::FlushPendingNotifications(FlushType aType
) {
885 // Only flush tags if we're not doing the notification ourselves
886 // (since we aren't reentrant)
887 if (!mInNotification
) {
888 // Only flush if we're still a document observer (so that our child counts
889 // should be correct).
890 if (mIsDocumentObserver
) {
891 if (aType
>= FlushType::ContentAndNotify
) {
895 if (aType
>= FlushType::EnsurePresShellInitAndFrames
) {
896 // Make sure that layout has started so that the reflow flush
897 // will actually happen.
903 nsresult
HTMLContentSink::FlushTags() {
904 if (!mNotifiedRootInsertion
) {
905 NotifyRootInsertion();
909 return mCurrentContext
? mCurrentContext
->FlushTags() : NS_OK
;
912 void HTMLContentSink::SetDocumentCharset(NotNull
<const Encoding
*> aEncoding
) {
913 MOZ_ASSERT_UNREACHABLE("<meta charset> case doesn't occur with about:blank");
916 nsISupports
* HTMLContentSink::GetTarget() { return ToSupports(mDocument
); }
918 bool HTMLContentSink::IsScriptExecuting() { return IsScriptExecutingImpl(); }
920 void HTMLContentSink::ContinueInterruptedParsingIfEnabled() {
921 if (mParser
&& mParser
->IsParserEnabled()) {
922 static_cast<nsIParser
*>(mParser
.get())->ContinueInterruptedParsing();
926 bool HTMLContentSink::WaitForPendingSheets() {
927 return nsContentSink::WaitForPendingSheets();
930 void HTMLContentSink::ContinueInterruptedParsingAsync() {
931 nsCOMPtr
<nsIRunnable
> ev
= NewRunnableMethod(
932 "HTMLContentSink::ContinueInterruptedParsingIfEnabled", this,
933 &HTMLContentSink::ContinueInterruptedParsingIfEnabled
);
934 mHTMLDocument
->Dispatch(ev
.forget());