Bug 1665252 - remove allowpaymentrequest attribute from HTMLIFrameElement r=dom-worke...
[gecko.git] / dom / xml / nsXMLContentSink.cpp
blob3bc4112ae68874f53a66f7e68611b06dd3ecbab1
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 "nsIScriptContext.h"
22 #include "nsNameSpaceManager.h"
23 #include "nsIScriptSecurityManager.h"
24 #include "nsIContentViewer.h"
25 #include "prtime.h"
26 #include "mozilla/Logging.h"
27 #include "nsRect.h"
28 #include "nsIScriptElement.h"
29 #include "nsReadableUtils.h"
30 #include "nsUnicharUtils.h"
31 #include "nsIChannel.h"
32 #include "nsXMLPrettyPrinter.h"
33 #include "nsNodeInfoManager.h"
34 #include "nsContentCreatorFunctions.h"
35 #include "nsIContentPolicy.h"
36 #include "nsContentPolicyUtils.h"
37 #include "nsError.h"
38 #include "nsIScriptGlobalObject.h"
39 #include "mozAutoDocUpdate.h"
40 #include "nsMimeTypes.h"
41 #include "nsHtml5SVGLoadDispatcher.h"
42 #include "nsTextNode.h"
43 #include "mozilla/dom/CDATASection.h"
44 #include "mozilla/dom/Comment.h"
45 #include "mozilla/dom/DocumentType.h"
46 #include "mozilla/dom/Element.h"
47 #include "mozilla/dom/HTMLTemplateElement.h"
48 #include "mozilla/dom/MutationObservers.h"
49 #include "mozilla/dom/ProcessingInstruction.h"
50 #include "mozilla/dom/ScriptLoader.h"
51 #include "mozilla/dom/txMozillaXSLTProcessor.h"
52 #include "mozilla/CycleCollectedJSContext.h"
53 #include "mozilla/LoadInfo.h"
55 using namespace mozilla;
56 using namespace mozilla::dom;
58 // XXX Open Issues:
59 // 1) what's not allowed - We need to figure out which HTML tags
60 // (prefixed with a HTML namespace qualifier) are explicitly not
61 // allowed (if any).
62 // 2) factoring code with nsHTMLContentSink - There's some amount of
63 // common code between this and the HTML content sink. This will
64 // increase as we support more and more HTML elements. How can code
65 // from the code be factored?
67 nsresult NS_NewXMLContentSink(nsIXMLContentSink** aResult, Document* aDoc,
68 nsIURI* aURI, nsISupports* aContainer,
69 nsIChannel* aChannel) {
70 MOZ_ASSERT(nullptr != aResult, "null ptr");
71 if (nullptr == aResult) {
72 return NS_ERROR_NULL_POINTER;
74 RefPtr<nsXMLContentSink> it = new nsXMLContentSink();
76 nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
77 NS_ENSURE_SUCCESS(rv, rv);
79 it.forget(aResult);
80 return NS_OK;
83 nsXMLContentSink::nsXMLContentSink()
84 : mState(eXMLContentSinkState_InProlog),
85 mTextLength(0),
86 mNotifyLevel(0),
87 mPrettyPrintXML(true),
88 mPrettyPrintHasSpecialRoot(0),
89 mPrettyPrintHasFactoredElements(0),
90 mPrettyPrinting(0),
91 mPreventScriptExecution(0) {
92 PodArrayZero(mText);
95 nsXMLContentSink::~nsXMLContentSink() = default;
97 nsresult nsXMLContentSink::Init(Document* aDoc, nsIURI* aURI,
98 nsISupports* aContainer, nsIChannel* aChannel) {
99 nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
100 NS_ENSURE_SUCCESS(rv, rv);
102 aDoc->AddObserver(this);
103 mIsDocumentObserver = true;
105 if (!mDocShell) {
106 mPrettyPrintXML = false;
109 mState = eXMLContentSinkState_InProlog;
110 mDocElement = nullptr;
112 return NS_OK;
115 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXMLContentSink)
116 NS_INTERFACE_MAP_ENTRY(nsIContentSink)
117 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
118 NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
119 NS_INTERFACE_MAP_ENTRY(nsITransformObserver)
120 NS_INTERFACE_MAP_END_INHERITING(nsContentSink)
122 NS_IMPL_ADDREF_INHERITED(nsXMLContentSink, nsContentSink)
123 NS_IMPL_RELEASE_INHERITED(nsXMLContentSink, nsContentSink)
125 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLContentSink)
127 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLContentSink,
128 nsContentSink)
129 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentHead)
130 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocElement)
131 for (uint32_t i = 0, count = tmp->mContentStack.Length(); i < count; i++) {
132 const StackNode& node = tmp->mContentStack.ElementAt(i);
133 cb.NoteXPCOMChild(node.mContent);
135 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentChildren)
136 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
138 // nsIContentSink
139 NS_IMETHODIMP
140 nsXMLContentSink::WillParse(void) { return WillParseImpl(); }
142 NS_IMETHODIMP
143 nsXMLContentSink::WillBuildModel(nsDTDMode aDTDMode) {
144 WillBuildModelImpl();
146 // Notify document that the load is beginning
147 mDocument->BeginLoad();
149 // Check for correct load-command for maybe prettyprinting
150 if (mPrettyPrintXML) {
151 nsAutoCString command;
152 GetParser()->GetCommand(command);
153 if (!command.EqualsLiteral("view")) {
154 mPrettyPrintXML = false;
158 return NS_OK;
161 bool nsXMLContentSink::CanStillPrettyPrint() {
162 return mPrettyPrintXML &&
163 (!mPrettyPrintHasFactoredElements || mPrettyPrintHasSpecialRoot);
166 nsresult nsXMLContentSink::MaybePrettyPrint() {
167 if (!CanStillPrettyPrint()) {
168 mPrettyPrintXML = false;
170 return NS_OK;
174 // Try to perform a microtask checkpoint; this avoids always breaking
175 // pretty-printing if webextensions insert new content right after the
176 // document loads.
177 nsAutoMicroTask mt;
180 // stop observing in order to avoid crashing when replacing content
181 mDocument->RemoveObserver(this);
182 mIsDocumentObserver = false;
184 // Reenable the CSSLoader so that the prettyprinting stylesheets can load
185 if (mCSSLoader) {
186 mCSSLoader->SetEnabled(true);
189 RefPtr<nsXMLPrettyPrinter> printer;
190 nsresult rv = NS_NewXMLPrettyPrinter(getter_AddRefs(printer));
191 NS_ENSURE_SUCCESS(rv, rv);
193 bool isPrettyPrinting;
194 rv = printer->PrettyPrint(mDocument, &isPrettyPrinting);
195 NS_ENSURE_SUCCESS(rv, rv);
197 mPrettyPrinting = isPrettyPrinting;
198 return NS_OK;
201 static void CheckXSLTParamPI(ProcessingInstruction* aPi,
202 nsIDocumentTransformer* aProcessor,
203 nsINode* aSource) {
204 nsAutoString target, data;
205 aPi->GetTarget(target);
207 // Check for namespace declarations
208 if (target.EqualsLiteral("xslt-param-namespace")) {
209 aPi->GetData(data);
210 nsAutoString prefix, namespaceAttr;
211 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::prefix, prefix);
212 if (!prefix.IsEmpty() && nsContentUtils::GetPseudoAttributeValue(
213 data, nsGkAtoms::_namespace, namespaceAttr)) {
214 aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr);
218 // Check for actual parameters
219 else if (target.EqualsLiteral("xslt-param")) {
220 aPi->GetData(data);
221 nsAutoString name, namespaceAttr, select, value;
222 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name, name);
223 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
224 namespaceAttr);
225 if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select,
226 select)) {
227 select.SetIsVoid(true);
229 if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value,
230 value)) {
231 value.SetIsVoid(true);
233 if (!name.IsEmpty()) {
234 aProcessor->AddXSLTParam(name, namespaceAttr, select, value, aSource);
239 NS_IMETHODIMP
240 nsXMLContentSink::DidBuildModel(bool aTerminated) {
241 if (!mParser) {
242 // If mParser is null, this parse has already been terminated and must
243 // not been terminated again. However, Document may still think that
244 // the parse has not been terminated and call back into here in the case
245 // where the XML parser has finished but the XSLT transform associated
246 // with the document has not.
247 return NS_OK;
250 DidBuildModelImpl(aTerminated);
252 if (mXSLTProcessor) {
253 // stop observing in order to avoid crashing when replacing content
254 mDocument->RemoveObserver(this);
255 mIsDocumentObserver = false;
257 ErrorResult rv;
258 RefPtr<DocumentFragment> source = mDocument->CreateDocumentFragment();
259 for (nsIContent* child : mDocumentChildren) {
260 // XPath data model doesn't have DocumentType nodes.
261 if (child->NodeType() != nsINode::DOCUMENT_TYPE_NODE) {
262 source->AppendChild(*child, rv);
263 if (rv.Failed()) {
264 return rv.StealNSResult();
269 // Check for xslt-param and xslt-param-namespace PIs
270 for (nsIContent* child : mDocumentChildren) {
271 if (auto pi = ProcessingInstruction::FromNode(child)) {
272 CheckXSLTParamPI(pi, mXSLTProcessor, source);
273 } else if (child->IsElement()) {
274 // Only honor PIs in the prolog
275 break;
279 mXSLTProcessor->SetSourceContentModel(source);
280 // Since the processor now holds a reference to us we drop our reference
281 // to it to avoid owning cycles
282 mXSLTProcessor = nullptr;
283 } else {
284 // Kick off layout for non-XSLT transformed documents.
286 // Check if we want to prettyprint
287 MaybePrettyPrint();
289 bool startLayout = true;
291 if (mPrettyPrinting) {
292 NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!");
294 // We're pretty-printing now. See whether we should wait up on
295 // stylesheet loads
296 if (mDocument->CSSLoader()->HasPendingLoads()) {
297 mDocument->CSSLoader()->AddObserver(this);
298 // wait for those sheets to load
299 startLayout = false;
303 if (startLayout) {
304 StartLayout(false);
306 ScrollToRef();
309 mDocument->RemoveObserver(this);
310 mIsDocumentObserver = false;
312 mDocument->EndLoad();
314 DropParserAndPerfHint();
317 return NS_OK;
320 NS_IMETHODIMP
321 nsXMLContentSink::OnDocumentCreated(Document* aResultDocument) {
322 NS_ENSURE_ARG(aResultDocument);
324 aResultDocument->SetDocWriteDisabled(true);
326 nsCOMPtr<nsIContentViewer> contentViewer;
327 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
328 if (contentViewer) {
329 return contentViewer->SetDocumentInternal(aResultDocument, true);
331 return NS_OK;
334 NS_IMETHODIMP
335 nsXMLContentSink::OnTransformDone(nsresult aResult, Document* aResultDocument) {
336 MOZ_ASSERT(aResultDocument,
337 "Don't notify about transform end without a document.");
339 mDocumentChildren.Clear();
341 nsCOMPtr<nsIContentViewer> contentViewer;
342 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
344 if (NS_FAILED(aResult) && contentViewer) {
345 // Transform failed.
346 aResultDocument->SetMayStartLayout(false);
347 // We have an error document.
348 contentViewer->SetDocument(aResultDocument);
351 RefPtr<Document> originalDocument = mDocument;
352 bool blockingOnload = mIsBlockingOnload;
353 if (!mRunsToCompletion) {
354 // This BlockOnload call corresponds to the UnblockOnload call in
355 // nsContentSink::DropParserAndPerfHint.
356 aResultDocument->BlockOnload();
357 mIsBlockingOnload = true;
359 // Transform succeeded, or it failed and we have an error document to display.
360 mDocument = aResultDocument;
361 aResultDocument->SetDocWriteDisabled(false);
363 // Notify document observers that all the content has been stuck
364 // into the document.
365 // XXX do we need to notify for things like PIs? Or just the
366 // documentElement?
367 nsIContent* rootElement = mDocument->GetRootElement();
368 if (rootElement) {
369 NS_ASSERTION(mDocument->ComputeIndexOf(rootElement) != -1,
370 "rootElement not in doc?");
371 mDocument->BeginUpdate();
372 MutationObservers::NotifyContentInserted(mDocument, rootElement);
373 mDocument->EndUpdate();
376 // Start the layout process
377 StartLayout(false);
379 ScrollToRef();
381 originalDocument->EndLoad();
382 if (blockingOnload) {
383 // This UnblockOnload call corresponds to the BlockOnload call in
384 // nsContentSink::WillBuildModelImpl.
385 originalDocument->UnblockOnload(true);
388 DropParserAndPerfHint();
390 return NS_OK;
393 NS_IMETHODIMP
394 nsXMLContentSink::StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
395 nsresult aStatus) {
396 if (!mPrettyPrinting) {
397 return nsContentSink::StyleSheetLoaded(aSheet, aWasDeferred, aStatus);
400 if (!mDocument->CSSLoader()->HasPendingLoads()) {
401 mDocument->CSSLoader()->RemoveObserver(this);
402 StartLayout(false);
403 ScrollToRef();
406 return NS_OK;
409 NS_IMETHODIMP
410 nsXMLContentSink::WillInterrupt(void) { return WillInterruptImpl(); }
412 NS_IMETHODIMP
413 nsXMLContentSink::WillResume(void) { return WillResumeImpl(); }
415 NS_IMETHODIMP
416 nsXMLContentSink::SetParser(nsParserBase* aParser) {
417 MOZ_ASSERT(aParser, "Should have a parser here!");
418 mParser = aParser;
419 return NS_OK;
422 static bool FindIsAttrValue(const char16_t** aAtts, const char16_t** aResult) {
423 RefPtr<nsAtom> prefix, localName;
424 for (; *aAtts; aAtts += 2) {
425 int32_t nameSpaceID;
426 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
427 getter_AddRefs(localName), &nameSpaceID);
428 if (nameSpaceID == kNameSpaceID_None && localName == nsGkAtoms::is) {
429 *aResult = aAtts[1];
431 return true;
435 return false;
438 nsresult nsXMLContentSink::CreateElement(
439 const char16_t** aAtts, uint32_t aAttsCount,
440 mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
441 uint32_t aColumnNumber, nsIContent** aResult, bool* aAppendContent,
442 FromParser aFromParser) {
443 NS_ASSERTION(aNodeInfo, "can't create element without nodeinfo");
445 *aResult = nullptr;
446 *aAppendContent = true;
447 nsresult rv = NS_OK;
449 RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
450 RefPtr<Element> content;
452 const char16_t* is = nullptr;
453 if ((aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML) ||
454 aNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) &&
455 FindIsAttrValue(aAtts, &is)) {
456 const nsDependentString isStr(is);
457 rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser,
458 &isStr);
459 } else {
460 rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser);
463 NS_ENSURE_SUCCESS(rv, rv);
465 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
466 aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)) {
467 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
468 if (sele) {
469 sele->SetScriptLineNumber(aLineNumber);
470 sele->SetScriptColumnNumber(aColumnNumber);
471 sele->SetCreatorParser(GetParser());
472 } else {
473 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
474 "Node didn't QI to script, but SVG wasn't disabled.");
478 // XHTML needs some special attention
479 if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
480 mPrettyPrintHasFactoredElements = true;
481 } else {
482 // If we care, find out if we just used a special factory.
483 if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
484 mPrettyPrintXML) {
485 mPrettyPrintHasFactoredElements =
486 nsContentUtils::NameSpaceManager()->HasElementCreator(
487 aNodeInfo->NamespaceID());
490 if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
491 content.forget(aResult);
493 return NS_OK;
497 if (aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
498 aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
499 aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
500 if (auto* linkStyle = LinkStyle::FromNode(*content)) {
501 if (aFromParser) {
502 linkStyle->SetEnableUpdates(false);
504 if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
505 linkStyle->SetLineNumber(aFromParser ? aLineNumber : 0);
506 linkStyle->SetColumnNumber(aFromParser ? aColumnNumber : 0);
511 content.forget(aResult);
513 return NS_OK;
516 nsresult nsXMLContentSink::CloseElement(nsIContent* aContent) {
517 NS_ASSERTION(aContent, "missing element to close");
519 mozilla::dom::NodeInfo* nodeInfo = aContent->NodeInfo();
521 // Some HTML nodes need DoneAddingChildren() called to initialize
522 // properly (eg form state restoration).
523 if (nsIContent::RequiresDoneAddingChildren(nodeInfo->NamespaceID(),
524 nodeInfo->NameAtom())) {
525 aContent->DoneAddingChildren(HaveNotifiedForCurrentContent());
528 if (IsMonolithicContainer(nodeInfo)) {
529 mInMonolithicContainer--;
532 if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) &&
533 !nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
534 return NS_OK;
537 if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
538 nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)) {
539 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
540 if (!sele) {
541 MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
542 "Node didn't QI to script, but SVG wasn't disabled.");
543 return NS_OK;
546 if (mPreventScriptExecution) {
547 sele->PreventExecution();
548 return NS_OK;
551 // Always check the clock in nsContentSink right after a script
552 StopDeflecting();
554 // Now tell the script that it's ready to go. This may execute the script
555 // or return true, or neither if the script doesn't need executing.
556 bool block = sele->AttemptToExecute();
558 // If the parser got blocked, make sure to return the appropriate rv.
559 // I'm not sure if this is actually needed or not.
560 if (mParser && !mParser->IsParserEnabled()) {
561 block = true;
564 return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
567 nsresult rv = NS_OK;
568 if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
569 nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
570 nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
571 if (auto* linkStyle = LinkStyle::FromNode(*aContent)) {
572 linkStyle->SetEnableUpdates(true);
573 auto updateOrError =
574 linkStyle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this);
575 if (updateOrError.isErr()) {
576 rv = updateOrError.unwrapErr();
577 } else if (updateOrError.unwrap().ShouldBlock() && !mRunsToCompletion) {
578 ++mPendingSheetCount;
579 mScriptLoader->AddParserBlockingScriptExecutionBlocker();
584 return rv;
587 nsresult nsXMLContentSink::AddContentAsLeaf(nsIContent* aContent) {
588 nsresult result = NS_OK;
590 if (mState == eXMLContentSinkState_InProlog) {
591 NS_ASSERTION(mDocument, "Fragments have no prolog");
592 mDocumentChildren.AppendElement(aContent);
593 } else if (mState == eXMLContentSinkState_InEpilog) {
594 NS_ASSERTION(mDocument, "Fragments have no epilog");
595 if (mXSLTProcessor) {
596 mDocumentChildren.AppendElement(aContent);
597 } else {
598 mDocument->AppendChildTo(aContent, false);
600 } else {
601 nsCOMPtr<nsIContent> parent = GetCurrentContent();
603 if (parent) {
604 result = parent->AppendChildTo(aContent, false);
607 return result;
610 // Create an XML parser and an XSL content sink and start parsing
611 // the XSL stylesheet located at the given URI.
612 nsresult nsXMLContentSink::LoadXSLStyleSheet(nsIURI* aUrl) {
613 nsCOMPtr<nsIDocumentTransformer> processor = new txMozillaXSLTProcessor();
615 processor->SetTransformObserver(this);
617 if (NS_SUCCEEDED(processor->LoadStyleSheet(aUrl, mDocument))) {
618 mXSLTProcessor.swap(processor);
621 // Intentionally ignore errors here, we should continue loading the
622 // XML document whether we're able to load the XSLT stylesheet or
623 // not.
625 return NS_OK;
628 nsresult nsXMLContentSink::ProcessStyleLinkFromHeader(
629 const nsAString& aHref, bool aAlternate, const nsAString& aTitle,
630 const nsAString& aIntegrity, const nsAString& aType,
631 const nsAString& aMedia, const nsAString& aReferrerPolicy) {
632 mPrettyPrintXML = false;
634 nsAutoCString cmd;
635 if (mParser) GetParser()->GetCommand(cmd);
636 if (cmd.EqualsASCII(kLoadAsData))
637 return NS_OK; // Do not load stylesheets when loading as data
639 bool wasXSLT;
640 nsresult rv = MaybeProcessXSLTLink(nullptr, aHref, aAlternate, aType, aType,
641 aMedia, aReferrerPolicy, &wasXSLT);
642 NS_ENSURE_SUCCESS(rv, rv);
643 if (wasXSLT) {
644 // We're done here.
645 return NS_OK;
648 // Otherwise fall through to nsContentSink to handle CSS Link headers.
649 return nsContentSink::ProcessStyleLinkFromHeader(
650 aHref, aAlternate, aTitle, aIntegrity, aType, aMedia, aReferrerPolicy);
653 nsresult nsXMLContentSink::MaybeProcessXSLTLink(
654 ProcessingInstruction* aProcessingInstruction, const nsAString& aHref,
655 bool aAlternate, const nsAString& aTitle, const nsAString& aType,
656 const nsAString& aMedia, const nsAString& aReferrerPolicy, bool* aWasXSLT) {
657 bool wasXSLT = aType.LowerCaseEqualsLiteral(TEXT_XSL) ||
658 aType.LowerCaseEqualsLiteral(APPLICATION_XSLT_XML) ||
659 aType.LowerCaseEqualsLiteral(TEXT_XML) ||
660 aType.LowerCaseEqualsLiteral(APPLICATION_XML);
662 if (aWasXSLT) {
663 *aWasXSLT = wasXSLT;
666 if (!wasXSLT) {
667 return NS_OK;
670 if (aAlternate) {
671 // don't load alternate XSLT
672 return NS_OK;
674 // LoadXSLStyleSheet needs a mDocShell.
675 if (!mDocShell) {
676 return NS_OK;
679 nsCOMPtr<nsIURI> url;
680 nsresult rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
681 mDocument->GetDocBaseURI());
682 NS_ENSURE_SUCCESS(rv, rv);
684 // Do security check
685 nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
686 rv = secMan->CheckLoadURIWithPrincipal(mDocument->NodePrincipal(), url,
687 nsIScriptSecurityManager::ALLOW_CHROME,
688 mDocument->InnerWindowID());
689 NS_ENSURE_SUCCESS(rv, NS_OK);
691 nsCOMPtr<nsILoadInfo> secCheckLoadInfo =
692 new net::LoadInfo(mDocument->NodePrincipal(), // loading principal
693 mDocument->NodePrincipal(), // triggering principal
694 aProcessingInstruction,
695 nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
696 nsIContentPolicy::TYPE_XSLT);
698 // Do content policy check
699 int16_t decision = nsIContentPolicy::ACCEPT;
700 rv = NS_CheckContentLoadPolicy(url, secCheckLoadInfo,
701 NS_ConvertUTF16toUTF8(aType), &decision,
702 nsContentUtils::GetContentPolicy());
704 NS_ENSURE_SUCCESS(rv, rv);
706 if (NS_CP_REJECTED(decision)) {
707 return NS_OK;
710 return LoadXSLStyleSheet(url);
713 void nsXMLContentSink::SetDocumentCharset(NotNull<const Encoding*> aEncoding) {
714 if (mDocument) {
715 mDocument->SetDocumentCharacterSet(aEncoding);
719 nsISupports* nsXMLContentSink::GetTarget() { return ToSupports(mDocument); }
721 bool nsXMLContentSink::IsScriptExecuting() { return IsScriptExecutingImpl(); }
723 nsresult nsXMLContentSink::FlushText(bool aReleaseTextNode) {
724 nsresult rv = NS_OK;
726 if (mTextLength != 0) {
727 if (mLastTextNode) {
728 bool notify = HaveNotifiedForCurrentContent();
729 // We could probably always increase mInNotification here since
730 // if AppendText doesn't notify it shouldn't trigger evil code.
731 // But just in case it does, we don't want to mask any notifications.
732 if (notify) {
733 ++mInNotification;
735 rv = mLastTextNode->AppendText(mText, mTextLength, notify);
736 if (notify) {
737 --mInNotification;
740 mTextLength = 0;
741 } else {
742 RefPtr<nsTextNode> textContent =
743 new (mNodeInfoManager) nsTextNode(mNodeInfoManager);
745 mLastTextNode = textContent;
747 // Set the text in the text node
748 textContent->SetText(mText, mTextLength, false);
749 mTextLength = 0;
751 // Add text to its parent
752 rv = AddContentAsLeaf(textContent);
756 if (aReleaseTextNode) {
757 mLastTextNode = nullptr;
760 return rv;
763 nsIContent* nsXMLContentSink::GetCurrentContent() {
764 if (mContentStack.Length() == 0) {
765 return nullptr;
767 return GetCurrentStackNode()->mContent;
770 StackNode* nsXMLContentSink::GetCurrentStackNode() {
771 int32_t count = mContentStack.Length();
772 return count != 0 ? &mContentStack[count - 1] : nullptr;
775 nsresult nsXMLContentSink::PushContent(nsIContent* aContent) {
776 MOZ_ASSERT(aContent, "Null content being pushed!");
777 StackNode* sn = mContentStack.AppendElement();
778 NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY);
780 nsIContent* contentToPush = aContent;
782 // When an XML parser would append a node to a template element, it
783 // must instead append it to the template element's template contents.
784 if (contentToPush->IsHTMLElement(nsGkAtoms::_template)) {
785 HTMLTemplateElement* templateElement =
786 static_cast<HTMLTemplateElement*>(contentToPush);
787 contentToPush = templateElement->Content();
790 sn->mContent = contentToPush;
791 sn->mNumFlushed = 0;
792 return NS_OK;
795 void nsXMLContentSink::PopContent() {
796 if (mContentStack.IsEmpty()) {
797 NS_WARNING("Popping empty stack");
798 return;
801 mContentStack.RemoveLastElement();
804 bool nsXMLContentSink::HaveNotifiedForCurrentContent() const {
805 uint32_t stackLength = mContentStack.Length();
806 if (stackLength) {
807 const StackNode& stackNode = mContentStack[stackLength - 1];
808 nsIContent* parent = stackNode.mContent;
809 return stackNode.mNumFlushed == parent->GetChildCount();
811 return true;
814 void nsXMLContentSink::MaybeStartLayout(bool aIgnorePendingSheets) {
815 // XXXbz if aIgnorePendingSheets is true, what should we do when
816 // mXSLTProcessor or CanStillPrettyPrint()?
817 if (mLayoutStarted || mXSLTProcessor || CanStillPrettyPrint()) {
818 return;
820 StartLayout(aIgnorePendingSheets);
823 ////////////////////////////////////////////////////////////////////////
825 bool nsXMLContentSink::SetDocElement(int32_t aNameSpaceID, nsAtom* aTagName,
826 nsIContent* aContent) {
827 if (mDocElement) return false;
829 mDocElement = aContent;
831 if (mXSLTProcessor) {
832 mDocumentChildren.AppendElement(aContent);
833 return true;
836 if (!mDocumentChildren.IsEmpty()) {
837 for (nsIContent* child : mDocumentChildren) {
838 mDocument->AppendChildTo(child, false);
840 mDocumentChildren.Clear();
843 // check for root elements that needs special handling for
844 // prettyprinting
845 if (aNameSpaceID == kNameSpaceID_XSLT &&
846 (aTagName == nsGkAtoms::stylesheet || aTagName == nsGkAtoms::transform)) {
847 mPrettyPrintHasSpecialRoot = true;
848 if (mPrettyPrintXML) {
849 // In this case, disable script execution, stylesheet
850 // loading, and auto XLinks since we plan to prettyprint.
851 mDocument->ScriptLoader()->SetEnabled(false);
852 if (mCSSLoader) {
853 mCSSLoader->SetEnabled(false);
858 nsresult rv = mDocument->AppendChildTo(mDocElement, NotifyForDocElement());
859 if (NS_FAILED(rv)) {
860 // If we return false here, the caller will bail out because it won't
861 // find a parent content node to append to, which is fine.
862 return false;
865 if (aTagName == nsGkAtoms::html && aNameSpaceID == kNameSpaceID_XHTML) {
866 ProcessOfflineManifest(aContent);
869 return true;
872 NS_IMETHODIMP
873 nsXMLContentSink::HandleStartElement(const char16_t* aName,
874 const char16_t** aAtts,
875 uint32_t aAttsCount, uint32_t aLineNumber,
876 uint32_t aColumnNumber) {
877 return HandleStartElement(aName, aAtts, aAttsCount, aLineNumber,
878 aColumnNumber, true);
881 nsresult nsXMLContentSink::HandleStartElement(
882 const char16_t* aName, const char16_t** aAtts, uint32_t aAttsCount,
883 uint32_t aLineNumber, uint32_t aColumnNumber, bool aInterruptable) {
884 MOZ_ASSERT(aAttsCount % 2 == 0, "incorrect aAttsCount");
885 // Adjust aAttsCount so it's the actual number of attributes
886 aAttsCount /= 2;
888 nsresult result = NS_OK;
889 bool appendContent = true;
890 nsCOMPtr<nsIContent> content;
892 // XXX Hopefully the parser will flag this before we get
893 // here. If we're in the epilog, there should be no
894 // new elements
895 MOZ_ASSERT(eXMLContentSinkState_InEpilog != mState);
897 FlushText();
898 DidAddContent();
900 mState = eXMLContentSinkState_InDocumentElement;
902 int32_t nameSpaceID;
903 RefPtr<nsAtom> prefix, localName;
904 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
905 getter_AddRefs(localName), &nameSpaceID);
907 if (!OnOpenContainer(aAtts, aAttsCount, nameSpaceID, localName,
908 aLineNumber)) {
909 return NS_OK;
912 RefPtr<mozilla::dom::NodeInfo> nodeInfo;
913 nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
914 nsINode::ELEMENT_NODE);
916 result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
917 aColumnNumber, getter_AddRefs(content), &appendContent,
918 FROM_PARSER_NETWORK);
919 NS_ENSURE_SUCCESS(result, result);
921 // Have to do this before we push the new content on the stack... and have to
922 // do that before we set attributes, call BindToTree, etc. Ideally we'd push
923 // on the stack inside CreateElement (which is effectively what the HTML sink
924 // does), but that's hard with all the subclass overrides going on.
925 nsCOMPtr<nsIContent> parent = GetCurrentContent();
927 result = PushContent(content);
928 NS_ENSURE_SUCCESS(result, result);
930 // Set the attributes on the new content element
931 result = AddAttributes(aAtts, content->AsElement());
933 if (NS_OK == result) {
934 // Store the element
935 if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
936 NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
938 parent->AppendChildTo(content, false);
942 // Some HTML nodes need DoneCreatingElement() called to initialize
943 // properly (eg form state restoration).
944 if (nsIContent::RequiresDoneCreatingElement(nodeInfo->NamespaceID(),
945 nodeInfo->NameAtom())) {
946 content->DoneCreatingElement();
949 if (nodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
950 nodeInfo->NameAtom() == nsGkAtoms::head && !mCurrentHead) {
951 mCurrentHead = content;
954 if (IsMonolithicContainer(nodeInfo)) {
955 mInMonolithicContainer++;
958 if (!mXSLTProcessor) {
959 if (content == mDocElement) {
960 nsContentUtils::AddScriptRunner(
961 new nsDocElementCreatedNotificationRunner(mDocument));
963 if (aInterruptable && NS_SUCCEEDED(result) && mParser &&
964 !mParser->IsParserEnabled()) {
965 return NS_ERROR_HTMLPARSER_BLOCK;
967 } else if (!mCurrentHead) {
968 // This isn't the root and we're not inside an XHTML <head>.
969 // Might need to start layout
970 MaybeStartLayout(false);
974 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl()
975 : result;
978 NS_IMETHODIMP
979 nsXMLContentSink::HandleEndElement(const char16_t* aName) {
980 return HandleEndElement(aName, true);
983 nsresult nsXMLContentSink::HandleEndElement(const char16_t* aName,
984 bool aInterruptable) {
985 nsresult result = NS_OK;
987 // XXX Hopefully the parser will flag this before we get
988 // here. If we're in the prolog or epilog, there should be
989 // no close tags for elements.
990 MOZ_ASSERT(eXMLContentSinkState_InDocumentElement == mState);
992 FlushText();
994 StackNode* sn = GetCurrentStackNode();
995 if (!sn) {
996 return NS_ERROR_UNEXPECTED;
999 nsCOMPtr<nsIContent> content;
1000 sn->mContent.swap(content);
1001 uint32_t numFlushed = sn->mNumFlushed;
1003 PopContent();
1004 NS_ASSERTION(content, "failed to pop content");
1005 #ifdef DEBUG
1006 // Check that we're closing the right thing
1007 RefPtr<nsAtom> debugNameSpacePrefix, debugTagAtom;
1008 int32_t debugNameSpaceID;
1009 nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
1010 getter_AddRefs(debugTagAtom),
1011 &debugNameSpaceID);
1012 // Check if we are closing a template element because template
1013 // elements do not get pushed on the stack, the template
1014 // element content is pushed instead.
1015 bool isTemplateElement = debugTagAtom == nsGkAtoms::_template &&
1016 debugNameSpaceID == kNameSpaceID_XHTML;
1017 NS_ASSERTION(
1018 content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID) ||
1019 (debugNameSpaceID == kNameSpaceID_MathML &&
1020 content->NodeInfo()->NamespaceID() == kNameSpaceID_disabled_MathML &&
1021 content->NodeInfo()->Equals(debugTagAtom)) ||
1022 (debugNameSpaceID == kNameSpaceID_SVG &&
1023 content->NodeInfo()->NamespaceID() == kNameSpaceID_disabled_SVG &&
1024 content->NodeInfo()->Equals(debugTagAtom)) ||
1025 isTemplateElement,
1026 "Wrong element being closed");
1027 #endif
1029 // Make sure to notify on our kids before we call out to any other code that
1030 // might reenter us and call FlushTags, in a state in which we've already
1031 // popped "content" from the stack but haven't notified on its kids yet.
1032 int32_t stackLen = mContentStack.Length();
1033 if (mNotifyLevel >= stackLen) {
1034 if (numFlushed < content->GetChildCount()) {
1035 NotifyAppend(content, numFlushed);
1037 mNotifyLevel = stackLen - 1;
1040 result = CloseElement(content);
1042 if (mCurrentHead == content) {
1043 mCurrentHead = nullptr;
1046 if (mDocElement == content) {
1047 // XXXbz for roots that don't want to be appended on open, we
1048 // probably need to deal here.... (and stop appending them on open).
1049 mState = eXMLContentSinkState_InEpilog;
1051 mDocument->OnParsingCompleted();
1053 // We might have had no occasion to start layout yet. Do so now.
1054 MaybeStartLayout(false);
1057 DidAddContent();
1059 if (content->IsSVGElement(nsGkAtoms::svg)) {
1060 FlushTags();
1061 nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(content);
1062 if (NS_FAILED(content->OwnerDoc()->Dispatch(TaskCategory::Other,
1063 event.forget()))) {
1064 NS_WARNING("failed to dispatch svg load dispatcher");
1068 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl()
1069 : result;
1072 NS_IMETHODIMP
1073 nsXMLContentSink::HandleComment(const char16_t* aName) {
1074 FlushText();
1076 RefPtr<Comment> comment = new (mNodeInfoManager) Comment(mNodeInfoManager);
1077 comment->SetText(nsDependentString(aName), false);
1078 nsresult rv = AddContentAsLeaf(comment);
1079 DidAddContent();
1081 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1084 NS_IMETHODIMP
1085 nsXMLContentSink::HandleCDataSection(const char16_t* aData, uint32_t aLength) {
1086 // XSLT doesn't differentiate between text and cdata and wants adjacent
1087 // textnodes merged, so add as text.
1088 if (mXSLTProcessor) {
1089 return AddText(aData, aLength);
1092 FlushText();
1094 RefPtr<CDATASection> cdata =
1095 new (mNodeInfoManager) CDATASection(mNodeInfoManager);
1096 cdata->SetText(aData, aLength, false);
1097 nsresult rv = AddContentAsLeaf(cdata);
1098 DidAddContent();
1100 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1103 NS_IMETHODIMP
1104 nsXMLContentSink::HandleDoctypeDecl(const nsAString& aSubset,
1105 const nsAString& aName,
1106 const nsAString& aSystemId,
1107 const nsAString& aPublicId,
1108 nsISupports* aCatalogData) {
1109 FlushText();
1111 NS_ASSERTION(mDocument, "Shouldn't get here from a document fragment");
1113 RefPtr<nsAtom> name = NS_Atomize(aName);
1114 NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
1116 // Create a new doctype node
1117 RefPtr<DocumentType> docType = NS_NewDOMDocumentType(
1118 mNodeInfoManager, name, aPublicId, aSystemId, aSubset);
1120 MOZ_ASSERT(!aCatalogData,
1121 "Need to add back support for catalog style "
1122 "sheets");
1124 mDocumentChildren.AppendElement(docType);
1125 DidAddContent();
1126 return DidProcessATokenImpl();
1129 NS_IMETHODIMP
1130 nsXMLContentSink::HandleCharacterData(const char16_t* aData, uint32_t aLength) {
1131 return HandleCharacterData(aData, aLength, true);
1134 nsresult nsXMLContentSink::HandleCharacterData(const char16_t* aData,
1135 uint32_t aLength,
1136 bool aInterruptable) {
1137 nsresult rv = NS_OK;
1138 if (aData && mState != eXMLContentSinkState_InProlog &&
1139 mState != eXMLContentSinkState_InEpilog) {
1140 rv = AddText(aData, aLength);
1142 return aInterruptable && NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1145 NS_IMETHODIMP
1146 nsXMLContentSink::HandleProcessingInstruction(const char16_t* aTarget,
1147 const char16_t* aData) {
1148 FlushText();
1150 const nsDependentString target(aTarget);
1151 const nsDependentString data(aData);
1153 RefPtr<ProcessingInstruction> node =
1154 NS_NewXMLProcessingInstruction(mNodeInfoManager, target, data);
1156 auto* linkStyle = LinkStyle::FromNode(*node);
1157 if (linkStyle) {
1158 linkStyle->SetEnableUpdates(false);
1159 mPrettyPrintXML = false;
1162 nsresult rv = AddContentAsLeaf(node);
1163 NS_ENSURE_SUCCESS(rv, rv);
1164 DidAddContent();
1166 if (linkStyle) {
1167 // This is an xml-stylesheet processing instruction... but it might not be
1168 // a CSS one if the type is set to something else.
1169 linkStyle->SetEnableUpdates(true);
1170 auto updateOrError =
1171 linkStyle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this);
1172 if (updateOrError.isErr()) {
1173 return updateOrError.unwrapErr();
1176 auto update = updateOrError.unwrap();
1177 if (update.WillNotify()) {
1178 // Successfully started a stylesheet load
1179 if (update.ShouldBlock() && !mRunsToCompletion) {
1180 ++mPendingSheetCount;
1181 mScriptLoader->AddParserBlockingScriptExecutionBlocker();
1183 return NS_OK;
1187 // Check whether this is a CSS stylesheet PI. Make sure the type
1188 // handling here matches
1189 // XMLStylesheetProcessingInstruction::GetStyleSheetInfo.
1190 nsAutoString type;
1191 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type);
1192 nsAutoString mimeType, notUsed;
1193 nsContentUtils::SplitMimeType(type, mimeType, notUsed);
1195 if (mState != eXMLContentSinkState_InProlog ||
1196 !target.EqualsLiteral("xml-stylesheet") || mimeType.IsEmpty() ||
1197 mimeType.LowerCaseEqualsLiteral("text/css")) {
1198 // Either not a useful stylesheet PI, or a CSS stylesheet PI that
1199 // got handled above by the "ssle" bits. We're done here.
1200 return DidProcessATokenImpl();
1203 // If it's not a CSS stylesheet PI...
1204 nsAutoString href, title, media;
1205 bool isAlternate = false;
1207 // If there was no href, we can't do anything with this PI
1208 if (!ParsePIData(data, href, title, media, isAlternate)) {
1209 return DidProcessATokenImpl();
1212 // <?xml-stylesheet?> processing instructions don't have a referrerpolicy
1213 // pseudo-attribute, so we pass in an empty string
1214 rv =
1215 MaybeProcessXSLTLink(node, href, isAlternate, title, type, media, u""_ns);
1216 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1219 /* static */
1220 bool nsXMLContentSink::ParsePIData(const nsString& aData, nsString& aHref,
1221 nsString& aTitle, nsString& aMedia,
1222 bool& aIsAlternate) {
1223 // If there was no href, we can't do anything with this PI
1224 if (!nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::href, aHref)) {
1225 return false;
1228 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::title, aTitle);
1230 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::media, aMedia);
1232 nsAutoString alternate;
1233 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::alternate,
1234 alternate);
1236 aIsAlternate = alternate.EqualsLiteral("yes");
1238 return true;
1241 NS_IMETHODIMP
1242 nsXMLContentSink::HandleXMLDeclaration(const char16_t* aVersion,
1243 const char16_t* aEncoding,
1244 int32_t aStandalone) {
1245 mDocument->SetXMLDeclaration(aVersion, aEncoding, aStandalone);
1247 return DidProcessATokenImpl();
1250 NS_IMETHODIMP
1251 nsXMLContentSink::ReportError(const char16_t* aErrorText,
1252 const char16_t* aSourceText,
1253 nsIScriptError* aError, bool* _retval) {
1254 MOZ_ASSERT(aError && aSourceText && aErrorText, "Check arguments!!!");
1255 nsresult rv = NS_OK;
1257 // The expat driver should report the error. We're just cleaning up the mess.
1258 *_retval = true;
1260 mPrettyPrintXML = false;
1262 mState = eXMLContentSinkState_InProlog;
1264 // XXX need to stop scripts here -- hsivonen
1266 // stop observing in order to avoid crashing when removing content
1267 mDocument->RemoveObserver(this);
1268 mIsDocumentObserver = false;
1270 // Clear the current content
1271 mDocumentChildren.Clear();
1272 while (mDocument->GetLastChild()) {
1273 mDocument->GetLastChild()->Remove();
1275 mDocElement = nullptr;
1277 // Clear any buffered-up text we have. It's enough to set the length to 0.
1278 // The buffer itself is allocated when we're created and deleted in our
1279 // destructor, so don't mess with it.
1280 mTextLength = 0;
1282 if (mXSLTProcessor) {
1283 // Get rid of the XSLT processor.
1284 mXSLTProcessor->CancelLoads();
1285 mXSLTProcessor = nullptr;
1288 // release the nodes on stack
1289 mContentStack.Clear();
1290 mNotifyLevel = 0;
1292 // return leaving the document empty if we're asked to not add a <parsererror>
1293 // root node
1294 if (mDocument->SuppressParserErrorElement()) {
1295 return NS_OK;
1298 // prepare to set <parsererror> as the document root
1299 rv = HandleProcessingInstruction(
1300 u"xml-stylesheet",
1301 u"href=\"chrome://global/locale/intl.css\" type=\"text/css\"");
1302 NS_ENSURE_SUCCESS(rv, rv);
1304 const char16_t* noAtts[] = {0, 0};
1306 constexpr auto errorNs =
1307 u"http://www.mozilla.org/newlayout/xml/parsererror.xml"_ns;
1309 nsAutoString parsererror(errorNs);
1310 parsererror.Append((char16_t)0xFFFF);
1311 parsererror.AppendLiteral("parsererror");
1313 rv = HandleStartElement(parsererror.get(), noAtts, 0, (uint32_t)-1, false);
1314 NS_ENSURE_SUCCESS(rv, rv);
1316 rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText), false);
1317 NS_ENSURE_SUCCESS(rv, rv);
1319 nsAutoString sourcetext(errorNs);
1320 sourcetext.Append((char16_t)0xFFFF);
1321 sourcetext.AppendLiteral("sourcetext");
1323 rv = HandleStartElement(sourcetext.get(), noAtts, 0, (uint32_t)-1, false);
1324 NS_ENSURE_SUCCESS(rv, rv);
1326 rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText), false);
1327 NS_ENSURE_SUCCESS(rv, rv);
1329 rv = HandleEndElement(sourcetext.get(), false);
1330 NS_ENSURE_SUCCESS(rv, rv);
1332 rv = HandleEndElement(parsererror.get(), false);
1333 NS_ENSURE_SUCCESS(rv, rv);
1335 FlushTags();
1337 return NS_OK;
1340 nsresult nsXMLContentSink::AddAttributes(const char16_t** aAtts,
1341 Element* aContent) {
1342 // Add tag attributes to the content attributes
1343 RefPtr<nsAtom> prefix, localName;
1344 while (*aAtts) {
1345 int32_t nameSpaceID;
1346 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
1347 getter_AddRefs(localName), &nameSpaceID);
1349 // Add attribute to content
1350 aContent->SetAttr(nameSpaceID, localName, prefix,
1351 nsDependentString(aAtts[1]), false);
1352 aAtts += 2;
1355 return NS_OK;
1358 #define NS_ACCUMULATION_BUFFER_SIZE 4096
1360 nsresult nsXMLContentSink::AddText(const char16_t* aText, int32_t aLength) {
1361 // Copy data from string into our buffer; flush buffer when it fills up.
1362 int32_t offset = 0;
1363 while (0 != aLength) {
1364 int32_t amount = NS_ACCUMULATION_BUFFER_SIZE - mTextLength;
1365 if (0 == amount) {
1366 nsresult rv = FlushText(false);
1367 if (NS_WARN_IF(NS_FAILED(rv))) {
1368 return rv;
1370 MOZ_ASSERT(mTextLength == 0);
1371 amount = NS_ACCUMULATION_BUFFER_SIZE;
1374 if (amount > aLength) {
1375 amount = aLength;
1377 memcpy(&mText[mTextLength], &aText[offset], sizeof(char16_t) * amount);
1378 mTextLength += amount;
1379 offset += amount;
1380 aLength -= amount;
1383 return NS_OK;
1386 void nsXMLContentSink::InitialTranslationCompleted() { StartLayout(false); }
1388 void nsXMLContentSink::FlushPendingNotifications(FlushType aType) {
1389 // Only flush tags if we're not doing the notification ourselves
1390 // (since we aren't reentrant)
1391 if (!mInNotification) {
1392 if (mIsDocumentObserver) {
1393 // Only flush if we're still a document observer (so that our child
1394 // counts should be correct).
1395 if (aType >= FlushType::ContentAndNotify) {
1396 FlushTags();
1397 } else {
1398 FlushText(false);
1401 if (aType >= FlushType::EnsurePresShellInitAndFrames) {
1402 // Make sure that layout has started so that the reflow flush
1403 // will actually happen.
1404 MaybeStartLayout(true);
1410 * NOTE!! Forked from SinkContext. Please keep in sync.
1412 * Flush all elements that have been seen so far such that
1413 * they are visible in the tree. Specifically, make sure
1414 * that they are all added to their respective parents.
1415 * Also, do notification at the top for all content that
1416 * has been newly added so that the frame tree is complete.
1418 nsresult nsXMLContentSink::FlushTags() {
1419 mDeferredFlushTags = false;
1420 uint32_t oldUpdates = mUpdatesInNotification;
1422 mUpdatesInNotification = 0;
1423 ++mInNotification;
1425 // Scope so we call EndUpdate before we decrease mInNotification
1426 mozAutoDocUpdate updateBatch(mDocument, true);
1428 // Don't release last text node in case we need to add to it again
1429 FlushText(false);
1431 // Start from the base of the stack (growing downward) and do
1432 // a notification from the node that is closest to the root of
1433 // tree for any content that has been added.
1435 int32_t stackPos;
1436 int32_t stackLen = mContentStack.Length();
1437 bool flushed = false;
1438 uint32_t childCount;
1439 nsIContent* content;
1441 for (stackPos = 0; stackPos < stackLen; ++stackPos) {
1442 content = mContentStack[stackPos].mContent;
1443 childCount = content->GetChildCount();
1445 if (!flushed && (mContentStack[stackPos].mNumFlushed < childCount)) {
1446 NotifyAppend(content, mContentStack[stackPos].mNumFlushed);
1447 flushed = true;
1450 mContentStack[stackPos].mNumFlushed = childCount;
1452 mNotifyLevel = stackLen - 1;
1454 --mInNotification;
1456 if (mUpdatesInNotification > 1) {
1457 UpdateChildCounts();
1460 mUpdatesInNotification = oldUpdates;
1461 return NS_OK;
1465 * NOTE!! Forked from SinkContext. Please keep in sync.
1467 void nsXMLContentSink::UpdateChildCounts() {
1468 // Start from the top of the stack (growing upwards) and see if any
1469 // new content has been appended. If so, we recognize that reflows
1470 // have been generated for it and we should make sure that no
1471 // further reflows occur. Note that we have to include stackPos == 0
1472 // to properly notify on kids of <html>.
1473 int32_t stackLen = mContentStack.Length();
1474 int32_t stackPos = stackLen - 1;
1475 while (stackPos >= 0) {
1476 StackNode& node = mContentStack[stackPos];
1477 node.mNumFlushed = node.mContent->GetChildCount();
1479 stackPos--;
1481 mNotifyLevel = stackLen - 1;
1484 bool nsXMLContentSink::IsMonolithicContainer(
1485 mozilla::dom::NodeInfo* aNodeInfo) {
1486 return ((aNodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
1487 (aNodeInfo->NameAtom() == nsGkAtoms::tr ||
1488 aNodeInfo->NameAtom() == nsGkAtoms::select ||
1489 aNodeInfo->NameAtom() == nsGkAtoms::object)) ||
1490 (aNodeInfo->NamespaceID() == kNameSpaceID_MathML &&
1491 (aNodeInfo->NameAtom() == nsGkAtoms::math)));
1494 void nsXMLContentSink::ContinueInterruptedParsingIfEnabled() {
1495 if (mParser && mParser->IsParserEnabled()) {
1496 GetParser()->ContinueInterruptedParsing();
1500 void nsXMLContentSink::ContinueInterruptedParsingAsync() {
1501 nsCOMPtr<nsIRunnable> ev = NewRunnableMethod(
1502 "nsXMLContentSink::ContinueInterruptedParsingIfEnabled", this,
1503 &nsXMLContentSink::ContinueInterruptedParsingIfEnabled);
1505 mDocument->Dispatch(mozilla::TaskCategory::Other, ev.forget());
1508 nsIParser* nsXMLContentSink::GetParser() {
1509 return static_cast<nsIParser*>(mParser.get());