Back to index

lightning-sunbird  0.9+nobinonly
nsXMLContentSink.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "nsCOMPtr.h"
00039 #include "nsXMLContentSink.h"
00040 #include "nsIParser.h"
00041 #include "nsIUnicharInputStream.h"
00042 #include "nsIDocument.h"
00043 #include "nsIDOMDocument.h"
00044 #include "nsIDOMDocumentType.h"
00045 #include "nsIDOMDOMImplementation.h"
00046 #include "nsIDOMNSDocument.h"
00047 #include "nsIXMLContent.h"
00048 #include "nsIScriptGlobalObject.h"
00049 #include "nsIURI.h"
00050 #include "nsNetUtil.h"
00051 #include "nsIDocShell.h"
00052 #include "nsIDocShellTreeItem.h"
00053 #include "nsIContent.h"
00054 #include "nsITextContent.h"
00055 #include "nsIStyleSheetLinkingElement.h"
00056 #include "nsPresContext.h"
00057 #include "nsIPresShell.h"
00058 #include "nsIViewManager.h"
00059 #include "nsIDOMComment.h"
00060 #include "nsIDOMCDATASection.h"
00061 #include "nsDOMDocumentType.h"
00062 #include "nsHTMLParts.h"
00063 #include "nsVoidArray.h"
00064 #include "nsCRT.h"
00065 #include "nsICSSLoader.h"
00066 #include "nsICSSStyleSheet.h"
00067 #include "nsHTMLAtoms.h"
00068 #include "nsContentUtils.h"
00069 #include "nsLayoutAtoms.h"
00070 #include "nsIScriptContext.h"
00071 #include "nsINameSpaceManager.h"
00072 #include "nsIServiceManager.h"
00073 #include "nsIScriptSecurityManager.h"
00074 #include "nsIContentViewer.h"
00075 #include "prtime.h"
00076 #include "prlog.h"
00077 #include "prmem.h"
00078 #include "nsParserUtils.h"
00079 #include "nsRect.h"
00080 #include "nsGenericElement.h"
00081 #include "nsIWebNavigation.h"
00082 #include "nsIScriptElement.h"
00083 #include "nsIScriptLoader.h"
00084 #include "nsStyleLinkElement.h"
00085 #include "nsIImageLoadingContent.h"
00086 #include "nsReadableUtils.h"
00087 #include "nsUnicharUtils.h"
00088 #include "nsICookieService.h"
00089 #include "nsIPrompt.h"
00090 #include "nsIDOMWindowInternal.h"
00091 #include "nsIChannel.h"
00092 #include "nsIPrincipal.h"
00093 #include "nsXBLAtoms.h"
00094 #include "nsXMLPrettyPrinter.h"
00095 #include "nsNodeInfoManager.h"
00096 #include "nsContentCreatorFunctions.h"
00097 #include "nsIContentPolicy.h"
00098 #include "nsContentPolicyUtils.h"
00099 #include "nsIDOMProcessingInstruction.h"
00100 
00101 #ifdef MOZ_SVG
00102 #include "nsSVGAtoms.h"
00103 #include "nsGUIEvent.h"
00104 #endif
00105 
00106 #define kXSLType "text/xsl"
00107 
00108 static const char kLoadAsData[] = "loadAsData";
00109 
00110 
00111 
00112 // XXX Open Issues:
00113 // 1) what's not allowed - We need to figure out which HTML tags
00114 //    (prefixed with a HTML namespace qualifier) are explicitly not
00115 //    allowed (if any).
00116 // 2) factoring code with nsHTMLContentSink - There's some amount of
00117 //    common code between this and the HTML content sink. This will
00118 //    increase as we support more and more HTML elements. How can code
00119 //    from the code be factored?
00120 
00121 nsresult
00122 NS_NewXMLContentSink(nsIXMLContentSink** aResult,
00123                      nsIDocument* aDoc,
00124                      nsIURI* aURI,
00125                      nsISupports* aContainer,
00126                      nsIChannel* aChannel)
00127 {
00128   NS_PRECONDITION(nsnull != aResult, "null ptr");
00129   if (nsnull == aResult) {
00130     return NS_ERROR_NULL_POINTER;
00131   }
00132   nsXMLContentSink* it;
00133   NS_NEWXPCOM(it, nsXMLContentSink);
00134   if (nsnull == it) {
00135     return NS_ERROR_OUT_OF_MEMORY;
00136   }
00137   
00138   nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it;
00139   nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
00140   NS_ENSURE_SUCCESS(rv, rv);
00141   
00142   return CallQueryInterface(it, aResult);
00143 }
00144 
00145 nsXMLContentSink::nsXMLContentSink()
00146   : mDocElement(nsnull),
00147     mText(nsnull),
00148     mTextLength(0),
00149     mTextSize(0),
00150     mConstrainSize(PR_TRUE),
00151     mInTitle(PR_FALSE),
00152     mPrettyPrintXML(PR_TRUE),
00153     mPrettyPrintHasSpecialRoot(PR_FALSE),
00154     mPrettyPrintHasFactoredElements(PR_FALSE),
00155     mHasProcessedBase(PR_FALSE),
00156     mAllowAutoXLinks(PR_TRUE)
00157 {
00158 }
00159 
00160 nsXMLContentSink::~nsXMLContentSink()
00161 {
00162   NS_IF_RELEASE(mDocElement);
00163   if (mText) {
00164     PR_Free(mText);  //  Doesn't null out, unlike PR_FREEIF
00165   }
00166 }
00167 
00168 nsresult
00169 nsXMLContentSink::Init(nsIDocument* aDoc,
00170                        nsIURI* aURI,
00171                        nsISupports* aContainer,
00172                        nsIChannel* aChannel)
00173 {
00174   nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
00175   NS_ENSURE_SUCCESS(rv, rv);
00176 
00177   if (!mDocShell) {
00178     mPrettyPrintXML = PR_FALSE;
00179   }
00180   
00181   mState = eXMLContentSinkState_InProlog;
00182   mDocElement = nsnull;
00183   return NS_OK;
00184 }
00185 
00186 NS_IMPL_ISUPPORTS_INHERITED4(nsXMLContentSink,
00187                              nsContentSink,
00188                              nsIContentSink,
00189                              nsIXMLContentSink,
00190                              nsIExpatSink,
00191                              nsITransformObserver)
00192 
00193 // nsIContentSink
00194 NS_IMETHODIMP
00195 nsXMLContentSink::WillBuildModel(void)
00196 {
00197   // Notify document that the load is beginning
00198   mDocument->BeginLoad();
00199 
00200   // Check for correct load-command for maybe prettyprinting
00201   if (mPrettyPrintXML) {
00202     nsCAutoString command;
00203     mParser->GetCommand(command);
00204     if (!command.EqualsLiteral("view")) {
00205       mPrettyPrintXML = PR_FALSE;
00206     }
00207   }
00208   
00209   return NS_OK;
00210 }
00211 
00212 nsresult
00213 nsXMLContentSink::MaybePrettyPrint()
00214 {
00215   if (!mPrettyPrintXML || (mPrettyPrintHasFactoredElements &&
00216                            !mPrettyPrintHasSpecialRoot)) {
00217     mPrettyPrintXML = PR_FALSE;
00218 
00219     return NS_OK;
00220   }
00221 
00222   // Reenable the CSSLoader so that the prettyprinting stylesheets can load
00223   if (mCSSLoader) {
00224     mCSSLoader->SetEnabled(PR_TRUE);
00225   }
00226   
00227   nsCOMPtr<nsXMLPrettyPrinter> printer;
00228   nsresult rv = NS_NewXMLPrettyPrinter(getter_AddRefs(printer));
00229   NS_ENSURE_SUCCESS(rv, rv);
00230 
00231   return printer->PrettyPrint(mDocument);
00232 }
00233 
00234 static void
00235 CheckXSLTParamPI(nsIDOMProcessingInstruction* aPi,
00236                  nsIDocumentTransformer* aProcessor,
00237                  nsIDocument* aDocument)
00238 {
00239   nsAutoString target, data;
00240   aPi->GetTarget(target);
00241 
00242   nsCOMPtr<nsIDocumentTransformer_1_8_BRANCH> proc = do_QueryInterface(aProcessor);
00243 
00244   // Check for namespace declarations
00245   if (target.EqualsLiteral("xslt-param-namespace")) {
00246     aPi->GetData(data);
00247     nsAutoString prefix, namespaceAttr;
00248     nsParserUtils::GetQuotedAttributeValue(data, nsHTMLAtoms::prefix,
00249                                            prefix, PR_TRUE);
00250     if (!prefix.IsEmpty() &&
00251         nsParserUtils::GetQuotedAttributeValue(data, nsHTMLAtoms::_namespace,
00252                                                namespaceAttr, PR_TRUE)) {
00253       proc->AddXSLTParamNamespace(prefix, namespaceAttr);
00254     }
00255   }
00256 
00257   // Check for actual parameters
00258   else if (target.EqualsLiteral("xslt-param")) {
00259     aPi->GetData(data);
00260     nsAutoString name, namespaceAttr, select, value;
00261     nsParserUtils::GetQuotedAttributeValue(data, nsHTMLAtoms::name,
00262                                            name, PR_TRUE);
00263     nsParserUtils::GetQuotedAttributeValue(data, nsHTMLAtoms::_namespace,
00264                                            namespaceAttr, PR_TRUE);
00265     if (!nsParserUtils::GetQuotedAttributeValue(data, nsHTMLAtoms::select,
00266                                                 select, PR_TRUE)) {
00267       select.SetIsVoid(PR_TRUE);
00268     }
00269     if (!nsParserUtils::GetQuotedAttributeValue(data, nsHTMLAtoms::value, value,
00270                                                 PR_TRUE)) {
00271       value.SetIsVoid(PR_TRUE);
00272     }
00273     if (!name.IsEmpty()) {
00274       nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument);
00275       proc->AddXSLTParam(name, namespaceAttr, select, value, doc);
00276     }
00277   }
00278 }
00279 
00280 NS_IMETHODIMP
00281 nsXMLContentSink::DidBuildModel()
00282 {
00283   if (mDocument && mDocument->GetDocumentTitle().IsVoid()) {
00284     nsCOMPtr<nsIDOMNSDocument> dom_doc(do_QueryInterface(mDocument));
00285     dom_doc->SetTitle(EmptyString());
00286   }
00287 
00288   if (mXSLTProcessor) {
00289 
00290     // Check for xslt-param and xslt-param-namespace PIs
00291     PRUint32 i;
00292     nsIContent* child;
00293     for (i = 0; (child = mDocument->GetChildAt(i)); ++i) {
00294       if (child->IsContentOfType(nsIContent::ePROCESSING_INSTRUCTION)) {
00295         nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(child);
00296         CheckXSLTParamPI(pi, mXSLTProcessor, mDocument);
00297       }
00298       else if (child->IsContentOfType(nsIContent::eELEMENT)) {
00299         // Only honor PIs in the prolog
00300         break;
00301       }
00302     }
00303 
00304     nsCOMPtr<nsIDOMDocument> currentDOMDoc(do_QueryInterface(mDocument));
00305     mXSLTProcessor->SetSourceContentModel(currentDOMDoc);
00306     // Since the processor now holds a reference to us we drop our reference
00307     // to it to avoid owning cycles
00308     mXSLTProcessor = nsnull;
00309   }
00310   else {
00311     // Kick off layout for non-XSLT transformed documents.
00312     nsIScriptLoader *loader = mDocument->GetScriptLoader();
00313     if (loader) {
00314       loader->RemoveObserver(this);
00315     }
00316 
00317     if (mDocElement) {
00318       // Notify document observers that all the content has been stuck
00319       // into the document.
00320       // XXX do we need to notify for things like PIs?  Or just the
00321       // documentElement?
00322       NS_ASSERTION(mDocument->IndexOf(mDocElement) != -1,
00323                    "mDocElement not in doc?");
00324 
00325       mozAutoDocUpdate docUpdate(mDocument, UPDATE_CONTENT_MODEL, PR_TRUE);
00326       mDocument->ContentInserted(nsnull, mDocElement,
00327                                  // XXXbz is this last arg relevant if
00328                                  // the container is null?
00329                                  mDocument->IndexOf(mDocElement));
00330     }
00331 
00332     // Check if we want to prettyprint
00333     MaybePrettyPrint();
00334 
00335     StartLayout();
00336 
00337 #if 0 /* Disable until this works for XML */
00338     //  Scroll to Anchor only if the document was *not* loaded through history means. 
00339     if (mDocShell) {
00340       PRUint32 documentLoadType = 0;
00341       mDocShell->GetLoadType(&documentLoadType);
00342       ScrollToRef(!(documentLoadType & nsIDocShell::LOAD_CMD_HISTORY));
00343     }
00344 #else
00345     ScrollToRef(PR_TRUE);
00346 #endif
00347 
00348     mDocument->EndLoad();
00349   }
00350 
00351   // Drop our reference to the parser to get rid of a circular
00352   // reference.
00353   mParser = nsnull;
00354 
00355   return NS_OK;
00356 }
00357 
00358 NS_IMETHODIMP
00359 nsXMLContentSink::OnDocumentCreated(nsIDOMDocument* aResultDocument)
00360 {
00361   NS_ENSURE_ARG(aResultDocument);
00362 
00363   nsCOMPtr<nsIContentViewer> contentViewer;
00364   mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
00365   if (contentViewer) {
00366     contentViewer->SetDOMDocument(aResultDocument);
00367   }
00368   return NS_OK;
00369 }
00370 
00371 NS_IMETHODIMP
00372 nsXMLContentSink::OnTransformDone(nsresult aResult,
00373                                   nsIDOMDocument* aResultDocument)
00374 {
00375   NS_ASSERTION(NS_FAILED(aResult) || aResultDocument,
00376                "Don't notify about transform success without a document.");
00377 
00378   nsCOMPtr<nsIContentViewer> contentViewer;
00379   mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
00380 
00381   if (NS_FAILED(aResult) && contentViewer) {
00382     // Transform failed.
00383     if (aResultDocument) {
00384       // We have an error document.
00385       contentViewer->SetDOMDocument(aResultDocument);
00386     }
00387     else {
00388       // We don't have an error document, display the
00389       // untransformed source document.
00390       nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(mDocument);
00391       contentViewer->SetDOMDocument(document);
00392     }
00393   }
00394 
00395   nsCOMPtr<nsIDocument> originalDocument = mDocument;
00396   if (NS_SUCCEEDED(aResult) || aResultDocument) {
00397     // Transform succeeded or it failed and we have an error
00398     // document to display.
00399     mDocument = do_QueryInterface(aResultDocument);
00400   }
00401 
00402   nsIScriptLoader *loader = originalDocument->GetScriptLoader();
00403   if (loader) {
00404     loader->RemoveObserver(this);
00405   }
00406 
00407   // Notify document observers that all the content has been stuck
00408   // into the document.  
00409   // XXX do we need to notify for things like PIs?  Or just the
00410   // documentElement?
00411   nsIContent *rootContent = mDocument->GetRootContent();
00412   if (rootContent) {
00413     NS_ASSERTION(mDocument->IndexOf(rootContent) != -1,
00414                  "rootContent not in doc?");
00415     mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
00416     mDocument->ContentInserted(nsnull, rootContent,
00417                                // XXXbz is this last arg relevant if
00418                                // the container is null?
00419                                mDocument->IndexOf(rootContent));
00420     mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
00421   }
00422   
00423   // Start the layout process
00424   StartLayout();
00425 
00426 #if 0 /* Disable until this works for XML */
00427   //  Scroll to Anchor only if the document was *not* loaded through history means. 
00428   PRUint32 documentLoadType = 0;
00429   docShell->GetLoadType(&documentLoadType);
00430   ScrollToRef(!(documentLoadType & nsIDocShell::LOAD_CMD_HISTORY));
00431 #else
00432   ScrollToRef(PR_TRUE);
00433 #endif
00434 
00435   originalDocument->EndLoad();
00436 
00437   return NS_OK;
00438 }
00439 
00440 
00441 NS_IMETHODIMP
00442 nsXMLContentSink::WillInterrupt(void)
00443 {
00444   return NS_OK;
00445 }
00446 
00447 NS_IMETHODIMP
00448 nsXMLContentSink::WillResume(void)
00449 {
00450   return NS_OK;
00451 }
00452 
00453 NS_IMETHODIMP
00454 nsXMLContentSink::SetParser(nsIParser* aParser)
00455 {
00456   mParser = aParser;
00457   return NS_OK;
00458 }
00459 
00460 nsresult
00461 nsXMLContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
00462                                 nsINodeInfo* aNodeInfo, PRUint32 aLineNumber,
00463                                 nsIContent** aResult, PRBool* aAppendContent)
00464 {
00465   NS_ASSERTION(aNodeInfo, "can't create element without nodeinfo");
00466 
00467   *aResult = nsnull;
00468   *aAppendContent = PR_TRUE;
00469   nsresult rv = NS_OK;
00470 
00471   nsCOMPtr<nsIContent> content;
00472   rv = NS_NewElement(getter_AddRefs(content), aNodeInfo->NamespaceID(),
00473                      aNodeInfo);
00474   NS_ENSURE_SUCCESS(rv, rv);
00475 
00476   if (aNodeInfo->Equals(nsHTMLAtoms::script, kNameSpaceID_XHTML)
00477 #ifdef MOZ_SVG
00478       || aNodeInfo->Equals(nsSVGAtoms::script, kNameSpaceID_SVG)
00479 #endif
00480     ) {
00481     // Don't append the content to the tree until we're all
00482     // done collecting its contents
00483     mConstrainSize = PR_FALSE;
00484     mScriptLineNo = aLineNumber;
00485     *aAppendContent = PR_FALSE;
00486   }
00487 
00488   // XHTML needs some special attention
00489   if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
00490     mPrettyPrintHasFactoredElements = PR_TRUE;
00491   }
00492   else {
00493     // If we care, find out if we just used a special factory.
00494     if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
00495         mPrettyPrintXML) {
00496       mPrettyPrintHasFactoredElements =
00497         nsContentUtils::GetNSManagerWeakRef()->
00498           HasElementCreator(aNodeInfo->NamespaceID());
00499     }
00500 
00501     if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
00502       content.swap(*aResult);
00503 
00504       return NS_OK;
00505     }
00506   }
00507 
00508   if (aNodeInfo->Equals(nsHTMLAtoms::title, kNameSpaceID_XHTML)) {
00509     if (mDocument && mDocument->GetDocumentTitle().IsVoid()) {
00510       mInTitle = PR_TRUE; // The first title wins
00511     }
00512   }
00513 #ifdef MOZ_SVG
00514   else if (aNodeInfo->Equals(nsSVGAtoms::title, kNameSpaceID_SVG)) {
00515     nsIContent* parent = GetCurrentContent();
00516     if (mDocument && mDocument->GetDocumentTitle().IsVoid() &&
00517         parent && parent == mDocElement &&
00518         parent->GetNodeInfo()->Equals(nsSVGAtoms::svg, kNameSpaceID_SVG)) {
00519       mInTitle = PR_TRUE; // The first title wins
00520     }
00521   }
00522 #endif // MOZ_SVG
00523   else if (aNodeInfo->Equals(nsHTMLAtoms::link, kNameSpaceID_XHTML) ||
00524            aNodeInfo->Equals(nsHTMLAtoms::style, kNameSpaceID_XHTML) ||
00525            aNodeInfo->Equals(nsHTMLAtoms::style, kNameSpaceID_SVG)) {
00526     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(content));
00527     if (ssle) {
00528       ssle->InitStyleLinkElement(mParser, PR_FALSE);
00529       ssle->SetEnableUpdates(PR_FALSE);
00530       if (!aNodeInfo->Equals(nsHTMLAtoms::link, kNameSpaceID_XHTML)) {
00531         ssle->SetLineNumber(aLineNumber);
00532       }
00533     }
00534   } 
00535 
00536   content.swap(*aResult);
00537 
00538   return NS_OK;
00539 }
00540 
00541 
00542 nsresult
00543 nsXMLContentSink::CloseElement(nsIContent* aContent, nsIContent* aParent,
00544                                PRBool* aAppendContent)
00545 {
00546   NS_ASSERTION(aContent, "missing element to close");
00547 
00548   *aAppendContent = PR_FALSE;
00549 
00550   nsINodeInfo* nodeInfo = aContent->GetNodeInfo();
00551 
00552   // Some HTML nodes need DoneAddingChildren() called to initialize
00553   // properly (eg form state restoration).
00554   if ((nodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
00555        (nodeInfo->NameAtom() == nsHTMLAtoms::select ||
00556         nodeInfo->NameAtom() == nsHTMLAtoms::textarea ||
00557         nodeInfo->NameAtom() == nsHTMLAtoms::object ||
00558         nodeInfo->NameAtom() == nsHTMLAtoms::applet))
00559 #ifdef MOZ_XTF
00560       || nodeInfo->NamespaceID() > kNameSpaceID_LastBuiltin
00561 #endif
00562       ) {
00563     aContent->DoneAddingChildren();
00564   }
00565   
00566   if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) &&
00567       !nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
00568     return NS_OK;
00569   }
00570 
00571   nsresult rv = NS_OK;
00572 
00573   if (nodeInfo->Equals(nsHTMLAtoms::script, kNameSpaceID_XHTML)
00574 #ifdef MOZ_SVG
00575       || nodeInfo->Equals(nsSVGAtoms::script, kNameSpaceID_SVG)
00576 #endif
00577     ) {
00578     rv = ProcessEndSCRIPTTag(aContent, aParent);
00579     *aAppendContent = PR_TRUE;
00580     return rv;
00581   }
00582   
00583   if ((nodeInfo->Equals(nsHTMLAtoms::title, kNameSpaceID_XHTML)
00584 #ifdef MOZ_SVG
00585        || nodeInfo->Equals(nsSVGAtoms::title, kNameSpaceID_SVG)
00586 #endif // MOZ_SVG
00587       ) && mInTitle) {
00588     NS_ASSERTION(mDocument, "How did mInTitle get to be true if mDocument is null?");
00589     // The first title wins
00590     nsCOMPtr<nsIDOMNSDocument> dom_doc(do_QueryInterface(mDocument));
00591     mTitleText.CompressWhitespace();
00592     dom_doc->SetTitle(mTitleText);
00593     mInTitle = PR_FALSE;
00594   }
00595   else if (nodeInfo->Equals(nsHTMLAtoms::base, kNameSpaceID_XHTML) &&
00596            !mHasProcessedBase) {
00597     // The first base wins
00598     rv = ProcessBASETag(aContent);
00599     mHasProcessedBase = PR_TRUE;
00600   }
00601   else if (nodeInfo->Equals(nsHTMLAtoms::meta, kNameSpaceID_XHTML) &&
00602            // Need to check here to make sure this meta tag does not set
00603            // mPrettyPrintXML to false when we have a special root!
00604            (!mPrettyPrintXML || !mPrettyPrintHasSpecialRoot)) {
00605     rv = ProcessMETATag(aContent);
00606   }
00607   else if (nodeInfo->Equals(nsHTMLAtoms::link, kNameSpaceID_XHTML) ||
00608            nodeInfo->Equals(nsHTMLAtoms::style, kNameSpaceID_XHTML) ||
00609            nodeInfo->Equals(nsHTMLAtoms::style, kNameSpaceID_SVG)) {
00610     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
00611     if (ssle) {
00612       ssle->SetEnableUpdates(PR_TRUE);
00613       rv = ssle->UpdateStyleSheet(nsnull, nsnull);
00614       if (rv == NS_ERROR_HTMLPARSER_BLOCK && mParser) {
00615         mParser->BlockParser();
00616       }
00617     }
00618   }
00619 
00620   return rv;
00621 }  
00622 
00623 nsresult
00624 nsXMLContentSink::AddContentAsLeaf(nsIContent *aContent)
00625 {
00626   nsresult result = NS_OK;
00627 
00628   if ((eXMLContentSinkState_InProlog == mState) ||
00629       (eXMLContentSinkState_InEpilog == mState)) {
00630     nsCOMPtr<nsIDOMDocument> domDoc( do_QueryInterface(mDocument) );
00631     nsCOMPtr<nsIDOMNode> trash;
00632     nsCOMPtr<nsIDOMNode> child( do_QueryInterface(aContent) );
00633     NS_ASSERTION(child, "not a dom node");
00634     domDoc->AppendChild(child, getter_AddRefs(trash));
00635   }
00636   else {
00637     nsCOMPtr<nsIContent> parent = GetCurrentContent();
00638 
00639     if (parent) {
00640       result = parent->AppendChildTo(aContent, PR_FALSE);
00641     }
00642   }
00643 
00644   return result;
00645 }
00646 
00647 // Create an XML parser and an XSL content sink and start parsing
00648 // the XSL stylesheet located at the given URI.
00649 nsresult
00650 nsXMLContentSink::LoadXSLStyleSheet(nsIURI* aUrl)
00651 {
00652   mXSLTProcessor =
00653     do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt");
00654   if (!mXSLTProcessor) {
00655     // No XSLT processor available, continue normal document loading
00656     return NS_OK;
00657   }
00658 
00659   mXSLTProcessor->SetTransformObserver(this);
00660 
00661   nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup();
00662   if (!loadGroup) {
00663     mXSLTProcessor = nsnull;
00664     return NS_ERROR_FAILURE;
00665   }
00666 
00667   return mXSLTProcessor->LoadStyleSheet(aUrl, loadGroup, mDocument->GetPrincipal());
00668 }
00669 
00670 nsresult
00671 nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
00672                                    const nsSubstring& aHref,
00673                                    PRBool aAlternate,
00674                                    const nsSubstring& aTitle,
00675                                    const nsSubstring& aType,
00676                                    const nsSubstring& aMedia)
00677 {
00678   nsresult rv = NS_OK;
00679   mPrettyPrintXML = PR_FALSE;
00680 
00681   nsCAutoString cmd;
00682   if (mParser)
00683     mParser->GetCommand(cmd);
00684   if (cmd.EqualsASCII(kLoadAsData))
00685     return NS_OK; // Do not load stylesheets when loading as data
00686 
00687   NS_ConvertUTF16toUTF8 type(aType);
00688   if (type.EqualsIgnoreCase(kXSLType) ||
00689       type.EqualsIgnoreCase(kXMLTextContentType) ||
00690       type.EqualsIgnoreCase(kXMLApplicationContentType)) {
00691     if (aAlternate) {
00692       // don't load alternate XSLT
00693       return NS_OK;
00694     }
00695     // LoadXSLStyleSheet needs a mDocShell.
00696     if (!mDocShell)
00697       return NS_OK;
00698 
00699     nsCOMPtr<nsIURI> url;
00700     rv = NS_NewURI(getter_AddRefs(url), aHref, nsnull, mDocumentBaseURI);
00701     NS_ENSURE_SUCCESS(rv, rv);
00702 
00703     // Do security check
00704     nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
00705     rv = secMan->
00706       CheckLoadURIWithPrincipal(mDocument->GetPrincipal(), url,
00707                                 nsIScriptSecurityManager::ALLOW_CHROME);
00708     NS_ENSURE_SUCCESS(rv, NS_OK);
00709 
00710     rv = secMan->CheckSameOriginURI(mDocumentURI, url);
00711     NS_ENSURE_SUCCESS(rv, NS_OK);
00712 
00713     // Do content policy check
00714     PRInt16 decision = nsIContentPolicy::ACCEPT;
00715     rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_STYLESHEET,
00716                                    url,
00717                                    mDocument->GetDocumentURI(),
00718                                    aElement,
00719                                    type,
00720                                    nsnull,
00721                                    &decision);
00722 
00723     NS_ENSURE_SUCCESS(rv, rv);
00724 
00725     if (NS_CP_REJECTED(decision)) {
00726       return NS_OK;
00727     }
00728 
00729     return LoadXSLStyleSheet(url);
00730   }
00731 
00732   // Let nsContentSink deal with css.
00733   rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate,
00734                                        aTitle, aType, aMedia);
00735 
00736   if (rv == NS_ERROR_HTMLPARSER_BLOCK) {
00737     if (mParser) {
00738       mParser->BlockParser();
00739     }
00740     return NS_OK;
00741   }
00742 
00743   return rv;
00744 }
00745 
00746 nsresult
00747 nsXMLContentSink::ProcessBASETag(nsIContent* aContent)
00748 {
00749   NS_ASSERTION(aContent, "missing base-element");
00750 
00751   nsresult rv = NS_OK;
00752 
00753   if (mDocument) {
00754     nsAutoString value;
00755   
00756     if (aContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::target, value) ==
00757         NS_CONTENT_ATTR_HAS_VALUE) {
00758       mDocument->SetBaseTarget(value);
00759     }
00760 
00761     if (aContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::href, value) ==
00762         NS_CONTENT_ATTR_HAS_VALUE) {
00763       nsCOMPtr<nsIURI> baseURI;
00764       rv = NS_NewURI(getter_AddRefs(baseURI), value);
00765       if (NS_SUCCEEDED(rv)) {
00766         rv = mDocument->SetBaseURI(baseURI); // The document checks if it is legal to set this base
00767         if (NS_SUCCEEDED(rv)) {
00768           mDocumentBaseURI = mDocument->GetBaseURI();
00769         }
00770       }
00771     }
00772   }
00773 
00774   return rv;
00775 }
00776 
00777 
00778 NS_IMETHODIMP 
00779 nsXMLContentSink::SetDocumentCharset(nsACString& aCharset)
00780 {
00781   if (mDocument) {
00782     mDocument->SetDocumentCharacterSet(aCharset);
00783   }
00784   
00785   return NS_OK;
00786 }
00787 
00788 nsISupports *
00789 nsXMLContentSink::GetTarget()
00790 {
00791   return mDocument;
00792 }
00793 
00794 nsresult
00795 nsXMLContentSink::FlushText(PRBool aCreateTextNode, PRBool* aDidFlush)
00796 {
00797   nsresult rv = NS_OK;
00798   PRBool didFlush = PR_FALSE;
00799   if (0 != mTextLength) {
00800     if (aCreateTextNode) {
00801       nsCOMPtr<nsITextContent> textContent;
00802       rv = NS_NewTextNode(getter_AddRefs(textContent), mNodeInfoManager);
00803       NS_ENSURE_SUCCESS(rv, rv);
00804 
00805       // Set the text in the text node
00806       textContent->SetText(mText, mTextLength, PR_FALSE);
00807 
00808       // Add text to its parent
00809       AddContentAsLeaf(textContent);
00810     }
00811     mTextLength = 0;
00812     didFlush = PR_TRUE;
00813   }
00814 
00815   if (nsnull != aDidFlush) {
00816     *aDidFlush = didFlush;
00817   }
00818   return rv;
00819 }
00820 
00821 nsIContent*
00822 nsXMLContentSink::GetCurrentContent()
00823 {
00824   PRInt32 count = mContentStack.Count();
00825 
00826   if (count == 0) {
00827     return nsnull;
00828   }
00829 
00830   NS_ASSERTION(count > 0, "Bogus Count()");
00831 
00832   return mContentStack[count-1];
00833 }
00834 
00835 PRInt32
00836 nsXMLContentSink::PushContent(nsIContent *aContent)
00837 {
00838   NS_PRECONDITION(aContent, "Null content being pushed!");
00839   mContentStack.AppendObject(aContent);
00840   return mContentStack.Count();
00841 }
00842 
00843 already_AddRefed<nsIContent>
00844 nsXMLContentSink::PopContent()
00845 {  
00846   PRInt32 count = mContentStack.Count();
00847 
00848   if (count == 0) {
00849     NS_WARNING("Popping empty stack");
00850     return nsnull;
00851   }
00852 
00853   NS_ASSERTION(count > 0, "Bogus Count()");
00854 
00855   nsIContent* content = mContentStack[count - 1];
00856   NS_IF_ADDREF(content);
00857   mContentStack.RemoveObjectAt(count - 1);
00858   
00859   return content;
00860 }
00861 
00862 void
00863 nsXMLContentSink::StartLayout()
00864 {
00865   PRBool topLevelFrameset = PR_FALSE;
00866   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
00867   if (docShellAsItem) {
00868     nsCOMPtr<nsIDocShellTreeItem> root;
00869     docShellAsItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
00870     if(docShellAsItem == root) {
00871       topLevelFrameset = PR_TRUE;
00872     }
00873   }
00874   
00875   nsContentSink::StartLayout(topLevelFrameset);
00876 
00877 }
00878 
00879 #ifdef MOZ_MATHML
00880 
00881 // MathML Element Factory - temporary location for bug 132844
00882 // Will be factored out post 1.0
00883 
00884 nsresult
00885 NS_NewMathMLElement(nsIContent** aResult, nsINodeInfo* aNodeInfo)
00886 {
00887   static const char kMathMLStyleSheetURI[] = "resource://gre/res/mathml.css";
00888 
00889   aNodeInfo->SetIDAttributeAtom(nsHTMLAtoms::id);
00890   
00891   // this bit of code is to load mathml.css on demand
00892   nsIDocument* doc = nsContentUtils::GetDocument(aNodeInfo);
00893   if (doc)
00894     doc->EnsureCatalogStyleSheet(kMathMLStyleSheetURI);
00895 
00896   return NS_NewXMLElement(aResult, aNodeInfo);
00897 }
00898 #endif // MOZ_MATHML
00899 
00900 
00902 
00903 PRBool
00904 nsXMLContentSink::SetDocElement(PRInt32 aNameSpaceID,
00905                                 nsIAtom* aTagName,
00906                                 nsIContent *aContent)
00907 {
00908   if (mDocElement)
00909     return PR_FALSE;
00910 
00911   // check for root elements that needs special handling for
00912   // prettyprinting
00913   if ((aNameSpaceID == kNameSpaceID_XBL &&
00914        aTagName == nsXBLAtoms::bindings) ||
00915       (aNameSpaceID == kNameSpaceID_XSLT &&
00916        (aTagName == nsLayoutAtoms::stylesheet ||
00917         aTagName == nsLayoutAtoms::transform))) {
00918     mPrettyPrintHasSpecialRoot = PR_TRUE;
00919     if (mPrettyPrintXML) {
00920       // In this case, disable script execution, stylesheet
00921       // loading, and auto XLinks since we plan to prettyprint.
00922       mAllowAutoXLinks = PR_FALSE;
00923       nsIScriptLoader* scriptLoader = mDocument->GetScriptLoader();
00924       if (scriptLoader) {
00925         scriptLoader->SetEnabled(PR_FALSE);
00926       }
00927       if (mCSSLoader) {
00928         mCSSLoader->SetEnabled(PR_FALSE);
00929       }
00930     }        
00931   }
00932 
00933   mDocElement = aContent;
00934   NS_ADDREF(mDocElement);
00935 
00936   nsresult rv = mDocument->SetRootContent(mDocElement);
00937   if (NS_FAILED(rv)) {
00938     // If we return PR_FALSE here, the caller will bail out because it won't
00939     // find a parent content node to append to, which is fine.
00940     return PR_FALSE;
00941   }
00942   return PR_TRUE;
00943 }
00944 
00945 NS_IMETHODIMP 
00946 nsXMLContentSink::HandleStartElement(const PRUnichar *aName, 
00947                                      const PRUnichar **aAtts, 
00948                                      PRUint32 aAttsCount, 
00949                                      PRInt32 aIndex, 
00950                                      PRUint32 aLineNumber)
00951 {
00952   NS_PRECONDITION(aIndex >= -1, "Bogus aIndex");
00953   NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
00954   // Adjust aAttsCount so it's the actual number of attributes
00955   aAttsCount /= 2;
00956 
00957   nsresult result = NS_OK;
00958   PRBool appendContent = PR_TRUE;
00959   nsCOMPtr<nsIContent> content;
00960 
00961   // XXX Hopefully the parser will flag this before we get
00962   // here. If we're in the epilog, there should be no
00963   // new elements
00964   PR_ASSERT(eXMLContentSinkState_InEpilog != mState);
00965 
00966   FlushText();
00967 
00968   mState = eXMLContentSinkState_InDocumentElement;
00969 
00970   PRInt32 nameSpaceID;
00971   nsCOMPtr<nsIAtom> prefix, localName;
00972   nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
00973                                  getter_AddRefs(localName), &nameSpaceID);
00974 
00975   if (!OnOpenContainer(aAtts, aAttsCount, nameSpaceID, localName, aLineNumber)) {
00976     return NS_OK;
00977   }
00978   
00979   nsCOMPtr<nsINodeInfo> nodeInfo;
00980   result = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
00981                                          getter_AddRefs(nodeInfo));
00982   NS_ENSURE_SUCCESS(result, result);
00983 
00984   result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
00985                          getter_AddRefs(content), &appendContent);
00986   NS_ENSURE_SUCCESS(result, result);
00987 
00988   if (mDocument) {
00989     content->SetContentID(mDocument->GetAndIncrementContentID());
00990   }
00991 
00992   // Set the ID attribute atom on the node info object for this node
00993   // This must occur before the attributes are added so the name
00994   // of the id attribute is known.
00995   if (aIndex != -1 && NS_SUCCEEDED(result)) {
00996     nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]);
00997 
00998     if (IDAttr) {
00999       nodeInfo->SetIDAttributeAtom(IDAttr);
01000     }
01001   }
01002   
01003 #ifdef MOZ_XTF
01004   if (nameSpaceID > kNameSpaceID_LastBuiltin)
01005     content->BeginAddingChildren();
01006 #endif
01007 
01008   // Set the attributes on the new content element
01009   result = AddAttributes(aAtts, content);
01010 
01011   if (NS_OK == result) {
01012     // Store the element 
01013     if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
01014       nsCOMPtr<nsIContent> parent = GetCurrentContent();
01015       NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
01016 
01017       parent->AppendChildTo(content, PR_FALSE);
01018     }
01019 
01020     PushContent(content);
01021   }
01022 
01023   // Some HTML nodes need DoneCreatingElement() called to initialize
01024   // properly (eg form state restoration).
01025   if (nodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
01026       (nodeInfo->NameAtom() == nsHTMLAtoms::input ||
01027        nodeInfo->NameAtom() == nsHTMLAtoms::button)) {
01028     content->DoneCreatingElement();
01029   }
01030 
01031   return result;
01032 }
01033 
01034 NS_IMETHODIMP 
01035 nsXMLContentSink::HandleEndElement(const PRUnichar *aName)
01036 {
01037   nsresult result = NS_OK;
01038   PRBool appendContent = PR_FALSE;
01039 
01040   // XXX Hopefully the parser will flag this before we get
01041   // here. If we're in the prolog or epilog, there should be
01042   // no close tags for elements.
01043   PR_ASSERT(eXMLContentSinkState_InDocumentElement == mState);
01044 
01045   FlushText();
01046 
01047   nsCOMPtr<nsIContent> content = PopContent();
01048   NS_ASSERTION(content, "failed to pop content");
01049 #ifdef DEBUG
01050   // Check that we're closing the right thing
01051   nsCOMPtr<nsIAtom> debugNameSpacePrefix, debugTagAtom;
01052   PRInt32 debugNameSpaceID;
01053   nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
01054                                  getter_AddRefs(debugTagAtom),
01055                                  &debugNameSpaceID);
01056   NS_ASSERTION(content->GetNodeInfo()->Equals(debugTagAtom, debugNameSpaceID),
01057                "Wrong element being closed");
01058 #endif  
01059 
01060   nsCOMPtr<nsIContent> parent = GetCurrentContent();
01061   
01062   result = CloseElement(content, parent, &appendContent);
01063   NS_ENSURE_SUCCESS(result, result);
01064 
01065   if (mDocElement == content) {
01066     // XXXbz for roots that don't want to be appended on open, we
01067     // probably need to deal here.... (and stop appending them on open).
01068     mState = eXMLContentSinkState_InEpilog;
01069   }
01070   else if (appendContent) {
01071     NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
01072 
01073     parent->AppendChildTo(content, PR_FALSE);
01074   }
01075 
01076   if (mNeedToBlockParser || (mParser && !mParser->IsParserEnabled())) {
01077     if (mParser) mParser->BlockParser();
01078     result = NS_ERROR_HTMLPARSER_BLOCK;
01079   }
01080 
01081 #ifdef MOZ_SVG
01082   if (content->GetNameSpaceID() == kNameSpaceID_SVG &&
01083       content->HasAttr(kNameSpaceID_None, nsSVGAtoms::onload)) {
01084     nsEventStatus status = nsEventStatus_eIgnore;
01085     nsEvent event(PR_TRUE, NS_SVG_LOAD);
01086     event.eventStructType = NS_SVG_EVENT;
01087     nsCOMPtr<nsIPresShell> presShell = mDocument->GetShellAt(0);
01088     if (presShell)
01089       presShell->HandleDOMEventWithTarget(content, &event, &status);
01090   }
01091 #endif
01092 
01093   return result;
01094 }
01095 
01096 NS_IMETHODIMP 
01097 nsXMLContentSink::HandleComment(const PRUnichar *aName)
01098 {
01099   FlushText();
01100 
01101   nsCOMPtr<nsIContent> comment;
01102   nsresult rv = NS_NewCommentNode(getter_AddRefs(comment), mNodeInfoManager);
01103   if (comment) {
01104     nsCOMPtr<nsIDOMComment> domComment = do_QueryInterface(comment, &rv);
01105     if (domComment) {
01106       domComment->AppendData(nsDependentString(aName));
01107       rv = AddContentAsLeaf(comment);
01108     }
01109   }
01110 
01111   return rv;
01112 }
01113 
01114 NS_IMETHODIMP 
01115 nsXMLContentSink::HandleCDataSection(const PRUnichar *aData, 
01116                                      PRUint32 aLength)
01117 {
01118   // XSLT doesn't differentiate between text and cdata and wants adjacent
01119   // textnodes merged, so add as text.
01120   if (mXSLTProcessor) {
01121     return AddText(aData, aLength);
01122   }
01123 
01124   FlushText();
01125   
01126   if (mInTitle) {
01127     mTitleText.Append(aData, aLength);
01128   }
01129   
01130   nsCOMPtr<nsIContent> cdata;
01131   nsresult rv = NS_NewXMLCDATASection(getter_AddRefs(cdata), mNodeInfoManager);
01132   if (cdata) {
01133     nsCOMPtr<nsIDOMCDATASection> domCDATA = do_QueryInterface(cdata);
01134     if (domCDATA) {
01135       domCDATA->SetData(nsDependentString(aData, aLength));
01136       rv = AddContentAsLeaf(cdata);
01137     }
01138   }
01139 
01140   return rv;
01141 }
01142 
01143 NS_IMETHODIMP
01144 nsXMLContentSink::HandleDoctypeDecl(const nsAString & aSubset, 
01145                                     const nsAString & aName, 
01146                                     const nsAString & aSystemId, 
01147                                     const nsAString & aPublicId,
01148                                     nsISupports* aCatalogData)
01149 {
01150   FlushText();
01151 
01152   nsresult rv = NS_OK;
01153 
01154   nsCOMPtr<nsIDOMDocument> doc(do_QueryInterface(mDocument));
01155   if (!doc)
01156     return NS_OK;
01157 
01158   nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
01159   NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
01160 
01161   // Create a new doctype node
01162   nsCOMPtr<nsIDOMDocumentType> docType;
01163   rv = NS_NewDOMDocumentType(getter_AddRefs(docType), mNodeInfoManager, nsnull,
01164                              name, nsnull, nsnull, aPublicId, aSystemId,
01165                              aSubset);
01166   if (NS_FAILED(rv) || !docType) {
01167     return rv;
01168   }
01169 
01170   if (aCatalogData && mCSSLoader && mDocument) {
01171     // bug 124570 - we only expect additional agent sheets for now -- ignore
01172     // exit codes, error are not fatal here, just that the stylesheet won't apply
01173     nsCOMPtr<nsIURI> uri(do_QueryInterface(aCatalogData));
01174     if (uri) {
01175       nsCOMPtr<nsICSSStyleSheet> sheet;
01176       nsCOMPtr<nsICSSLoader_MOZILLA_1_8_BRANCH> loader =
01177         do_QueryInterface(mCSSLoader);
01178       loader->LoadSheetSync(uri, PR_TRUE, getter_AddRefs(sheet));
01179       
01180 #ifdef NS_DEBUG
01181       nsCAutoString uriStr;
01182       uri->GetSpec(uriStr);
01183       printf("Loading catalog stylesheet: %s ... %s\n", uriStr.get(), sheet.get() ? "Done" : "Failed");
01184 #endif
01185       if (sheet) {
01186         mDocument->BeginUpdate(UPDATE_STYLE);
01187         mDocument->AddCatalogStyleSheet(sheet);
01188         mDocument->EndUpdate(UPDATE_STYLE);
01189       }
01190     }
01191   }
01192 
01193   nsCOMPtr<nsIDOMNode> tmpNode;
01194   
01195   return doc->AppendChild(docType, getter_AddRefs(tmpNode));
01196 }
01197 
01198 NS_IMETHODIMP 
01199 nsXMLContentSink::HandleCharacterData(const PRUnichar *aData, 
01200                                       PRUint32 aLength)
01201 {
01202   if (aData && mState != eXMLContentSinkState_InProlog &&
01203       mState != eXMLContentSinkState_InEpilog) {
01204     return AddText(aData, aLength);
01205   }
01206   return NS_OK;
01207 }
01208 
01209 NS_IMETHODIMP
01210 nsXMLContentSink::HandleProcessingInstruction(const PRUnichar *aTarget, 
01211                                               const PRUnichar *aData)
01212 {
01213   FlushText();
01214 
01215   const nsDependentString target(aTarget);
01216   const nsDependentString data(aData);
01217 
01218   nsCOMPtr<nsIContent> node;
01219 
01220   nsresult rv = NS_NewXMLProcessingInstruction(getter_AddRefs(node),
01221                                                mNodeInfoManager, target,
01222                                                data);
01223   NS_ENSURE_SUCCESS(rv, rv);
01224 
01225   nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(node));
01226   if (ssle) {
01227     ssle->InitStyleLinkElement(mParser, PR_FALSE);
01228     ssle->SetEnableUpdates(PR_FALSE);
01229     mPrettyPrintXML = PR_FALSE;
01230   }
01231 
01232   rv = AddContentAsLeaf(node);
01233   NS_ENSURE_SUCCESS(rv, rv);
01234 
01235   if (ssle) {
01236     ssle->SetEnableUpdates(PR_TRUE);
01237     rv = ssle->UpdateStyleSheet(nsnull, nsnull);
01238 
01239     if (NS_FAILED(rv)) {
01240       if (rv == NS_ERROR_HTMLPARSER_BLOCK && mParser) {
01241         mParser->BlockParser();
01242       }
01243       return rv;
01244     }
01245   }
01246 
01247   // If it's not a CSS stylesheet PI...
01248   nsAutoString type;
01249   nsParserUtils::GetQuotedAttributeValue(data, nsHTMLAtoms::type, type);
01250 
01251   if (mState != eXMLContentSinkState_InProlog ||
01252       !target.EqualsLiteral("xml-stylesheet") ||
01253       type.LowerCaseEqualsLiteral("text/css")) {
01254     return NS_OK;
01255   }
01256 
01257   nsAutoString href, title, media;
01258   PRBool isAlternate = PR_FALSE;
01259   ParsePIData(data, href, title, media, isAlternate);
01260 
01261   // If there was no href, we can't do anything with this PI
01262   if (href.IsEmpty()) {
01263       return NS_OK;
01264   }
01265 
01266   return ProcessStyleLink(node, href, isAlternate, title, type, media);
01267 }
01268 
01269 /* static */
01270 void
01271 nsXMLContentSink::ParsePIData(const nsString &aData, nsString &aHref,
01272                               nsString &aTitle, nsString &aMedia,
01273                               PRBool &aIsAlternate)
01274 {
01275   nsParserUtils::GetQuotedAttributeValue(aData, nsHTMLAtoms::href, aHref);
01276 
01277   // If there was no href, we can't do anything with this PI
01278   if (aHref.IsEmpty()) {
01279     return;
01280   }
01281 
01282   nsParserUtils::GetQuotedAttributeValue(aData, nsHTMLAtoms::title, aTitle);
01283 
01284   nsParserUtils::GetQuotedAttributeValue(aData, nsHTMLAtoms::media, aMedia);
01285 
01286   nsAutoString alternate;
01287   nsParserUtils::GetQuotedAttributeValue(aData, nsHTMLAtoms::alternate,
01288                                          alternate);
01289 
01290   aIsAlternate = alternate.EqualsLiteral("yes");
01291 }
01292 
01293 NS_IMETHODIMP
01294 nsXMLContentSink::HandleXMLDeclaration(const PRUnichar *aVersion,
01295                                        const PRUnichar *aEncoding,
01296                                        PRInt32 aStandalone)
01297 {
01298   mDocument->SetXMLDeclaration(aVersion, aEncoding, aStandalone);
01299 
01300   return NS_OK;
01301 }
01302 
01303 NS_IMETHODIMP
01304 nsXMLContentSink::ReportError(const PRUnichar* aErrorText, 
01305                               const PRUnichar* aSourceText)
01306 {
01307   nsresult rv = NS_OK;
01308   
01309   mPrettyPrintXML = PR_FALSE;
01310 
01311   mState = eXMLContentSinkState_InProlog;
01312 
01313   // Clear the current content and
01314   // prepare to set <parsererror> as the document root
01315   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mDocument));
01316   if (node) {
01317     for (;;) {
01318       nsCOMPtr<nsIDOMNode> child, dummy;
01319       node->GetLastChild(getter_AddRefs(child));
01320       if (!child)
01321         break;
01322       node->RemoveChild(child, getter_AddRefs(dummy));
01323     }
01324   }
01325   NS_IF_RELEASE(mDocElement); 
01326 
01327   // Clear any buffered-up text we have.  It's enough to set the length to 0.
01328   // The buffer itself is allocated when we're created and deleted in our
01329   // destructor, so don't mess with it.
01330   mTextLength = 0;
01331 
01332   if (mXSLTProcessor) {
01333     // Get rid of the XSLT processor.
01334     mXSLTProcessor->CancelLoads();
01335     mXSLTProcessor = nsnull;
01336   }
01337 
01338   const PRUnichar* noAtts[] = { 0, 0 };
01339 
01340   NS_NAMED_LITERAL_STRING(errorNs,
01341                           "http://www.mozilla.org/newlayout/xml/parsererror.xml");
01342 
01343   nsAutoString parsererror(errorNs);
01344   parsererror.Append((PRUnichar)0xFFFF);
01345   parsererror.AppendLiteral("parsererror");
01346   
01347   rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, (PRUint32)-1);
01348   NS_ENSURE_SUCCESS(rv,rv);
01349 
01350   rv = HandleCharacterData(aErrorText, nsCRT::strlen(aErrorText));
01351   NS_ENSURE_SUCCESS(rv,rv);  
01352   
01353   nsAutoString sourcetext(errorNs);
01354   sourcetext.Append((PRUnichar)0xFFFF);
01355   sourcetext.AppendLiteral("sourcetext");
01356 
01357   rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, (PRUint32)-1);
01358   NS_ENSURE_SUCCESS(rv,rv);
01359   
01360   rv = HandleCharacterData(aSourceText, nsCRT::strlen(aSourceText));
01361   NS_ENSURE_SUCCESS(rv,rv);
01362   
01363   rv = HandleEndElement(sourcetext.get());
01364   NS_ENSURE_SUCCESS(rv,rv); 
01365   
01366   rv = HandleEndElement(parsererror.get());
01367   NS_ENSURE_SUCCESS(rv,rv);
01368 
01369   return NS_OK;
01370 }
01371 
01372 nsresult
01373 nsXMLContentSink::AddAttributes(const PRUnichar** aAtts,
01374                                 nsIContent* aContent)
01375 {
01376   // Add tag attributes to the content attributes
01377   nsCOMPtr<nsIAtom> prefix, localName;
01378   while (*aAtts) {
01379     PRInt32 nameSpaceID;
01380     nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
01381                                    getter_AddRefs(localName), &nameSpaceID);
01382 
01383     // Add attribute to content
01384     aContent->SetAttr(nameSpaceID, localName, prefix,
01385                       nsDependentString(aAtts[1]), PR_FALSE);
01386     aAtts += 2;
01387   }
01388 
01389   // Give autoloading links a chance to fire
01390   if (mDocShell && mAllowAutoXLinks) {
01391     nsCOMPtr<nsIXMLContent> xmlcontent(do_QueryInterface(aContent));
01392     if (xmlcontent) {
01393       nsresult rv = xmlcontent->MaybeTriggerAutoLink(mDocShell);
01394       if (rv == NS_XML_AUTOLINK_REPLACE ||
01395           rv == NS_XML_AUTOLINK_UNDEFINED) {
01396         // If we do not terminate the parse, we just keep generating link trigger
01397         // events. We want to parse only up to the first replace link, and stop.
01398         mParser->Terminate();
01399       }
01400     }
01401   }
01402 
01403   return NS_OK;
01404 }
01405 
01406 #define NS_ACCUMULATION_BUFFER_SIZE 4096
01407 
01408 nsresult
01409 nsXMLContentSink::AddText(const PRUnichar* aText, 
01410                           PRInt32 aLength)
01411 {
01412 
01413   if (mInTitle) {
01414     mTitleText.Append(aText,aLength);
01415   }
01416 
01417   // Create buffer when we first need it
01418   if (0 == mTextSize) {
01419     mText = (PRUnichar *) PR_MALLOC(sizeof(PRUnichar) * NS_ACCUMULATION_BUFFER_SIZE);
01420     if (nsnull == mText) {
01421       return NS_ERROR_OUT_OF_MEMORY;
01422     }
01423     mTextSize = NS_ACCUMULATION_BUFFER_SIZE;
01424   }
01425 
01426   const nsAString& str = Substring(aText, aText+aLength);
01427 
01428   // Copy data from string into our buffer; flush buffer when it fills up
01429   PRInt32 offset = 0;
01430   PRBool  isLastCharCR = PR_FALSE;
01431   while (0 != aLength) {
01432     PRInt32 amount = mTextSize - mTextLength;
01433     if (amount > aLength) {
01434       amount = aLength;
01435     }
01436     if (0 == amount) {
01437       // XSLT wants adjacent textnodes merged.
01438       if (mConstrainSize && !mXSLTProcessor) {
01439         nsresult rv = FlushText();
01440         if (NS_OK != rv) {
01441           return rv;
01442         }
01443       }
01444       else {
01445         mTextSize += aLength;
01446         mText = (PRUnichar *) PR_REALLOC(mText, sizeof(PRUnichar) * mTextSize);
01447         if (nsnull == mText) {
01448           return NS_ERROR_OUT_OF_MEMORY;
01449         }
01450       }
01451     }
01452     mTextLength +=
01453       nsContentUtils::CopyNewlineNormalizedUnicodeTo(str, 
01454                                                      offset, 
01455                                                      &mText[mTextLength], 
01456                                                      amount,
01457                                                      isLastCharCR);
01458     offset  += amount;
01459     aLength -= amount;
01460   }
01461 
01462   return NS_OK;
01463 }
01464 
01465 nsresult
01466 nsXMLContentSink::ProcessEndSCRIPTTag(nsIContent* aContent,
01467                                       nsIContent* aParent)
01468 {
01469   nsresult result = NS_OK;
01470 
01471   mConstrainSize = PR_TRUE; 
01472   nsCOMPtr<nsIScriptElement> scriptElement(do_QueryInterface(aContent));
01473   NS_ASSERTION(scriptElement, "null script element in XML content sink");
01474 
01475   scriptElement->SetScriptLineNumber(mScriptLineNo);
01476 
01477   if (!aParent || aParent->GetCurrentDoc() == mDocument) {
01478     // Assume that we're going to block the parser with a script load.
01479     // If it's an inline script, we'll be told otherwise in the call
01480     // to our ScriptAvailable method.
01481     mScriptElements.AppendObject(scriptElement);
01482     mNeedToBlockParser = PR_TRUE;
01483   }
01484 
01485   return result;
01486 }