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"
56 #include "nsLayoutCID.h"
59 #include "nsNodeInfoManager.h"
60 #include "nsContentCreatorFunctions.h"
61 #include "mozAutoDocUpdate.h"
62 #include "nsTextNode.h"
64 using namespace mozilla
;
65 using namespace mozilla::dom
;
67 //----------------------------------------------------------------------
69 nsGenericHTMLElement
* NS_NewHTMLNOTUSEDElement(
70 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
,
71 FromParser aFromParser
) {
72 MOZ_ASSERT_UNREACHABLE("The element ctor should never be called");
76 #define HTML_TAG(_tag, _classname, _interfacename) \
77 NS_NewHTML##_classname##Element,
78 #define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement,
79 static const HTMLContentCreatorFunction sHTMLContentCreatorFunctions
[] = {
80 NS_NewHTMLUnknownElement
,
81 #include "nsHTMLTagList.h"
84 NS_NewHTMLUnknownElement
};
87 class HTMLContentSink
;
90 * This class is near-OBSOLETE. It is used for about:blank only.
91 * Don't bother adding new stuff in this file.
93 class HTMLContentSink
: public nsContentSink
, public nsIHTMLContentSink
{
95 friend class SinkContext
;
99 nsresult
Init(Document
* aDoc
, nsIURI
* aURI
, nsISupports
* aContainer
,
100 nsIChannel
* aChannel
);
103 NS_DECL_ISUPPORTS_INHERITED
104 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLContentSink
, nsContentSink
)
107 NS_IMETHOD
WillParse(void) override
;
108 NS_IMETHOD
WillBuildModel(nsDTDMode aDTDMode
) override
;
109 NS_IMETHOD
DidBuildModel(bool aTerminated
) override
;
110 NS_IMETHOD
WillInterrupt(void) override
;
111 void WillResume() override
;
112 NS_IMETHOD
SetParser(nsParserBase
* aParser
) override
;
113 virtual void FlushPendingNotifications(FlushType aType
) override
;
114 virtual void SetDocumentCharset(NotNull
<const Encoding
*> aEncoding
) override
;
115 virtual nsISupports
* GetTarget() override
;
116 virtual bool IsScriptExecuting() override
;
117 virtual bool WaitForPendingSheets() override
;
118 virtual void ContinueInterruptedParsingAsync() override
;
120 // nsIHTMLContentSink
121 NS_IMETHOD
OpenContainer(ElementType aNodeType
) override
;
122 NS_IMETHOD
CloseContainer(ElementType aTag
) override
;
125 virtual ~HTMLContentSink();
127 RefPtr
<nsHTMLDocument
> mHTMLDocument
;
129 // The maximum length of a text run
132 RefPtr
<nsGenericHTMLElement
> mRoot
;
133 RefPtr
<nsGenericHTMLElement
> mBody
;
134 RefPtr
<nsGenericHTMLElement
> mHead
;
136 AutoTArray
<SinkContext
*, 8> mContextStack
;
137 SinkContext
* mCurrentContext
;
138 SinkContext
* mHeadContext
;
140 // Boolean indicating whether we've seen a <head> tag that might have had
141 // attributes once already.
144 // Boolean indicating whether we've notified insertion of our root content
145 // yet. We want to make sure to only do this once.
146 bool mNotifiedRootInsertion
;
148 nsresult
FlushTags() override
;
150 // Routines for tags that require special handling
151 nsresult
CloseHTML();
153 nsresult
CloseBody();
155 void CloseHeadContext();
157 // nsContentSink overrides
158 void UpdateChildCounts() override
;
160 void NotifyInsert(nsIContent
* aContent
, nsIContent
* aChildContent
);
161 void NotifyRootInsertion();
164 void ContinueInterruptedParsingIfEnabled();
169 explicit SinkContext(HTMLContentSink
* aSink
);
172 nsresult
Begin(nsHTMLTag aNodeType
, nsGenericHTMLElement
* aRoot
,
173 uint32_t aNumFlushed
, int32_t aInsertionPoint
);
175 nsresult
CloseBody();
178 nsresult
GrowStack();
179 nsresult
FlushTags();
181 bool IsCurrentContainer(nsHTMLTag aTag
) const;
183 void DidAddContent(nsIContent
* aContent
);
184 void UpdateChildCounts();
187 // Function to check whether we've notified for the current content.
188 // What this actually does is check whether we've notified for all
189 // of the parent's kids.
190 bool HaveNotifiedForCurrentContent() const;
193 HTMLContentSink
* mSink
;
194 int32_t mNotifyLevel
;
198 nsGenericHTMLElement
* mContent
;
199 uint32_t mNumFlushed
;
200 int32_t mInsertionPoint
;
202 nsIContent
* Add(nsIContent
* child
);
210 nsresult
NS_NewHTMLElement(Element
** aResult
,
211 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
,
212 FromParser aFromParser
, nsAtom
* aIsAtom
,
213 mozilla::dom::CustomElementDefinition
* aDefinition
) {
214 RefPtr
<mozilla::dom::NodeInfo
> nodeInfo
= aNodeInfo
;
217 nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
),
218 "Trying to create HTML elements that don't have the XHTML namespace");
220 return nsContentUtils::NewXULOrHTMLElement(aResult
, nodeInfo
, aFromParser
,
221 aIsAtom
, aDefinition
);
224 already_AddRefed
<nsGenericHTMLElement
> CreateHTMLElement(
225 uint32_t aNodeType
, already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
,
226 FromParser aFromParser
) {
228 aNodeType
<= NS_HTML_TAG_MAX
|| aNodeType
== eHTMLTag_userdefined
,
229 "aNodeType is out of bounds");
231 HTMLContentCreatorFunction cb
= sHTMLContentCreatorFunctions
[aNodeType
];
233 NS_ASSERTION(cb
!= NS_NewHTMLNOTUSEDElement
,
234 "Don't know how to construct tag element!");
236 RefPtr
<nsGenericHTMLElement
> result
= cb(std::move(aNodeInfo
), aFromParser
);
238 return result
.forget();
241 //----------------------------------------------------------------------
243 SinkContext::SinkContext(HTMLContentSink
* aSink
)
249 MOZ_COUNT_CTOR(SinkContext
);
252 SinkContext::~SinkContext() {
253 MOZ_COUNT_DTOR(SinkContext
);
256 for (int32_t i
= 0; i
< mStackPos
; i
++) {
257 NS_RELEASE(mStack
[i
].mContent
);
263 nsresult
SinkContext::Begin(nsHTMLTag aNodeType
, nsGenericHTMLElement
* aRoot
,
264 uint32_t aNumFlushed
, int32_t aInsertionPoint
) {
265 if (mStackSize
< 1) {
266 nsresult rv
= GrowStack();
272 mStack
[0].mType
= aNodeType
;
273 mStack
[0].mContent
= aRoot
;
274 mStack
[0].mNumFlushed
= aNumFlushed
;
275 mStack
[0].mInsertionPoint
= aInsertionPoint
;
282 bool SinkContext::IsCurrentContainer(nsHTMLTag aTag
) const {
283 return aTag
== mStack
[mStackPos
- 1].mType
;
286 void SinkContext::DidAddContent(nsIContent
* aContent
) {
287 if ((mStackPos
== 2) && (mSink
->mBody
== mStack
[1].mContent
)) {
288 // We just finished adding something to the body
292 // If we just added content to a node for which
293 // an insertion happen, we need to do an immediate
294 // notification for that insertion.
295 if (0 < mStackPos
&& mStack
[mStackPos
- 1].mInsertionPoint
!= -1 &&
296 mStack
[mStackPos
- 1].mNumFlushed
<
297 mStack
[mStackPos
- 1].mContent
->GetChildCount()) {
298 nsIContent
* parent
= mStack
[mStackPos
- 1].mContent
;
299 mSink
->NotifyInsert(parent
, aContent
);
300 mStack
[mStackPos
- 1].mNumFlushed
= parent
->GetChildCount();
301 } else if (mSink
->IsTimeToNotify()) {
306 nsresult
SinkContext::OpenBody() {
307 if (mStackPos
<= 0) {
308 NS_ERROR("container w/o parent");
310 return NS_ERROR_FAILURE
;
314 if (mStackPos
+ 1 > mStackSize
) {
321 RefPtr
<mozilla::dom::NodeInfo
> nodeInfo
=
322 mSink
->mNodeInfoManager
->GetNodeInfo(
323 nsGkAtoms::body
, nullptr, kNameSpaceID_XHTML
, nsINode::ELEMENT_NODE
);
324 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_UNEXPECTED
);
326 // Make the content object
327 RefPtr
<nsGenericHTMLElement
> body
=
328 NS_NewHTMLBodyElement(nodeInfo
.forget(), FROM_PARSER_NETWORK
);
330 return NS_ERROR_OUT_OF_MEMORY
;
333 mStack
[mStackPos
].mType
= eHTMLTag_body
;
334 body
.forget(&mStack
[mStackPos
].mContent
);
335 mStack
[mStackPos
].mNumFlushed
= 0;
336 mStack
[mStackPos
].mInsertionPoint
= -1;
338 mStack
[mStackPos
- 2].Add(mStack
[mStackPos
- 1].mContent
);
343 bool SinkContext::HaveNotifiedForCurrentContent() const {
345 nsIContent
* parent
= mStack
[mStackPos
- 1].mContent
;
346 return mStack
[mStackPos
- 1].mNumFlushed
== parent
->GetChildCount();
352 nsIContent
* SinkContext::Node::Add(nsIContent
* child
) {
353 NS_ASSERTION(mContent
, "No parent to insert/append into!");
354 if (mInsertionPoint
!= -1) {
355 NS_ASSERTION(mNumFlushed
== mContent
->GetChildCount(),
356 "Inserting multiple children without flushing.");
357 nsCOMPtr
<nsIContent
> nodeToInsertBefore
=
358 mContent
->GetChildAt_Deprecated(mInsertionPoint
++);
359 mContent
->InsertChildBefore(child
, nodeToInsertBefore
, false,
362 mContent
->AppendChildTo(child
, false, IgnoreErrors());
367 nsresult
SinkContext::CloseBody() {
368 NS_ASSERTION(mStackPos
> 0, "stack out of bounds. wrong context probably!");
370 if (mStackPos
<= 0) {
371 return NS_OK
; // Fix crash - Ref. bug 45975 or 45007
375 NS_ASSERTION(mStack
[mStackPos
].mType
== eHTMLTag_body
,
376 "Tag mismatch. Closing tag on wrong context or something?");
378 nsGenericHTMLElement
* content
= mStack
[mStackPos
].mContent
;
382 // If we're in a state where we do append notifications as
383 // we go up the tree, and we're at the level where the next
384 // notification needs to be done, do the notification.
385 if (mNotifyLevel
>= mStackPos
) {
386 // Check to see if new content has been added after our last
389 if (mStack
[mStackPos
].mNumFlushed
< content
->GetChildCount()) {
390 mSink
->NotifyAppend(content
, mStack
[mStackPos
].mNumFlushed
);
391 mStack
[mStackPos
].mNumFlushed
= content
->GetChildCount();
394 // Indicate that notification has now happened at this level
395 mNotifyLevel
= mStackPos
- 1;
398 DidAddContent(content
);
399 NS_IF_RELEASE(content
);
404 nsresult
SinkContext::End() {
405 for (int32_t i
= 0; i
< mStackPos
; i
++) {
406 NS_RELEASE(mStack
[i
].mContent
);
414 nsresult
SinkContext::GrowStack() {
415 int32_t newSize
= mStackSize
* 2;
420 Node
* stack
= new Node
[newSize
];
422 if (mStackPos
!= 0) {
423 memcpy(stack
, mStack
, sizeof(Node
) * mStackPos
);
428 mStackSize
= newSize
;
434 * NOTE!! Forked into nsXMLContentSink. Please keep in sync.
436 * Flush all elements that have been seen so far such that
437 * they are visible in the tree. Specifically, make sure
438 * that they are all added to their respective parents.
439 * Also, do notification at the top for all content that
440 * has been newly added so that the frame tree is complete.
442 nsresult
SinkContext::FlushTags() {
443 mSink
->mDeferredFlushTags
= false;
444 uint32_t oldUpdates
= mSink
->mUpdatesInNotification
;
446 ++(mSink
->mInNotification
);
447 mSink
->mUpdatesInNotification
= 0;
449 // Scope so we call EndUpdate before we decrease mInNotification
450 mozAutoDocUpdate
updateBatch(mSink
->mDocument
, true);
452 // Start from the base of the stack (growing downward) and do
453 // a notification from the node that is closest to the root of
454 // tree for any content that has been added.
456 // Note that we can start at stackPos == 0 here, because it's the caller's
457 // responsibility to handle flushing interactions between contexts (see
458 // HTMLContentSink::BeginContext).
459 int32_t stackPos
= 0;
460 bool flushed
= false;
462 nsGenericHTMLElement
* content
;
464 while (stackPos
< mStackPos
) {
465 content
= mStack
[stackPos
].mContent
;
466 childCount
= content
->GetChildCount();
468 if (!flushed
&& (mStack
[stackPos
].mNumFlushed
< childCount
)) {
469 if (mStack
[stackPos
].mInsertionPoint
!= -1) {
470 // We might have popped the child off our stack already
471 // but not notified on it yet, which is why we have to get it
472 // directly from its parent node.
474 int32_t childIndex
= mStack
[stackPos
].mInsertionPoint
- 1;
475 nsIContent
* child
= content
->GetChildAt_Deprecated(childIndex
);
476 // Child not on stack anymore; can't assert it's correct
477 NS_ASSERTION(!(mStackPos
> (stackPos
+ 1)) ||
478 (child
== mStack
[stackPos
+ 1].mContent
),
479 "Flushing the wrong child.");
480 mSink
->NotifyInsert(content
, child
);
482 mSink
->NotifyAppend(content
, mStack
[stackPos
].mNumFlushed
);
488 mStack
[stackPos
].mNumFlushed
= childCount
;
491 mNotifyLevel
= mStackPos
- 1;
493 --(mSink
->mInNotification
);
495 if (mSink
->mUpdatesInNotification
> 1) {
499 mSink
->mUpdatesInNotification
= oldUpdates
;
505 * NOTE!! Forked into nsXMLContentSink. Please keep in sync.
507 void SinkContext::UpdateChildCounts() {
508 // Start from the top of the stack (growing upwards) and see if any
509 // new content has been appended. If so, we recognize that reflows
510 // have been generated for it and we should make sure that no
511 // further reflows occur. Note that we have to include stackPos == 0
512 // to properly notify on kids of <html>.
513 int32_t stackPos
= mStackPos
- 1;
514 while (stackPos
>= 0) {
515 Node
& node
= mStack
[stackPos
];
516 node
.mNumFlushed
= node
.mContent
->GetChildCount();
521 mNotifyLevel
= mStackPos
- 1;
524 nsresult
NS_NewHTMLContentSink(nsIHTMLContentSink
** aResult
, Document
* aDoc
,
525 nsIURI
* aURI
, nsISupports
* aContainer
,
526 nsIChannel
* aChannel
) {
527 NS_ENSURE_ARG_POINTER(aResult
);
529 RefPtr
<HTMLContentSink
> it
= new HTMLContentSink();
531 nsresult rv
= it
->Init(aDoc
, aURI
, aContainer
, aChannel
);
533 NS_ENSURE_SUCCESS(rv
, rv
);
541 HTMLContentSink::HTMLContentSink()
543 mCurrentContext(nullptr),
544 mHeadContext(nullptr),
545 mHaveSeenHead(false),
546 mNotifiedRootInsertion(false) {}
548 HTMLContentSink::~HTMLContentSink() {
549 if (mNotificationTimer
) {
550 mNotificationTimer
->Cancel();
553 if (mCurrentContext
== mHeadContext
&& !mContextStack
.IsEmpty()) {
554 // Pop off the second html context if it's not done earlier
555 mContextStack
.RemoveLastElement();
558 for (int32_t i
= 0, numContexts
= mContextStack
.Length(); i
< numContexts
;
560 SinkContext
* sc
= mContextStack
.ElementAt(i
);
563 if (sc
== mCurrentContext
) {
564 mCurrentContext
= nullptr;
571 if (mCurrentContext
== mHeadContext
) {
572 mCurrentContext
= nullptr;
575 delete mCurrentContext
;
580 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLContentSink
, nsContentSink
,
581 mHTMLDocument
, mRoot
, mBody
, mHead
)
583 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLContentSink
, nsContentSink
,
584 nsIContentSink
, nsIHTMLContentSink
)
586 nsresult
HTMLContentSink::Init(Document
* aDoc
, nsIURI
* aURI
,
587 nsISupports
* aContainer
, nsIChannel
* aChannel
) {
588 NS_ENSURE_TRUE(aContainer
, NS_ERROR_NULL_POINTER
);
590 nsresult rv
= nsContentSink::Init(aDoc
, aURI
, aContainer
, aChannel
);
595 aDoc
->AddObserver(this);
596 mIsDocumentObserver
= true;
597 mHTMLDocument
= aDoc
->AsHTMLDocument();
599 NS_ASSERTION(mDocShell
, "oops no docshell!");
601 // Changed from 8192 to greatly improve page loading performance on
602 // large pages. See bugzilla bug 77540.
603 mMaxTextRun
= Preferences::GetInt("content.maxtextrun", 8191);
605 RefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
606 nodeInfo
= mNodeInfoManager
->GetNodeInfo(
607 nsGkAtoms::html
, nullptr, kNameSpaceID_XHTML
, nsINode::ELEMENT_NODE
);
610 mRoot
= NS_NewHTMLHtmlElement(nodeInfo
.forget());
612 return NS_ERROR_OUT_OF_MEMORY
;
615 NS_ASSERTION(mDocument
->GetChildCount() == 0,
616 "Document should have no kids here!");
618 mDocument
->AppendChildTo(mRoot
, false, error
);
619 if (error
.Failed()) {
620 return error
.StealNSResult();
624 nodeInfo
= mNodeInfoManager
->GetNodeInfo(
625 nsGkAtoms::head
, nullptr, kNameSpaceID_XHTML
, nsINode::ELEMENT_NODE
);
627 mHead
= NS_NewHTMLHeadElement(nodeInfo
.forget());
629 return NS_ERROR_OUT_OF_MEMORY
;
632 mRoot
->AppendChildTo(mHead
, false, IgnoreErrors());
634 mCurrentContext
= new SinkContext(this);
635 mCurrentContext
->Begin(eHTMLTag_html
, mRoot
, 0, -1);
636 mContextStack
.AppendElement(mCurrentContext
);
642 HTMLContentSink::WillParse(void) { return WillParseImpl(); }
645 HTMLContentSink::WillBuildModel(nsDTDMode aDTDMode
) {
646 WillBuildModelImpl();
648 mDocument
->SetCompatibilityMode(aDTDMode
== eDTDMode_full_standards
649 ? eCompatibility_FullStandards
650 : eCompatibility_NavQuirks
);
652 // Notify document that the load is beginning
653 mDocument
->BeginLoad();
659 HTMLContentSink::DidBuildModel(bool aTerminated
) {
660 DidBuildModelImpl(aTerminated
);
662 // Reflow the last batch of content
664 mCurrentContext
->FlushTags();
665 } else if (!mLayoutStarted
) {
666 // We never saw the body, and layout never got started. Force
667 // layout *now*, to get an initial reflow.
668 // NOTE: only force the layout if we are NOT destroying the
669 // docshell. If we are destroying it, then starting layout will
670 // likely cause us to crash, or at best waste a lot of time as we
671 // are just going to tear it down anyway.
672 bool bDestroying
= true;
674 mDocShell
->IsBeingDestroyed(&bDestroying
);
684 // Make sure we no longer respond to document mutations. We've flushed all
685 // our notifications out, so there's no need to do anything else here.
687 // XXXbz I wonder whether we could End() our contexts here too, or something,
688 // just to make sure we no longer notify... Or is the mIsDocumentObserver
690 mDocument
->RemoveObserver(this);
691 mIsDocumentObserver
= false;
693 mDocument
->EndLoad();
695 DropParserAndPerfHint();
701 HTMLContentSink::SetParser(nsParserBase
* aParser
) {
702 MOZ_ASSERT(aParser
, "Should have a parser here!");
707 nsresult
HTMLContentSink::CloseHTML() {
709 if (mCurrentContext
== mHeadContext
) {
710 // Pop off the second html context if it's not done earlier
711 mCurrentContext
= mContextStack
.PopLastElement();
717 mHeadContext
= nullptr;
723 nsresult
HTMLContentSink::OpenBody() {
724 CloseHeadContext(); // do this just in case if the HEAD was left open!
726 // if we already have a body we're done
731 nsresult rv
= mCurrentContext
->OpenBody();
737 mBody
= mCurrentContext
->mStack
[mCurrentContext
->mStackPos
- 1].mContent
;
739 if (mCurrentContext
->mStackPos
> 1) {
740 int32_t parentIndex
= mCurrentContext
->mStackPos
- 2;
741 nsGenericHTMLElement
* parent
=
742 mCurrentContext
->mStack
[parentIndex
].mContent
;
743 int32_t numFlushed
= mCurrentContext
->mStack
[parentIndex
].mNumFlushed
;
744 int32_t childCount
= parent
->GetChildCount();
745 NS_ASSERTION(numFlushed
< childCount
, "Already notified on the body?");
747 int32_t insertionPoint
=
748 mCurrentContext
->mStack
[parentIndex
].mInsertionPoint
;
750 // XXX: I have yet to see a case where numFlushed is non-zero and
751 // insertionPoint is not -1, but this code will try to handle
754 uint32_t oldUpdates
= mUpdatesInNotification
;
755 mUpdatesInNotification
= 0;
756 if (insertionPoint
!= -1) {
757 NotifyInsert(parent
, mBody
);
759 NotifyAppend(parent
, numFlushed
);
761 mCurrentContext
->mStack
[parentIndex
].mNumFlushed
= childCount
;
762 if (mUpdatesInNotification
> 1) {
765 mUpdatesInNotification
= oldUpdates
;
773 nsresult
HTMLContentSink::CloseBody() {
774 // Flush out anything that's left
775 mCurrentContext
->FlushTags();
776 mCurrentContext
->CloseBody();
782 HTMLContentSink::OpenContainer(ElementType aElementType
) {
785 switch (aElementType
) {
791 // If we've already hit this code once, then we're done
792 if (!mNotifiedRootInsertion
) {
793 NotifyRootInsertion();
803 HTMLContentSink::CloseContainer(const ElementType aTag
) {
819 HTMLContentSink::WillInterrupt() { return WillInterruptImpl(); }
821 void HTMLContentSink::WillResume() { WillResumeImpl(); }
823 void HTMLContentSink::CloseHeadContext() {
824 if (mCurrentContext
) {
825 if (!mCurrentContext
->IsCurrentContainer(eHTMLTag_head
)) return;
827 mCurrentContext
->FlushTags();
830 if (!mContextStack
.IsEmpty()) {
831 mCurrentContext
= mContextStack
.PopLastElement();
835 void HTMLContentSink::NotifyInsert(nsIContent
* aContent
,
836 nsIContent
* aChildContent
) {
840 // Scope so we call EndUpdate before we decrease mInNotification
841 // Note that aContent->OwnerDoc() may be different to mDocument already.
842 MOZ_AUTO_DOC_UPDATE(aContent
? aContent
->OwnerDoc() : mDocument
.get(),
844 MutationObservers::NotifyContentInserted(NODE_FROM(aContent
, mDocument
),
846 mLastNotificationTime
= PR_Now();
852 void HTMLContentSink::NotifyRootInsertion() {
853 MOZ_ASSERT(!mNotifiedRootInsertion
, "Double-notifying on root?");
854 NS_ASSERTION(!mLayoutStarted
,
855 "How did we start layout without notifying on root?");
856 // Now make sure to notify that we have now inserted our root. If
857 // there has been no initial reflow yet it'll be a no-op, but if
858 // there has been one we need this to get its frames constructed.
859 // Note that if mNotifiedRootInsertion is true we don't notify here,
860 // since that just means there are multiple <html> tags in the
861 // document; in those cases we just want to put all the attrs on one
863 mNotifiedRootInsertion
= true;
864 NotifyInsert(nullptr, mRoot
);
866 // Now update the notification information in all our
867 // contexts, since we just inserted the root and notified on
871 nsContentUtils::AddScriptRunner(
872 new nsDocElementCreatedNotificationRunner(mDocument
));
875 void HTMLContentSink::UpdateChildCounts() {
876 uint32_t numContexts
= mContextStack
.Length();
877 for (uint32_t i
= 0; i
< numContexts
; i
++) {
878 SinkContext
* sc
= mContextStack
.ElementAt(i
);
880 sc
->UpdateChildCounts();
883 mCurrentContext
->UpdateChildCounts();
886 void HTMLContentSink::FlushPendingNotifications(FlushType aType
) {
887 // Only flush tags if we're not doing the notification ourselves
888 // (since we aren't reentrant)
889 if (!mInNotification
) {
890 // Only flush if we're still a document observer (so that our child counts
891 // should be correct).
892 if (mIsDocumentObserver
) {
893 if (aType
>= FlushType::ContentAndNotify
) {
897 if (aType
>= FlushType::EnsurePresShellInitAndFrames
) {
898 // Make sure that layout has started so that the reflow flush
899 // will actually happen.
905 nsresult
HTMLContentSink::FlushTags() {
906 if (!mNotifiedRootInsertion
) {
907 NotifyRootInsertion();
911 return mCurrentContext
? mCurrentContext
->FlushTags() : NS_OK
;
914 void HTMLContentSink::SetDocumentCharset(NotNull
<const Encoding
*> aEncoding
) {
915 MOZ_ASSERT_UNREACHABLE("<meta charset> case doesn't occur with about:blank");
918 nsISupports
* HTMLContentSink::GetTarget() { return ToSupports(mDocument
); }
920 bool HTMLContentSink::IsScriptExecuting() { return IsScriptExecutingImpl(); }
922 void HTMLContentSink::ContinueInterruptedParsingIfEnabled() {
923 if (mParser
&& mParser
->IsParserEnabled()) {
924 static_cast<nsIParser
*>(mParser
.get())->ContinueInterruptedParsing();
928 bool HTMLContentSink::WaitForPendingSheets() {
929 return nsContentSink::WaitForPendingSheets();
932 void HTMLContentSink::ContinueInterruptedParsingAsync() {
933 nsCOMPtr
<nsIRunnable
> ev
= NewRunnableMethod(
934 "HTMLContentSink::ContinueInterruptedParsingIfEnabled", this,
935 &HTMLContentSink::ContinueInterruptedParsingIfEnabled
);
936 mHTMLDocument
->Dispatch(ev
.forget());