Bug 1834993 - Fix nursery allocatable flag for objects with foreground finalizers...
[gecko.git] / dom / xml / nsXMLContentSink.cpp
blob4080a10b93fc5ffac98acc9e9f7cbf54a1c1b31a
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/. */
7 #include "nsCOMPtr.h"
8 #include "nsXMLContentSink.h"
9 #include "nsIParser.h"
10 #include "mozilla/dom/Document.h"
11 #include "nsIContent.h"
12 #include "nsIURI.h"
13 #include "nsNetUtil.h"
14 #include "nsHTMLParts.h"
15 #include "nsCRT.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"
26 #include "prtime.h"
27 #include "mozilla/Logging.h"
28 #include "nsRect.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"
38 #include "nsError.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;
60 // XXX Open Issues:
61 // 1) what's not allowed - We need to figure out which HTML tags
62 // (prefixed with a HTML namespace qualifier) are explicitly not
63 // allowed (if any).
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);
81 it.forget(aResult);
82 return NS_OK;
85 nsXMLContentSink::nsXMLContentSink()
86 : mState(eXMLContentSinkState_InProlog),
87 mTextLength(0),
88 mNotifyLevel(0),
89 mPrettyPrintXML(true),
90 mPrettyPrintHasSpecialRoot(0),
91 mPrettyPrintHasFactoredElements(0),
92 mPrettyPrinting(0),
93 mPreventScriptExecution(0) {
94 PodArrayZero(mText);
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;
107 if (!mDocShell) {
108 mPrettyPrintXML = false;
111 mState = eXMLContentSinkState_InProlog;
112 mDocElement = nullptr;
114 return NS_OK;
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)
142 // nsIContentSink
143 NS_IMETHODIMP
144 nsXMLContentSink::WillParse(void) { return WillParseImpl(); }
146 NS_IMETHODIMP
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;
162 return NS_OK;
165 bool nsXMLContentSink::CanStillPrettyPrint() {
166 return mPrettyPrintXML &&
167 (!mPrettyPrintHasFactoredElements || mPrettyPrintHasSpecialRoot);
170 nsresult nsXMLContentSink::MaybePrettyPrint() {
171 if (!CanStillPrettyPrint()) {
172 mPrettyPrintXML = false;
174 return NS_OK;
178 // Try to perform a microtask checkpoint; this avoids always breaking
179 // pretty-printing if webextensions insert new content right after the
180 // document loads.
181 nsAutoMicroTask mt;
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
189 if (mCSSLoader) {
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;
202 return NS_OK;
205 static void CheckXSLTParamPI(ProcessingInstruction* aPi,
206 nsIDocumentTransformer* aProcessor,
207 nsINode* aSource) {
208 nsAutoString target, data;
209 aPi->GetTarget(target);
211 // Check for namespace declarations
212 if (target.EqualsLiteral("xslt-param-namespace")) {
213 aPi->GetData(data);
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")) {
224 aPi->GetData(data);
225 nsAutoString name, namespaceAttr, select, value;
226 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name, name);
227 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
228 namespaceAttr);
229 if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select,
230 select)) {
231 select.SetIsVoid(true);
233 if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value,
234 value)) {
235 value.SetIsVoid(true);
237 if (!name.IsEmpty()) {
238 aProcessor->AddXSLTParam(name, namespaceAttr, select, value, aSource);
243 NS_IMETHODIMP
244 nsXMLContentSink::DidBuildModel(bool aTerminated) {
245 if (!mParser) {
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.
251 return NS_OK;
254 FlushTags();
256 DidBuildModelImpl(aTerminated);
258 if (mXSLTProcessor) {
259 // stop observing in order to avoid crashing when replacing content
260 mDocument->RemoveObserver(this);
261 mIsDocumentObserver = false;
263 ErrorResult rv;
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);
269 if (rv.Failed()) {
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
281 break;
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;
289 } else {
290 // Kick off layout for non-XSLT transformed documents.
292 // Check if we want to prettyprint
293 MaybePrettyPrint();
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
301 // stylesheet loads
302 if (mDocument->CSSLoader()->HasPendingLoads()) {
303 mDocument->CSSLoader()->AddObserver(this);
304 // wait for those sheets to load
305 startLayout = false;
309 if (startLayout) {
310 StartLayout(false);
312 ScrollToRef();
315 mDocument->RemoveObserver(this);
316 mIsDocumentObserver = false;
318 mDocument->EndLoad();
320 DropParserAndPerfHint();
323 return NS_OK;
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);
337 return NS_OK;
340 nsresult nsXMLContentSink::OnTransformDone(Document* aSourceDocument,
341 nsresult aResult,
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)) {
359 // Transform failed.
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
372 // display.
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
379 // documentElement?
380 nsIContent* rootElement = mDocument->GetRootElement();
381 if (rootElement) {
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
390 StartLayout(false);
392 ScrollToRef();
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();
412 return NS_OK;
415 NS_IMETHODIMP
416 nsXMLContentSink::StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
417 nsresult aStatus) {
418 if (!mPrettyPrinting) {
419 return nsContentSink::StyleSheetLoaded(aSheet, aWasDeferred, aStatus);
422 if (!mDocument->CSSLoader()->HasPendingLoads()) {
423 mDocument->CSSLoader()->RemoveObserver(this);
424 StartLayout(false);
425 ScrollToRef();
428 return NS_OK;
431 NS_IMETHODIMP
432 nsXMLContentSink::WillInterrupt(void) { return WillInterruptImpl(); }
434 void nsXMLContentSink::WillResume() { WillResumeImpl(); }
436 NS_IMETHODIMP
437 nsXMLContentSink::SetParser(nsParserBase* aParser) {
438 MOZ_ASSERT(aParser, "Should have a parser here!");
439 mParser = aParser;
440 return NS_OK;
443 static bool FindIsAttrValue(const char16_t** aAtts, const char16_t** aResult) {
444 RefPtr<nsAtom> prefix, localName;
445 for (; *aAtts; aAtts += 2) {
446 int32_t nameSpaceID;
447 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
448 getter_AddRefs(localName), &nameSpaceID);
449 if (nameSpaceID == kNameSpaceID_None && localName == nsGkAtoms::is) {
450 *aResult = aAtts[1];
452 return true;
456 return false;
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");
466 *aResult = nullptr;
467 *aAppendContent = true;
468 nsresult rv = NS_OK;
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,
479 &isStr);
480 } else {
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);
489 if (sele) {
490 sele->SetScriptLineNumber(aLineNumber);
491 sele->SetScriptColumnNumber(aColumnNumber);
492 sele->SetCreatorParser(GetParser());
493 } else {
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;
502 } else {
503 // If we care, find out if we just used a special factory.
504 if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
505 mPrettyPrintXML) {
506 mPrettyPrintHasFactoredElements =
507 nsNameSpaceManager::GetInstance()->HasElementCreator(
508 aNodeInfo->NamespaceID());
511 if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
512 content.forget(aResult);
514 return NS_OK;
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)) {
522 if (aFromParser) {
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);
534 return NS_OK;
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)) {
555 return NS_OK;
558 if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
559 nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)) {
560 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
561 if (!sele) {
562 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
563 "Node didn't QI to script, but SVG wasn't disabled.");
564 return NS_OK;
567 if (mPreventScriptExecution) {
568 sele->PreventExecution();
569 return NS_OK;
572 // Always check the clock in nsContentSink right after a script
573 StopDeflecting();
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();
578 if (mParser) {
579 if (block) {
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()) {
586 block = true;
590 return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
593 nsresult rv = 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);
599 auto updateOrError =
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();
610 return rv;
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);
623 } else {
624 mDocument->AppendChildTo(aContent, false, IgnoreErrors());
626 } else {
627 nsCOMPtr<nsIContent> parent = GetCurrentContent();
629 if (parent) {
630 ErrorResult rv;
631 parent->AppendChildTo(aContent, false, rv);
632 result = rv.StealNSResult();
635 return result;
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
652 // not.
654 return NS_OK;
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;
663 nsAutoCString cmd;
664 if (mParser) GetParser()->GetCommand(cmd);
665 if (cmd.EqualsASCII(kLoadAsData))
666 return NS_OK; // Do not load stylesheets when loading as data
668 bool wasXSLT;
669 nsresult rv = MaybeProcessXSLTLink(nullptr, aHref, aAlternate, aType, aType,
670 aMedia, aReferrerPolicy, &wasXSLT);
671 NS_ENSURE_SUCCESS(rv, rv);
672 if (wasXSLT) {
673 // We're done here.
674 return NS_OK;
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);
691 if (aWasXSLT) {
692 *aWasXSLT = wasXSLT;
695 if (!wasXSLT) {
696 return NS_OK;
699 if (aAlternate) {
700 // don't load alternate XSLT
701 return NS_OK;
703 // LoadXSLStyleSheet needs a mDocShell.
704 if (!mDocShell) {
705 return NS_OK;
708 nsCOMPtr<nsIURI> url;
709 nsresult rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
710 mDocument->GetDocBaseURI());
711 NS_ENSURE_SUCCESS(rv, rv);
713 // Do security check
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)) {
736 return NS_OK;
739 return LoadXSLStyleSheet(url);
742 void nsXMLContentSink::SetDocumentCharset(NotNull<const Encoding*> aEncoding) {
743 if (mDocument) {
744 mDocument->SetDocumentCharacterSet(aEncoding);
748 nsISupports* nsXMLContentSink::GetTarget() { return ToSupports(mDocument); }
750 bool nsXMLContentSink::IsScriptExecuting() { return IsScriptExecutingImpl(); }
752 nsresult nsXMLContentSink::FlushText(bool aReleaseTextNode) {
753 nsresult rv = NS_OK;
755 if (mTextLength != 0) {
756 if (mLastTextNode) {
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.
761 if (notify) {
762 ++mInNotification;
764 rv = mLastTextNode->AppendText(mText, mTextLength, notify);
765 if (notify) {
766 --mInNotification;
769 mTextLength = 0;
770 } else {
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);
778 mTextLength = 0;
780 // Add text to its parent
781 rv = AddContentAsLeaf(textContent);
785 if (aReleaseTextNode) {
786 mLastTextNode = nullptr;
789 return rv;
792 nsIContent* nsXMLContentSink::GetCurrentContent() {
793 if (mContentStack.Length() == 0) {
794 return nullptr;
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;
820 sn->mNumFlushed = 0;
821 return NS_OK;
824 void nsXMLContentSink::PopContent() {
825 if (mContentStack.IsEmpty()) {
826 NS_WARNING("Popping empty stack");
827 return;
830 mContentStack.RemoveLastElement();
833 bool nsXMLContentSink::HaveNotifiedForCurrentContent() const {
834 uint32_t stackLength = mContentStack.Length();
835 if (stackLength) {
836 const StackNode& stackNode = mContentStack[stackLength - 1];
837 nsIContent* parent = stackNode.mContent;
838 return stackNode.mNumFlushed == parent->GetChildCount();
840 return true;
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()) {
847 return;
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);
862 return true;
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
873 // prettyprinting
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);
881 if (mCSSLoader) {
882 mCSSLoader->SetEnabled(false);
887 IgnoredErrorResult rv;
888 mDocument->AppendChildTo(mDocElement, NotifyForDocElement(), rv);
889 if (rv.Failed()) {
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.
892 return false;
895 return true;
898 NS_IMETHODIMP
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
912 aAttsCount /= 2;
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
920 // new elements
921 MOZ_ASSERT(eXMLContentSinkState_InEpilog != mState);
923 FlushText();
924 DidAddContent();
926 mState = eXMLContentSinkState_InDocumentElement;
928 int32_t nameSpaceID;
929 RefPtr<nsAtom> prefix, localName;
930 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
931 getter_AddRefs(localName), &nameSpaceID);
933 if (!OnOpenContainer(aAtts, aAttsCount, nameSpaceID, localName,
934 aLineNumber)) {
935 return NS_OK;
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) {
960 // Store the element
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()
1001 : result;
1004 NS_IMETHODIMP
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);
1018 FlushText();
1020 StackNode* sn = GetCurrentStackNode();
1021 if (!sn) {
1022 return NS_ERROR_UNEXPECTED;
1025 nsCOMPtr<nsIContent> content;
1026 sn->mContent.swap(content);
1027 uint32_t numFlushed = sn->mNumFlushed;
1029 PopContent();
1030 NS_ASSERTION(content, "failed to pop content");
1031 #ifdef DEBUG
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),
1037 &debugNameSpaceID);
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;
1043 NS_ASSERTION(
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)) ||
1051 isTemplateElement,
1052 "Wrong element being closed");
1053 #endif
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);
1083 DidAddContent();
1085 if (content->IsSVGElement(nsGkAtoms::svg)) {
1086 FlushTags();
1087 nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(content);
1088 if (NS_FAILED(content->OwnerDoc()->Dispatch(TaskCategory::Other,
1089 event.forget()))) {
1090 NS_WARNING("failed to dispatch svg load dispatcher");
1094 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl()
1095 : result;
1098 NS_IMETHODIMP
1099 nsXMLContentSink::HandleComment(const char16_t* aName) {
1100 FlushText();
1102 RefPtr<Comment> comment = new (mNodeInfoManager) Comment(mNodeInfoManager);
1103 comment->SetText(nsDependentString(aName), false);
1104 nsresult rv = AddContentAsLeaf(comment);
1105 DidAddContent();
1107 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1110 NS_IMETHODIMP
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);
1118 FlushText();
1120 RefPtr<CDATASection> cdata =
1121 new (mNodeInfoManager) CDATASection(mNodeInfoManager);
1122 cdata->SetText(aData, aLength, false);
1123 nsresult rv = AddContentAsLeaf(cdata);
1124 DidAddContent();
1126 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1129 NS_IMETHODIMP
1130 nsXMLContentSink::HandleDoctypeDecl(const nsAString& aSubset,
1131 const nsAString& aName,
1132 const nsAString& aSystemId,
1133 const nsAString& aPublicId,
1134 nsISupports* aCatalogData) {
1135 FlushText();
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 "
1148 "sheets");
1150 mDocumentChildren.AppendElement(docType);
1151 DidAddContent();
1152 return DidProcessATokenImpl();
1155 NS_IMETHODIMP
1156 nsXMLContentSink::HandleCharacterData(const char16_t* aData, uint32_t aLength) {
1157 return HandleCharacterData(aData, aLength, true);
1160 nsresult nsXMLContentSink::HandleCharacterData(const char16_t* aData,
1161 uint32_t aLength,
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;
1171 NS_IMETHODIMP
1172 nsXMLContentSink::HandleProcessingInstruction(const char16_t* aTarget,
1173 const char16_t* aData) {
1174 FlushText();
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);
1183 if (linkStyle) {
1184 linkStyle->SetEnableUpdates(false);
1185 mPrettyPrintXML = false;
1188 nsresult rv = AddContentAsLeaf(node);
1189 NS_ENSURE_SUCCESS(rv, rv);
1190 DidAddContent();
1192 if (linkStyle) {
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();
1209 return NS_OK;
1213 // Check whether this is a CSS stylesheet PI. Make sure the type
1214 // handling here matches
1215 // XMLStylesheetProcessingInstruction::GetStyleSheetInfo.
1216 nsAutoString type;
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
1240 rv =
1241 MaybeProcessXSLTLink(node, href, isAlternate, title, type, media, u""_ns);
1242 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1245 /* static */
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)) {
1251 return false;
1254 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::title, aTitle);
1256 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::media, aMedia);
1258 nsAutoString alternate;
1259 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::alternate,
1260 alternate);
1262 aIsAlternate = alternate.EqualsLiteral("yes");
1264 return true;
1267 NS_IMETHODIMP
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();
1276 NS_IMETHODIMP
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.
1284 *_retval = true;
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.
1306 mTextLength = 0;
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();
1316 mNotifyLevel = 0;
1318 // return leaving the document empty if we're asked to not add a <parsererror>
1319 // root node
1320 if (mDocument->SuppressParserErrorElement()) {
1321 return NS_OK;
1324 // prepare to set <parsererror> as the document root
1325 rv = HandleProcessingInstruction(
1326 u"xml-stylesheet",
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);
1361 FlushTags();
1363 return NS_OK;
1366 nsresult nsXMLContentSink::AddAttributes(const char16_t** aAtts,
1367 Element* aContent) {
1368 // Add tag attributes to the content attributes
1369 RefPtr<nsAtom> prefix, localName;
1370 while (*aAtts) {
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);
1378 aAtts += 2;
1381 return NS_OK;
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.
1388 int32_t offset = 0;
1389 while (0 != aLength) {
1390 int32_t amount = NS_ACCUMULATION_BUFFER_SIZE - mTextLength;
1391 if (0 == amount) {
1392 nsresult rv = FlushText(false);
1393 if (NS_WARN_IF(NS_FAILED(rv))) {
1394 return rv;
1396 MOZ_ASSERT(mTextLength == 0);
1397 amount = NS_ACCUMULATION_BUFFER_SIZE;
1400 if (amount > aLength) {
1401 amount = aLength;
1403 memcpy(&mText[mTextLength], &aText[offset], sizeof(char16_t) * amount);
1404 mTextLength += amount;
1405 offset += amount;
1406 aLength -= amount;
1409 return NS_OK;
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) {
1422 FlushTags();
1423 } else {
1424 FlushText(false);
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;
1449 ++mInNotification;
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
1455 FlushText(false);
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.
1461 int32_t stackPos;
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);
1473 flushed = true;
1476 mContentStack[stackPos].mNumFlushed = childCount;
1478 mNotifyLevel = stackLen - 1;
1480 --mInNotification;
1482 if (mUpdatesInNotification > 1) {
1483 UpdateChildCounts();
1486 mUpdatesInNotification = oldUpdates;
1487 return NS_OK;
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();
1505 stackPos--;
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());