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 #include "nsXMLContentSink.h"
10 #include "mozilla/dom/Document.h"
11 #include "nsIContent.h"
13 #include "nsNetUtil.h"
14 #include "nsHTMLParts.h"
16 #include "mozilla/StyleSheetInlines.h"
17 #include "mozilla/css/Loader.h"
18 #include "nsGkAtoms.h"
19 #include "nsContentUtils.h"
20 #include "nsDocElementCreatedNotificationRunner.h"
21 #include "nsIDocShell.h"
22 #include "nsIScriptContext.h"
23 #include "nsNameSpaceManager.h"
24 #include "nsIScriptSecurityManager.h"
25 #include "nsIContentViewer.h"
27 #include "mozilla/Logging.h"
29 #include "nsIScriptElement.h"
30 #include "nsReadableUtils.h"
31 #include "nsUnicharUtils.h"
32 #include "nsIChannel.h"
33 #include "nsXMLPrettyPrinter.h"
34 #include "nsNodeInfoManager.h"
35 #include "nsContentCreatorFunctions.h"
36 #include "nsIContentPolicy.h"
37 #include "nsContentPolicyUtils.h"
39 #include "nsIScriptGlobalObject.h"
40 #include "mozAutoDocUpdate.h"
41 #include "nsMimeTypes.h"
42 #include "nsHtml5SVGLoadDispatcher.h"
43 #include "nsTextNode.h"
44 #include "mozilla/dom/CDATASection.h"
45 #include "mozilla/dom/Comment.h"
46 #include "mozilla/dom/DocumentType.h"
47 #include "mozilla/dom/Element.h"
48 #include "mozilla/dom/HTMLTemplateElement.h"
49 #include "mozilla/dom/MutationObservers.h"
50 #include "mozilla/dom/ProcessingInstruction.h"
51 #include "mozilla/dom/ScriptLoader.h"
52 #include "mozilla/dom/txMozillaXSLTProcessor.h"
53 #include "mozilla/CycleCollectedJSContext.h"
54 #include "mozilla/LoadInfo.h"
55 #include "mozilla/UseCounter.h"
57 using namespace mozilla
;
58 using namespace mozilla::dom
;
61 // 1) what's not allowed - We need to figure out which HTML tags
62 // (prefixed with a HTML namespace qualifier) are explicitly not
64 // 2) factoring code with nsHTMLContentSink - There's some amount of
65 // common code between this and the HTML content sink. This will
66 // increase as we support more and more HTML elements. How can code
67 // from the code be factored?
69 nsresult
NS_NewXMLContentSink(nsIXMLContentSink
** aResult
, Document
* aDoc
,
70 nsIURI
* aURI
, nsISupports
* aContainer
,
71 nsIChannel
* aChannel
) {
72 MOZ_ASSERT(nullptr != aResult
, "null ptr");
73 if (nullptr == aResult
) {
74 return NS_ERROR_NULL_POINTER
;
76 RefPtr
<nsXMLContentSink
> it
= new nsXMLContentSink();
78 nsresult rv
= it
->Init(aDoc
, aURI
, aContainer
, aChannel
);
79 NS_ENSURE_SUCCESS(rv
, rv
);
85 nsXMLContentSink::nsXMLContentSink()
86 : mState(eXMLContentSinkState_InProlog
),
89 mPrettyPrintXML(true),
90 mPrettyPrintHasSpecialRoot(0),
91 mPrettyPrintHasFactoredElements(0),
93 mPreventScriptExecution(0) {
97 nsXMLContentSink::~nsXMLContentSink() = default;
99 nsresult
nsXMLContentSink::Init(Document
* aDoc
, nsIURI
* aURI
,
100 nsISupports
* aContainer
, nsIChannel
* aChannel
) {
101 nsresult rv
= nsContentSink::Init(aDoc
, aURI
, aContainer
, aChannel
);
102 NS_ENSURE_SUCCESS(rv
, rv
);
104 aDoc
->AddObserver(this);
105 mIsDocumentObserver
= true;
108 mPrettyPrintXML
= false;
111 mState
= eXMLContentSinkState_InProlog
;
112 mDocElement
= nullptr;
117 inline void ImplCycleCollectionTraverse(
118 nsCycleCollectionTraversalCallback
& aCallback
,
119 nsXMLContentSink::StackNode
& aField
, const char* aName
,
120 uint32_t aFlags
= 0) {
121 ImplCycleCollectionTraverse(aCallback
, aField
.mContent
, aName
, aFlags
);
124 inline void ImplCycleCollectionUnlink(nsXMLContentSink::StackNode
& aField
) {
125 ImplCycleCollectionUnlink(aField
.mContent
);
128 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXMLContentSink
)
129 NS_INTERFACE_MAP_ENTRY(nsIContentSink
)
130 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink
)
131 NS_INTERFACE_MAP_ENTRY(nsIExpatSink
)
132 NS_INTERFACE_MAP_ENTRY(nsITransformObserver
)
133 NS_INTERFACE_MAP_END_INHERITING(nsContentSink
)
135 NS_IMPL_ADDREF_INHERITED(nsXMLContentSink
, nsContentSink
)
136 NS_IMPL_RELEASE_INHERITED(nsXMLContentSink
, nsContentSink
)
138 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsXMLContentSink
, nsContentSink
,
139 mCurrentHead
, mDocElement
, mLastTextNode
,
140 mContentStack
, mDocumentChildren
)
144 nsXMLContentSink::WillParse(void) { return WillParseImpl(); }
147 nsXMLContentSink::WillBuildModel(nsDTDMode aDTDMode
) {
148 WillBuildModelImpl();
150 // Notify document that the load is beginning
151 mDocument
->BeginLoad();
153 // Check for correct load-command for maybe prettyprinting
154 if (mPrettyPrintXML
) {
155 nsAutoCString command
;
156 GetParser()->GetCommand(command
);
157 if (!command
.EqualsLiteral("view")) {
158 mPrettyPrintXML
= false;
165 bool nsXMLContentSink::CanStillPrettyPrint() {
166 return mPrettyPrintXML
&&
167 (!mPrettyPrintHasFactoredElements
|| mPrettyPrintHasSpecialRoot
);
170 nsresult
nsXMLContentSink::MaybePrettyPrint() {
171 if (!CanStillPrettyPrint()) {
172 mPrettyPrintXML
= false;
178 // Try to perform a microtask checkpoint; this avoids always breaking
179 // pretty-printing if webextensions insert new content right after the
184 // stop observing in order to avoid crashing when replacing content
185 mDocument
->RemoveObserver(this);
186 mIsDocumentObserver
= false;
188 // Reenable the CSSLoader so that the prettyprinting stylesheets can load
190 mCSSLoader
->SetEnabled(true);
193 RefPtr
<nsXMLPrettyPrinter
> printer
;
194 nsresult rv
= NS_NewXMLPrettyPrinter(getter_AddRefs(printer
));
195 NS_ENSURE_SUCCESS(rv
, rv
);
197 bool isPrettyPrinting
;
198 rv
= printer
->PrettyPrint(mDocument
, &isPrettyPrinting
);
199 NS_ENSURE_SUCCESS(rv
, rv
);
201 mPrettyPrinting
= isPrettyPrinting
;
205 static void CheckXSLTParamPI(ProcessingInstruction
* aPi
,
206 nsIDocumentTransformer
* aProcessor
,
208 nsAutoString target
, data
;
209 aPi
->GetTarget(target
);
211 // Check for namespace declarations
212 if (target
.EqualsLiteral("xslt-param-namespace")) {
214 nsAutoString prefix
, namespaceAttr
;
215 nsContentUtils::GetPseudoAttributeValue(data
, nsGkAtoms::prefix
, prefix
);
216 if (!prefix
.IsEmpty() && nsContentUtils::GetPseudoAttributeValue(
217 data
, nsGkAtoms::_namespace
, namespaceAttr
)) {
218 aProcessor
->AddXSLTParamNamespace(prefix
, namespaceAttr
);
222 // Check for actual parameters
223 else if (target
.EqualsLiteral("xslt-param")) {
225 nsAutoString name
, namespaceAttr
, select
, value
;
226 nsContentUtils::GetPseudoAttributeValue(data
, nsGkAtoms::name
, name
);
227 nsContentUtils::GetPseudoAttributeValue(data
, nsGkAtoms::_namespace
,
229 if (!nsContentUtils::GetPseudoAttributeValue(data
, nsGkAtoms::select
,
231 select
.SetIsVoid(true);
233 if (!nsContentUtils::GetPseudoAttributeValue(data
, nsGkAtoms::value
,
235 value
.SetIsVoid(true);
237 if (!name
.IsEmpty()) {
238 aProcessor
->AddXSLTParam(name
, namespaceAttr
, select
, value
, aSource
);
244 nsXMLContentSink::DidBuildModel(bool aTerminated
) {
246 // If mParser is null, this parse has already been terminated and must
247 // not been terminated again. However, Document may still think that
248 // the parse has not been terminated and call back into here in the case
249 // where the XML parser has finished but the XSLT transform associated
250 // with the document has not.
256 DidBuildModelImpl(aTerminated
);
258 if (mXSLTProcessor
) {
259 // stop observing in order to avoid crashing when replacing content
260 mDocument
->RemoveObserver(this);
261 mIsDocumentObserver
= false;
264 RefPtr
<DocumentFragment
> source
= mDocument
->CreateDocumentFragment();
265 for (nsIContent
* child
: mDocumentChildren
) {
266 // XPath data model doesn't have DocumentType nodes.
267 if (child
->NodeType() != nsINode::DOCUMENT_TYPE_NODE
) {
268 source
->AppendChild(*child
, rv
);
270 return rv
.StealNSResult();
275 // Check for xslt-param and xslt-param-namespace PIs
276 for (nsIContent
* child
: mDocumentChildren
) {
277 if (auto pi
= ProcessingInstruction::FromNode(child
)) {
278 CheckXSLTParamPI(pi
, mXSLTProcessor
, source
);
279 } else if (child
->IsElement()) {
280 // Only honor PIs in the prolog
285 mXSLTProcessor
->SetSourceContentModel(source
);
286 // Since the processor now holds a reference to us we drop our reference
287 // to it to avoid owning cycles
288 mXSLTProcessor
= nullptr;
290 // Kick off layout for non-XSLT transformed documents.
292 // Check if we want to prettyprint
295 bool startLayout
= true;
297 if (mPrettyPrinting
) {
298 NS_ASSERTION(!mPendingSheetCount
, "Shouldn't have pending sheets here!");
300 // We're pretty-printing now. See whether we should wait up on
302 if (mDocument
->CSSLoader()->HasPendingLoads()) {
303 mDocument
->CSSLoader()->AddObserver(this);
304 // wait for those sheets to load
315 mDocument
->RemoveObserver(this);
316 mIsDocumentObserver
= false;
318 mDocument
->EndLoad();
320 DropParserAndPerfHint();
326 nsresult
nsXMLContentSink::OnDocumentCreated(Document
* aSourceDocument
,
327 Document
* aResultDocument
) {
328 aResultDocument
->SetDocWriteDisabled(true);
330 nsCOMPtr
<nsIContentViewer
> contentViewer
;
331 mDocShell
->GetContentViewer(getter_AddRefs(contentViewer
));
332 // Make sure that we haven't loaded a new document into the contentviewer
333 // after starting the XSLT transform.
334 if (contentViewer
&& contentViewer
->GetDocument() == aSourceDocument
) {
335 return contentViewer
->SetDocumentInternal(aResultDocument
, true);
340 nsresult
nsXMLContentSink::OnTransformDone(Document
* aSourceDocument
,
342 Document
* aResultDocument
) {
343 MOZ_ASSERT(aResultDocument
,
344 "Don't notify about transform end without a document.");
346 mDocumentChildren
.Clear();
348 nsCOMPtr
<nsIContentViewer
> contentViewer
;
349 mDocShell
->GetContentViewer(getter_AddRefs(contentViewer
));
351 RefPtr
<Document
> originalDocument
= mDocument
;
352 bool blockingOnload
= mIsBlockingOnload
;
354 // Make sure that we haven't loaded a new document into the contentviewer
355 // after starting the XSLT transform.
356 if (contentViewer
&& (contentViewer
->GetDocument() == aSourceDocument
||
357 contentViewer
->GetDocument() == aResultDocument
)) {
358 if (NS_FAILED(aResult
)) {
360 aResultDocument
->SetMayStartLayout(false);
361 // We have an error document.
362 contentViewer
->SetDocument(aResultDocument
);
365 if (!mRunsToCompletion
) {
366 // This BlockOnload call corresponds to the UnblockOnload call in
367 // nsContentSink::DropParserAndPerfHint.
368 aResultDocument
->BlockOnload();
369 mIsBlockingOnload
= true;
371 // Transform succeeded, or it failed and we have an error document to
373 mDocument
= aResultDocument
;
374 aResultDocument
->SetDocWriteDisabled(false);
376 // Notify document observers that all the content has been stuck
377 // into the document.
378 // XXX do we need to notify for things like PIs? Or just the
380 nsIContent
* rootElement
= mDocument
->GetRootElement();
382 NS_ASSERTION(mDocument
->ComputeIndexOf(rootElement
).isSome(),
383 "rootElement not in doc?");
384 mDocument
->BeginUpdate();
385 MutationObservers::NotifyContentInserted(mDocument
, rootElement
);
386 mDocument
->EndUpdate();
389 // Start the layout process
395 originalDocument
->EndLoad();
396 if (blockingOnload
) {
397 // This UnblockOnload call corresponds to the BlockOnload call in
398 // nsContentSink::WillBuildModelImpl.
399 originalDocument
->UnblockOnload(true);
402 DropParserAndPerfHint();
404 // By this point, the result document has been set in the content viewer. But
405 // the content viewer does not call Destroy on the original document, so we
406 // won't end up reporting document use counters. It's possible we should be
407 // detaching the document from the window, but for now, we call
408 // ReportDocumentUseCounters on the original document here, to avoid
409 // assertions in ~Document about not having reported them.
410 originalDocument
->ReportDocumentUseCounters();
416 nsXMLContentSink::StyleSheetLoaded(StyleSheet
* aSheet
, bool aWasDeferred
,
418 if (!mPrettyPrinting
) {
419 return nsContentSink::StyleSheetLoaded(aSheet
, aWasDeferred
, aStatus
);
422 if (!mDocument
->CSSLoader()->HasPendingLoads()) {
423 mDocument
->CSSLoader()->RemoveObserver(this);
432 nsXMLContentSink::WillInterrupt(void) { return WillInterruptImpl(); }
434 void nsXMLContentSink::WillResume() { WillResumeImpl(); }
437 nsXMLContentSink::SetParser(nsParserBase
* aParser
) {
438 MOZ_ASSERT(aParser
, "Should have a parser here!");
443 static bool FindIsAttrValue(const char16_t
** aAtts
, const char16_t
** aResult
) {
444 RefPtr
<nsAtom
> prefix
, localName
;
445 for (; *aAtts
; aAtts
+= 2) {
447 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
448 getter_AddRefs(localName
), &nameSpaceID
);
449 if (nameSpaceID
== kNameSpaceID_None
&& localName
== nsGkAtoms::is
) {
459 nsresult
nsXMLContentSink::CreateElement(
460 const char16_t
** aAtts
, uint32_t aAttsCount
,
461 mozilla::dom::NodeInfo
* aNodeInfo
, uint32_t aLineNumber
,
462 uint32_t aColumnNumber
, nsIContent
** aResult
, bool* aAppendContent
,
463 FromParser aFromParser
) {
464 NS_ASSERTION(aNodeInfo
, "can't create element without nodeinfo");
467 *aAppendContent
= true;
470 RefPtr
<mozilla::dom::NodeInfo
> ni
= aNodeInfo
;
471 RefPtr
<Element
> content
;
473 const char16_t
* is
= nullptr;
474 if ((aNodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
) ||
475 aNodeInfo
->NamespaceEquals(kNameSpaceID_XUL
)) &&
476 FindIsAttrValue(aAtts
, &is
)) {
477 const nsDependentString
isStr(is
);
478 rv
= NS_NewElement(getter_AddRefs(content
), ni
.forget(), aFromParser
,
481 rv
= NS_NewElement(getter_AddRefs(content
), ni
.forget(), aFromParser
);
484 NS_ENSURE_SUCCESS(rv
, rv
);
486 if (aNodeInfo
->Equals(nsGkAtoms::script
, kNameSpaceID_XHTML
) ||
487 aNodeInfo
->Equals(nsGkAtoms::script
, kNameSpaceID_SVG
)) {
488 nsCOMPtr
<nsIScriptElement
> sele
= do_QueryInterface(content
);
490 sele
->SetScriptLineNumber(aLineNumber
);
491 sele
->SetScriptColumnNumber(aColumnNumber
);
492 sele
->SetCreatorParser(GetParser());
494 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled
,
495 "Node didn't QI to script, but SVG wasn't disabled.");
499 // XHTML needs some special attention
500 if (aNodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
501 mPrettyPrintHasFactoredElements
= true;
503 // If we care, find out if we just used a special factory.
504 if (!mPrettyPrintHasFactoredElements
&& !mPrettyPrintHasSpecialRoot
&&
506 mPrettyPrintHasFactoredElements
=
507 nsNameSpaceManager::GetInstance()->HasElementCreator(
508 aNodeInfo
->NamespaceID());
511 if (!aNodeInfo
->NamespaceEquals(kNameSpaceID_SVG
)) {
512 content
.forget(aResult
);
518 if (aNodeInfo
->Equals(nsGkAtoms::link
, kNameSpaceID_XHTML
) ||
519 aNodeInfo
->Equals(nsGkAtoms::style
, kNameSpaceID_XHTML
) ||
520 aNodeInfo
->Equals(nsGkAtoms::style
, kNameSpaceID_SVG
)) {
521 if (auto* linkStyle
= LinkStyle::FromNode(*content
)) {
523 linkStyle
->SetEnableUpdates(false);
525 if (!aNodeInfo
->Equals(nsGkAtoms::link
, kNameSpaceID_XHTML
)) {
526 linkStyle
->SetLineNumber(aFromParser
? aLineNumber
: 0);
527 linkStyle
->SetColumnNumber(aFromParser
? aColumnNumber
: 0);
532 content
.forget(aResult
);
537 nsresult
nsXMLContentSink::CloseElement(nsIContent
* aContent
) {
538 NS_ASSERTION(aContent
, "missing element to close");
540 mozilla::dom::NodeInfo
* nodeInfo
= aContent
->NodeInfo();
542 // Some HTML nodes need DoneAddingChildren() called to initialize
543 // properly (eg form state restoration).
544 if (nsIContent::RequiresDoneAddingChildren(nodeInfo
->NamespaceID(),
545 nodeInfo
->NameAtom())) {
546 aContent
->DoneAddingChildren(HaveNotifiedForCurrentContent());
549 if (IsMonolithicContainer(nodeInfo
)) {
550 mInMonolithicContainer
--;
553 if (!nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
) &&
554 !nodeInfo
->NamespaceEquals(kNameSpaceID_SVG
)) {
558 if (nodeInfo
->Equals(nsGkAtoms::script
, kNameSpaceID_XHTML
) ||
559 nodeInfo
->Equals(nsGkAtoms::script
, kNameSpaceID_SVG
)) {
560 nsCOMPtr
<nsIScriptElement
> sele
= do_QueryInterface(aContent
);
562 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled
,
563 "Node didn't QI to script, but SVG wasn't disabled.");
567 if (mPreventScriptExecution
) {
568 sele
->PreventExecution();
572 // Always check the clock in nsContentSink right after a script
575 // Now tell the script that it's ready to go. This may execute the script
576 // or return true, or neither if the script doesn't need executing.
577 bool block
= sele
->AttemptToExecute();
580 GetParser()->BlockParser();
583 // If the parser got blocked, make sure to return the appropriate rv.
584 // I'm not sure if this is actually needed or not.
585 if (!mParser
->IsParserEnabled()) {
590 return block
? NS_ERROR_HTMLPARSER_BLOCK
: NS_OK
;
594 if (nodeInfo
->Equals(nsGkAtoms::link
, kNameSpaceID_XHTML
) ||
595 nodeInfo
->Equals(nsGkAtoms::style
, kNameSpaceID_XHTML
) ||
596 nodeInfo
->Equals(nsGkAtoms::style
, kNameSpaceID_SVG
)) {
597 if (auto* linkStyle
= LinkStyle::FromNode(*aContent
)) {
598 linkStyle
->SetEnableUpdates(true);
600 linkStyle
->UpdateStyleSheet(mRunsToCompletion
? nullptr : this);
601 if (updateOrError
.isErr()) {
602 rv
= updateOrError
.unwrapErr();
603 } else if (updateOrError
.unwrap().ShouldBlock() && !mRunsToCompletion
) {
604 ++mPendingSheetCount
;
605 mScriptLoader
->AddParserBlockingScriptExecutionBlocker();
613 nsresult
nsXMLContentSink::AddContentAsLeaf(nsIContent
* aContent
) {
614 nsresult result
= NS_OK
;
616 if (mState
== eXMLContentSinkState_InProlog
) {
617 NS_ASSERTION(mDocument
, "Fragments have no prolog");
618 mDocumentChildren
.AppendElement(aContent
);
619 } else if (mState
== eXMLContentSinkState_InEpilog
) {
620 NS_ASSERTION(mDocument
, "Fragments have no epilog");
621 if (mXSLTProcessor
) {
622 mDocumentChildren
.AppendElement(aContent
);
624 mDocument
->AppendChildTo(aContent
, false, IgnoreErrors());
627 nsCOMPtr
<nsIContent
> parent
= GetCurrentContent();
631 parent
->AppendChildTo(aContent
, false, rv
);
632 result
= rv
.StealNSResult();
638 // Create an XML parser and an XSL content sink and start parsing
639 // the XSL stylesheet located at the given URI.
640 nsresult
nsXMLContentSink::LoadXSLStyleSheet(nsIURI
* aUrl
) {
641 nsCOMPtr
<nsIDocumentTransformer
> processor
= new txMozillaXSLTProcessor();
642 mDocument
->SetUseCounter(eUseCounter_custom_XSLStylesheet
);
644 processor
->SetTransformObserver(this);
646 if (NS_SUCCEEDED(processor
->LoadStyleSheet(aUrl
, mDocument
))) {
647 mXSLTProcessor
.swap(processor
);
650 // Intentionally ignore errors here, we should continue loading the
651 // XML document whether we're able to load the XSLT stylesheet or
657 nsresult
nsXMLContentSink::ProcessStyleLinkFromHeader(
658 const nsAString
& aHref
, bool aAlternate
, const nsAString
& aTitle
,
659 const nsAString
& aIntegrity
, const nsAString
& aType
,
660 const nsAString
& aMedia
, const nsAString
& aReferrerPolicy
) {
661 mPrettyPrintXML
= false;
664 if (mParser
) GetParser()->GetCommand(cmd
);
665 if (cmd
.EqualsASCII(kLoadAsData
))
666 return NS_OK
; // Do not load stylesheets when loading as data
669 nsresult rv
= MaybeProcessXSLTLink(nullptr, aHref
, aAlternate
, aType
, aType
,
670 aMedia
, aReferrerPolicy
, &wasXSLT
);
671 NS_ENSURE_SUCCESS(rv
, rv
);
677 // Otherwise fall through to nsContentSink to handle CSS Link headers.
678 return nsContentSink::ProcessStyleLinkFromHeader(
679 aHref
, aAlternate
, aTitle
, aIntegrity
, aType
, aMedia
, aReferrerPolicy
);
682 nsresult
nsXMLContentSink::MaybeProcessXSLTLink(
683 ProcessingInstruction
* aProcessingInstruction
, const nsAString
& aHref
,
684 bool aAlternate
, const nsAString
& aTitle
, const nsAString
& aType
,
685 const nsAString
& aMedia
, const nsAString
& aReferrerPolicy
, bool* aWasXSLT
) {
686 bool wasXSLT
= aType
.LowerCaseEqualsLiteral(TEXT_XSL
) ||
687 aType
.LowerCaseEqualsLiteral(APPLICATION_XSLT_XML
) ||
688 aType
.LowerCaseEqualsLiteral(TEXT_XML
) ||
689 aType
.LowerCaseEqualsLiteral(APPLICATION_XML
);
700 // don't load alternate XSLT
703 // LoadXSLStyleSheet needs a mDocShell.
708 nsCOMPtr
<nsIURI
> url
;
709 nsresult rv
= NS_NewURI(getter_AddRefs(url
), aHref
, nullptr,
710 mDocument
->GetDocBaseURI());
711 NS_ENSURE_SUCCESS(rv
, rv
);
714 nsIScriptSecurityManager
* secMan
= nsContentUtils::GetSecurityManager();
715 rv
= secMan
->CheckLoadURIWithPrincipal(mDocument
->NodePrincipal(), url
,
716 nsIScriptSecurityManager::ALLOW_CHROME
,
717 mDocument
->InnerWindowID());
718 NS_ENSURE_SUCCESS(rv
, NS_OK
);
720 nsCOMPtr
<nsILoadInfo
> secCheckLoadInfo
=
721 new net::LoadInfo(mDocument
->NodePrincipal(), // loading principal
722 mDocument
->NodePrincipal(), // triggering principal
723 aProcessingInstruction
,
724 nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK
,
725 nsIContentPolicy::TYPE_XSLT
);
727 // Do content policy check
728 int16_t decision
= nsIContentPolicy::ACCEPT
;
729 rv
= NS_CheckContentLoadPolicy(url
, secCheckLoadInfo
,
730 NS_ConvertUTF16toUTF8(aType
), &decision
,
731 nsContentUtils::GetContentPolicy());
733 NS_ENSURE_SUCCESS(rv
, rv
);
735 if (NS_CP_REJECTED(decision
)) {
739 return LoadXSLStyleSheet(url
);
742 void nsXMLContentSink::SetDocumentCharset(NotNull
<const Encoding
*> aEncoding
) {
744 mDocument
->SetDocumentCharacterSet(aEncoding
);
748 nsISupports
* nsXMLContentSink::GetTarget() { return ToSupports(mDocument
); }
750 bool nsXMLContentSink::IsScriptExecuting() { return IsScriptExecutingImpl(); }
752 nsresult
nsXMLContentSink::FlushText(bool aReleaseTextNode
) {
755 if (mTextLength
!= 0) {
757 bool notify
= HaveNotifiedForCurrentContent();
758 // We could probably always increase mInNotification here since
759 // if AppendText doesn't notify it shouldn't trigger evil code.
760 // But just in case it does, we don't want to mask any notifications.
764 rv
= mLastTextNode
->AppendText(mText
, mTextLength
, notify
);
771 RefPtr
<nsTextNode
> textContent
=
772 new (mNodeInfoManager
) nsTextNode(mNodeInfoManager
);
774 mLastTextNode
= textContent
;
776 // Set the text in the text node
777 textContent
->SetText(mText
, mTextLength
, false);
780 // Add text to its parent
781 rv
= AddContentAsLeaf(textContent
);
785 if (aReleaseTextNode
) {
786 mLastTextNode
= nullptr;
792 nsIContent
* nsXMLContentSink::GetCurrentContent() {
793 if (mContentStack
.Length() == 0) {
796 return GetCurrentStackNode()->mContent
;
799 nsXMLContentSink::StackNode
* nsXMLContentSink::GetCurrentStackNode() {
800 int32_t count
= mContentStack
.Length();
801 return count
!= 0 ? &mContentStack
[count
- 1] : nullptr;
804 nsresult
nsXMLContentSink::PushContent(nsIContent
* aContent
) {
805 MOZ_ASSERT(aContent
, "Null content being pushed!");
806 StackNode
* sn
= mContentStack
.AppendElement();
807 NS_ENSURE_TRUE(sn
, NS_ERROR_OUT_OF_MEMORY
);
809 nsIContent
* contentToPush
= aContent
;
811 // When an XML parser would append a node to a template element, it
812 // must instead append it to the template element's template contents.
813 if (contentToPush
->IsHTMLElement(nsGkAtoms::_template
)) {
814 HTMLTemplateElement
* templateElement
=
815 static_cast<HTMLTemplateElement
*>(contentToPush
);
816 contentToPush
= templateElement
->Content();
819 sn
->mContent
= contentToPush
;
824 void nsXMLContentSink::PopContent() {
825 if (mContentStack
.IsEmpty()) {
826 NS_WARNING("Popping empty stack");
830 mContentStack
.RemoveLastElement();
833 bool nsXMLContentSink::HaveNotifiedForCurrentContent() const {
834 uint32_t stackLength
= mContentStack
.Length();
836 const StackNode
& stackNode
= mContentStack
[stackLength
- 1];
837 nsIContent
* parent
= stackNode
.mContent
;
838 return stackNode
.mNumFlushed
== parent
->GetChildCount();
843 void nsXMLContentSink::MaybeStartLayout(bool aIgnorePendingSheets
) {
844 // XXXbz if aIgnorePendingSheets is true, what should we do when
845 // mXSLTProcessor or CanStillPrettyPrint()?
846 if (mLayoutStarted
|| mXSLTProcessor
|| CanStillPrettyPrint()) {
849 StartLayout(aIgnorePendingSheets
);
852 ////////////////////////////////////////////////////////////////////////
854 bool nsXMLContentSink::SetDocElement(int32_t aNameSpaceID
, nsAtom
* aTagName
,
855 nsIContent
* aContent
) {
856 if (mDocElement
) return false;
858 mDocElement
= aContent
;
860 if (mXSLTProcessor
) {
861 mDocumentChildren
.AppendElement(aContent
);
865 if (!mDocumentChildren
.IsEmpty()) {
866 for (nsIContent
* child
: mDocumentChildren
) {
867 mDocument
->AppendChildTo(child
, false, IgnoreErrors());
869 mDocumentChildren
.Clear();
872 // check for root elements that needs special handling for
874 if (aNameSpaceID
== kNameSpaceID_XSLT
&&
875 (aTagName
== nsGkAtoms::stylesheet
|| aTagName
== nsGkAtoms::transform
)) {
876 mPrettyPrintHasSpecialRoot
= true;
877 if (mPrettyPrintXML
) {
878 // In this case, disable script execution, stylesheet
879 // loading, and auto XLinks since we plan to prettyprint.
880 mDocument
->ScriptLoader()->SetEnabled(false);
882 mCSSLoader
->SetEnabled(false);
887 IgnoredErrorResult rv
;
888 mDocument
->AppendChildTo(mDocElement
, NotifyForDocElement(), rv
);
890 // If we return false here, the caller will bail out because it won't
891 // find a parent content node to append to, which is fine.
899 nsXMLContentSink::HandleStartElement(const char16_t
* aName
,
900 const char16_t
** aAtts
,
901 uint32_t aAttsCount
, uint32_t aLineNumber
,
902 uint32_t aColumnNumber
) {
903 return HandleStartElement(aName
, aAtts
, aAttsCount
, aLineNumber
,
904 aColumnNumber
, true);
907 nsresult
nsXMLContentSink::HandleStartElement(
908 const char16_t
* aName
, const char16_t
** aAtts
, uint32_t aAttsCount
,
909 uint32_t aLineNumber
, uint32_t aColumnNumber
, bool aInterruptable
) {
910 MOZ_ASSERT(aAttsCount
% 2 == 0, "incorrect aAttsCount");
911 // Adjust aAttsCount so it's the actual number of attributes
914 nsresult result
= NS_OK
;
915 bool appendContent
= true;
916 nsCOMPtr
<nsIContent
> content
;
918 // XXX Hopefully the parser will flag this before we get
919 // here. If we're in the epilog, there should be no
921 MOZ_ASSERT(eXMLContentSinkState_InEpilog
!= mState
);
926 mState
= eXMLContentSinkState_InDocumentElement
;
929 RefPtr
<nsAtom
> prefix
, localName
;
930 nsContentUtils::SplitExpatName(aName
, getter_AddRefs(prefix
),
931 getter_AddRefs(localName
), &nameSpaceID
);
933 if (!OnOpenContainer(aAtts
, aAttsCount
, nameSpaceID
, localName
,
938 RefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
939 nodeInfo
= mNodeInfoManager
->GetNodeInfo(localName
, prefix
, nameSpaceID
,
940 nsINode::ELEMENT_NODE
);
942 result
= CreateElement(aAtts
, aAttsCount
, nodeInfo
, aLineNumber
,
943 aColumnNumber
, getter_AddRefs(content
), &appendContent
,
944 FROM_PARSER_NETWORK
);
945 NS_ENSURE_SUCCESS(result
, result
);
947 // Have to do this before we push the new content on the stack... and have to
948 // do that before we set attributes, call BindToTree, etc. Ideally we'd push
949 // on the stack inside CreateElement (which is effectively what the HTML sink
950 // does), but that's hard with all the subclass overrides going on.
951 nsCOMPtr
<nsIContent
> parent
= GetCurrentContent();
953 result
= PushContent(content
);
954 NS_ENSURE_SUCCESS(result
, result
);
956 // Set the attributes on the new content element
957 result
= AddAttributes(aAtts
, content
->AsElement());
959 if (NS_OK
== result
) {
961 if (!SetDocElement(nameSpaceID
, localName
, content
) && appendContent
) {
962 NS_ENSURE_TRUE(parent
, NS_ERROR_UNEXPECTED
);
964 parent
->AppendChildTo(content
, false, IgnoreErrors());
968 // Some HTML nodes need DoneCreatingElement() called to initialize
969 // properly (eg form state restoration).
970 if (nsIContent::RequiresDoneCreatingElement(nodeInfo
->NamespaceID(),
971 nodeInfo
->NameAtom())) {
972 content
->DoneCreatingElement();
975 if (nodeInfo
->NamespaceID() == kNameSpaceID_XHTML
&&
976 nodeInfo
->NameAtom() == nsGkAtoms::head
&& !mCurrentHead
) {
977 mCurrentHead
= content
;
980 if (IsMonolithicContainer(nodeInfo
)) {
981 mInMonolithicContainer
++;
984 if (!mXSLTProcessor
) {
985 if (content
== mDocElement
) {
986 nsContentUtils::AddScriptRunner(
987 new nsDocElementCreatedNotificationRunner(mDocument
));
989 if (aInterruptable
&& NS_SUCCEEDED(result
) && mParser
&&
990 !mParser
->IsParserEnabled()) {
991 return NS_ERROR_HTMLPARSER_BLOCK
;
993 } else if (!mCurrentHead
) {
994 // This isn't the root and we're not inside an XHTML <head>.
995 // Might need to start layout
996 MaybeStartLayout(false);
1000 return aInterruptable
&& NS_SUCCEEDED(result
) ? DidProcessATokenImpl()
1005 nsXMLContentSink::HandleEndElement(const char16_t
* aName
) {
1006 return HandleEndElement(aName
, true);
1009 nsresult
nsXMLContentSink::HandleEndElement(const char16_t
* aName
,
1010 bool aInterruptable
) {
1011 nsresult result
= NS_OK
;
1013 // XXX Hopefully the parser will flag this before we get
1014 // here. If we're in the prolog or epilog, there should be
1015 // no close tags for elements.
1016 MOZ_ASSERT(eXMLContentSinkState_InDocumentElement
== mState
);
1020 StackNode
* sn
= GetCurrentStackNode();
1022 return NS_ERROR_UNEXPECTED
;
1025 nsCOMPtr
<nsIContent
> content
;
1026 sn
->mContent
.swap(content
);
1027 uint32_t numFlushed
= sn
->mNumFlushed
;
1030 NS_ASSERTION(content
, "failed to pop content");
1032 // Check that we're closing the right thing
1033 RefPtr
<nsAtom
> debugNameSpacePrefix
, debugTagAtom
;
1034 int32_t debugNameSpaceID
;
1035 nsContentUtils::SplitExpatName(aName
, getter_AddRefs(debugNameSpacePrefix
),
1036 getter_AddRefs(debugTagAtom
),
1038 // Check if we are closing a template element because template
1039 // elements do not get pushed on the stack, the template
1040 // element content is pushed instead.
1041 bool isTemplateElement
= debugTagAtom
== nsGkAtoms::_template
&&
1042 debugNameSpaceID
== kNameSpaceID_XHTML
;
1044 content
->NodeInfo()->Equals(debugTagAtom
, debugNameSpaceID
) ||
1045 (debugNameSpaceID
== kNameSpaceID_MathML
&&
1046 content
->NodeInfo()->NamespaceID() == kNameSpaceID_disabled_MathML
&&
1047 content
->NodeInfo()->Equals(debugTagAtom
)) ||
1048 (debugNameSpaceID
== kNameSpaceID_SVG
&&
1049 content
->NodeInfo()->NamespaceID() == kNameSpaceID_disabled_SVG
&&
1050 content
->NodeInfo()->Equals(debugTagAtom
)) ||
1052 "Wrong element being closed");
1055 // Make sure to notify on our kids before we call out to any other code that
1056 // might reenter us and call FlushTags, in a state in which we've already
1057 // popped "content" from the stack but haven't notified on its kids yet.
1058 int32_t stackLen
= mContentStack
.Length();
1059 if (mNotifyLevel
>= stackLen
) {
1060 if (numFlushed
< content
->GetChildCount()) {
1061 NotifyAppend(content
, numFlushed
);
1063 mNotifyLevel
= stackLen
- 1;
1066 result
= CloseElement(content
);
1068 if (mCurrentHead
== content
) {
1069 mCurrentHead
= nullptr;
1072 if (mDocElement
== content
) {
1073 // XXXbz for roots that don't want to be appended on open, we
1074 // probably need to deal here.... (and stop appending them on open).
1075 mState
= eXMLContentSinkState_InEpilog
;
1077 mDocument
->OnParsingCompleted();
1079 // We might have had no occasion to start layout yet. Do so now.
1080 MaybeStartLayout(false);
1085 if (content
->IsSVGElement(nsGkAtoms::svg
)) {
1087 nsCOMPtr
<nsIRunnable
> event
= new nsHtml5SVGLoadDispatcher(content
);
1088 if (NS_FAILED(content
->OwnerDoc()->Dispatch(TaskCategory::Other
,
1090 NS_WARNING("failed to dispatch svg load dispatcher");
1094 return aInterruptable
&& NS_SUCCEEDED(result
) ? DidProcessATokenImpl()
1099 nsXMLContentSink::HandleComment(const char16_t
* aName
) {
1102 RefPtr
<Comment
> comment
= new (mNodeInfoManager
) Comment(mNodeInfoManager
);
1103 comment
->SetText(nsDependentString(aName
), false);
1104 nsresult rv
= AddContentAsLeaf(comment
);
1107 return NS_SUCCEEDED(rv
) ? DidProcessATokenImpl() : rv
;
1111 nsXMLContentSink::HandleCDataSection(const char16_t
* aData
, uint32_t aLength
) {
1112 // XSLT doesn't differentiate between text and cdata and wants adjacent
1113 // textnodes merged, so add as text.
1114 if (mXSLTProcessor
) {
1115 return AddText(aData
, aLength
);
1120 RefPtr
<CDATASection
> cdata
=
1121 new (mNodeInfoManager
) CDATASection(mNodeInfoManager
);
1122 cdata
->SetText(aData
, aLength
, false);
1123 nsresult rv
= AddContentAsLeaf(cdata
);
1126 return NS_SUCCEEDED(rv
) ? DidProcessATokenImpl() : rv
;
1130 nsXMLContentSink::HandleDoctypeDecl(const nsAString
& aSubset
,
1131 const nsAString
& aName
,
1132 const nsAString
& aSystemId
,
1133 const nsAString
& aPublicId
,
1134 nsISupports
* aCatalogData
) {
1137 NS_ASSERTION(mDocument
, "Shouldn't get here from a document fragment");
1139 RefPtr
<nsAtom
> name
= NS_Atomize(aName
);
1140 NS_ENSURE_TRUE(name
, NS_ERROR_OUT_OF_MEMORY
);
1142 // Create a new doctype node
1143 RefPtr
<DocumentType
> docType
= NS_NewDOMDocumentType(
1144 mNodeInfoManager
, name
, aPublicId
, aSystemId
, aSubset
);
1146 MOZ_ASSERT(!aCatalogData
,
1147 "Need to add back support for catalog style "
1150 mDocumentChildren
.AppendElement(docType
);
1152 return DidProcessATokenImpl();
1156 nsXMLContentSink::HandleCharacterData(const char16_t
* aData
, uint32_t aLength
) {
1157 return HandleCharacterData(aData
, aLength
, true);
1160 nsresult
nsXMLContentSink::HandleCharacterData(const char16_t
* aData
,
1162 bool aInterruptable
) {
1163 nsresult rv
= NS_OK
;
1164 if (aData
&& mState
!= eXMLContentSinkState_InProlog
&&
1165 mState
!= eXMLContentSinkState_InEpilog
) {
1166 rv
= AddText(aData
, aLength
);
1168 return aInterruptable
&& NS_SUCCEEDED(rv
) ? DidProcessATokenImpl() : rv
;
1172 nsXMLContentSink::HandleProcessingInstruction(const char16_t
* aTarget
,
1173 const char16_t
* aData
) {
1176 const nsDependentString
target(aTarget
);
1177 const nsDependentString
data(aData
);
1179 RefPtr
<ProcessingInstruction
> node
=
1180 NS_NewXMLProcessingInstruction(mNodeInfoManager
, target
, data
);
1182 auto* linkStyle
= LinkStyle::FromNode(*node
);
1184 linkStyle
->SetEnableUpdates(false);
1185 mPrettyPrintXML
= false;
1188 nsresult rv
= AddContentAsLeaf(node
);
1189 NS_ENSURE_SUCCESS(rv
, rv
);
1193 // This is an xml-stylesheet processing instruction... but it might not be
1194 // a CSS one if the type is set to something else.
1195 linkStyle
->SetEnableUpdates(true);
1196 auto updateOrError
=
1197 linkStyle
->UpdateStyleSheet(mRunsToCompletion
? nullptr : this);
1198 if (updateOrError
.isErr()) {
1199 return updateOrError
.unwrapErr();
1202 auto update
= updateOrError
.unwrap();
1203 if (update
.WillNotify()) {
1204 // Successfully started a stylesheet load
1205 if (update
.ShouldBlock() && !mRunsToCompletion
) {
1206 ++mPendingSheetCount
;
1207 mScriptLoader
->AddParserBlockingScriptExecutionBlocker();
1213 // Check whether this is a CSS stylesheet PI. Make sure the type
1214 // handling here matches
1215 // XMLStylesheetProcessingInstruction::GetStyleSheetInfo.
1217 nsContentUtils::GetPseudoAttributeValue(data
, nsGkAtoms::type
, type
);
1218 nsAutoString mimeType
, notUsed
;
1219 nsContentUtils::SplitMimeType(type
, mimeType
, notUsed
);
1221 if (mState
!= eXMLContentSinkState_InProlog
||
1222 !target
.EqualsLiteral("xml-stylesheet") || mimeType
.IsEmpty() ||
1223 mimeType
.LowerCaseEqualsLiteral("text/css")) {
1224 // Either not a useful stylesheet PI, or a CSS stylesheet PI that
1225 // got handled above by the "ssle" bits. We're done here.
1226 return DidProcessATokenImpl();
1229 // If it's not a CSS stylesheet PI...
1230 nsAutoString href
, title
, media
;
1231 bool isAlternate
= false;
1233 // If there was no href, we can't do anything with this PI
1234 if (!ParsePIData(data
, href
, title
, media
, isAlternate
)) {
1235 return DidProcessATokenImpl();
1238 // <?xml-stylesheet?> processing instructions don't have a referrerpolicy
1239 // pseudo-attribute, so we pass in an empty string
1241 MaybeProcessXSLTLink(node
, href
, isAlternate
, title
, type
, media
, u
""_ns
);
1242 return NS_SUCCEEDED(rv
) ? DidProcessATokenImpl() : rv
;
1246 bool nsXMLContentSink::ParsePIData(const nsString
& aData
, nsString
& aHref
,
1247 nsString
& aTitle
, nsString
& aMedia
,
1248 bool& aIsAlternate
) {
1249 // If there was no href, we can't do anything with this PI
1250 if (!nsContentUtils::GetPseudoAttributeValue(aData
, nsGkAtoms::href
, aHref
)) {
1254 nsContentUtils::GetPseudoAttributeValue(aData
, nsGkAtoms::title
, aTitle
);
1256 nsContentUtils::GetPseudoAttributeValue(aData
, nsGkAtoms::media
, aMedia
);
1258 nsAutoString alternate
;
1259 nsContentUtils::GetPseudoAttributeValue(aData
, nsGkAtoms::alternate
,
1262 aIsAlternate
= alternate
.EqualsLiteral("yes");
1268 nsXMLContentSink::HandleXMLDeclaration(const char16_t
* aVersion
,
1269 const char16_t
* aEncoding
,
1270 int32_t aStandalone
) {
1271 mDocument
->SetXMLDeclaration(aVersion
, aEncoding
, aStandalone
);
1273 return DidProcessATokenImpl();
1277 nsXMLContentSink::ReportError(const char16_t
* aErrorText
,
1278 const char16_t
* aSourceText
,
1279 nsIScriptError
* aError
, bool* _retval
) {
1280 MOZ_ASSERT(aError
&& aSourceText
&& aErrorText
, "Check arguments!!!");
1281 nsresult rv
= NS_OK
;
1283 // The expat driver should report the error. We're just cleaning up the mess.
1286 mPrettyPrintXML
= false;
1288 mState
= eXMLContentSinkState_InProlog
;
1290 // XXX need to stop scripts here -- hsivonen
1292 // stop observing in order to avoid crashing when removing content
1293 mDocument
->RemoveObserver(this);
1294 mIsDocumentObserver
= false;
1296 // Clear the current content
1297 mDocumentChildren
.Clear();
1298 while (mDocument
->GetLastChild()) {
1299 mDocument
->GetLastChild()->Remove();
1301 mDocElement
= nullptr;
1303 // Clear any buffered-up text we have. It's enough to set the length to 0.
1304 // The buffer itself is allocated when we're created and deleted in our
1305 // destructor, so don't mess with it.
1308 if (mXSLTProcessor
) {
1309 // Get rid of the XSLT processor.
1310 mXSLTProcessor
->CancelLoads();
1311 mXSLTProcessor
= nullptr;
1314 // release the nodes on stack
1315 mContentStack
.Clear();
1318 // return leaving the document empty if we're asked to not add a <parsererror>
1320 if (mDocument
->SuppressParserErrorElement()) {
1324 // prepare to set <parsererror> as the document root
1325 rv
= HandleProcessingInstruction(
1327 u
"href=\"chrome://global/locale/intl.css\" type=\"text/css\"");
1328 NS_ENSURE_SUCCESS(rv
, rv
);
1330 const char16_t
* noAtts
[] = {0, 0};
1332 constexpr auto errorNs
=
1333 u
"http://www.mozilla.org/newlayout/xml/parsererror.xml"_ns
;
1335 nsAutoString
parsererror(errorNs
);
1336 parsererror
.Append((char16_t
)0xFFFF);
1337 parsererror
.AppendLiteral("parsererror");
1339 rv
= HandleStartElement(parsererror
.get(), noAtts
, 0, (uint32_t)-1, false);
1340 NS_ENSURE_SUCCESS(rv
, rv
);
1342 rv
= HandleCharacterData(aErrorText
, NS_strlen(aErrorText
), false);
1343 NS_ENSURE_SUCCESS(rv
, rv
);
1345 nsAutoString
sourcetext(errorNs
);
1346 sourcetext
.Append((char16_t
)0xFFFF);
1347 sourcetext
.AppendLiteral("sourcetext");
1349 rv
= HandleStartElement(sourcetext
.get(), noAtts
, 0, (uint32_t)-1, false);
1350 NS_ENSURE_SUCCESS(rv
, rv
);
1352 rv
= HandleCharacterData(aSourceText
, NS_strlen(aSourceText
), false);
1353 NS_ENSURE_SUCCESS(rv
, rv
);
1355 rv
= HandleEndElement(sourcetext
.get(), false);
1356 NS_ENSURE_SUCCESS(rv
, rv
);
1358 rv
= HandleEndElement(parsererror
.get(), false);
1359 NS_ENSURE_SUCCESS(rv
, rv
);
1366 nsresult
nsXMLContentSink::AddAttributes(const char16_t
** aAtts
,
1367 Element
* aContent
) {
1368 // Add tag attributes to the content attributes
1369 RefPtr
<nsAtom
> prefix
, localName
;
1371 int32_t nameSpaceID
;
1372 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
1373 getter_AddRefs(localName
), &nameSpaceID
);
1375 // Add attribute to content
1376 aContent
->SetAttr(nameSpaceID
, localName
, prefix
,
1377 nsDependentString(aAtts
[1]), false);
1384 #define NS_ACCUMULATION_BUFFER_SIZE 4096
1386 nsresult
nsXMLContentSink::AddText(const char16_t
* aText
, int32_t aLength
) {
1387 // Copy data from string into our buffer; flush buffer when it fills up.
1389 while (0 != aLength
) {
1390 int32_t amount
= NS_ACCUMULATION_BUFFER_SIZE
- mTextLength
;
1392 nsresult rv
= FlushText(false);
1393 if (NS_WARN_IF(NS_FAILED(rv
))) {
1396 MOZ_ASSERT(mTextLength
== 0);
1397 amount
= NS_ACCUMULATION_BUFFER_SIZE
;
1400 if (amount
> aLength
) {
1403 memcpy(&mText
[mTextLength
], &aText
[offset
], sizeof(char16_t
) * amount
);
1404 mTextLength
+= amount
;
1412 void nsXMLContentSink::InitialTranslationCompleted() { StartLayout(false); }
1414 void nsXMLContentSink::FlushPendingNotifications(FlushType aType
) {
1415 // Only flush tags if we're not doing the notification ourselves
1416 // (since we aren't reentrant)
1417 if (!mInNotification
) {
1418 if (mIsDocumentObserver
) {
1419 // Only flush if we're still a document observer (so that our child
1420 // counts should be correct).
1421 if (aType
>= FlushType::ContentAndNotify
) {
1427 if (aType
>= FlushType::EnsurePresShellInitAndFrames
) {
1428 // Make sure that layout has started so that the reflow flush
1429 // will actually happen.
1430 MaybeStartLayout(true);
1436 * NOTE!! Forked from SinkContext. Please keep in sync.
1438 * Flush all elements that have been seen so far such that
1439 * they are visible in the tree. Specifically, make sure
1440 * that they are all added to their respective parents.
1441 * Also, do notification at the top for all content that
1442 * has been newly added so that the frame tree is complete.
1444 nsresult
nsXMLContentSink::FlushTags() {
1445 mDeferredFlushTags
= false;
1446 uint32_t oldUpdates
= mUpdatesInNotification
;
1448 mUpdatesInNotification
= 0;
1451 // Scope so we call EndUpdate before we decrease mInNotification
1452 mozAutoDocUpdate
updateBatch(mDocument
, true);
1454 // Don't release last text node in case we need to add to it again
1457 // Start from the base of the stack (growing downward) and do
1458 // a notification from the node that is closest to the root of
1459 // tree for any content that has been added.
1462 int32_t stackLen
= mContentStack
.Length();
1463 bool flushed
= false;
1464 uint32_t childCount
;
1465 nsIContent
* content
;
1467 for (stackPos
= 0; stackPos
< stackLen
; ++stackPos
) {
1468 content
= mContentStack
[stackPos
].mContent
;
1469 childCount
= content
->GetChildCount();
1471 if (!flushed
&& (mContentStack
[stackPos
].mNumFlushed
< childCount
)) {
1472 NotifyAppend(content
, mContentStack
[stackPos
].mNumFlushed
);
1476 mContentStack
[stackPos
].mNumFlushed
= childCount
;
1478 mNotifyLevel
= stackLen
- 1;
1482 if (mUpdatesInNotification
> 1) {
1483 UpdateChildCounts();
1486 mUpdatesInNotification
= oldUpdates
;
1491 * NOTE!! Forked from SinkContext. Please keep in sync.
1493 void nsXMLContentSink::UpdateChildCounts() {
1494 // Start from the top of the stack (growing upwards) and see if any
1495 // new content has been appended. If so, we recognize that reflows
1496 // have been generated for it and we should make sure that no
1497 // further reflows occur. Note that we have to include stackPos == 0
1498 // to properly notify on kids of <html>.
1499 int32_t stackLen
= mContentStack
.Length();
1500 int32_t stackPos
= stackLen
- 1;
1501 while (stackPos
>= 0) {
1502 StackNode
& node
= mContentStack
[stackPos
];
1503 node
.mNumFlushed
= node
.mContent
->GetChildCount();
1507 mNotifyLevel
= stackLen
- 1;
1510 bool nsXMLContentSink::IsMonolithicContainer(
1511 mozilla::dom::NodeInfo
* aNodeInfo
) {
1512 return ((aNodeInfo
->NamespaceID() == kNameSpaceID_XHTML
&&
1513 (aNodeInfo
->NameAtom() == nsGkAtoms::tr
||
1514 aNodeInfo
->NameAtom() == nsGkAtoms::select
||
1515 aNodeInfo
->NameAtom() == nsGkAtoms::object
)) ||
1516 (aNodeInfo
->NamespaceID() == kNameSpaceID_MathML
&&
1517 (aNodeInfo
->NameAtom() == nsGkAtoms::math
)));
1520 void nsXMLContentSink::ContinueInterruptedParsingIfEnabled() {
1521 if (mParser
&& mParser
->IsParserEnabled()) {
1522 GetParser()->ContinueInterruptedParsing();
1526 void nsXMLContentSink::ContinueInterruptedParsingAsync() {
1527 nsCOMPtr
<nsIRunnable
> ev
= NewRunnableMethod(
1528 "nsXMLContentSink::ContinueInterruptedParsingIfEnabled", this,
1529 &nsXMLContentSink::ContinueInterruptedParsingIfEnabled
);
1531 mDocument
->Dispatch(mozilla::TaskCategory::Other
, ev
.forget());
1534 nsIParser
* nsXMLContentSink::GetParser() {
1535 return static_cast<nsIParser
*>(mParser
.get());