Bumping manifests a=b2g-bump
[gecko.git] / dom / xml / nsXMLContentSink.cpp
blob8d1d62511eb390a420b5722be0d3c3c54330f4d6
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
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 "nsIDocument.h"
11 #include "nsIDOMDocument.h"
12 #include "nsIDOMDocumentType.h"
13 #include "nsIContent.h"
14 #include "nsIURI.h"
15 #include "nsNetUtil.h"
16 #include "nsIDocShell.h"
17 #include "nsIStyleSheetLinkingElement.h"
18 #include "nsIDOMComment.h"
19 #include "nsIDOMCDATASection.h"
20 #include "DocumentType.h"
21 #include "nsHTMLParts.h"
22 #include "nsCRT.h"
23 #include "mozilla/CSSStyleSheet.h"
24 #include "mozilla/css/Loader.h"
25 #include "nsGkAtoms.h"
26 #include "nsContentUtils.h"
27 #include "nsIScriptContext.h"
28 #include "nsNameSpaceManager.h"
29 #include "nsIServiceManager.h"
30 #include "nsIScriptSecurityManager.h"
31 #include "nsIContentViewer.h"
32 #include "prtime.h"
33 #include "prlog.h"
34 #include "prmem.h"
35 #include "nsRect.h"
36 #include "nsIWebNavigation.h"
37 #include "nsIScriptElement.h"
38 #include "nsScriptLoader.h"
39 #include "nsStyleLinkElement.h"
40 #include "nsReadableUtils.h"
41 #include "nsUnicharUtils.h"
42 #include "nsICookieService.h"
43 #include "nsIPrompt.h"
44 #include "nsIChannel.h"
45 #include "nsIPrincipal.h"
46 #include "nsXMLPrettyPrinter.h"
47 #include "nsNodeInfoManager.h"
48 #include "nsContentCreatorFunctions.h"
49 #include "nsIContentPolicy.h"
50 #include "nsContentPolicyUtils.h"
51 #include "nsError.h"
52 #include "nsIDOMProcessingInstruction.h"
53 #include "nsNodeUtils.h"
54 #include "nsIScriptGlobalObject.h"
55 #include "nsIHTMLDocument.h"
56 #include "mozAutoDocUpdate.h"
57 #include "nsMimeTypes.h"
58 #include "nsHtml5SVGLoadDispatcher.h"
59 #include "nsTextNode.h"
60 #include "mozilla/dom/CDATASection.h"
61 #include "mozilla/dom/Comment.h"
62 #include "mozilla/dom/Element.h"
63 #include "mozilla/dom/HTMLTemplateElement.h"
64 #include "mozilla/dom/ProcessingInstruction.h"
66 using namespace mozilla;
67 using namespace mozilla::dom;
69 // XXX Open Issues:
70 // 1) what's not allowed - We need to figure out which HTML tags
71 // (prefixed with a HTML namespace qualifier) are explicitly not
72 // allowed (if any).
73 // 2) factoring code with nsHTMLContentSink - There's some amount of
74 // common code between this and the HTML content sink. This will
75 // increase as we support more and more HTML elements. How can code
76 // from the code be factored?
78 nsresult
79 NS_NewXMLContentSink(nsIXMLContentSink** aResult,
80 nsIDocument* aDoc,
81 nsIURI* aURI,
82 nsISupports* aContainer,
83 nsIChannel* aChannel)
85 NS_PRECONDITION(nullptr != aResult, "null ptr");
86 if (nullptr == aResult) {
87 return NS_ERROR_NULL_POINTER;
89 nsXMLContentSink* it = new nsXMLContentSink();
91 nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it;
92 nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
93 NS_ENSURE_SUCCESS(rv, rv);
95 return CallQueryInterface(it, aResult);
98 nsXMLContentSink::nsXMLContentSink()
99 : mConstrainSize(true),
100 mPrettyPrintXML(true)
104 nsXMLContentSink::~nsXMLContentSink()
106 if (mText) {
107 PR_Free(mText); // Doesn't null out, unlike PR_FREEIF
111 nsresult
112 nsXMLContentSink::Init(nsIDocument* aDoc,
113 nsIURI* aURI,
114 nsISupports* aContainer,
115 nsIChannel* aChannel)
117 nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
118 NS_ENSURE_SUCCESS(rv, rv);
120 aDoc->AddObserver(this);
121 mIsDocumentObserver = true;
123 if (!mDocShell) {
124 mPrettyPrintXML = false;
127 mState = eXMLContentSinkState_InProlog;
128 mDocElement = nullptr;
130 return NS_OK;
133 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLContentSink)
134 NS_INTERFACE_MAP_ENTRY(nsIContentSink)
135 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
136 NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
137 NS_INTERFACE_MAP_ENTRY(nsITransformObserver)
138 NS_INTERFACE_MAP_END_INHERITING(nsContentSink)
140 NS_IMPL_ADDREF_INHERITED(nsXMLContentSink, nsContentSink)
141 NS_IMPL_RELEASE_INHERITED(nsXMLContentSink, nsContentSink)
143 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLContentSink)
145 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLContentSink,
146 nsContentSink)
147 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentHead)
148 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocElement)
149 for (uint32_t i = 0, count = tmp->mContentStack.Length(); i < count; i++) {
150 const StackNode& node = tmp->mContentStack.ElementAt(i);
151 cb.NoteXPCOMChild(node.mContent);
153 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
155 // nsIContentSink
156 NS_IMETHODIMP
157 nsXMLContentSink::WillParse(void)
159 return WillParseImpl();
162 NS_IMETHODIMP
163 nsXMLContentSink::WillBuildModel(nsDTDMode aDTDMode)
165 WillBuildModelImpl();
167 // Notify document that the load is beginning
168 mDocument->BeginLoad();
170 // Check for correct load-command for maybe prettyprinting
171 if (mPrettyPrintXML) {
172 nsAutoCString command;
173 GetParser()->GetCommand(command);
174 if (!command.EqualsLiteral("view")) {
175 mPrettyPrintXML = false;
179 return NS_OK;
182 bool
183 nsXMLContentSink::CanStillPrettyPrint()
185 return mPrettyPrintXML &&
186 (!mPrettyPrintHasFactoredElements || mPrettyPrintHasSpecialRoot);
189 nsresult
190 nsXMLContentSink::MaybePrettyPrint()
192 if (!CanStillPrettyPrint()) {
193 mPrettyPrintXML = false;
195 return NS_OK;
198 // stop observing in order to avoid crashing when replacing content
199 mDocument->RemoveObserver(this);
200 mIsDocumentObserver = false;
202 // Reenable the CSSLoader so that the prettyprinting stylesheets can load
203 if (mCSSLoader) {
204 mCSSLoader->SetEnabled(true);
207 nsRefPtr<nsXMLPrettyPrinter> printer;
208 nsresult rv = NS_NewXMLPrettyPrinter(getter_AddRefs(printer));
209 NS_ENSURE_SUCCESS(rv, rv);
211 bool isPrettyPrinting;
212 rv = printer->PrettyPrint(mDocument, &isPrettyPrinting);
213 NS_ENSURE_SUCCESS(rv, rv);
215 mPrettyPrinting = isPrettyPrinting;
216 return NS_OK;
219 static void
220 CheckXSLTParamPI(nsIDOMProcessingInstruction* aPi,
221 nsIDocumentTransformer* aProcessor,
222 nsIDocument* aDocument)
224 nsAutoString target, data;
225 aPi->GetTarget(target);
227 // Check for namespace declarations
228 if (target.EqualsLiteral("xslt-param-namespace")) {
229 aPi->GetData(data);
230 nsAutoString prefix, namespaceAttr;
231 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::prefix,
232 prefix);
233 if (!prefix.IsEmpty() &&
234 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
235 namespaceAttr)) {
236 aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr);
240 // Check for actual parameters
241 else if (target.EqualsLiteral("xslt-param")) {
242 aPi->GetData(data);
243 nsAutoString name, namespaceAttr, select, value;
244 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name,
245 name);
246 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
247 namespaceAttr);
248 if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select, select)) {
249 select.SetIsVoid(true);
251 if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value, value)) {
252 value.SetIsVoid(true);
254 if (!name.IsEmpty()) {
255 nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument);
256 aProcessor->AddXSLTParam(name, namespaceAttr, select, value, doc);
261 NS_IMETHODIMP
262 nsXMLContentSink::DidBuildModel(bool aTerminated)
264 if (!mParser) {
265 // If mParser is null, this parse has already been terminated and must
266 // not been terminated again. However, nsDocument may still think that
267 // the parse has not been terminated and call back into here in the case
268 // where the XML parser has finished but the XSLT transform associated
269 // with the document has not.
270 return NS_OK;
273 DidBuildModelImpl(aTerminated);
275 if (mXSLTProcessor) {
276 // stop observing in order to avoid crashing when replacing content
277 mDocument->RemoveObserver(this);
278 mIsDocumentObserver = false;
280 // Check for xslt-param and xslt-param-namespace PIs
281 for (nsIContent* child = mDocument->GetFirstChild();
282 child;
283 child = child->GetNextSibling()) {
284 if (child->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
285 nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(child);
286 CheckXSLTParamPI(pi, mXSLTProcessor, mDocument);
288 else if (child->IsElement()) {
289 // Only honor PIs in the prolog
290 break;
294 nsCOMPtr<nsIDOMDocument> currentDOMDoc(do_QueryInterface(mDocument));
295 mXSLTProcessor->SetSourceContentModel(currentDOMDoc);
296 // Since the processor now holds a reference to us we drop our reference
297 // to it to avoid owning cycles
298 mXSLTProcessor = nullptr;
300 else {
301 // Kick off layout for non-XSLT transformed documents.
303 // Check if we want to prettyprint
304 MaybePrettyPrint();
306 bool startLayout = true;
308 if (mPrettyPrinting) {
309 NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!");
311 // We're pretty-printing now. See whether we should wait up on
312 // stylesheet loads
313 if (mDocument->CSSLoader()->HasPendingLoads() &&
314 NS_SUCCEEDED(mDocument->CSSLoader()->AddObserver(this))) {
315 // wait for those sheets to load
316 startLayout = false;
320 if (startLayout) {
321 StartLayout(false);
323 ScrollToRef();
326 mDocument->RemoveObserver(this);
327 mIsDocumentObserver = false;
329 mDocument->EndLoad();
332 DropParserAndPerfHint();
334 return NS_OK;
337 NS_IMETHODIMP
338 nsXMLContentSink::OnDocumentCreated(nsIDocument* aResultDocument)
340 NS_ENSURE_ARG(aResultDocument);
342 nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aResultDocument);
343 if (htmlDoc) {
344 htmlDoc->SetDocWriteDisabled(true);
347 nsCOMPtr<nsIContentViewer> contentViewer;
348 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
349 if (contentViewer) {
350 return contentViewer->SetDocumentInternal(aResultDocument, true);
352 return NS_OK;
355 NS_IMETHODIMP
356 nsXMLContentSink::OnTransformDone(nsresult aResult,
357 nsIDocument* aResultDocument)
359 NS_ASSERTION(NS_FAILED(aResult) || aResultDocument,
360 "Don't notify about transform success without a document.");
362 nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aResultDocument);
364 nsCOMPtr<nsIContentViewer> contentViewer;
365 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
367 if (NS_FAILED(aResult) && contentViewer) {
368 // Transform failed.
369 if (domDoc) {
370 aResultDocument->SetMayStartLayout(false);
371 // We have an error document.
372 contentViewer->SetDOMDocument(domDoc);
374 else {
375 // We don't have an error document, display the
376 // untransformed source document.
377 nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(mDocument);
378 contentViewer->SetDOMDocument(document);
382 nsCOMPtr<nsIDocument> originalDocument = mDocument;
383 if (NS_SUCCEEDED(aResult) || aResultDocument) {
384 // Transform succeeded or it failed and we have an error
385 // document to display.
386 mDocument = aResultDocument;
387 nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
388 if (htmlDoc) {
389 htmlDoc->SetDocWriteDisabled(false);
393 // Notify document observers that all the content has been stuck
394 // into the document.
395 // XXX do we need to notify for things like PIs? Or just the
396 // documentElement?
397 nsIContent *rootElement = mDocument->GetRootElement();
398 if (rootElement) {
399 NS_ASSERTION(mDocument->IndexOf(rootElement) != -1,
400 "rootElement not in doc?");
401 mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
402 nsNodeUtils::ContentInserted(mDocument, rootElement,
403 mDocument->IndexOf(rootElement));
404 mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
407 // Start the layout process
408 StartLayout(false);
410 ScrollToRef();
412 originalDocument->EndLoad();
414 return NS_OK;
417 NS_IMETHODIMP
418 nsXMLContentSink::StyleSheetLoaded(CSSStyleSheet* aSheet,
419 bool aWasAlternate,
420 nsresult aStatus)
422 if (!mPrettyPrinting) {
423 return nsContentSink::StyleSheetLoaded(aSheet, aWasAlternate, aStatus);
426 if (!mDocument->CSSLoader()->HasPendingLoads()) {
427 mDocument->CSSLoader()->RemoveObserver(this);
428 StartLayout(false);
429 ScrollToRef();
432 return NS_OK;
435 NS_IMETHODIMP
436 nsXMLContentSink::WillInterrupt(void)
438 return WillInterruptImpl();
441 NS_IMETHODIMP
442 nsXMLContentSink::WillResume(void)
444 return WillResumeImpl();
447 NS_IMETHODIMP
448 nsXMLContentSink::SetParser(nsParserBase* aParser)
450 NS_PRECONDITION(aParser, "Should have a parser here!");
451 mParser = aParser;
452 return NS_OK;
455 nsresult
456 nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
457 mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
458 nsIContent** aResult, bool* aAppendContent,
459 FromParser aFromParser)
461 NS_ASSERTION(aNodeInfo, "can't create element without nodeinfo");
463 *aResult = nullptr;
464 *aAppendContent = true;
465 nsresult rv = NS_OK;
467 nsRefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
468 nsRefPtr<Element> content;
469 rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser);
470 NS_ENSURE_SUCCESS(rv, rv);
472 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
473 || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
475 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
476 sele->SetScriptLineNumber(aLineNumber);
477 sele->SetCreatorParser(GetParser());
478 mConstrainSize = false;
481 // XHTML needs some special attention
482 if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
483 mPrettyPrintHasFactoredElements = true;
485 else {
486 // If we care, find out if we just used a special factory.
487 if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
488 mPrettyPrintXML) {
489 mPrettyPrintHasFactoredElements =
490 nsContentUtils::NameSpaceManager()->
491 HasElementCreator(aNodeInfo->NamespaceID());
494 if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
495 content.forget(aResult);
497 return NS_OK;
501 if (aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
502 aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
503 aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
504 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(content));
505 if (ssle) {
506 ssle->InitStyleLinkElement(false);
507 if (aFromParser) {
508 ssle->SetEnableUpdates(false);
510 if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
511 ssle->SetLineNumber(aFromParser ? aLineNumber : 0);
516 content.forget(aResult);
518 return NS_OK;
522 nsresult
523 nsXMLContentSink::CloseElement(nsIContent* aContent)
525 NS_ASSERTION(aContent, "missing element to close");
527 mozilla::dom::NodeInfo *nodeInfo = aContent->NodeInfo();
529 // Some HTML nodes need DoneAddingChildren() called to initialize
530 // properly (eg form state restoration).
531 if ((nodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
532 (nodeInfo->NameAtom() == nsGkAtoms::select ||
533 nodeInfo->NameAtom() == nsGkAtoms::textarea ||
534 nodeInfo->NameAtom() == nsGkAtoms::video ||
535 nodeInfo->NameAtom() == nsGkAtoms::audio ||
536 nodeInfo->NameAtom() == nsGkAtoms::object ||
537 nodeInfo->NameAtom() == nsGkAtoms::applet))
538 || nodeInfo->NameAtom() == nsGkAtoms::title
540 aContent->DoneAddingChildren(HaveNotifiedForCurrentContent());
543 if (IsMonolithicContainer(nodeInfo)) {
544 mInMonolithicContainer--;
547 if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) &&
548 !nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
549 return NS_OK;
552 if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
553 || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
555 mConstrainSize = true;
556 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
558 if (mPreventScriptExecution) {
559 sele->PreventExecution();
560 return NS_OK;
563 // Always check the clock in nsContentSink right after a script
564 StopDeflecting();
566 // Now tell the script that it's ready to go. This may execute the script
567 // or return true, or neither if the script doesn't need executing.
568 bool block = sele->AttemptToExecute();
570 // If the parser got blocked, make sure to return the appropriate rv.
571 // I'm not sure if this is actually needed or not.
572 if (mParser && !mParser->IsParserEnabled()) {
573 // XXX The HTML sink doesn't call BlockParser here, why do we?
574 GetParser()->BlockParser();
575 block = true;
578 return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
581 nsresult rv = NS_OK;
582 if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
583 // Need to check here to make sure this meta tag does not set
584 // mPrettyPrintXML to false when we have a special root!
585 (!mPrettyPrintXML || !mPrettyPrintHasSpecialRoot)) {
586 rv = ProcessMETATag(aContent);
588 else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
589 nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
590 nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
591 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
592 if (ssle) {
593 ssle->SetEnableUpdates(true);
594 bool willNotify;
595 bool isAlternate;
596 rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
597 &willNotify,
598 &isAlternate);
599 if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
600 ++mPendingSheetCount;
601 mScriptLoader->AddExecuteBlocker();
604 // Look for <link rel="dns-prefetch" href="hostname">
605 // and look for <link rel="next" href="hostname"> like in HTML sink
606 if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
607 nsAutoString relVal;
608 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
609 if (!relVal.IsEmpty()) {
610 uint32_t linkTypes =
611 nsStyleLinkElement::ParseLinkTypes(relVal, aContent->NodePrincipal());
612 bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
613 if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
614 nsAutoString hrefVal;
615 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
616 if (!hrefVal.IsEmpty()) {
617 PrefetchHref(hrefVal, aContent, hasPrefetch);
620 if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
621 nsAutoString hrefVal;
622 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
623 if (!hrefVal.IsEmpty()) {
624 PrefetchDNS(hrefVal);
631 return rv;
634 nsresult
635 nsXMLContentSink::AddContentAsLeaf(nsIContent *aContent)
637 nsresult result = NS_OK;
639 if ((eXMLContentSinkState_InProlog == mState) ||
640 (eXMLContentSinkState_InEpilog == mState)) {
641 NS_ASSERTION(mDocument, "Fragments have no prolog or epilog");
642 mDocument->AppendChildTo(aContent, false);
644 else {
645 nsCOMPtr<nsIContent> parent = GetCurrentContent();
647 if (parent) {
648 result = parent->AppendChildTo(aContent, false);
651 return result;
654 // Create an XML parser and an XSL content sink and start parsing
655 // the XSL stylesheet located at the given URI.
656 nsresult
657 nsXMLContentSink::LoadXSLStyleSheet(nsIURI* aUrl)
659 nsCOMPtr<nsIDocumentTransformer> processor =
660 do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt");
661 if (!processor) {
662 // No XSLT processor available, continue normal document loading
663 return NS_OK;
666 processor->Init(mDocument->NodePrincipal());
667 processor->SetTransformObserver(this);
669 nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup();
670 if (!loadGroup) {
671 return NS_ERROR_FAILURE;
674 if (NS_SUCCEEDED(processor->LoadStyleSheet(aUrl, loadGroup))) {
675 mXSLTProcessor.swap(processor);
678 // Intentionally ignore errors here, we should continue loading the
679 // XML document whether we're able to load the XSLT stylesheet or
680 // not.
682 return NS_OK;
685 nsresult
686 nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
687 const nsSubstring& aHref,
688 bool aAlternate,
689 const nsSubstring& aTitle,
690 const nsSubstring& aType,
691 const nsSubstring& aMedia)
693 nsresult rv = NS_OK;
694 mPrettyPrintXML = false;
696 nsAutoCString cmd;
697 if (mParser)
698 GetParser()->GetCommand(cmd);
699 if (cmd.EqualsASCII(kLoadAsData))
700 return NS_OK; // Do not load stylesheets when loading as data
702 NS_ConvertUTF16toUTF8 type(aType);
703 if (type.EqualsIgnoreCase(TEXT_XSL) ||
704 type.EqualsIgnoreCase(APPLICATION_XSLT_XML) ||
705 type.EqualsIgnoreCase(TEXT_XML) ||
706 type.EqualsIgnoreCase(APPLICATION_XML)) {
707 if (aAlternate) {
708 // don't load alternate XSLT
709 return NS_OK;
711 // LoadXSLStyleSheet needs a mDocShell.
712 if (!mDocShell)
713 return NS_OK;
715 nsCOMPtr<nsIURI> url;
716 rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
717 mDocument->GetDocBaseURI());
718 NS_ENSURE_SUCCESS(rv, rv);
720 // Do security check
721 nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
722 rv = secMan->
723 CheckLoadURIWithPrincipal(mDocument->NodePrincipal(), url,
724 nsIScriptSecurityManager::ALLOW_CHROME);
725 NS_ENSURE_SUCCESS(rv, NS_OK);
727 // Do content policy check
728 int16_t decision = nsIContentPolicy::ACCEPT;
729 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XSLT,
730 url,
731 mDocument->NodePrincipal(),
732 aElement,
733 type,
734 nullptr,
735 &decision,
736 nsContentUtils::GetContentPolicy(),
737 nsContentUtils::GetSecurityManager());
739 NS_ENSURE_SUCCESS(rv, rv);
741 if (NS_CP_REJECTED(decision)) {
742 return NS_OK;
745 return LoadXSLStyleSheet(url);
748 // Let nsContentSink deal with css.
749 rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate,
750 aTitle, aType, aMedia);
752 // nsContentSink::ProcessStyleLink handles the bookkeeping here wrt
753 // pending sheets.
755 return rv;
758 NS_IMETHODIMP
759 nsXMLContentSink::SetDocumentCharset(nsACString& aCharset)
761 if (mDocument) {
762 mDocument->SetDocumentCharacterSet(aCharset);
765 return NS_OK;
768 nsISupports *
769 nsXMLContentSink::GetTarget()
771 return mDocument;
774 bool
775 nsXMLContentSink::IsScriptExecuting()
777 return IsScriptExecutingImpl();
780 nsresult
781 nsXMLContentSink::FlushText(bool aReleaseTextNode)
783 nsresult rv = NS_OK;
785 if (mTextLength != 0) {
786 if (mLastTextNode) {
787 if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) {
788 mLastTextNodeSize = 0;
789 mLastTextNode = nullptr;
790 FlushText(aReleaseTextNode);
791 } else {
792 bool notify = HaveNotifiedForCurrentContent();
793 // We could probably always increase mInNotification here since
794 // if AppendText doesn't notify it shouldn't trigger evil code.
795 // But just in case it does, we don't want to mask any notifications.
796 if (notify) {
797 ++mInNotification;
799 rv = mLastTextNode->AppendText(mText, mTextLength, notify);
800 if (notify) {
801 --mInNotification;
804 mLastTextNodeSize += mTextLength;
805 mTextLength = 0;
807 } else {
808 nsRefPtr<nsTextNode> textContent = new nsTextNode(mNodeInfoManager);
810 mLastTextNode = textContent;
812 // Set the text in the text node
813 textContent->SetText(mText, mTextLength, false);
814 mLastTextNodeSize += mTextLength;
815 mTextLength = 0;
817 // Add text to its parent
818 rv = AddContentAsLeaf(textContent);
822 if (aReleaseTextNode) {
823 mLastTextNodeSize = 0;
824 mLastTextNode = nullptr;
827 return rv;
830 nsIContent*
831 nsXMLContentSink::GetCurrentContent()
833 if (mContentStack.Length() == 0) {
834 return nullptr;
836 return GetCurrentStackNode()->mContent;
839 StackNode*
840 nsXMLContentSink::GetCurrentStackNode()
842 int32_t count = mContentStack.Length();
843 return count != 0 ? &mContentStack[count-1] : nullptr;
847 nsresult
848 nsXMLContentSink::PushContent(nsIContent *aContent)
850 NS_PRECONDITION(aContent, "Null content being pushed!");
851 StackNode *sn = mContentStack.AppendElement();
852 NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY);
854 nsIContent* contentToPush = aContent;
856 // When an XML parser would append a node to a template element, it
857 // must instead append it to the template element's template contents.
858 if (contentToPush->IsHTML(nsGkAtoms::_template)) {
859 HTMLTemplateElement* templateElement =
860 static_cast<HTMLTemplateElement*>(contentToPush);
861 contentToPush = templateElement->Content();
864 sn->mContent = contentToPush;
865 sn->mNumFlushed = 0;
866 return NS_OK;
869 void
870 nsXMLContentSink::PopContent()
872 int32_t count = mContentStack.Length();
874 if (count == 0) {
875 NS_WARNING("Popping empty stack");
876 return;
879 mContentStack.RemoveElementAt(count - 1);
882 bool
883 nsXMLContentSink::HaveNotifiedForCurrentContent() const
885 uint32_t stackLength = mContentStack.Length();
886 if (stackLength) {
887 const StackNode& stackNode = mContentStack[stackLength - 1];
888 nsIContent* parent = stackNode.mContent;
889 return stackNode.mNumFlushed == parent->GetChildCount();
891 return true;
894 void
895 nsXMLContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
897 // XXXbz if aIgnorePendingSheets is true, what should we do when
898 // mXSLTProcessor or CanStillPrettyPrint()?
899 if (mLayoutStarted || mXSLTProcessor || CanStillPrettyPrint()) {
900 return;
902 StartLayout(aIgnorePendingSheets);
905 ////////////////////////////////////////////////////////////////////////
907 bool
908 nsXMLContentSink::SetDocElement(int32_t aNameSpaceID,
909 nsIAtom* aTagName,
910 nsIContent *aContent)
912 if (mDocElement)
913 return false;
915 // check for root elements that needs special handling for
916 // prettyprinting
917 if ((aNameSpaceID == kNameSpaceID_XBL &&
918 aTagName == nsGkAtoms::bindings) ||
919 (aNameSpaceID == kNameSpaceID_XSLT &&
920 (aTagName == nsGkAtoms::stylesheet ||
921 aTagName == nsGkAtoms::transform))) {
922 mPrettyPrintHasSpecialRoot = true;
923 if (mPrettyPrintXML) {
924 // In this case, disable script execution, stylesheet
925 // loading, and auto XLinks since we plan to prettyprint.
926 mDocument->ScriptLoader()->SetEnabled(false);
927 if (mCSSLoader) {
928 mCSSLoader->SetEnabled(false);
933 mDocElement = aContent;
934 nsresult rv = mDocument->AppendChildTo(mDocElement, NotifyForDocElement());
935 if (NS_FAILED(rv)) {
936 // If we return false here, the caller will bail out because it won't
937 // find a parent content node to append to, which is fine.
938 return false;
941 if (aTagName == nsGkAtoms::html &&
942 aNameSpaceID == kNameSpaceID_XHTML) {
943 ProcessOfflineManifest(aContent);
946 return true;
949 NS_IMETHODIMP
950 nsXMLContentSink::HandleStartElement(const char16_t *aName,
951 const char16_t **aAtts,
952 uint32_t aAttsCount,
953 uint32_t aLineNumber)
955 return HandleStartElement(aName, aAtts, aAttsCount, aLineNumber,
956 true);
959 nsresult
960 nsXMLContentSink::HandleStartElement(const char16_t *aName,
961 const char16_t **aAtts,
962 uint32_t aAttsCount,
963 uint32_t aLineNumber,
964 bool aInterruptable)
966 NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
967 // Adjust aAttsCount so it's the actual number of attributes
968 aAttsCount /= 2;
970 nsresult result = NS_OK;
971 bool appendContent = true;
972 nsCOMPtr<nsIContent> content;
974 // XXX Hopefully the parser will flag this before we get
975 // here. If we're in the epilog, there should be no
976 // new elements
977 PR_ASSERT(eXMLContentSinkState_InEpilog != mState);
979 FlushText();
980 DidAddContent();
982 mState = eXMLContentSinkState_InDocumentElement;
984 int32_t nameSpaceID;
985 nsCOMPtr<nsIAtom> prefix, localName;
986 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
987 getter_AddRefs(localName), &nameSpaceID);
989 if (!OnOpenContainer(aAtts, aAttsCount, nameSpaceID, localName, aLineNumber)) {
990 return NS_OK;
993 nsRefPtr<mozilla::dom::NodeInfo> nodeInfo;
994 nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
995 nsIDOMNode::ELEMENT_NODE);
997 result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
998 getter_AddRefs(content), &appendContent,
999 FROM_PARSER_NETWORK);
1000 NS_ENSURE_SUCCESS(result, result);
1002 // Have to do this before we push the new content on the stack... and have to
1003 // do that before we set attributes, call BindToTree, etc. Ideally we'd push
1004 // on the stack inside CreateElement (which is effectively what the HTML sink
1005 // does), but that's hard with all the subclass overrides going on.
1006 nsCOMPtr<nsIContent> parent = GetCurrentContent();
1008 result = PushContent(content);
1009 NS_ENSURE_SUCCESS(result, result);
1011 // Set the attributes on the new content element
1012 result = AddAttributes(aAtts, content);
1014 if (NS_OK == result) {
1015 // Store the element
1016 if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
1017 NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
1019 parent->AppendChildTo(content, false);
1023 // Some HTML nodes need DoneCreatingElement() called to initialize
1024 // properly (eg form state restoration).
1025 if (nodeInfo->NamespaceID() == kNameSpaceID_XHTML) {
1026 if (nodeInfo->NameAtom() == nsGkAtoms::input ||
1027 nodeInfo->NameAtom() == nsGkAtoms::button ||
1028 nodeInfo->NameAtom() == nsGkAtoms::menuitem ||
1029 nodeInfo->NameAtom() == nsGkAtoms::audio ||
1030 nodeInfo->NameAtom() == nsGkAtoms::video) {
1031 content->DoneCreatingElement();
1032 } else if (nodeInfo->NameAtom() == nsGkAtoms::head && !mCurrentHead) {
1033 mCurrentHead = content;
1037 if (IsMonolithicContainer(nodeInfo)) {
1038 mInMonolithicContainer++;
1041 if (content != mDocElement && !mCurrentHead) {
1042 // This isn't the root and we're not inside an XHTML <head>.
1043 // Might need to start layout
1044 MaybeStartLayout(false);
1047 if (content == mDocElement) {
1048 NotifyDocElementCreated(mDocument);
1051 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
1052 result;
1055 NS_IMETHODIMP
1056 nsXMLContentSink::HandleEndElement(const char16_t *aName)
1058 return HandleEndElement(aName, true);
1061 nsresult
1062 nsXMLContentSink::HandleEndElement(const char16_t *aName,
1063 bool aInterruptable)
1065 nsresult result = NS_OK;
1067 // XXX Hopefully the parser will flag this before we get
1068 // here. If we're in the prolog or epilog, there should be
1069 // no close tags for elements.
1070 PR_ASSERT(eXMLContentSinkState_InDocumentElement == mState);
1072 FlushText();
1074 StackNode* sn = GetCurrentStackNode();
1075 if (!sn) {
1076 return NS_ERROR_UNEXPECTED;
1079 nsCOMPtr<nsIContent> content;
1080 sn->mContent.swap(content);
1081 uint32_t numFlushed = sn->mNumFlushed;
1083 PopContent();
1084 NS_ASSERTION(content, "failed to pop content");
1085 #ifdef DEBUG
1086 // Check that we're closing the right thing
1087 nsCOMPtr<nsIAtom> debugNameSpacePrefix, debugTagAtom;
1088 int32_t debugNameSpaceID;
1089 nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
1090 getter_AddRefs(debugTagAtom),
1091 &debugNameSpaceID);
1092 // Check if we are closing a template element because template
1093 // elements do not get pushed on the stack, the template
1094 // element content is pushed instead.
1095 bool isTemplateElement = debugTagAtom == nsGkAtoms::_template &&
1096 debugNameSpaceID == kNameSpaceID_XHTML;
1097 NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID) ||
1098 isTemplateElement, "Wrong element being closed");
1099 #endif
1101 result = CloseElement(content);
1103 if (mCurrentHead == content) {
1104 mCurrentHead = nullptr;
1107 if (mDocElement == content) {
1108 // XXXbz for roots that don't want to be appended on open, we
1109 // probably need to deal here.... (and stop appending them on open).
1110 mState = eXMLContentSinkState_InEpilog;
1112 // We might have had no occasion to start layout yet. Do so now.
1113 MaybeStartLayout(false);
1116 int32_t stackLen = mContentStack.Length();
1117 if (mNotifyLevel >= stackLen) {
1118 if (numFlushed < content->GetChildCount()) {
1119 NotifyAppend(content, numFlushed);
1121 mNotifyLevel = stackLen - 1;
1123 DidAddContent();
1125 if (content->IsSVG(nsGkAtoms::svg)) {
1126 FlushTags();
1127 nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(content);
1128 if (NS_FAILED(NS_DispatchToMainThread(event))) {
1129 NS_WARNING("failed to dispatch svg load dispatcher");
1133 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
1134 result;
1137 NS_IMETHODIMP
1138 nsXMLContentSink::HandleComment(const char16_t *aName)
1140 FlushText();
1142 nsRefPtr<Comment> comment = new Comment(mNodeInfoManager);
1143 comment->SetText(nsDependentString(aName), false);
1144 nsresult rv = AddContentAsLeaf(comment);
1145 DidAddContent();
1147 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1150 NS_IMETHODIMP
1151 nsXMLContentSink::HandleCDataSection(const char16_t *aData,
1152 uint32_t aLength)
1154 // XSLT doesn't differentiate between text and cdata and wants adjacent
1155 // textnodes merged, so add as text.
1156 if (mXSLTProcessor) {
1157 return AddText(aData, aLength);
1160 FlushText();
1162 nsRefPtr<CDATASection> cdata = new CDATASection(mNodeInfoManager);
1163 cdata->SetText(aData, aLength, false);
1164 nsresult rv = AddContentAsLeaf(cdata);
1165 DidAddContent();
1167 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1170 NS_IMETHODIMP
1171 nsXMLContentSink::HandleDoctypeDecl(const nsAString & aSubset,
1172 const nsAString & aName,
1173 const nsAString & aSystemId,
1174 const nsAString & aPublicId,
1175 nsISupports* aCatalogData)
1177 FlushText();
1179 nsresult rv = NS_OK;
1181 NS_ASSERTION(mDocument, "Shouldn't get here from a document fragment");
1183 nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
1184 NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
1186 // Create a new doctype node
1187 nsCOMPtr<nsIDOMDocumentType> docType;
1188 rv = NS_NewDOMDocumentType(getter_AddRefs(docType), mNodeInfoManager,
1189 name, aPublicId, aSystemId, aSubset);
1190 if (NS_FAILED(rv) || !docType) {
1191 return rv;
1194 MOZ_ASSERT(!aCatalogData, "Need to add back support for catalog style "
1195 "sheets");
1197 nsCOMPtr<nsIContent> content = do_QueryInterface(docType);
1198 NS_ASSERTION(content, "doctype isn't content?");
1200 rv = mDocument->AppendChildTo(content, false);
1201 DidAddContent();
1202 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1205 NS_IMETHODIMP
1206 nsXMLContentSink::HandleCharacterData(const char16_t *aData,
1207 uint32_t aLength)
1209 return HandleCharacterData(aData, aLength, true);
1212 nsresult
1213 nsXMLContentSink::HandleCharacterData(const char16_t *aData, uint32_t aLength,
1214 bool aInterruptable)
1216 nsresult rv = NS_OK;
1217 if (aData && mState != eXMLContentSinkState_InProlog &&
1218 mState != eXMLContentSinkState_InEpilog) {
1219 rv = AddText(aData, aLength);
1221 return aInterruptable && NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1224 NS_IMETHODIMP
1225 nsXMLContentSink::HandleProcessingInstruction(const char16_t *aTarget,
1226 const char16_t *aData)
1228 FlushText();
1230 const nsDependentString target(aTarget);
1231 const nsDependentString data(aData);
1233 nsCOMPtr<nsIContent> node =
1234 NS_NewXMLProcessingInstruction(mNodeInfoManager, target, data);
1236 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(node));
1237 if (ssle) {
1238 ssle->InitStyleLinkElement(false);
1239 ssle->SetEnableUpdates(false);
1240 mPrettyPrintXML = false;
1243 nsresult rv = AddContentAsLeaf(node);
1244 NS_ENSURE_SUCCESS(rv, rv);
1245 DidAddContent();
1247 if (ssle) {
1248 // This is an xml-stylesheet processing instruction... but it might not be
1249 // a CSS one if the type is set to something else.
1250 ssle->SetEnableUpdates(true);
1251 bool willNotify;
1252 bool isAlternate;
1253 rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
1254 &willNotify,
1255 &isAlternate);
1256 NS_ENSURE_SUCCESS(rv, rv);
1258 if (willNotify) {
1259 // Successfully started a stylesheet load
1260 if (!isAlternate && !mRunsToCompletion) {
1261 ++mPendingSheetCount;
1262 mScriptLoader->AddExecuteBlocker();
1265 return NS_OK;
1269 // If it's not a CSS stylesheet PI...
1270 nsAutoString type;
1271 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type);
1273 if (mState != eXMLContentSinkState_InProlog ||
1274 !target.EqualsLiteral("xml-stylesheet") ||
1275 type.IsEmpty() ||
1276 type.LowerCaseEqualsLiteral("text/css")) {
1277 return DidProcessATokenImpl();
1280 nsAutoString href, title, media;
1281 bool isAlternate = false;
1283 // If there was no href, we can't do anything with this PI
1284 if (!ParsePIData(data, href, title, media, isAlternate)) {
1285 return DidProcessATokenImpl();
1288 rv = ProcessStyleLink(node, href, isAlternate, title, type, media);
1289 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1292 /* static */
1293 bool
1294 nsXMLContentSink::ParsePIData(const nsString &aData, nsString &aHref,
1295 nsString &aTitle, nsString &aMedia,
1296 bool &aIsAlternate)
1298 // If there was no href, we can't do anything with this PI
1299 if (!nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::href, aHref)) {
1300 return false;
1303 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::title, aTitle);
1305 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::media, aMedia);
1307 nsAutoString alternate;
1308 nsContentUtils::GetPseudoAttributeValue(aData,
1309 nsGkAtoms::alternate,
1310 alternate);
1312 aIsAlternate = alternate.EqualsLiteral("yes");
1314 return true;
1317 NS_IMETHODIMP
1318 nsXMLContentSink::HandleXMLDeclaration(const char16_t *aVersion,
1319 const char16_t *aEncoding,
1320 int32_t aStandalone)
1322 mDocument->SetXMLDeclaration(aVersion, aEncoding, aStandalone);
1324 return DidProcessATokenImpl();
1327 NS_IMETHODIMP
1328 nsXMLContentSink::ReportError(const char16_t* aErrorText,
1329 const char16_t* aSourceText,
1330 nsIScriptError *aError,
1331 bool *_retval)
1333 NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
1334 nsresult rv = NS_OK;
1336 // The expat driver should report the error. We're just cleaning up the mess.
1337 *_retval = true;
1339 mPrettyPrintXML = false;
1341 mState = eXMLContentSinkState_InProlog;
1343 // XXX need to stop scripts here -- hsivonen
1345 // stop observing in order to avoid crashing when removing content
1346 mDocument->RemoveObserver(this);
1347 mIsDocumentObserver = false;
1349 // Clear the current content and
1350 // prepare to set <parsererror> as the document root
1351 nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mDocument));
1352 if (node) {
1353 for (;;) {
1354 nsCOMPtr<nsIDOMNode> child, dummy;
1355 node->GetLastChild(getter_AddRefs(child));
1356 if (!child)
1357 break;
1358 node->RemoveChild(child, getter_AddRefs(dummy));
1361 mDocElement = nullptr;
1363 // Clear any buffered-up text we have. It's enough to set the length to 0.
1364 // The buffer itself is allocated when we're created and deleted in our
1365 // destructor, so don't mess with it.
1366 mTextLength = 0;
1368 if (mXSLTProcessor) {
1369 // Get rid of the XSLT processor.
1370 mXSLTProcessor->CancelLoads();
1371 mXSLTProcessor = nullptr;
1374 // release the nodes on stack
1375 mContentStack.Clear();
1376 mNotifyLevel = 0;
1378 rv = HandleProcessingInstruction(MOZ_UTF16("xml-stylesheet"),
1379 MOZ_UTF16("href=\"chrome://global/locale/intl.css\" type=\"text/css\""));
1380 NS_ENSURE_SUCCESS(rv, rv);
1382 const char16_t* noAtts[] = { 0, 0 };
1384 NS_NAMED_LITERAL_STRING(errorNs,
1385 "http://www.mozilla.org/newlayout/xml/parsererror.xml");
1387 nsAutoString parsererror(errorNs);
1388 parsererror.Append((char16_t)0xFFFF);
1389 parsererror.AppendLiteral("parsererror");
1391 rv = HandleStartElement(parsererror.get(), noAtts, 0, (uint32_t)-1,
1392 false);
1393 NS_ENSURE_SUCCESS(rv, rv);
1395 rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText), false);
1396 NS_ENSURE_SUCCESS(rv, rv);
1398 nsAutoString sourcetext(errorNs);
1399 sourcetext.Append((char16_t)0xFFFF);
1400 sourcetext.AppendLiteral("sourcetext");
1402 rv = HandleStartElement(sourcetext.get(), noAtts, 0, (uint32_t)-1,
1403 false);
1404 NS_ENSURE_SUCCESS(rv, rv);
1406 rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText), false);
1407 NS_ENSURE_SUCCESS(rv, rv);
1409 rv = HandleEndElement(sourcetext.get(), false);
1410 NS_ENSURE_SUCCESS(rv, rv);
1412 rv = HandleEndElement(parsererror.get(), false);
1413 NS_ENSURE_SUCCESS(rv, rv);
1415 FlushTags();
1417 return NS_OK;
1420 nsresult
1421 nsXMLContentSink::AddAttributes(const char16_t** aAtts,
1422 nsIContent* aContent)
1424 // Add tag attributes to the content attributes
1425 nsCOMPtr<nsIAtom> prefix, localName;
1426 while (*aAtts) {
1427 int32_t nameSpaceID;
1428 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
1429 getter_AddRefs(localName), &nameSpaceID);
1431 // Add attribute to content
1432 aContent->SetAttr(nameSpaceID, localName, prefix,
1433 nsDependentString(aAtts[1]), false);
1434 aAtts += 2;
1437 return NS_OK;
1440 #define NS_ACCUMULATION_BUFFER_SIZE 4096
1442 nsresult
1443 nsXMLContentSink::AddText(const char16_t* aText,
1444 int32_t aLength)
1446 // Create buffer when we first need it
1447 if (0 == mTextSize) {
1448 mText = (char16_t *) PR_MALLOC(sizeof(char16_t) * NS_ACCUMULATION_BUFFER_SIZE);
1449 if (nullptr == mText) {
1450 return NS_ERROR_OUT_OF_MEMORY;
1452 mTextSize = NS_ACCUMULATION_BUFFER_SIZE;
1455 // Copy data from string into our buffer; flush buffer when it fills up
1456 int32_t offset = 0;
1457 while (0 != aLength) {
1458 int32_t amount = mTextSize - mTextLength;
1459 if (0 == amount) {
1460 // XSLT wants adjacent textnodes merged.
1461 if (mConstrainSize && !mXSLTProcessor) {
1462 nsresult rv = FlushText();
1463 if (NS_OK != rv) {
1464 return rv;
1467 amount = mTextSize - mTextLength;
1469 else {
1470 mTextSize += aLength;
1471 mText = (char16_t *) PR_REALLOC(mText, sizeof(char16_t) * mTextSize);
1472 if (nullptr == mText) {
1473 mTextSize = 0;
1475 return NS_ERROR_OUT_OF_MEMORY;
1478 amount = aLength;
1481 if (amount > aLength) {
1482 amount = aLength;
1484 memcpy(&mText[mTextLength], &aText[offset], sizeof(char16_t) * amount);
1485 mTextLength += amount;
1486 offset += amount;
1487 aLength -= amount;
1490 return NS_OK;
1493 void
1494 nsXMLContentSink::FlushPendingNotifications(mozFlushType aType)
1496 // Only flush tags if we're not doing the notification ourselves
1497 // (since we aren't reentrant)
1498 if (!mInNotification) {
1499 if (mIsDocumentObserver) {
1500 // Only flush if we're still a document observer (so that our child
1501 // counts should be correct).
1502 if (aType >= Flush_ContentAndNotify) {
1503 FlushTags();
1505 else {
1506 FlushText(false);
1509 if (aType >= Flush_InterruptibleLayout) {
1510 // Make sure that layout has started so that the reflow flush
1511 // will actually happen.
1512 MaybeStartLayout(true);
1518 * NOTE!! Forked from SinkContext. Please keep in sync.
1520 * Flush all elements that have been seen so far such that
1521 * they are visible in the tree. Specifically, make sure
1522 * that they are all added to their respective parents.
1523 * Also, do notification at the top for all content that
1524 * has been newly added so that the frame tree is complete.
1526 nsresult
1527 nsXMLContentSink::FlushTags()
1529 mDeferredFlushTags = false;
1530 bool oldBeganUpdate = mBeganUpdate;
1531 uint32_t oldUpdates = mUpdatesInNotification;
1533 mUpdatesInNotification = 0;
1534 ++mInNotification;
1536 // Scope so we call EndUpdate before we decrease mInNotification
1537 mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, true);
1538 mBeganUpdate = true;
1540 // Don't release last text node in case we need to add to it again
1541 FlushText(false);
1543 // Start from the base of the stack (growing downward) and do
1544 // a notification from the node that is closest to the root of
1545 // tree for any content that has been added.
1547 int32_t stackPos;
1548 int32_t stackLen = mContentStack.Length();
1549 bool flushed = false;
1550 uint32_t childCount;
1551 nsIContent* content;
1553 for (stackPos = 0; stackPos < stackLen; ++stackPos) {
1554 content = mContentStack[stackPos].mContent;
1555 childCount = content->GetChildCount();
1557 if (!flushed && (mContentStack[stackPos].mNumFlushed < childCount)) {
1558 NotifyAppend(content, mContentStack[stackPos].mNumFlushed);
1559 flushed = true;
1562 mContentStack[stackPos].mNumFlushed = childCount;
1564 mNotifyLevel = stackLen - 1;
1566 --mInNotification;
1568 if (mUpdatesInNotification > 1) {
1569 UpdateChildCounts();
1572 mUpdatesInNotification = oldUpdates;
1573 mBeganUpdate = oldBeganUpdate;
1575 return NS_OK;
1579 * NOTE!! Forked from SinkContext. Please keep in sync.
1581 void
1582 nsXMLContentSink::UpdateChildCounts()
1584 // Start from the top of the stack (growing upwards) and see if any
1585 // new content has been appended. If so, we recognize that reflows
1586 // have been generated for it and we should make sure that no
1587 // further reflows occur. Note that we have to include stackPos == 0
1588 // to properly notify on kids of <html>.
1589 int32_t stackLen = mContentStack.Length();
1590 int32_t stackPos = stackLen - 1;
1591 while (stackPos >= 0) {
1592 StackNode & node = mContentStack[stackPos];
1593 node.mNumFlushed = node.mContent->GetChildCount();
1595 stackPos--;
1597 mNotifyLevel = stackLen - 1;
1600 bool
1601 nsXMLContentSink::IsMonolithicContainer(mozilla::dom::NodeInfo* aNodeInfo)
1603 return ((aNodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
1604 (aNodeInfo->NameAtom() == nsGkAtoms::tr ||
1605 aNodeInfo->NameAtom() == nsGkAtoms::select ||
1606 aNodeInfo->NameAtom() == nsGkAtoms::object ||
1607 aNodeInfo->NameAtom() == nsGkAtoms::applet)) ||
1608 (aNodeInfo->NamespaceID() == kNameSpaceID_MathML &&
1609 (aNodeInfo->NameAtom() == nsGkAtoms::math))
1613 void
1614 nsXMLContentSink::ContinueInterruptedParsingIfEnabled()
1616 if (mParser && mParser->IsParserEnabled()) {
1617 GetParser()->ContinueInterruptedParsing();
1621 void
1622 nsXMLContentSink::ContinueInterruptedParsingAsync()
1624 nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
1625 &nsXMLContentSink::ContinueInterruptedParsingIfEnabled);
1627 NS_DispatchToCurrentThread(ev);
1630 nsIParser*
1631 nsXMLContentSink::GetParser()
1633 return static_cast<nsIParser*>(mParser.get());