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 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Mozilla Communicator client code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * Pierre Phaneuf <pp@ludusdesign.com>
25 * Henri Sivonen <hsivonen@iki.fi>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nsXMLContentSink.h"
42 #include "nsIParser.h"
43 #include "nsIUnicharInputStream.h"
44 #include "nsIDocument.h"
45 #include "nsIDOMDocument.h"
46 #include "nsIDOMDocumentType.h"
47 #include "nsIDOMDOMImplementation.h"
48 #include "nsIDOMNSDocument.h"
49 #include "nsIContent.h"
51 #include "nsNetUtil.h"
52 #include "nsIDocShell.h"
53 #include "nsIDocShellTreeItem.h"
54 #include "nsIStyleSheetLinkingElement.h"
55 #include "nsPresContext.h"
56 #include "nsIPresShell.h"
57 #include "nsIDOMComment.h"
58 #include "nsIDOMCDATASection.h"
59 #include "nsDOMDocumentType.h"
60 #include "nsHTMLParts.h"
61 #include "nsVoidArray.h"
63 #include "nsICSSLoader.h"
64 #include "nsICSSStyleSheet.h"
65 #include "nsGkAtoms.h"
66 #include "nsContentUtils.h"
67 #include "nsIScriptContext.h"
68 #include "nsINameSpaceManager.h"
69 #include "nsIServiceManager.h"
70 #include "nsIScriptSecurityManager.h"
71 #include "nsIContentViewer.h"
75 #include "nsParserUtils.h"
77 #include "nsGenericElement.h"
78 #include "nsIWebNavigation.h"
79 #include "nsIScriptElement.h"
80 #include "nsScriptLoader.h"
81 #include "nsStyleLinkElement.h"
82 #include "nsIImageLoadingContent.h"
83 #include "nsReadableUtils.h"
84 #include "nsUnicharUtils.h"
85 #include "nsICookieService.h"
86 #include "nsIPrompt.h"
87 #include "nsIDOMWindowInternal.h"
88 #include "nsIChannel.h"
89 #include "nsIPrincipal.h"
90 #include "nsXMLPrettyPrinter.h"
91 #include "nsNodeInfoManager.h"
92 #include "nsContentCreatorFunctions.h"
93 #include "nsIContentPolicy.h"
94 #include "nsContentPolicyUtils.h"
95 #include "nsContentErrors.h"
96 #include "nsIDOMProcessingInstruction.h"
97 #include "nsNodeUtils.h"
98 #include "nsIScriptGlobalObject.h"
99 #include "nsEventDispatcher.h"
100 #include "mozAutoDocUpdate.h"
103 #include "nsGUIEvent.h"
106 #define kXSLType "text/xsl"
109 // 1) what's not allowed - We need to figure out which HTML tags
110 // (prefixed with a HTML namespace qualifier) are explicitly not
112 // 2) factoring code with nsHTMLContentSink - There's some amount of
113 // common code between this and the HTML content sink. This will
114 // increase as we support more and more HTML elements. How can code
115 // from the code be factored?
118 NS_NewXMLContentSink(nsIXMLContentSink
** aResult
,
121 nsISupports
* aContainer
,
122 nsIChannel
* aChannel
)
124 NS_PRECONDITION(nsnull
!= aResult
, "null ptr");
125 if (nsnull
== aResult
) {
126 return NS_ERROR_NULL_POINTER
;
128 nsXMLContentSink
* it
;
129 NS_NEWXPCOM(it
, nsXMLContentSink
);
131 return NS_ERROR_OUT_OF_MEMORY
;
134 nsCOMPtr
<nsIXMLContentSink
> kungFuDeathGrip
= it
;
135 nsresult rv
= it
->Init(aDoc
, aURI
, aContainer
, aChannel
);
136 NS_ENSURE_SUCCESS(rv
, rv
);
138 return CallQueryInterface(it
, aResult
);
141 nsXMLContentSink::nsXMLContentSink()
142 : mConstrainSize(PR_TRUE
),
143 mPrettyPrintXML(PR_TRUE
),
144 mAllowAutoXLinks(PR_TRUE
)
148 nsXMLContentSink::~nsXMLContentSink()
150 NS_IF_RELEASE(mDocElement
);
152 PR_Free(mText
); // Doesn't null out, unlike PR_FREEIF
157 nsXMLContentSink::Init(nsIDocument
* aDoc
,
159 nsISupports
* aContainer
,
160 nsIChannel
* aChannel
)
162 MOZ_TIMER_DEBUGLOG(("Reset and start: nsXMLContentSink::Init(), this=%p\n",
164 MOZ_TIMER_RESET(mWatch
);
165 MOZ_TIMER_START(mWatch
);
167 nsresult rv
= nsContentSink::Init(aDoc
, aURI
, aContainer
, aChannel
);
168 NS_ENSURE_SUCCESS(rv
, rv
);
170 aDoc
->AddObserver(this);
173 mPrettyPrintXML
= PR_FALSE
;
176 mState
= eXMLContentSinkState_InProlog
;
177 mDocElement
= nsnull
;
179 MOZ_TIMER_DEBUGLOG(("Stop: nsXMLContentSink::Init()\n"));
180 MOZ_TIMER_STOP(mWatch
);
184 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLContentSink
)
185 NS_INTERFACE_MAP_ENTRY(nsIContentSink
)
186 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink
)
187 NS_INTERFACE_MAP_ENTRY(nsIExpatSink
)
188 NS_INTERFACE_MAP_ENTRY(nsITransformObserver
)
189 NS_INTERFACE_MAP_END_INHERITING(nsContentSink
)
191 NS_IMPL_ADDREF_INHERITED(nsXMLContentSink
, nsContentSink
)
192 NS_IMPL_RELEASE_INHERITED(nsXMLContentSink
, nsContentSink
)
194 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLContentSink
)
196 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLContentSink
,
198 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCurrentHead
)
199 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDocElement
)
200 for (PRUint32 i
= 0, count
= tmp
->mContentStack
.Length(); i
< count
; i
++) {
201 const StackNode
& node
= tmp
->mContentStack
.ElementAt(i
);
202 cb
.NoteXPCOMChild(node
.mContent
);
204 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
208 nsXMLContentSink::WillParse(void)
210 return WillParseImpl();
214 nsXMLContentSink::WillBuildModel(void)
216 WillBuildModelImpl();
218 // Notify document that the load is beginning
219 mDocument
->BeginLoad();
221 // Check for correct load-command for maybe prettyprinting
222 if (mPrettyPrintXML
) {
223 nsCAutoString command
;
224 mParser
->GetCommand(command
);
225 if (!command
.EqualsLiteral("view")) {
226 mPrettyPrintXML
= PR_FALSE
;
234 nsXMLContentSink::CanStillPrettyPrint()
236 return mPrettyPrintXML
&&
237 (!mPrettyPrintHasFactoredElements
|| mPrettyPrintHasSpecialRoot
);
241 nsXMLContentSink::MaybePrettyPrint()
243 if (!CanStillPrettyPrint()) {
244 mPrettyPrintXML
= PR_FALSE
;
249 // stop observing in order to avoid crashing when replacing content
250 mDocument
->RemoveObserver(this);
252 // Reenable the CSSLoader so that the prettyprinting stylesheets can load
254 mCSSLoader
->SetEnabled(PR_TRUE
);
257 nsCOMPtr
<nsXMLPrettyPrinter
> printer
;
258 nsresult rv
= NS_NewXMLPrettyPrinter(getter_AddRefs(printer
));
259 NS_ENSURE_SUCCESS(rv
, rv
);
261 PRBool isPrettyPrinting
;
262 rv
= printer
->PrettyPrint(mDocument
, &isPrettyPrinting
);
263 NS_ENSURE_SUCCESS(rv
, rv
);
265 mPrettyPrinting
= isPrettyPrinting
;
270 CheckXSLTParamPI(nsIDOMProcessingInstruction
* aPi
,
271 nsIDocumentTransformer
* aProcessor
,
272 nsIDocument
* aDocument
)
274 nsAutoString target
, data
;
275 aPi
->GetTarget(target
);
277 // Check for namespace declarations
278 if (target
.EqualsLiteral("xslt-param-namespace")) {
280 nsAutoString prefix
, namespaceAttr
;
281 nsParserUtils::GetQuotedAttributeValue(data
, nsGkAtoms::prefix
,
283 if (!prefix
.IsEmpty() &&
284 nsParserUtils::GetQuotedAttributeValue(data
, nsGkAtoms::_namespace
,
286 aProcessor
->AddXSLTParamNamespace(prefix
, namespaceAttr
);
290 // Check for actual parameters
291 else if (target
.EqualsLiteral("xslt-param")) {
293 nsAutoString name
, namespaceAttr
, select
, value
;
294 nsParserUtils::GetQuotedAttributeValue(data
, nsGkAtoms::name
,
296 nsParserUtils::GetQuotedAttributeValue(data
, nsGkAtoms::_namespace
,
298 if (!nsParserUtils::GetQuotedAttributeValue(data
, nsGkAtoms::select
, select
)) {
299 select
.SetIsVoid(PR_TRUE
);
301 if (!nsParserUtils::GetQuotedAttributeValue(data
, nsGkAtoms::value
, value
)) {
302 value
.SetIsVoid(PR_TRUE
);
304 if (!name
.IsEmpty()) {
305 nsCOMPtr
<nsIDOMNode
> doc
= do_QueryInterface(aDocument
);
306 aProcessor
->AddXSLTParam(name
, namespaceAttr
, select
, value
, doc
);
312 nsXMLContentSink::DidBuildModel()
316 if (mXSLTProcessor
) {
317 // stop observing in order to avoid crashing when replacing content
318 mDocument
->RemoveObserver(this);
320 // Check for xslt-param and xslt-param-namespace PIs
323 for (i
= 0; (child
= mDocument
->GetChildAt(i
)); ++i
) {
324 if (child
->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION
)) {
325 nsCOMPtr
<nsIDOMProcessingInstruction
> pi
= do_QueryInterface(child
);
326 CheckXSLTParamPI(pi
, mXSLTProcessor
, mDocument
);
328 else if (child
->IsNodeOfType(nsINode::eELEMENT
)) {
329 // Only honor PIs in the prolog
334 nsCOMPtr
<nsIDOMDocument
> currentDOMDoc(do_QueryInterface(mDocument
));
335 mXSLTProcessor
->SetSourceContentModel(currentDOMDoc
);
336 // Since the processor now holds a reference to us we drop our reference
337 // to it to avoid owning cycles
338 mXSLTProcessor
= nsnull
;
341 // Kick off layout for non-XSLT transformed documents.
342 mDocument
->ScriptLoader()->RemoveObserver(this);
345 // Notify document observers that all the content has been stuck
346 // into the document.
347 // XXX do we need to notify for things like PIs? Or just the
349 NS_ASSERTION(mDocument
->IndexOf(mDocElement
) != -1,
350 "mDocElement not in doc?");
353 // Check if we want to prettyprint
356 PRBool startLayout
= PR_TRUE
;
358 if (mPrettyPrinting
) {
359 NS_ASSERTION(!mPendingSheetCount
, "Shouldn't have pending sheets here!");
361 // We're pretty-printing now. See whether we should wait up on
363 if (mDocument
->CSSLoader()->HasPendingLoads() &&
364 NS_SUCCEEDED(mDocument
->CSSLoader()->AddObserver(this))) {
365 // wait for those sheets to load
366 startLayout
= PR_FALSE
;
371 StartLayout(PR_FALSE
);
376 mDocument
->RemoveObserver(this);
378 mDocument
->EndLoad();
381 DropParserAndPerfHint();
387 nsXMLContentSink::OnDocumentCreated(nsIDocument
* aResultDocument
)
389 NS_ENSURE_ARG(aResultDocument
);
391 nsCOMPtr
<nsIContentViewer
> contentViewer
;
392 mDocShell
->GetContentViewer(getter_AddRefs(contentViewer
));
394 nsCOMPtr
<nsIDOMDocument
> doc
= do_QueryInterface(aResultDocument
);
395 return contentViewer
->SetDOMDocument(doc
);
401 nsXMLContentSink::OnTransformDone(nsresult aResult
,
402 nsIDocument
* aResultDocument
)
404 NS_ASSERTION(NS_FAILED(aResult
) || aResultDocument
,
405 "Don't notify about transform success without a document.");
407 nsCOMPtr
<nsIDOMDocument
> domDoc
= do_QueryInterface(aResultDocument
);
409 nsCOMPtr
<nsIContentViewer
> contentViewer
;
410 mDocShell
->GetContentViewer(getter_AddRefs(contentViewer
));
412 if (NS_FAILED(aResult
) && contentViewer
) {
415 aResultDocument
->SetMayStartLayout(PR_FALSE
);
416 // We have an error document.
417 contentViewer
->SetDOMDocument(domDoc
);
420 // We don't have an error document, display the
421 // untransformed source document.
422 nsCOMPtr
<nsIDOMDocument
> document
= do_QueryInterface(mDocument
);
423 contentViewer
->SetDOMDocument(document
);
427 nsCOMPtr
<nsIDocument
> originalDocument
= mDocument
;
428 if (NS_SUCCEEDED(aResult
) || aResultDocument
) {
429 // Transform succeeded or it failed and we have an error
430 // document to display.
431 mDocument
= aResultDocument
;
434 originalDocument
->ScriptLoader()->RemoveObserver(this);
436 // Notify document observers that all the content has been stuck
437 // into the document.
438 // XXX do we need to notify for things like PIs? Or just the
440 nsIContent
*rootContent
= mDocument
->GetRootContent();
442 NS_ASSERTION(mDocument
->IndexOf(rootContent
) != -1,
443 "rootContent not in doc?");
444 mDocument
->BeginUpdate(UPDATE_CONTENT_MODEL
);
445 nsNodeUtils::ContentInserted(mDocument
, rootContent
,
446 mDocument
->IndexOf(rootContent
));
447 mDocument
->EndUpdate(UPDATE_CONTENT_MODEL
);
450 // Start the layout process
451 StartLayout(PR_FALSE
);
455 originalDocument
->EndLoad();
461 nsXMLContentSink::StyleSheetLoaded(nsICSSStyleSheet
* aSheet
,
462 PRBool aWasAlternate
,
465 if (!mPrettyPrinting
) {
466 return nsContentSink::StyleSheetLoaded(aSheet
, aWasAlternate
, aStatus
);
469 if (!mDocument
->CSSLoader()->HasPendingLoads()) {
470 mDocument
->CSSLoader()->RemoveObserver(this);
471 StartLayout(PR_FALSE
);
479 nsXMLContentSink::WillInterrupt(void)
481 return WillInterruptImpl();
485 nsXMLContentSink::WillResume(void)
487 return WillResumeImpl();
491 nsXMLContentSink::SetParser(nsIParser
* aParser
)
493 NS_PRECONDITION(aParser
, "Should have a parser here!");
499 nsXMLContentSink::CreateElement(const PRUnichar
** aAtts
, PRUint32 aAttsCount
,
500 nsINodeInfo
* aNodeInfo
, PRUint32 aLineNumber
,
501 nsIContent
** aResult
, PRBool
* aAppendContent
,
504 NS_ASSERTION(aNodeInfo
, "can't create element without nodeinfo");
507 *aAppendContent
= PR_TRUE
;
510 nsCOMPtr
<nsIContent
> content
;
511 rv
= NS_NewElement(getter_AddRefs(content
), aNodeInfo
->NamespaceID(),
512 aNodeInfo
, aFromParser
);
513 NS_ENSURE_SUCCESS(rv
, rv
);
515 if (aNodeInfo
->Equals(nsGkAtoms::script
, kNameSpaceID_XHTML
)
517 || aNodeInfo
->Equals(nsGkAtoms::script
, kNameSpaceID_SVG
)
520 nsCOMPtr
<nsIScriptElement
> sele
= do_QueryInterface(content
);
521 sele
->SetScriptLineNumber(aLineNumber
);
522 if (aNodeInfo
->Equals(nsGkAtoms::script
, kNameSpaceID_SVG
)) {
523 sele
->WillCallDoneAddingChildren();
525 mConstrainSize
= PR_FALSE
;
528 // XHTML needs some special attention
529 if (aNodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
)) {
530 mPrettyPrintHasFactoredElements
= PR_TRUE
;
533 // If we care, find out if we just used a special factory.
534 if (!mPrettyPrintHasFactoredElements
&& !mPrettyPrintHasSpecialRoot
&&
536 mPrettyPrintHasFactoredElements
=
537 nsContentUtils::NameSpaceManager()->
538 HasElementCreator(aNodeInfo
->NamespaceID());
541 if (!aNodeInfo
->NamespaceEquals(kNameSpaceID_SVG
)) {
542 content
.swap(*aResult
);
548 if (aNodeInfo
->Equals(nsGkAtoms::link
, kNameSpaceID_XHTML
) ||
549 aNodeInfo
->Equals(nsGkAtoms::style
, kNameSpaceID_XHTML
) ||
550 aNodeInfo
->Equals(nsGkAtoms::style
, kNameSpaceID_SVG
)) {
551 nsCOMPtr
<nsIStyleSheetLinkingElement
> ssle(do_QueryInterface(content
));
553 ssle
->InitStyleLinkElement(PR_FALSE
);
554 ssle
->SetEnableUpdates(PR_FALSE
);
555 if (!aNodeInfo
->Equals(nsGkAtoms::link
, kNameSpaceID_XHTML
)) {
556 ssle
->SetLineNumber(aLineNumber
);
561 content
.swap(*aResult
);
568 nsXMLContentSink::CloseElement(nsIContent
* aContent
)
570 NS_ASSERTION(aContent
, "missing element to close");
572 nsINodeInfo
*nodeInfo
= aContent
->NodeInfo();
574 // Some HTML nodes need DoneAddingChildren() called to initialize
575 // properly (eg form state restoration).
576 if ((nodeInfo
->NamespaceID() == kNameSpaceID_XHTML
&&
577 (nodeInfo
->NameAtom() == nsGkAtoms::select
||
578 nodeInfo
->NameAtom() == nsGkAtoms::textarea
||
580 nodeInfo
->NameAtom() == nsGkAtoms::video
||
581 nodeInfo
->NameAtom() == nsGkAtoms::audio
||
583 nodeInfo
->NameAtom() == nsGkAtoms::object
||
584 nodeInfo
->NameAtom() == nsGkAtoms::applet
))
586 || nodeInfo
->NamespaceID() > kNameSpaceID_LastBuiltin
588 || nodeInfo
->NameAtom() == nsGkAtoms::title
590 aContent
->DoneAddingChildren(HaveNotifiedForCurrentContent());
593 if (IsMonolithicContainer(nodeInfo
)) {
594 mInMonolithicContainer
--;
597 if (!nodeInfo
->NamespaceEquals(kNameSpaceID_XHTML
) &&
598 !nodeInfo
->NamespaceEquals(kNameSpaceID_SVG
)) {
604 if (nodeInfo
->Equals(nsGkAtoms::script
, kNameSpaceID_XHTML
)
606 || nodeInfo
->Equals(nsGkAtoms::script
, kNameSpaceID_SVG
)
609 mConstrainSize
= PR_TRUE
;
611 // Now tell the script that it's ready to go. This may execute the script
612 // or return NS_ERROR_HTMLPARSER_BLOCK. Or neither if the script doesn't
614 rv
= aContent
->DoneAddingChildren(PR_TRUE
);
616 // If the act of insertion evaluated the script, we're fine.
617 // Else, block the parser till the script has loaded.
618 if (rv
== NS_ERROR_HTMLPARSER_BLOCK
) {
619 nsCOMPtr
<nsIScriptElement
> sele
= do_QueryInterface(aContent
);
620 mScriptElements
.AppendObject(sele
);
623 // If the parser got blocked, make sure to return the appropriate rv.
624 // I'm not sure if this is actually needed or not.
625 if (mParser
&& !mParser
->IsParserEnabled()) {
626 // XXX The HTML sink doesn't call BlockParser here, why do we?
627 mParser
->BlockParser();
628 rv
= NS_ERROR_HTMLPARSER_BLOCK
;
634 if (nodeInfo
->Equals(nsGkAtoms::base
, kNameSpaceID_XHTML
) &&
635 !mHasProcessedBase
) {
636 // The first base wins
637 ProcessBASETag(aContent
);
638 mHasProcessedBase
= PR_TRUE
;
640 else if (nodeInfo
->Equals(nsGkAtoms::meta
, kNameSpaceID_XHTML
) &&
641 // Need to check here to make sure this meta tag does not set
642 // mPrettyPrintXML to false when we have a special root!
643 (!mPrettyPrintXML
|| !mPrettyPrintHasSpecialRoot
)) {
644 rv
= ProcessMETATag(aContent
);
646 else if (nodeInfo
->Equals(nsGkAtoms::link
, kNameSpaceID_XHTML
) ||
647 nodeInfo
->Equals(nsGkAtoms::style
, kNameSpaceID_XHTML
) ||
648 nodeInfo
->Equals(nsGkAtoms::style
, kNameSpaceID_SVG
)) {
649 nsCOMPtr
<nsIStyleSheetLinkingElement
> ssle(do_QueryInterface(aContent
));
651 ssle
->SetEnableUpdates(PR_TRUE
);
654 rv
= ssle
->UpdateStyleSheet(this, &willNotify
, &isAlternate
);
655 if (NS_SUCCEEDED(rv
) && willNotify
&& !isAlternate
) {
656 ++mPendingSheetCount
;
657 mScriptLoader
->AddExecuteBlocker();
660 // Look for <link rel="dns-prefetch" href="hostname">
661 if (nodeInfo
->Equals(nsGkAtoms::link
, kNameSpaceID_XHTML
)) {
663 aContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::rel
, relVal
);
664 if (relVal
.EqualsLiteral("dns-prefetch")) {
665 nsAutoString hrefVal
;
666 aContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::href
, hrefVal
);
667 if (!hrefVal
.IsEmpty()) {
668 PrefetchDNS(hrefVal
);
678 nsXMLContentSink::AddContentAsLeaf(nsIContent
*aContent
)
680 nsresult result
= NS_OK
;
682 if ((eXMLContentSinkState_InProlog
== mState
) ||
683 (eXMLContentSinkState_InEpilog
== mState
)) {
684 NS_ASSERTION(mDocument
, "Fragments have no prolog or epilog");
685 mDocument
->AppendChildTo(aContent
, PR_FALSE
);
688 nsCOMPtr
<nsIContent
> parent
= GetCurrentContent();
691 result
= parent
->AppendChildTo(aContent
, PR_FALSE
);
697 // Create an XML parser and an XSL content sink and start parsing
698 // the XSL stylesheet located at the given URI.
700 nsXMLContentSink::LoadXSLStyleSheet(nsIURI
* aUrl
)
702 nsCOMPtr
<nsIDocumentTransformer
> processor
=
703 do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt");
705 // No XSLT processor available, continue normal document loading
709 processor
->Init(mDocument
->NodePrincipal());
710 processor
->SetTransformObserver(this);
712 nsCOMPtr
<nsILoadGroup
> loadGroup
= mDocument
->GetDocumentLoadGroup();
714 return NS_ERROR_FAILURE
;
717 if (NS_SUCCEEDED(processor
->LoadStyleSheet(aUrl
, loadGroup
))) {
718 mXSLTProcessor
.swap(processor
);
721 // Intentionally ignore errors here, we should continue loading the
722 // XML document whether we're able to load the XSLT stylesheet or
729 nsXMLContentSink::ProcessStyleLink(nsIContent
* aElement
,
730 const nsSubstring
& aHref
,
732 const nsSubstring
& aTitle
,
733 const nsSubstring
& aType
,
734 const nsSubstring
& aMedia
)
737 mPrettyPrintXML
= PR_FALSE
;
741 mParser
->GetCommand(cmd
);
742 if (cmd
.EqualsASCII(kLoadAsData
))
743 return NS_OK
; // Do not load stylesheets when loading as data
745 NS_ConvertUTF16toUTF8
type(aType
);
746 if (type
.EqualsIgnoreCase(kXSLType
) ||
747 type
.EqualsIgnoreCase(kXMLTextContentType
) ||
748 type
.EqualsIgnoreCase(kXMLApplicationContentType
)) {
750 // don't load alternate XSLT
753 // LoadXSLStyleSheet needs a mDocShell.
757 nsCOMPtr
<nsIURI
> url
;
758 rv
= NS_NewURI(getter_AddRefs(url
), aHref
, nsnull
, mDocumentBaseURI
);
759 NS_ENSURE_SUCCESS(rv
, rv
);
762 nsIScriptSecurityManager
*secMan
= nsContentUtils::GetSecurityManager();
764 CheckLoadURIWithPrincipal(mDocument
->NodePrincipal(), url
,
765 nsIScriptSecurityManager::ALLOW_CHROME
);
766 NS_ENSURE_SUCCESS(rv
, NS_OK
);
768 // Do content policy check
769 PRInt16 decision
= nsIContentPolicy::ACCEPT
;
770 rv
= NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET
,
772 mDocument
->NodePrincipal(),
777 nsContentUtils::GetContentPolicy(),
778 nsContentUtils::GetSecurityManager());
780 NS_ENSURE_SUCCESS(rv
, rv
);
782 if (NS_CP_REJECTED(decision
)) {
786 return LoadXSLStyleSheet(url
);
789 // Let nsContentSink deal with css.
790 rv
= nsContentSink::ProcessStyleLink(aElement
, aHref
, aAlternate
,
791 aTitle
, aType
, aMedia
);
793 // nsContentSink::ProcessStyleLink handles the bookkeeping here wrt
800 nsXMLContentSink::ProcessBASETag(nsIContent
* aContent
)
802 NS_ASSERTION(aContent
, "missing base-element");
807 if (aContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::target
, value
)) {
808 mDocument
->SetBaseTarget(value
);
811 if (aContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::href
, value
)) {
812 nsCOMPtr
<nsIURI
> baseURI
;
813 nsresult rv
= NS_NewURI(getter_AddRefs(baseURI
), value
);
814 if (NS_SUCCEEDED(rv
)) {
815 rv
= mDocument
->SetBaseURI(baseURI
); // The document checks if it is legal to set this base
816 if (NS_SUCCEEDED(rv
)) {
817 mDocumentBaseURI
= mDocument
->GetBaseURI();
826 nsXMLContentSink::SetDocumentCharset(nsACString
& aCharset
)
829 mDocument
->SetDocumentCharacterSet(aCharset
);
836 nsXMLContentSink::GetTarget()
842 nsXMLContentSink::FlushText(PRBool aReleaseTextNode
)
846 if (mTextLength
!= 0) {
848 if ((mLastTextNodeSize
+ mTextLength
) > mTextSize
&& !mXSLTProcessor
) {
849 mLastTextNodeSize
= 0;
850 mLastTextNode
= nsnull
;
851 FlushText(aReleaseTextNode
);
853 PRBool notify
= HaveNotifiedForCurrentContent();
854 // We could probably always increase mInNotification here since
855 // if AppendText doesn't notify it shouldn't trigger evil code.
856 // But just in case it does, we don't want to mask any notifications.
860 rv
= mLastTextNode
->AppendText(mText
, mTextLength
, notify
);
865 mLastTextNodeSize
+= mTextLength
;
869 nsCOMPtr
<nsIContent
> textContent
;
870 rv
= NS_NewTextNode(getter_AddRefs(textContent
),
872 NS_ENSURE_SUCCESS(rv
, rv
);
874 mLastTextNode
= textContent
;
876 // Set the text in the text node
877 textContent
->SetText(mText
, mTextLength
, PR_FALSE
);
878 mLastTextNodeSize
+= mTextLength
;
881 // Add text to its parent
882 rv
= AddContentAsLeaf(textContent
);
886 if (aReleaseTextNode
) {
887 mLastTextNodeSize
= 0;
888 mLastTextNode
= nsnull
;
895 nsXMLContentSink::GetCurrentContent()
897 if (mContentStack
.Length() == 0) {
900 return GetCurrentStackNode().mContent
;
904 nsXMLContentSink::GetCurrentStackNode()
906 PRInt32 count
= mContentStack
.Length();
907 NS_ASSERTION(count
> 0, "Bogus Length()");
908 return mContentStack
[count
-1];
913 nsXMLContentSink::PushContent(nsIContent
*aContent
)
915 NS_PRECONDITION(aContent
, "Null content being pushed!");
916 StackNode
*sn
= mContentStack
.AppendElement();
917 NS_ENSURE_TRUE(sn
, NS_ERROR_OUT_OF_MEMORY
);
919 sn
->mContent
= aContent
;
925 nsXMLContentSink::PopContent()
927 PRInt32 count
= mContentStack
.Length();
930 NS_WARNING("Popping empty stack");
934 mContentStack
.RemoveElementAt(count
- 1);
938 nsXMLContentSink::HaveNotifiedForCurrentContent() const
940 PRUint32 stackLength
= mContentStack
.Length();
942 const StackNode
& stackNode
= mContentStack
[stackLength
- 1];
943 nsIContent
* parent
= stackNode
.mContent
;
944 return stackNode
.mNumFlushed
== parent
->GetChildCount();
950 nsXMLContentSink::MaybeStartLayout(PRBool aIgnorePendingSheets
)
952 // XXXbz if aIgnorePendingSheets is true, what should we do when
953 // mXSLTProcessor or CanStillPrettyPrint()?
954 if (mLayoutStarted
|| mXSLTProcessor
|| CanStillPrettyPrint()) {
957 StartLayout(aIgnorePendingSheets
);
960 ////////////////////////////////////////////////////////////////////////
963 nsXMLContentSink::SetDocElement(PRInt32 aNameSpaceID
,
965 nsIContent
*aContent
)
970 // check for root elements that needs special handling for
972 if ((aNameSpaceID
== kNameSpaceID_XBL
&&
973 aTagName
== nsGkAtoms::bindings
) ||
974 (aNameSpaceID
== kNameSpaceID_XSLT
&&
975 (aTagName
== nsGkAtoms::stylesheet
||
976 aTagName
== nsGkAtoms::transform
))) {
977 mPrettyPrintHasSpecialRoot
= PR_TRUE
;
978 if (mPrettyPrintXML
) {
979 // In this case, disable script execution, stylesheet
980 // loading, and auto XLinks since we plan to prettyprint.
981 mAllowAutoXLinks
= PR_FALSE
;
982 mDocument
->ScriptLoader()->SetEnabled(PR_FALSE
);
984 mCSSLoader
->SetEnabled(PR_FALSE
);
989 mDocElement
= aContent
;
990 NS_ADDREF(mDocElement
);
991 nsresult rv
= mDocument
->AppendChildTo(mDocElement
, PR_TRUE
);
993 // If we return PR_FALSE here, the caller will bail out because it won't
994 // find a parent content node to append to, which is fine.
1001 nsXMLContentSink::HandleStartElement(const PRUnichar
*aName
,
1002 const PRUnichar
**aAtts
,
1003 PRUint32 aAttsCount
,
1005 PRUint32 aLineNumber
)
1007 return HandleStartElement(aName
, aAtts
, aAttsCount
, aIndex
, aLineNumber
,
1012 nsXMLContentSink::HandleStartElement(const PRUnichar
*aName
,
1013 const PRUnichar
**aAtts
,
1014 PRUint32 aAttsCount
,
1016 PRUint32 aLineNumber
,
1017 PRBool aInterruptable
)
1019 NS_PRECONDITION(aIndex
>= -1, "Bogus aIndex");
1020 NS_PRECONDITION(aAttsCount
% 2 == 0, "incorrect aAttsCount");
1021 // Adjust aAttsCount so it's the actual number of attributes
1024 nsresult result
= NS_OK
;
1025 PRBool appendContent
= PR_TRUE
;
1026 nsCOMPtr
<nsIContent
> content
;
1028 // XXX Hopefully the parser will flag this before we get
1029 // here. If we're in the epilog, there should be no
1031 PR_ASSERT(eXMLContentSinkState_InEpilog
!= mState
);
1036 mState
= eXMLContentSinkState_InDocumentElement
;
1038 PRInt32 nameSpaceID
;
1039 nsCOMPtr
<nsIAtom
> prefix
, localName
;
1040 nsContentUtils::SplitExpatName(aName
, getter_AddRefs(prefix
),
1041 getter_AddRefs(localName
), &nameSpaceID
);
1043 if (!OnOpenContainer(aAtts
, aAttsCount
, nameSpaceID
, localName
, aLineNumber
)) {
1047 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
1048 nodeInfo
= mNodeInfoManager
->GetNodeInfo(localName
, prefix
, nameSpaceID
);
1049 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
1051 result
= CreateElement(aAtts
, aAttsCount
, nodeInfo
, aLineNumber
,
1052 getter_AddRefs(content
), &appendContent
, PR_TRUE
);
1053 NS_ENSURE_SUCCESS(result
, result
);
1055 // Have to do this before we push the new content on the stack... and have to
1056 // do that before we set attributes, call BindToTree, etc. Ideally we'd push
1057 // on the stack inside CreateElement (which is effectively what the HTML sink
1058 // does), but that's hard with all the subclass overrides going on.
1059 nsCOMPtr
<nsIContent
> parent
= GetCurrentContent();
1061 result
= PushContent(content
);
1062 NS_ENSURE_SUCCESS(result
, result
);
1064 // Set the ID attribute atom on the node info object for this node
1065 // This must occur before the attributes are added so the name
1066 // of the id attribute is known.
1067 if (aIndex
!= -1 && NS_SUCCEEDED(result
)) {
1068 nsCOMPtr
<nsIAtom
> IDAttr
= do_GetAtom(aAtts
[aIndex
]);
1071 nodeInfo
->SetIDAttributeAtom(IDAttr
);
1076 if (nameSpaceID
> kNameSpaceID_LastBuiltin
)
1077 content
->BeginAddingChildren();
1080 // Set the attributes on the new content element
1081 result
= AddAttributes(aAtts
, content
);
1083 if (NS_OK
== result
) {
1084 // Store the element
1085 if (!SetDocElement(nameSpaceID
, localName
, content
) && appendContent
) {
1086 NS_ENSURE_TRUE(parent
, NS_ERROR_UNEXPECTED
);
1088 parent
->AppendChildTo(content
, PR_FALSE
);
1092 // Some HTML nodes need DoneCreatingElement() called to initialize
1093 // properly (eg form state restoration).
1094 if (nodeInfo
->NamespaceID() == kNameSpaceID_XHTML
) {
1095 if (nodeInfo
->NameAtom() == nsGkAtoms::input
||
1096 nodeInfo
->NameAtom() == nsGkAtoms::button
) {
1097 content
->DoneCreatingElement();
1098 } else if (nodeInfo
->NameAtom() == nsGkAtoms::head
&& !mCurrentHead
) {
1099 mCurrentHead
= content
;
1103 if (IsMonolithicContainer(nodeInfo
)) {
1104 mInMonolithicContainer
++;
1107 if (content
!= mDocElement
&& !mCurrentHead
) {
1108 // This isn't the root and we're not inside an XHTML <head>.
1109 // Might need to start layout
1110 MaybeStartLayout(PR_FALSE
);
1113 return aInterruptable
&& NS_SUCCEEDED(result
) ? DidProcessATokenImpl() :
1118 nsXMLContentSink::HandleEndElement(const PRUnichar
*aName
)
1120 return HandleEndElement(aName
, PR_TRUE
);
1124 nsXMLContentSink::HandleEndElement(const PRUnichar
*aName
,
1125 PRBool aInterruptable
)
1127 nsresult result
= NS_OK
;
1129 // XXX Hopefully the parser will flag this before we get
1130 // here. If we're in the prolog or epilog, there should be
1131 // no close tags for elements.
1132 PR_ASSERT(eXMLContentSinkState_InDocumentElement
== mState
);
1136 StackNode
& sn
= GetCurrentStackNode();
1138 nsCOMPtr
<nsIContent
> content
;
1139 sn
.mContent
.swap(content
);
1140 PRUint32 numFlushed
= sn
.mNumFlushed
;
1143 NS_ASSERTION(content
, "failed to pop content");
1145 // Check that we're closing the right thing
1146 nsCOMPtr
<nsIAtom
> debugNameSpacePrefix
, debugTagAtom
;
1147 PRInt32 debugNameSpaceID
;
1148 nsContentUtils::SplitExpatName(aName
, getter_AddRefs(debugNameSpacePrefix
),
1149 getter_AddRefs(debugTagAtom
),
1151 NS_ASSERTION(content
->NodeInfo()->Equals(debugTagAtom
, debugNameSpaceID
),
1152 "Wrong element being closed");
1155 result
= CloseElement(content
);
1157 if (mCurrentHead
== content
) {
1158 mCurrentHead
= nsnull
;
1161 if (mDocElement
== content
) {
1162 // XXXbz for roots that don't want to be appended on open, we
1163 // probably need to deal here.... (and stop appending them on open).
1164 mState
= eXMLContentSinkState_InEpilog
;
1166 // We might have had no occasion to start layout yet. Do so now.
1167 MaybeStartLayout(PR_FALSE
);
1170 PRInt32 stackLen
= mContentStack
.Length();
1171 if (mNotifyLevel
>= stackLen
) {
1172 if (numFlushed
< content
->GetChildCount()) {
1173 NotifyAppend(content
, numFlushed
);
1175 mNotifyLevel
= stackLen
- 1;
1181 content
->GetNameSpaceID() == kNameSpaceID_SVG
&&
1182 content
->HasAttr(kNameSpaceID_None
, nsGkAtoms::onload
)) {
1185 nsEvent
event(PR_TRUE
, NS_SVG_LOAD
);
1186 event
.eventStructType
= NS_SVG_EVENT
;
1187 event
.flags
|= NS_EVENT_FLAG_CANT_BUBBLE
;
1189 // Do we care about forcing presshell creation if it hasn't happened yet?
1190 // That is, should this code flush or something? Does it really matter?
1191 // For that matter, do we really want to try getting the prescontext? Does
1192 // this event ever want one?
1193 nsRefPtr
<nsPresContext
> ctx
;
1194 nsCOMPtr
<nsIPresShell
> shell
= mDocument
->GetPrimaryShell();
1196 ctx
= shell
->GetPresContext();
1198 nsEventDispatcher::Dispatch(content
, ctx
, &event
);
1202 return aInterruptable
&& NS_SUCCEEDED(result
) ? DidProcessATokenImpl() :
1207 nsXMLContentSink::HandleComment(const PRUnichar
*aName
)
1211 nsCOMPtr
<nsIContent
> comment
;
1212 nsresult rv
= NS_NewCommentNode(getter_AddRefs(comment
), mNodeInfoManager
);
1214 comment
->SetText(nsDependentString(aName
), PR_FALSE
);
1215 rv
= AddContentAsLeaf(comment
);
1219 return NS_SUCCEEDED(rv
) ? DidProcessATokenImpl() : rv
;
1223 nsXMLContentSink::HandleCDataSection(const PRUnichar
*aData
,
1226 // XSLT doesn't differentiate between text and cdata and wants adjacent
1227 // textnodes merged, so add as text.
1228 if (mXSLTProcessor
) {
1229 return AddText(aData
, aLength
);
1234 nsCOMPtr
<nsIContent
> cdata
;
1235 nsresult rv
= NS_NewXMLCDATASection(getter_AddRefs(cdata
), mNodeInfoManager
);
1237 cdata
->SetText(aData
, aLength
, PR_FALSE
);
1238 rv
= AddContentAsLeaf(cdata
);
1242 return NS_SUCCEEDED(rv
) ? DidProcessATokenImpl() : rv
;
1246 nsXMLContentSink::HandleDoctypeDecl(const nsAString
& aSubset
,
1247 const nsAString
& aName
,
1248 const nsAString
& aSystemId
,
1249 const nsAString
& aPublicId
,
1250 nsISupports
* aCatalogData
)
1254 nsresult rv
= NS_OK
;
1256 NS_ASSERTION(mDocument
, "Shouldn't get here from a document fragment");
1258 nsCOMPtr
<nsIAtom
> name
= do_GetAtom(aName
);
1259 NS_ENSURE_TRUE(name
, NS_ERROR_OUT_OF_MEMORY
);
1261 // Create a new doctype node
1262 nsCOMPtr
<nsIDOMDocumentType
> docType
;
1263 rv
= NS_NewDOMDocumentType(getter_AddRefs(docType
), mNodeInfoManager
, nsnull
,
1264 name
, nsnull
, nsnull
, aPublicId
, aSystemId
,
1266 if (NS_FAILED(rv
) || !docType
) {
1270 if (aCatalogData
&& mCSSLoader
&& mDocument
) {
1271 // bug 124570 - we only expect additional agent sheets for now -- ignore
1272 // exit codes, error are not fatal here, just that the stylesheet won't apply
1273 nsCOMPtr
<nsIURI
> uri(do_QueryInterface(aCatalogData
));
1275 nsCOMPtr
<nsICSSStyleSheet
> sheet
;
1276 mCSSLoader
->LoadSheetSync(uri
, PR_TRUE
, getter_AddRefs(sheet
));
1279 nsCAutoString uriStr
;
1280 uri
->GetSpec(uriStr
);
1281 printf("Loading catalog stylesheet: %s ... %s\n", uriStr
.get(), sheet
.get() ? "Done" : "Failed");
1284 mDocument
->BeginUpdate(UPDATE_STYLE
);
1285 mDocument
->AddCatalogStyleSheet(sheet
);
1286 mDocument
->EndUpdate(UPDATE_STYLE
);
1291 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(docType
);
1292 NS_ASSERTION(content
, "doctype isn't content?");
1294 rv
= mDocument
->AppendChildTo(content
, PR_FALSE
);
1296 return NS_SUCCEEDED(rv
) ? DidProcessATokenImpl() : rv
;
1300 nsXMLContentSink::HandleCharacterData(const PRUnichar
*aData
,
1303 return HandleCharacterData(aData
, aLength
, PR_TRUE
);
1307 nsXMLContentSink::HandleCharacterData(const PRUnichar
*aData
, PRUint32 aLength
,
1308 PRBool aInterruptable
)
1310 nsresult rv
= NS_OK
;
1311 if (aData
&& mState
!= eXMLContentSinkState_InProlog
&&
1312 mState
!= eXMLContentSinkState_InEpilog
) {
1313 rv
= AddText(aData
, aLength
);
1315 return aInterruptable
&& NS_SUCCEEDED(rv
) ? DidProcessATokenImpl() : rv
;
1319 nsXMLContentSink::HandleProcessingInstruction(const PRUnichar
*aTarget
,
1320 const PRUnichar
*aData
)
1324 const nsDependentString
target(aTarget
);
1325 const nsDependentString
data(aData
);
1327 nsCOMPtr
<nsIContent
> node
;
1329 nsresult rv
= NS_NewXMLProcessingInstruction(getter_AddRefs(node
),
1330 mNodeInfoManager
, target
, data
);
1331 NS_ENSURE_SUCCESS(rv
, rv
);
1333 nsCOMPtr
<nsIStyleSheetLinkingElement
> ssle(do_QueryInterface(node
));
1335 ssle
->InitStyleLinkElement(PR_FALSE
);
1336 ssle
->SetEnableUpdates(PR_FALSE
);
1337 mPrettyPrintXML
= PR_FALSE
;
1340 rv
= AddContentAsLeaf(node
);
1341 NS_ENSURE_SUCCESS(rv
, rv
);
1345 // This is an xml-stylesheet processing instruction... but it might not be
1346 // a CSS one if the type is set to something else.
1347 ssle
->SetEnableUpdates(PR_TRUE
);
1350 rv
= ssle
->UpdateStyleSheet(this, &willNotify
, &isAlternate
);
1351 NS_ENSURE_SUCCESS(rv
, rv
);
1354 // Successfully started a stylesheet load
1356 ++mPendingSheetCount
;
1357 mScriptLoader
->AddExecuteBlocker();
1364 // If it's not a CSS stylesheet PI...
1366 nsParserUtils::GetQuotedAttributeValue(data
, nsGkAtoms::type
, type
);
1368 if (mState
!= eXMLContentSinkState_InProlog
||
1369 !target
.EqualsLiteral("xml-stylesheet") ||
1371 type
.LowerCaseEqualsLiteral("text/css")) {
1372 return DidProcessATokenImpl();
1375 nsAutoString href
, title
, media
;
1376 PRBool isAlternate
= PR_FALSE
;
1378 // If there was no href, we can't do anything with this PI
1379 if (!ParsePIData(data
, href
, title
, media
, isAlternate
)) {
1380 return DidProcessATokenImpl();
1383 rv
= ProcessStyleLink(node
, href
, isAlternate
, title
, type
, media
);
1384 return NS_SUCCEEDED(rv
) ? DidProcessATokenImpl() : rv
;
1389 nsXMLContentSink::ParsePIData(const nsString
&aData
, nsString
&aHref
,
1390 nsString
&aTitle
, nsString
&aMedia
,
1391 PRBool
&aIsAlternate
)
1393 // If there was no href, we can't do anything with this PI
1394 if (!nsParserUtils::GetQuotedAttributeValue(aData
, nsGkAtoms::href
, aHref
)) {
1398 nsParserUtils::GetQuotedAttributeValue(aData
, nsGkAtoms::title
, aTitle
);
1400 nsParserUtils::GetQuotedAttributeValue(aData
, nsGkAtoms::media
, aMedia
);
1402 nsAutoString alternate
;
1403 nsParserUtils::GetQuotedAttributeValue(aData
, nsGkAtoms::alternate
, alternate
);
1405 aIsAlternate
= alternate
.EqualsLiteral("yes");
1411 * Extends nsContentSink::ProcessMETATag to grab the 'viewport' meta tag. This
1412 * information is ignored by the generic content sink because it only stores
1413 * http-equiv meta tags. We need it in the XMLContentSink for XHTML documents.
1415 * Initially implemented for bug #436083
1418 nsXMLContentSink::ProcessMETATag(nsIContent
*aContent
) {
1420 /* Call the superclass method. */
1421 nsContentSink::ProcessMETATag(aContent
);
1423 nsresult rv
= NS_OK
;
1425 /* Look for the viewport meta tag. If we find it, process it and put the
1426 * data into the document header. */
1427 if (aContent
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::name
,
1428 nsGkAtoms::viewport
, eIgnoreCase
)) {
1430 aContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::content
, value
);
1431 rv
= nsContentUtils::ProcessViewportInfo(mDocument
, value
);
1438 nsXMLContentSink::HandleXMLDeclaration(const PRUnichar
*aVersion
,
1439 const PRUnichar
*aEncoding
,
1440 PRInt32 aStandalone
)
1442 mDocument
->SetXMLDeclaration(aVersion
, aEncoding
, aStandalone
);
1444 return DidProcessATokenImpl();
1448 nsXMLContentSink::ReportError(const PRUnichar
* aErrorText
,
1449 const PRUnichar
* aSourceText
,
1450 nsIScriptError
*aError
,
1453 NS_PRECONDITION(aError
&& aSourceText
&& aErrorText
, "Check arguments!!!");
1454 nsresult rv
= NS_OK
;
1456 // The expat driver should report the error. We're just cleaning up the mess.
1459 mPrettyPrintXML
= PR_FALSE
;
1461 mState
= eXMLContentSinkState_InProlog
;
1463 // XXX need to stop scripts here -- hsivonen
1465 // stop observing in order to avoid crashing when removing content
1466 mDocument
->RemoveObserver(this);
1468 // Clear the current content and
1469 // prepare to set <parsererror> as the document root
1470 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(mDocument
));
1473 nsCOMPtr
<nsIDOMNode
> child
, dummy
;
1474 node
->GetLastChild(getter_AddRefs(child
));
1477 node
->RemoveChild(child
, getter_AddRefs(dummy
));
1480 NS_IF_RELEASE(mDocElement
);
1482 // Clear any buffered-up text we have. It's enough to set the length to 0.
1483 // The buffer itself is allocated when we're created and deleted in our
1484 // destructor, so don't mess with it.
1487 if (mXSLTProcessor
) {
1488 // Get rid of the XSLT processor.
1489 mXSLTProcessor
->CancelLoads();
1490 mXSLTProcessor
= nsnull
;
1493 // release the nodes on stack
1494 mContentStack
.Clear();
1497 const PRUnichar
* noAtts
[] = { 0, 0 };
1499 NS_NAMED_LITERAL_STRING(errorNs
,
1500 "http://www.mozilla.org/newlayout/xml/parsererror.xml");
1502 nsAutoString
parsererror(errorNs
);
1503 parsererror
.Append((PRUnichar
)0xFFFF);
1504 parsererror
.AppendLiteral("parsererror");
1506 rv
= HandleStartElement(parsererror
.get(), noAtts
, 0, -1, (PRUint32
)-1,
1508 NS_ENSURE_SUCCESS(rv
, rv
);
1510 rv
= HandleCharacterData(aErrorText
, nsCRT::strlen(aErrorText
), PR_FALSE
);
1511 NS_ENSURE_SUCCESS(rv
, rv
);
1513 nsAutoString
sourcetext(errorNs
);
1514 sourcetext
.Append((PRUnichar
)0xFFFF);
1515 sourcetext
.AppendLiteral("sourcetext");
1517 rv
= HandleStartElement(sourcetext
.get(), noAtts
, 0, -1, (PRUint32
)-1,
1519 NS_ENSURE_SUCCESS(rv
, rv
);
1521 rv
= HandleCharacterData(aSourceText
, nsCRT::strlen(aSourceText
), PR_FALSE
);
1522 NS_ENSURE_SUCCESS(rv
, rv
);
1524 rv
= HandleEndElement(sourcetext
.get(), PR_FALSE
);
1525 NS_ENSURE_SUCCESS(rv
, rv
);
1527 rv
= HandleEndElement(parsererror
.get(), PR_FALSE
);
1528 NS_ENSURE_SUCCESS(rv
, rv
);
1536 nsXMLContentSink::AddAttributes(const PRUnichar
** aAtts
,
1537 nsIContent
* aContent
)
1539 // Add tag attributes to the content attributes
1540 nsCOMPtr
<nsIAtom
> prefix
, localName
;
1542 PRInt32 nameSpaceID
;
1543 nsContentUtils::SplitExpatName(aAtts
[0], getter_AddRefs(prefix
),
1544 getter_AddRefs(localName
), &nameSpaceID
);
1546 // Add attribute to content
1547 aContent
->SetAttr(nameSpaceID
, localName
, prefix
,
1548 nsDependentString(aAtts
[1]), PR_FALSE
);
1552 // Give autoloading links a chance to fire
1553 if (mDocShell
&& mAllowAutoXLinks
) {
1554 nsresult rv
= aContent
->MaybeTriggerAutoLink(mDocShell
);
1555 if (rv
== NS_XML_AUTOLINK_REPLACE
||
1556 rv
== NS_XML_AUTOLINK_UNDEFINED
) {
1557 // If we do not terminate the parse, we just keep generating link trigger
1558 // events. We want to parse only up to the first replace link, and stop.
1559 mParser
->Terminate();
1566 #define NS_ACCUMULATION_BUFFER_SIZE 4096
1569 nsXMLContentSink::AddText(const PRUnichar
* aText
,
1572 // Create buffer when we first need it
1573 if (0 == mTextSize
) {
1574 mText
= (PRUnichar
*) PR_MALLOC(sizeof(PRUnichar
) * NS_ACCUMULATION_BUFFER_SIZE
);
1575 if (nsnull
== mText
) {
1576 return NS_ERROR_OUT_OF_MEMORY
;
1578 mTextSize
= NS_ACCUMULATION_BUFFER_SIZE
;
1581 // Copy data from string into our buffer; flush buffer when it fills up
1583 while (0 != aLength
) {
1584 PRInt32 amount
= mTextSize
- mTextLength
;
1586 // XSLT wants adjacent textnodes merged.
1587 if (mConstrainSize
&& !mXSLTProcessor
) {
1588 nsresult rv
= FlushText();
1593 amount
= mTextSize
- mTextLength
;
1596 mTextSize
+= aLength
;
1597 mText
= (PRUnichar
*) PR_REALLOC(mText
, sizeof(PRUnichar
) * mTextSize
);
1598 if (nsnull
== mText
) {
1601 return NS_ERROR_OUT_OF_MEMORY
;
1607 if (amount
> aLength
) {
1610 memcpy(&mText
[mTextLength
], &aText
[offset
], sizeof(PRUnichar
) * amount
);
1611 mTextLength
+= amount
;
1620 nsXMLContentSink::FlushPendingNotifications(mozFlushType aType
)
1622 // Only flush tags if we're not doing the notification ourselves
1623 // (since we aren't reentrant)
1624 if (!mInNotification
) {
1625 if (aType
>= Flush_ContentAndNotify
) {
1629 FlushText(PR_FALSE
);
1631 if (aType
>= Flush_Layout
) {
1632 // Make sure that layout has started so that the reflow flush
1633 // will actually happen.
1634 MaybeStartLayout(PR_TRUE
);
1640 * NOTE!! Forked from SinkContext. Please keep in sync.
1642 * Flush all elements that have been seen so far such that
1643 * they are visible in the tree. Specifically, make sure
1644 * that they are all added to their respective parents.
1645 * Also, do notification at the top for all content that
1646 * has been newly added so that the frame tree is complete.
1649 nsXMLContentSink::FlushTags()
1651 mDeferredFlushTags
= PR_FALSE
;
1652 PRBool oldBeganUpdate
= mBeganUpdate
;
1653 PRUint32 oldUpdates
= mUpdatesInNotification
;
1655 mUpdatesInNotification
= 0;
1658 // Scope so we call EndUpdate before we decrease mInNotification
1659 mozAutoDocUpdate
updateBatch(mDocument
, UPDATE_CONTENT_MODEL
, PR_TRUE
);
1660 mBeganUpdate
= PR_TRUE
;
1662 // Don't release last text node in case we need to add to it again
1663 FlushText(PR_FALSE
);
1665 // Start from the base of the stack (growing downward) and do
1666 // a notification from the node that is closest to the root of
1667 // tree for any content that has been added.
1670 PRInt32 stackLen
= mContentStack
.Length();
1671 PRBool flushed
= PR_FALSE
;
1672 PRUint32 childCount
;
1673 nsIContent
* content
;
1675 for (stackPos
= 0; stackPos
< stackLen
; ++stackPos
) {
1676 content
= mContentStack
[stackPos
].mContent
;
1677 childCount
= content
->GetChildCount();
1679 if (!flushed
&& (mContentStack
[stackPos
].mNumFlushed
< childCount
)) {
1680 NotifyAppend(content
, mContentStack
[stackPos
].mNumFlushed
);
1684 mContentStack
[stackPos
].mNumFlushed
= childCount
;
1686 mNotifyLevel
= stackLen
- 1;
1690 if (mUpdatesInNotification
> 1) {
1691 UpdateChildCounts();
1694 mUpdatesInNotification
= oldUpdates
;
1695 mBeganUpdate
= oldBeganUpdate
;
1701 * NOTE!! Forked from SinkContext. Please keep in sync.
1704 nsXMLContentSink::UpdateChildCounts()
1706 // Start from the top of the stack (growing upwards) and see if any
1707 // new content has been appended. If so, we recognize that reflows
1708 // have been generated for it and we should make sure that no
1709 // further reflows occur. Note that we have to include stackPos == 0
1710 // to properly notify on kids of <html>.
1711 PRInt32 stackLen
= mContentStack
.Length();
1712 PRInt32 stackPos
= stackLen
- 1;
1713 while (stackPos
>= 0) {
1714 StackNode
& node
= mContentStack
[stackPos
];
1715 node
.mNumFlushed
= node
.mContent
->GetChildCount();
1719 mNotifyLevel
= stackLen
- 1;
1723 nsXMLContentSink::IsMonolithicContainer(nsINodeInfo
* aNodeInfo
)
1725 return ((aNodeInfo
->NamespaceID() == kNameSpaceID_XHTML
&&
1726 (aNodeInfo
->NameAtom() == nsGkAtoms::tr
||
1727 aNodeInfo
->NameAtom() == nsGkAtoms::select
||
1728 aNodeInfo
->NameAtom() == nsGkAtoms::object
||
1729 aNodeInfo
->NameAtom() == nsGkAtoms::applet
))
1731 || (aNodeInfo
->NamespaceID() == kNameSpaceID_MathML
&&
1732 (aNodeInfo
->NameAtom() == nsGkAtoms::math
))