Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 "nsCSSStyleSheet.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/ProcessingInstruction.h"
65 using namespace mozilla::dom;
67 // XXX Open Issues:
68 // 1) what's not allowed - We need to figure out which HTML tags
69 // (prefixed with a HTML namespace qualifier) are explicitly not
70 // allowed (if any).
71 // 2) factoring code with nsHTMLContentSink - There's some amount of
72 // common code between this and the HTML content sink. This will
73 // increase as we support more and more HTML elements. How can code
74 // from the code be factored?
76 nsresult
77 NS_NewXMLContentSink(nsIXMLContentSink** aResult,
78 nsIDocument* aDoc,
79 nsIURI* aURI,
80 nsISupports* aContainer,
81 nsIChannel* aChannel)
82 {
83 NS_PRECONDITION(nullptr != aResult, "null ptr");
84 if (nullptr == aResult) {
85 return NS_ERROR_NULL_POINTER;
86 }
87 nsXMLContentSink* it = new nsXMLContentSink();
89 nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it;
90 nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
91 NS_ENSURE_SUCCESS(rv, rv);
93 return CallQueryInterface(it, aResult);
94 }
96 nsXMLContentSink::nsXMLContentSink()
97 : mConstrainSize(true),
98 mPrettyPrintXML(true)
99 {
100 }
102 nsXMLContentSink::~nsXMLContentSink()
103 {
104 if (mText) {
105 PR_Free(mText); // Doesn't null out, unlike PR_FREEIF
106 }
107 }
109 nsresult
110 nsXMLContentSink::Init(nsIDocument* aDoc,
111 nsIURI* aURI,
112 nsISupports* aContainer,
113 nsIChannel* aChannel)
114 {
115 nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
116 NS_ENSURE_SUCCESS(rv, rv);
118 aDoc->AddObserver(this);
119 mIsDocumentObserver = true;
121 if (!mDocShell) {
122 mPrettyPrintXML = false;
123 }
125 mState = eXMLContentSinkState_InProlog;
126 mDocElement = nullptr;
128 return NS_OK;
129 }
131 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLContentSink)
132 NS_INTERFACE_MAP_ENTRY(nsIContentSink)
133 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
134 NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
135 NS_INTERFACE_MAP_ENTRY(nsITransformObserver)
136 NS_INTERFACE_MAP_END_INHERITING(nsContentSink)
138 NS_IMPL_ADDREF_INHERITED(nsXMLContentSink, nsContentSink)
139 NS_IMPL_RELEASE_INHERITED(nsXMLContentSink, nsContentSink)
141 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLContentSink)
143 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLContentSink,
144 nsContentSink)
145 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentHead)
146 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocElement)
147 for (uint32_t i = 0, count = tmp->mContentStack.Length(); i < count; i++) {
148 const StackNode& node = tmp->mContentStack.ElementAt(i);
149 cb.NoteXPCOMChild(node.mContent);
150 }
151 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
153 // nsIContentSink
154 NS_IMETHODIMP
155 nsXMLContentSink::WillParse(void)
156 {
157 return WillParseImpl();
158 }
160 NS_IMETHODIMP
161 nsXMLContentSink::WillBuildModel(nsDTDMode aDTDMode)
162 {
163 WillBuildModelImpl();
165 // Notify document that the load is beginning
166 mDocument->BeginLoad();
168 // Check for correct load-command for maybe prettyprinting
169 if (mPrettyPrintXML) {
170 nsAutoCString command;
171 GetParser()->GetCommand(command);
172 if (!command.EqualsLiteral("view")) {
173 mPrettyPrintXML = false;
174 }
175 }
177 return NS_OK;
178 }
180 bool
181 nsXMLContentSink::CanStillPrettyPrint()
182 {
183 return mPrettyPrintXML &&
184 (!mPrettyPrintHasFactoredElements || mPrettyPrintHasSpecialRoot);
185 }
187 nsresult
188 nsXMLContentSink::MaybePrettyPrint()
189 {
190 if (!CanStillPrettyPrint()) {
191 mPrettyPrintXML = false;
193 return NS_OK;
194 }
196 // stop observing in order to avoid crashing when replacing content
197 mDocument->RemoveObserver(this);
198 mIsDocumentObserver = false;
200 // Reenable the CSSLoader so that the prettyprinting stylesheets can load
201 if (mCSSLoader) {
202 mCSSLoader->SetEnabled(true);
203 }
205 nsRefPtr<nsXMLPrettyPrinter> printer;
206 nsresult rv = NS_NewXMLPrettyPrinter(getter_AddRefs(printer));
207 NS_ENSURE_SUCCESS(rv, rv);
209 bool isPrettyPrinting;
210 rv = printer->PrettyPrint(mDocument, &isPrettyPrinting);
211 NS_ENSURE_SUCCESS(rv, rv);
213 mPrettyPrinting = isPrettyPrinting;
214 return NS_OK;
215 }
217 static void
218 CheckXSLTParamPI(nsIDOMProcessingInstruction* aPi,
219 nsIDocumentTransformer* aProcessor,
220 nsIDocument* aDocument)
221 {
222 nsAutoString target, data;
223 aPi->GetTarget(target);
225 // Check for namespace declarations
226 if (target.EqualsLiteral("xslt-param-namespace")) {
227 aPi->GetData(data);
228 nsAutoString prefix, namespaceAttr;
229 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::prefix,
230 prefix);
231 if (!prefix.IsEmpty() &&
232 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
233 namespaceAttr)) {
234 aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr);
235 }
236 }
238 // Check for actual parameters
239 else if (target.EqualsLiteral("xslt-param")) {
240 aPi->GetData(data);
241 nsAutoString name, namespaceAttr, select, value;
242 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name,
243 name);
244 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
245 namespaceAttr);
246 if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select, select)) {
247 select.SetIsVoid(true);
248 }
249 if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value, value)) {
250 value.SetIsVoid(true);
251 }
252 if (!name.IsEmpty()) {
253 nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument);
254 aProcessor->AddXSLTParam(name, namespaceAttr, select, value, doc);
255 }
256 }
257 }
259 NS_IMETHODIMP
260 nsXMLContentSink::DidBuildModel(bool aTerminated)
261 {
262 if (!mParser) {
263 // If mParser is null, this parse has already been terminated and must
264 // not been terminated again. However, nsDocument may still think that
265 // the parse has not been terminated and call back into here in the case
266 // where the XML parser has finished but the XSLT transform associated
267 // with the document has not.
268 return NS_OK;
269 }
271 DidBuildModelImpl(aTerminated);
273 if (mXSLTProcessor) {
274 // stop observing in order to avoid crashing when replacing content
275 mDocument->RemoveObserver(this);
276 mIsDocumentObserver = false;
278 // Check for xslt-param and xslt-param-namespace PIs
279 for (nsIContent* child = mDocument->GetFirstChild();
280 child;
281 child = child->GetNextSibling()) {
282 if (child->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
283 nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(child);
284 CheckXSLTParamPI(pi, mXSLTProcessor, mDocument);
285 }
286 else if (child->IsElement()) {
287 // Only honor PIs in the prolog
288 break;
289 }
290 }
292 nsCOMPtr<nsIDOMDocument> currentDOMDoc(do_QueryInterface(mDocument));
293 mXSLTProcessor->SetSourceContentModel(currentDOMDoc);
294 // Since the processor now holds a reference to us we drop our reference
295 // to it to avoid owning cycles
296 mXSLTProcessor = nullptr;
297 }
298 else {
299 // Kick off layout for non-XSLT transformed documents.
301 // Check if we want to prettyprint
302 MaybePrettyPrint();
304 bool startLayout = true;
306 if (mPrettyPrinting) {
307 NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!");
309 // We're pretty-printing now. See whether we should wait up on
310 // stylesheet loads
311 if (mDocument->CSSLoader()->HasPendingLoads() &&
312 NS_SUCCEEDED(mDocument->CSSLoader()->AddObserver(this))) {
313 // wait for those sheets to load
314 startLayout = false;
315 }
316 }
318 if (startLayout) {
319 StartLayout(false);
321 ScrollToRef();
322 }
324 mDocument->RemoveObserver(this);
325 mIsDocumentObserver = false;
327 mDocument->EndLoad();
328 }
330 DropParserAndPerfHint();
332 return NS_OK;
333 }
335 NS_IMETHODIMP
336 nsXMLContentSink::OnDocumentCreated(nsIDocument* aResultDocument)
337 {
338 NS_ENSURE_ARG(aResultDocument);
340 nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aResultDocument);
341 if (htmlDoc) {
342 htmlDoc->SetDocWriteDisabled(true);
343 }
345 nsCOMPtr<nsIContentViewer> contentViewer;
346 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
347 if (contentViewer) {
348 return contentViewer->SetDocumentInternal(aResultDocument, true);
349 }
350 return NS_OK;
351 }
353 NS_IMETHODIMP
354 nsXMLContentSink::OnTransformDone(nsresult aResult,
355 nsIDocument* aResultDocument)
356 {
357 NS_ASSERTION(NS_FAILED(aResult) || aResultDocument,
358 "Don't notify about transform success without a document.");
360 nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aResultDocument);
362 nsCOMPtr<nsIContentViewer> contentViewer;
363 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
365 if (NS_FAILED(aResult) && contentViewer) {
366 // Transform failed.
367 if (domDoc) {
368 aResultDocument->SetMayStartLayout(false);
369 // We have an error document.
370 contentViewer->SetDOMDocument(domDoc);
371 }
372 else {
373 // We don't have an error document, display the
374 // untransformed source document.
375 nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(mDocument);
376 contentViewer->SetDOMDocument(document);
377 }
378 }
380 nsCOMPtr<nsIDocument> originalDocument = mDocument;
381 if (NS_SUCCEEDED(aResult) || aResultDocument) {
382 // Transform succeeded or it failed and we have an error
383 // document to display.
384 mDocument = aResultDocument;
385 nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
386 if (htmlDoc) {
387 htmlDoc->SetDocWriteDisabled(false);
388 }
389 }
391 // Notify document observers that all the content has been stuck
392 // into the document.
393 // XXX do we need to notify for things like PIs? Or just the
394 // documentElement?
395 nsIContent *rootElement = mDocument->GetRootElement();
396 if (rootElement) {
397 NS_ASSERTION(mDocument->IndexOf(rootElement) != -1,
398 "rootElement not in doc?");
399 mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
400 nsNodeUtils::ContentInserted(mDocument, rootElement,
401 mDocument->IndexOf(rootElement));
402 mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
403 }
405 // Start the layout process
406 StartLayout(false);
408 ScrollToRef();
410 originalDocument->EndLoad();
412 return NS_OK;
413 }
415 NS_IMETHODIMP
416 nsXMLContentSink::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
417 bool aWasAlternate,
418 nsresult aStatus)
419 {
420 if (!mPrettyPrinting) {
421 return nsContentSink::StyleSheetLoaded(aSheet, aWasAlternate, aStatus);
422 }
424 if (!mDocument->CSSLoader()->HasPendingLoads()) {
425 mDocument->CSSLoader()->RemoveObserver(this);
426 StartLayout(false);
427 ScrollToRef();
428 }
430 return NS_OK;
431 }
433 NS_IMETHODIMP
434 nsXMLContentSink::WillInterrupt(void)
435 {
436 return WillInterruptImpl();
437 }
439 NS_IMETHODIMP
440 nsXMLContentSink::WillResume(void)
441 {
442 return WillResumeImpl();
443 }
445 NS_IMETHODIMP
446 nsXMLContentSink::SetParser(nsParserBase* aParser)
447 {
448 NS_PRECONDITION(aParser, "Should have a parser here!");
449 mParser = aParser;
450 return NS_OK;
451 }
453 nsresult
454 nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
455 nsINodeInfo* aNodeInfo, uint32_t aLineNumber,
456 nsIContent** aResult, bool* aAppendContent,
457 FromParser aFromParser)
458 {
459 NS_ASSERTION(aNodeInfo, "can't create element without nodeinfo");
461 *aResult = nullptr;
462 *aAppendContent = true;
463 nsresult rv = NS_OK;
465 nsCOMPtr<nsINodeInfo> ni = aNodeInfo;
466 nsCOMPtr<Element> content;
467 rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser);
468 NS_ENSURE_SUCCESS(rv, rv);
470 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
471 || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
472 ) {
473 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
474 sele->SetScriptLineNumber(aLineNumber);
475 sele->SetCreatorParser(GetParser());
476 mConstrainSize = false;
477 }
479 // XHTML needs some special attention
480 if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
481 mPrettyPrintHasFactoredElements = true;
482 }
483 else {
484 // If we care, find out if we just used a special factory.
485 if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
486 mPrettyPrintXML) {
487 mPrettyPrintHasFactoredElements =
488 nsContentUtils::NameSpaceManager()->
489 HasElementCreator(aNodeInfo->NamespaceID());
490 }
492 if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
493 content.forget(aResult);
495 return NS_OK;
496 }
497 }
499 if (aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
500 aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
501 aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
502 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(content));
503 if (ssle) {
504 ssle->InitStyleLinkElement(false);
505 if (aFromParser) {
506 ssle->SetEnableUpdates(false);
507 }
508 if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
509 ssle->SetLineNumber(aFromParser ? aLineNumber : 0);
510 }
511 }
512 }
514 content.forget(aResult);
516 return NS_OK;
517 }
520 nsresult
521 nsXMLContentSink::CloseElement(nsIContent* aContent)
522 {
523 NS_ASSERTION(aContent, "missing element to close");
525 nsINodeInfo *nodeInfo = aContent->NodeInfo();
527 // Some HTML nodes need DoneAddingChildren() called to initialize
528 // properly (eg form state restoration).
529 if ((nodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
530 (nodeInfo->NameAtom() == nsGkAtoms::select ||
531 nodeInfo->NameAtom() == nsGkAtoms::textarea ||
532 nodeInfo->NameAtom() == nsGkAtoms::video ||
533 nodeInfo->NameAtom() == nsGkAtoms::audio ||
534 nodeInfo->NameAtom() == nsGkAtoms::object ||
535 nodeInfo->NameAtom() == nsGkAtoms::applet))
536 || nodeInfo->NameAtom() == nsGkAtoms::title
537 ) {
538 aContent->DoneAddingChildren(HaveNotifiedForCurrentContent());
539 }
541 if (IsMonolithicContainer(nodeInfo)) {
542 mInMonolithicContainer--;
543 }
545 if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) &&
546 !nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
547 return NS_OK;
548 }
550 if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
551 || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
552 ) {
553 mConstrainSize = true;
554 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
556 if (mPreventScriptExecution) {
557 sele->PreventExecution();
558 return NS_OK;
559 }
561 // Always check the clock in nsContentSink right after a script
562 StopDeflecting();
564 // Now tell the script that it's ready to go. This may execute the script
565 // or return true, or neither if the script doesn't need executing.
566 bool block = sele->AttemptToExecute();
568 // If the parser got blocked, make sure to return the appropriate rv.
569 // I'm not sure if this is actually needed or not.
570 if (mParser && !mParser->IsParserEnabled()) {
571 // XXX The HTML sink doesn't call BlockParser here, why do we?
572 GetParser()->BlockParser();
573 block = true;
574 }
576 return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
577 }
579 nsresult rv = NS_OK;
580 if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
581 // Need to check here to make sure this meta tag does not set
582 // mPrettyPrintXML to false when we have a special root!
583 (!mPrettyPrintXML || !mPrettyPrintHasSpecialRoot)) {
584 rv = ProcessMETATag(aContent);
585 }
586 else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
587 nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
588 nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
589 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
590 if (ssle) {
591 ssle->SetEnableUpdates(true);
592 bool willNotify;
593 bool isAlternate;
594 rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
595 &willNotify,
596 &isAlternate);
597 if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
598 ++mPendingSheetCount;
599 mScriptLoader->AddExecuteBlocker();
600 }
601 }
602 // Look for <link rel="dns-prefetch" href="hostname">
603 // and look for <link rel="next" href="hostname"> like in HTML sink
604 if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
605 nsAutoString relVal;
606 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
607 if (!relVal.IsEmpty()) {
608 uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal);
609 bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
610 if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
611 nsAutoString hrefVal;
612 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
613 if (!hrefVal.IsEmpty()) {
614 PrefetchHref(hrefVal, aContent, hasPrefetch);
615 }
616 }
617 if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
618 nsAutoString hrefVal;
619 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
620 if (!hrefVal.IsEmpty()) {
621 PrefetchDNS(hrefVal);
622 }
623 }
624 }
625 }
626 }
628 return rv;
629 }
631 nsresult
632 nsXMLContentSink::AddContentAsLeaf(nsIContent *aContent)
633 {
634 nsresult result = NS_OK;
636 if ((eXMLContentSinkState_InProlog == mState) ||
637 (eXMLContentSinkState_InEpilog == mState)) {
638 NS_ASSERTION(mDocument, "Fragments have no prolog or epilog");
639 mDocument->AppendChildTo(aContent, false);
640 }
641 else {
642 nsCOMPtr<nsIContent> parent = GetCurrentContent();
644 if (parent) {
645 result = parent->AppendChildTo(aContent, false);
646 }
647 }
648 return result;
649 }
651 // Create an XML parser and an XSL content sink and start parsing
652 // the XSL stylesheet located at the given URI.
653 nsresult
654 nsXMLContentSink::LoadXSLStyleSheet(nsIURI* aUrl)
655 {
656 nsCOMPtr<nsIDocumentTransformer> processor =
657 do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt");
658 if (!processor) {
659 // No XSLT processor available, continue normal document loading
660 return NS_OK;
661 }
663 processor->Init(mDocument->NodePrincipal());
664 processor->SetTransformObserver(this);
666 nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup();
667 if (!loadGroup) {
668 return NS_ERROR_FAILURE;
669 }
671 if (NS_SUCCEEDED(processor->LoadStyleSheet(aUrl, loadGroup))) {
672 mXSLTProcessor.swap(processor);
673 }
675 // Intentionally ignore errors here, we should continue loading the
676 // XML document whether we're able to load the XSLT stylesheet or
677 // not.
679 return NS_OK;
680 }
682 nsresult
683 nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
684 const nsSubstring& aHref,
685 bool aAlternate,
686 const nsSubstring& aTitle,
687 const nsSubstring& aType,
688 const nsSubstring& aMedia)
689 {
690 nsresult rv = NS_OK;
691 mPrettyPrintXML = false;
693 nsAutoCString cmd;
694 if (mParser)
695 GetParser()->GetCommand(cmd);
696 if (cmd.EqualsASCII(kLoadAsData))
697 return NS_OK; // Do not load stylesheets when loading as data
699 NS_ConvertUTF16toUTF8 type(aType);
700 if (type.EqualsIgnoreCase(TEXT_XSL) ||
701 type.EqualsIgnoreCase(APPLICATION_XSLT_XML) ||
702 type.EqualsIgnoreCase(TEXT_XML) ||
703 type.EqualsIgnoreCase(APPLICATION_XML)) {
704 if (aAlternate) {
705 // don't load alternate XSLT
706 return NS_OK;
707 }
708 // LoadXSLStyleSheet needs a mDocShell.
709 if (!mDocShell)
710 return NS_OK;
712 nsCOMPtr<nsIURI> url;
713 rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
714 mDocument->GetDocBaseURI());
715 NS_ENSURE_SUCCESS(rv, rv);
717 // Do security check
718 nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
719 rv = secMan->
720 CheckLoadURIWithPrincipal(mDocument->NodePrincipal(), url,
721 nsIScriptSecurityManager::ALLOW_CHROME);
722 NS_ENSURE_SUCCESS(rv, NS_OK);
724 // Do content policy check
725 int16_t decision = nsIContentPolicy::ACCEPT;
726 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XSLT,
727 url,
728 mDocument->NodePrincipal(),
729 aElement,
730 type,
731 nullptr,
732 &decision,
733 nsContentUtils::GetContentPolicy(),
734 nsContentUtils::GetSecurityManager());
736 NS_ENSURE_SUCCESS(rv, rv);
738 if (NS_CP_REJECTED(decision)) {
739 return NS_OK;
740 }
742 return LoadXSLStyleSheet(url);
743 }
745 // Let nsContentSink deal with css.
746 rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate,
747 aTitle, aType, aMedia);
749 // nsContentSink::ProcessStyleLink handles the bookkeeping here wrt
750 // pending sheets.
752 return rv;
753 }
755 NS_IMETHODIMP
756 nsXMLContentSink::SetDocumentCharset(nsACString& aCharset)
757 {
758 if (mDocument) {
759 mDocument->SetDocumentCharacterSet(aCharset);
760 }
762 return NS_OK;
763 }
765 nsISupports *
766 nsXMLContentSink::GetTarget()
767 {
768 return mDocument;
769 }
771 bool
772 nsXMLContentSink::IsScriptExecuting()
773 {
774 return IsScriptExecutingImpl();
775 }
777 nsresult
778 nsXMLContentSink::FlushText(bool aReleaseTextNode)
779 {
780 nsresult rv = NS_OK;
782 if (mTextLength != 0) {
783 if (mLastTextNode) {
784 if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) {
785 mLastTextNodeSize = 0;
786 mLastTextNode = nullptr;
787 FlushText(aReleaseTextNode);
788 } else {
789 bool notify = HaveNotifiedForCurrentContent();
790 // We could probably always increase mInNotification here since
791 // if AppendText doesn't notify it shouldn't trigger evil code.
792 // But just in case it does, we don't want to mask any notifications.
793 if (notify) {
794 ++mInNotification;
795 }
796 rv = mLastTextNode->AppendText(mText, mTextLength, notify);
797 if (notify) {
798 --mInNotification;
799 }
801 mLastTextNodeSize += mTextLength;
802 mTextLength = 0;
803 }
804 } else {
805 nsRefPtr<nsTextNode> textContent = new nsTextNode(mNodeInfoManager);
807 mLastTextNode = textContent;
809 // Set the text in the text node
810 textContent->SetText(mText, mTextLength, false);
811 mLastTextNodeSize += mTextLength;
812 mTextLength = 0;
814 // Add text to its parent
815 rv = AddContentAsLeaf(textContent);
816 }
817 }
819 if (aReleaseTextNode) {
820 mLastTextNodeSize = 0;
821 mLastTextNode = nullptr;
822 }
824 return rv;
825 }
827 nsIContent*
828 nsXMLContentSink::GetCurrentContent()
829 {
830 if (mContentStack.Length() == 0) {
831 return nullptr;
832 }
833 return GetCurrentStackNode()->mContent;
834 }
836 StackNode*
837 nsXMLContentSink::GetCurrentStackNode()
838 {
839 int32_t count = mContentStack.Length();
840 return count != 0 ? &mContentStack[count-1] : nullptr;
841 }
844 nsresult
845 nsXMLContentSink::PushContent(nsIContent *aContent)
846 {
847 NS_PRECONDITION(aContent, "Null content being pushed!");
848 StackNode *sn = mContentStack.AppendElement();
849 NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY);
851 sn->mContent = aContent;
852 sn->mNumFlushed = 0;
853 return NS_OK;
854 }
856 void
857 nsXMLContentSink::PopContent()
858 {
859 int32_t count = mContentStack.Length();
861 if (count == 0) {
862 NS_WARNING("Popping empty stack");
863 return;
864 }
866 mContentStack.RemoveElementAt(count - 1);
867 }
869 bool
870 nsXMLContentSink::HaveNotifiedForCurrentContent() const
871 {
872 uint32_t stackLength = mContentStack.Length();
873 if (stackLength) {
874 const StackNode& stackNode = mContentStack[stackLength - 1];
875 nsIContent* parent = stackNode.mContent;
876 return stackNode.mNumFlushed == parent->GetChildCount();
877 }
878 return true;
879 }
881 void
882 nsXMLContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
883 {
884 // XXXbz if aIgnorePendingSheets is true, what should we do when
885 // mXSLTProcessor or CanStillPrettyPrint()?
886 if (mLayoutStarted || mXSLTProcessor || CanStillPrettyPrint()) {
887 return;
888 }
889 StartLayout(aIgnorePendingSheets);
890 }
892 ////////////////////////////////////////////////////////////////////////
894 bool
895 nsXMLContentSink::SetDocElement(int32_t aNameSpaceID,
896 nsIAtom* aTagName,
897 nsIContent *aContent)
898 {
899 if (mDocElement)
900 return false;
902 // check for root elements that needs special handling for
903 // prettyprinting
904 if ((aNameSpaceID == kNameSpaceID_XBL &&
905 aTagName == nsGkAtoms::bindings) ||
906 (aNameSpaceID == kNameSpaceID_XSLT &&
907 (aTagName == nsGkAtoms::stylesheet ||
908 aTagName == nsGkAtoms::transform))) {
909 mPrettyPrintHasSpecialRoot = true;
910 if (mPrettyPrintXML) {
911 // In this case, disable script execution, stylesheet
912 // loading, and auto XLinks since we plan to prettyprint.
913 mDocument->ScriptLoader()->SetEnabled(false);
914 if (mCSSLoader) {
915 mCSSLoader->SetEnabled(false);
916 }
917 }
918 }
920 mDocElement = aContent;
921 nsresult rv = mDocument->AppendChildTo(mDocElement, NotifyForDocElement());
922 if (NS_FAILED(rv)) {
923 // If we return false here, the caller will bail out because it won't
924 // find a parent content node to append to, which is fine.
925 return false;
926 }
928 if (aTagName == nsGkAtoms::html &&
929 aNameSpaceID == kNameSpaceID_XHTML) {
930 ProcessOfflineManifest(aContent);
931 }
933 return true;
934 }
936 NS_IMETHODIMP
937 nsXMLContentSink::HandleStartElement(const char16_t *aName,
938 const char16_t **aAtts,
939 uint32_t aAttsCount,
940 int32_t aIndex,
941 uint32_t aLineNumber)
942 {
943 return HandleStartElement(aName, aAtts, aAttsCount, aIndex, aLineNumber,
944 true);
945 }
947 nsresult
948 nsXMLContentSink::HandleStartElement(const char16_t *aName,
949 const char16_t **aAtts,
950 uint32_t aAttsCount,
951 int32_t aIndex,
952 uint32_t aLineNumber,
953 bool aInterruptable)
954 {
955 NS_PRECONDITION(aIndex >= -1, "Bogus aIndex");
956 NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
957 // Adjust aAttsCount so it's the actual number of attributes
958 aAttsCount /= 2;
960 nsresult result = NS_OK;
961 bool appendContent = true;
962 nsCOMPtr<nsIContent> content;
964 // XXX Hopefully the parser will flag this before we get
965 // here. If we're in the epilog, there should be no
966 // new elements
967 PR_ASSERT(eXMLContentSinkState_InEpilog != mState);
969 FlushText();
970 DidAddContent();
972 mState = eXMLContentSinkState_InDocumentElement;
974 int32_t nameSpaceID;
975 nsCOMPtr<nsIAtom> prefix, localName;
976 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
977 getter_AddRefs(localName), &nameSpaceID);
979 if (!OnOpenContainer(aAtts, aAttsCount, nameSpaceID, localName, aLineNumber)) {
980 return NS_OK;
981 }
983 nsCOMPtr<nsINodeInfo> nodeInfo;
984 nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
985 nsIDOMNode::ELEMENT_NODE);
987 result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
988 getter_AddRefs(content), &appendContent,
989 FROM_PARSER_NETWORK);
990 NS_ENSURE_SUCCESS(result, result);
992 // Have to do this before we push the new content on the stack... and have to
993 // do that before we set attributes, call BindToTree, etc. Ideally we'd push
994 // on the stack inside CreateElement (which is effectively what the HTML sink
995 // does), but that's hard with all the subclass overrides going on.
996 nsCOMPtr<nsIContent> parent = GetCurrentContent();
998 result = PushContent(content);
999 NS_ENSURE_SUCCESS(result, result);
1001 // Set the ID attribute atom on the node info object for this node
1002 // This must occur before the attributes are added so the name
1003 // of the id attribute is known.
1004 if (aIndex != -1 && NS_SUCCEEDED(result)) {
1005 nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]);
1007 if (IDAttr) {
1008 nodeInfo->SetIDAttributeAtom(IDAttr);
1009 }
1010 }
1012 // Set the attributes on the new content element
1013 result = AddAttributes(aAtts, content);
1015 if (NS_OK == result) {
1016 // Store the element
1017 if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
1018 NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
1020 parent->AppendChildTo(content, false);
1021 }
1022 }
1024 // Some HTML nodes need DoneCreatingElement() called to initialize
1025 // properly (eg form state restoration).
1026 if (nodeInfo->NamespaceID() == kNameSpaceID_XHTML) {
1027 if (nodeInfo->NameAtom() == nsGkAtoms::input ||
1028 nodeInfo->NameAtom() == nsGkAtoms::button ||
1029 nodeInfo->NameAtom() == nsGkAtoms::menuitem ||
1030 nodeInfo->NameAtom() == nsGkAtoms::audio ||
1031 nodeInfo->NameAtom() == nsGkAtoms::video) {
1032 content->DoneCreatingElement();
1033 } else if (nodeInfo->NameAtom() == nsGkAtoms::head && !mCurrentHead) {
1034 mCurrentHead = content;
1035 }
1036 }
1038 if (IsMonolithicContainer(nodeInfo)) {
1039 mInMonolithicContainer++;
1040 }
1042 if (content != mDocElement && !mCurrentHead) {
1043 // This isn't the root and we're not inside an XHTML <head>.
1044 // Might need to start layout
1045 MaybeStartLayout(false);
1046 }
1048 if (content == mDocElement) {
1049 NotifyDocElementCreated(mDocument);
1050 }
1052 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
1053 result;
1054 }
1056 NS_IMETHODIMP
1057 nsXMLContentSink::HandleEndElement(const char16_t *aName)
1058 {
1059 return HandleEndElement(aName, true);
1060 }
1062 nsresult
1063 nsXMLContentSink::HandleEndElement(const char16_t *aName,
1064 bool aInterruptable)
1065 {
1066 nsresult result = NS_OK;
1068 // XXX Hopefully the parser will flag this before we get
1069 // here. If we're in the prolog or epilog, there should be
1070 // no close tags for elements.
1071 PR_ASSERT(eXMLContentSinkState_InDocumentElement == mState);
1073 FlushText();
1075 StackNode* sn = GetCurrentStackNode();
1076 if (!sn) {
1077 return NS_ERROR_UNEXPECTED;
1078 }
1080 nsCOMPtr<nsIContent> content;
1081 sn->mContent.swap(content);
1082 uint32_t numFlushed = sn->mNumFlushed;
1084 PopContent();
1085 NS_ASSERTION(content, "failed to pop content");
1086 #ifdef DEBUG
1087 // Check that we're closing the right thing
1088 nsCOMPtr<nsIAtom> debugNameSpacePrefix, debugTagAtom;
1089 int32_t debugNameSpaceID;
1090 nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
1091 getter_AddRefs(debugTagAtom),
1092 &debugNameSpaceID);
1093 NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID),
1094 "Wrong element being closed");
1095 #endif
1097 result = CloseElement(content);
1099 if (mCurrentHead == content) {
1100 mCurrentHead = nullptr;
1101 }
1103 if (mDocElement == content) {
1104 // XXXbz for roots that don't want to be appended on open, we
1105 // probably need to deal here.... (and stop appending them on open).
1106 mState = eXMLContentSinkState_InEpilog;
1108 // We might have had no occasion to start layout yet. Do so now.
1109 MaybeStartLayout(false);
1110 }
1112 int32_t stackLen = mContentStack.Length();
1113 if (mNotifyLevel >= stackLen) {
1114 if (numFlushed < content->GetChildCount()) {
1115 NotifyAppend(content, numFlushed);
1116 }
1117 mNotifyLevel = stackLen - 1;
1118 }
1119 DidAddContent();
1121 if (content->IsSVG(nsGkAtoms::svg)) {
1122 FlushTags();
1123 nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(content);
1124 if (NS_FAILED(NS_DispatchToMainThread(event))) {
1125 NS_WARNING("failed to dispatch svg load dispatcher");
1126 }
1127 }
1129 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
1130 result;
1131 }
1133 NS_IMETHODIMP
1134 nsXMLContentSink::HandleComment(const char16_t *aName)
1135 {
1136 FlushText();
1138 nsRefPtr<Comment> comment = new Comment(mNodeInfoManager);
1139 comment->SetText(nsDependentString(aName), false);
1140 nsresult rv = AddContentAsLeaf(comment);
1141 DidAddContent();
1143 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1144 }
1146 NS_IMETHODIMP
1147 nsXMLContentSink::HandleCDataSection(const char16_t *aData,
1148 uint32_t aLength)
1149 {
1150 // XSLT doesn't differentiate between text and cdata and wants adjacent
1151 // textnodes merged, so add as text.
1152 if (mXSLTProcessor) {
1153 return AddText(aData, aLength);
1154 }
1156 FlushText();
1158 nsRefPtr<CDATASection> cdata = new CDATASection(mNodeInfoManager);
1159 cdata->SetText(aData, aLength, false);
1160 nsresult rv = AddContentAsLeaf(cdata);
1161 DidAddContent();
1163 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1164 }
1166 NS_IMETHODIMP
1167 nsXMLContentSink::HandleDoctypeDecl(const nsAString & aSubset,
1168 const nsAString & aName,
1169 const nsAString & aSystemId,
1170 const nsAString & aPublicId,
1171 nsISupports* aCatalogData)
1172 {
1173 FlushText();
1175 nsresult rv = NS_OK;
1177 NS_ASSERTION(mDocument, "Shouldn't get here from a document fragment");
1179 nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
1180 NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
1182 // Create a new doctype node
1183 nsCOMPtr<nsIDOMDocumentType> docType;
1184 rv = NS_NewDOMDocumentType(getter_AddRefs(docType), mNodeInfoManager,
1185 name, aPublicId, aSystemId, aSubset);
1186 if (NS_FAILED(rv) || !docType) {
1187 return rv;
1188 }
1190 if (aCatalogData && mCSSLoader && mDocument) {
1191 // bug 124570 - we only expect additional agent sheets for now -- ignore
1192 // exit codes, error are not fatal here, just that the stylesheet won't apply
1193 nsCOMPtr<nsIURI> uri(do_QueryInterface(aCatalogData));
1194 if (uri) {
1195 nsRefPtr<nsCSSStyleSheet> sheet;
1196 mCSSLoader->LoadSheetSync(uri, true, true, getter_AddRefs(sheet));
1198 #ifdef DEBUG
1199 nsAutoCString uriStr;
1200 uri->GetSpec(uriStr);
1201 printf("Loading catalog stylesheet: %s ... %s\n", uriStr.get(), sheet.get() ? "Done" : "Failed");
1202 #endif
1203 if (sheet) {
1204 mDocument->BeginUpdate(UPDATE_STYLE);
1205 mDocument->AddCatalogStyleSheet(sheet);
1206 mDocument->EndUpdate(UPDATE_STYLE);
1207 }
1208 }
1209 }
1211 nsCOMPtr<nsIContent> content = do_QueryInterface(docType);
1212 NS_ASSERTION(content, "doctype isn't content?");
1214 rv = mDocument->AppendChildTo(content, false);
1215 DidAddContent();
1216 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1217 }
1219 NS_IMETHODIMP
1220 nsXMLContentSink::HandleCharacterData(const char16_t *aData,
1221 uint32_t aLength)
1222 {
1223 return HandleCharacterData(aData, aLength, true);
1224 }
1226 nsresult
1227 nsXMLContentSink::HandleCharacterData(const char16_t *aData, uint32_t aLength,
1228 bool aInterruptable)
1229 {
1230 nsresult rv = NS_OK;
1231 if (aData && mState != eXMLContentSinkState_InProlog &&
1232 mState != eXMLContentSinkState_InEpilog) {
1233 rv = AddText(aData, aLength);
1234 }
1235 return aInterruptable && NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1236 }
1238 NS_IMETHODIMP
1239 nsXMLContentSink::HandleProcessingInstruction(const char16_t *aTarget,
1240 const char16_t *aData)
1241 {
1242 FlushText();
1244 const nsDependentString target(aTarget);
1245 const nsDependentString data(aData);
1247 nsCOMPtr<nsIContent> node =
1248 NS_NewXMLProcessingInstruction(mNodeInfoManager, target, data);
1250 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(node));
1251 if (ssle) {
1252 ssle->InitStyleLinkElement(false);
1253 ssle->SetEnableUpdates(false);
1254 mPrettyPrintXML = false;
1255 }
1257 nsresult rv = AddContentAsLeaf(node);
1258 NS_ENSURE_SUCCESS(rv, rv);
1259 DidAddContent();
1261 if (ssle) {
1262 // This is an xml-stylesheet processing instruction... but it might not be
1263 // a CSS one if the type is set to something else.
1264 ssle->SetEnableUpdates(true);
1265 bool willNotify;
1266 bool isAlternate;
1267 rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
1268 &willNotify,
1269 &isAlternate);
1270 NS_ENSURE_SUCCESS(rv, rv);
1272 if (willNotify) {
1273 // Successfully started a stylesheet load
1274 if (!isAlternate && !mRunsToCompletion) {
1275 ++mPendingSheetCount;
1276 mScriptLoader->AddExecuteBlocker();
1277 }
1279 return NS_OK;
1280 }
1281 }
1283 // If it's not a CSS stylesheet PI...
1284 nsAutoString type;
1285 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type);
1287 if (mState != eXMLContentSinkState_InProlog ||
1288 !target.EqualsLiteral("xml-stylesheet") ||
1289 type.IsEmpty() ||
1290 type.LowerCaseEqualsLiteral("text/css")) {
1291 return DidProcessATokenImpl();
1292 }
1294 nsAutoString href, title, media;
1295 bool isAlternate = false;
1297 // If there was no href, we can't do anything with this PI
1298 if (!ParsePIData(data, href, title, media, isAlternate)) {
1299 return DidProcessATokenImpl();
1300 }
1302 rv = ProcessStyleLink(node, href, isAlternate, title, type, media);
1303 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
1304 }
1306 /* static */
1307 bool
1308 nsXMLContentSink::ParsePIData(const nsString &aData, nsString &aHref,
1309 nsString &aTitle, nsString &aMedia,
1310 bool &aIsAlternate)
1311 {
1312 // If there was no href, we can't do anything with this PI
1313 if (!nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::href, aHref)) {
1314 return false;
1315 }
1317 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::title, aTitle);
1319 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::media, aMedia);
1321 nsAutoString alternate;
1322 nsContentUtils::GetPseudoAttributeValue(aData,
1323 nsGkAtoms::alternate,
1324 alternate);
1326 aIsAlternate = alternate.EqualsLiteral("yes");
1328 return true;
1329 }
1331 NS_IMETHODIMP
1332 nsXMLContentSink::HandleXMLDeclaration(const char16_t *aVersion,
1333 const char16_t *aEncoding,
1334 int32_t aStandalone)
1335 {
1336 mDocument->SetXMLDeclaration(aVersion, aEncoding, aStandalone);
1338 return DidProcessATokenImpl();
1339 }
1341 NS_IMETHODIMP
1342 nsXMLContentSink::ReportError(const char16_t* aErrorText,
1343 const char16_t* aSourceText,
1344 nsIScriptError *aError,
1345 bool *_retval)
1346 {
1347 NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
1348 nsresult rv = NS_OK;
1350 // The expat driver should report the error. We're just cleaning up the mess.
1351 *_retval = true;
1353 mPrettyPrintXML = false;
1355 mState = eXMLContentSinkState_InProlog;
1357 // XXX need to stop scripts here -- hsivonen
1359 // stop observing in order to avoid crashing when removing content
1360 mDocument->RemoveObserver(this);
1361 mIsDocumentObserver = false;
1363 // Clear the current content and
1364 // prepare to set <parsererror> as the document root
1365 nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mDocument));
1366 if (node) {
1367 for (;;) {
1368 nsCOMPtr<nsIDOMNode> child, dummy;
1369 node->GetLastChild(getter_AddRefs(child));
1370 if (!child)
1371 break;
1372 node->RemoveChild(child, getter_AddRefs(dummy));
1373 }
1374 }
1375 mDocElement = nullptr;
1377 // Clear any buffered-up text we have. It's enough to set the length to 0.
1378 // The buffer itself is allocated when we're created and deleted in our
1379 // destructor, so don't mess with it.
1380 mTextLength = 0;
1382 if (mXSLTProcessor) {
1383 // Get rid of the XSLT processor.
1384 mXSLTProcessor->CancelLoads();
1385 mXSLTProcessor = nullptr;
1386 }
1388 // release the nodes on stack
1389 mContentStack.Clear();
1390 mNotifyLevel = 0;
1392 rv = HandleProcessingInstruction(MOZ_UTF16("xml-stylesheet"),
1393 MOZ_UTF16("href=\"chrome://global/locale/intl.css\" type=\"text/css\""));
1394 NS_ENSURE_SUCCESS(rv, rv);
1396 const char16_t* noAtts[] = { 0, 0 };
1398 NS_NAMED_LITERAL_STRING(errorNs,
1399 "http://www.mozilla.org/newlayout/xml/parsererror.xml");
1401 nsAutoString parsererror(errorNs);
1402 parsererror.Append((char16_t)0xFFFF);
1403 parsererror.AppendLiteral("parsererror");
1405 rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, (uint32_t)-1,
1406 false);
1407 NS_ENSURE_SUCCESS(rv, rv);
1409 rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText), false);
1410 NS_ENSURE_SUCCESS(rv, rv);
1412 nsAutoString sourcetext(errorNs);
1413 sourcetext.Append((char16_t)0xFFFF);
1414 sourcetext.AppendLiteral("sourcetext");
1416 rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, (uint32_t)-1,
1417 false);
1418 NS_ENSURE_SUCCESS(rv, rv);
1420 rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText), false);
1421 NS_ENSURE_SUCCESS(rv, rv);
1423 rv = HandleEndElement(sourcetext.get(), false);
1424 NS_ENSURE_SUCCESS(rv, rv);
1426 rv = HandleEndElement(parsererror.get(), false);
1427 NS_ENSURE_SUCCESS(rv, rv);
1429 FlushTags();
1431 return NS_OK;
1432 }
1434 nsresult
1435 nsXMLContentSink::AddAttributes(const char16_t** aAtts,
1436 nsIContent* aContent)
1437 {
1438 // Add tag attributes to the content attributes
1439 nsCOMPtr<nsIAtom> prefix, localName;
1440 while (*aAtts) {
1441 int32_t nameSpaceID;
1442 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
1443 getter_AddRefs(localName), &nameSpaceID);
1445 // Add attribute to content
1446 aContent->SetAttr(nameSpaceID, localName, prefix,
1447 nsDependentString(aAtts[1]), false);
1448 aAtts += 2;
1449 }
1451 return NS_OK;
1452 }
1454 #define NS_ACCUMULATION_BUFFER_SIZE 4096
1456 nsresult
1457 nsXMLContentSink::AddText(const char16_t* aText,
1458 int32_t aLength)
1459 {
1460 // Create buffer when we first need it
1461 if (0 == mTextSize) {
1462 mText = (char16_t *) PR_MALLOC(sizeof(char16_t) * NS_ACCUMULATION_BUFFER_SIZE);
1463 if (nullptr == mText) {
1464 return NS_ERROR_OUT_OF_MEMORY;
1465 }
1466 mTextSize = NS_ACCUMULATION_BUFFER_SIZE;
1467 }
1469 // Copy data from string into our buffer; flush buffer when it fills up
1470 int32_t offset = 0;
1471 while (0 != aLength) {
1472 int32_t amount = mTextSize - mTextLength;
1473 if (0 == amount) {
1474 // XSLT wants adjacent textnodes merged.
1475 if (mConstrainSize && !mXSLTProcessor) {
1476 nsresult rv = FlushText();
1477 if (NS_OK != rv) {
1478 return rv;
1479 }
1481 amount = mTextSize - mTextLength;
1482 }
1483 else {
1484 mTextSize += aLength;
1485 mText = (char16_t *) PR_REALLOC(mText, sizeof(char16_t) * mTextSize);
1486 if (nullptr == mText) {
1487 mTextSize = 0;
1489 return NS_ERROR_OUT_OF_MEMORY;
1490 }
1492 amount = aLength;
1493 }
1494 }
1495 if (amount > aLength) {
1496 amount = aLength;
1497 }
1498 memcpy(&mText[mTextLength], &aText[offset], sizeof(char16_t) * amount);
1499 mTextLength += amount;
1500 offset += amount;
1501 aLength -= amount;
1502 }
1504 return NS_OK;
1505 }
1507 void
1508 nsXMLContentSink::FlushPendingNotifications(mozFlushType aType)
1509 {
1510 // Only flush tags if we're not doing the notification ourselves
1511 // (since we aren't reentrant)
1512 if (!mInNotification) {
1513 if (mIsDocumentObserver) {
1514 // Only flush if we're still a document observer (so that our child
1515 // counts should be correct).
1516 if (aType >= Flush_ContentAndNotify) {
1517 FlushTags();
1518 }
1519 else {
1520 FlushText(false);
1521 }
1522 }
1523 if (aType >= Flush_InterruptibleLayout) {
1524 // Make sure that layout has started so that the reflow flush
1525 // will actually happen.
1526 MaybeStartLayout(true);
1527 }
1528 }
1529 }
1531 /**
1532 * NOTE!! Forked from SinkContext. Please keep in sync.
1533 *
1534 * Flush all elements that have been seen so far such that
1535 * they are visible in the tree. Specifically, make sure
1536 * that they are all added to their respective parents.
1537 * Also, do notification at the top for all content that
1538 * has been newly added so that the frame tree is complete.
1539 */
1540 nsresult
1541 nsXMLContentSink::FlushTags()
1542 {
1543 mDeferredFlushTags = false;
1544 bool oldBeganUpdate = mBeganUpdate;
1545 uint32_t oldUpdates = mUpdatesInNotification;
1547 mUpdatesInNotification = 0;
1548 ++mInNotification;
1549 {
1550 // Scope so we call EndUpdate before we decrease mInNotification
1551 mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, true);
1552 mBeganUpdate = true;
1554 // Don't release last text node in case we need to add to it again
1555 FlushText(false);
1557 // Start from the base of the stack (growing downward) and do
1558 // a notification from the node that is closest to the root of
1559 // tree for any content that has been added.
1561 int32_t stackPos;
1562 int32_t stackLen = mContentStack.Length();
1563 bool flushed = false;
1564 uint32_t childCount;
1565 nsIContent* content;
1567 for (stackPos = 0; stackPos < stackLen; ++stackPos) {
1568 content = mContentStack[stackPos].mContent;
1569 childCount = content->GetChildCount();
1571 if (!flushed && (mContentStack[stackPos].mNumFlushed < childCount)) {
1572 NotifyAppend(content, mContentStack[stackPos].mNumFlushed);
1573 flushed = true;
1574 }
1576 mContentStack[stackPos].mNumFlushed = childCount;
1577 }
1578 mNotifyLevel = stackLen - 1;
1579 }
1580 --mInNotification;
1582 if (mUpdatesInNotification > 1) {
1583 UpdateChildCounts();
1584 }
1586 mUpdatesInNotification = oldUpdates;
1587 mBeganUpdate = oldBeganUpdate;
1589 return NS_OK;
1590 }
1592 /**
1593 * NOTE!! Forked from SinkContext. Please keep in sync.
1594 */
1595 void
1596 nsXMLContentSink::UpdateChildCounts()
1597 {
1598 // Start from the top of the stack (growing upwards) and see if any
1599 // new content has been appended. If so, we recognize that reflows
1600 // have been generated for it and we should make sure that no
1601 // further reflows occur. Note that we have to include stackPos == 0
1602 // to properly notify on kids of <html>.
1603 int32_t stackLen = mContentStack.Length();
1604 int32_t stackPos = stackLen - 1;
1605 while (stackPos >= 0) {
1606 StackNode & node = mContentStack[stackPos];
1607 node.mNumFlushed = node.mContent->GetChildCount();
1609 stackPos--;
1610 }
1611 mNotifyLevel = stackLen - 1;
1612 }
1614 bool
1615 nsXMLContentSink::IsMonolithicContainer(nsINodeInfo* aNodeInfo)
1616 {
1617 return ((aNodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
1618 (aNodeInfo->NameAtom() == nsGkAtoms::tr ||
1619 aNodeInfo->NameAtom() == nsGkAtoms::select ||
1620 aNodeInfo->NameAtom() == nsGkAtoms::object ||
1621 aNodeInfo->NameAtom() == nsGkAtoms::applet)) ||
1622 (aNodeInfo->NamespaceID() == kNameSpaceID_MathML &&
1623 (aNodeInfo->NameAtom() == nsGkAtoms::math))
1624 );
1625 }
1627 void
1628 nsXMLContentSink::ContinueInterruptedParsingIfEnabled()
1629 {
1630 if (mParser && mParser->IsParserEnabled()) {
1631 GetParser()->ContinueInterruptedParsing();
1632 }
1633 }
1635 void
1636 nsXMLContentSink::ContinueInterruptedParsingAsync()
1637 {
1638 nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
1639 &nsXMLContentSink::ContinueInterruptedParsingIfEnabled);
1641 NS_DispatchToCurrentThread(ev);
1642 }
1644 nsIParser*
1645 nsXMLContentSink::GetParser()
1646 {
1647 return static_cast<nsIParser*>(mParser.get());
1648 }