Back to index

lightning-sunbird  0.9+nobinonly
nsXULContentSink.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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  *   Chris Waterson <waterson@netscape.com>
00024  *   David Hyatt <hyatt@netscape.com>
00025  *   Brendan Eich <brendan@mozilla.org>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 /*
00042 
00043   An implementation for a Gecko-style content sink that knows how
00044   to build a content model from XUL.
00045 
00046   For more information on XUL, see http://www.mozilla.org/xpfe
00047 
00048   TO DO
00049   -----
00050 
00051 */
00052 
00053 #include "nsCOMPtr.h"
00054 #include "nsForwardReference.h"
00055 #include "nsICSSLoader.h"
00056 #include "nsICSSParser.h"
00057 #include "nsICSSStyleSheet.h"
00058 #include "nsIContentSink.h"
00059 #include "nsIDOMDocument.h"
00060 #include "nsIDOMEventListener.h"
00061 #include "nsIDOMHTMLFormElement.h"
00062 #include "nsIDOMXULDocument.h"
00063 #include "nsIDocument.h"
00064 #include "nsIDocumentLoader.h"
00065 #include "nsIFormControl.h"
00066 #include "nsHTMLStyleSheet.h"
00067 #include "nsINameSpaceManager.h"
00068 #include "nsINodeInfo.h"
00069 #include "nsIParser.h"
00070 #include "nsIPresShell.h"
00071 #include "nsIScriptContext.h"
00072 #include "nsIScriptGlobalObject.h"
00073 #include "nsIServiceManager.h"
00074 #include "nsITextContent.h"
00075 #include "nsIURL.h"
00076 #include "nsIViewManager.h"
00077 #include "nsIXULContentSink.h"
00078 #include "nsIXULDocument.h"
00079 #include "nsIXULPrototypeDocument.h"
00080 #include "nsIXULPrototypeCache.h"
00081 #include "nsIScriptSecurityManager.h"
00082 #include "nsLayoutCID.h"
00083 #include "nsNetUtil.h"
00084 #include "nsRDFCID.h"
00085 #include "nsParserUtils.h"
00086 #include "nsIMIMEHeaderParam.h"
00087 #include "nsVoidArray.h"
00088 #include "nsWeakPtr.h"
00089 #include "nsXPIDLString.h"
00090 #include "nsReadableUtils.h"
00091 #include "nsXULElement.h"
00092 #include "prlog.h"
00093 #include "prmem.h"
00094 #include "jsapi.h"  // for JSVERSION_*, JS_VersionToString, etc.
00095 #include "nsCRT.h"
00096 
00097 #include "nsIFastLoadService.h"         // XXXbe temporary
00098 #include "nsIObjectInputStream.h"       // XXXbe temporary
00099 #include "nsXULDocument.h"              // XXXbe temporary
00100 
00101 #include "nsIExpatSink.h"
00102 #include "nsUnicharUtils.h"
00103 #include "nsXULAtoms.h"
00104 #include "nsHTMLAtoms.h"
00105 #include "nsNodeInfoManager.h"
00106 #include "nsContentUtils.h"
00107 #include "nsAttrName.h"
00108 #include "nsXMLContentSink.h"
00109 #include "nsLayoutAtoms.h"
00110 
00111 #ifdef PR_LOGGING
00112 static PRLogModuleInfo* gLog;
00113 #endif
00114 
00115 static NS_DEFINE_CID(kXULPrototypeCacheCID,      NS_XULPROTOTYPECACHE_CID);
00116 
00117 //----------------------------------------------------------------------
00118 
00119 class XULContentSinkImpl : public nsIXULContentSink,
00120                            public nsIExpatSink
00121 {
00122 public:
00123     XULContentSinkImpl(nsresult& aRV);
00124     virtual ~XULContentSinkImpl();
00125 
00126     // nsISupports
00127     NS_DECL_ISUPPORTS
00128     NS_DECL_NSIEXPATSINK
00129 
00130     // nsIContentSink
00131     NS_IMETHOD WillBuildModel(void);
00132     NS_IMETHOD DidBuildModel(void);
00133     NS_IMETHOD WillInterrupt(void);
00134     NS_IMETHOD WillResume(void);
00135     NS_IMETHOD SetParser(nsIParser* aParser);  
00136     virtual void FlushPendingNotifications(mozFlushType aType) { }
00137     NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
00138     virtual nsISupports *GetTarget();
00139 
00140     // nsIXULContentSink
00141     NS_IMETHOD Init(nsIDocument* aDocument, nsIXULPrototypeDocument* aPrototype);
00142 
00143 protected:
00144     // pseudo-constants
00145     static nsrefcnt               gRefCnt;
00146     static nsIXULPrototypeCache*  gXULCache;
00147 
00148     PRUnichar* mText;
00149     PRInt32 mTextLength;
00150     PRInt32 mTextSize;
00151     PRBool mConstrainSize;
00152 
00153     nsresult AddAttributes(const PRUnichar** aAttributes, 
00154                            const PRUint32 aAttrLen, 
00155                            nsXULPrototypeElement* aElement);
00156    
00157     nsresult OpenRoot(const PRUnichar** aAttributes, 
00158                       const PRUint32 aAttrLen, 
00159                       nsINodeInfo *aNodeInfo);
00160 
00161     nsresult OpenTag(const PRUnichar** aAttributes, 
00162                      const PRUint32 aAttrLen, 
00163                      const PRUint32 aLineNumber, 
00164                      nsINodeInfo *aNodeInfo);
00165     
00166     nsresult OpenScript(const PRUnichar** aAttributes,
00167                         const PRUint32 aLineNumber);
00168 
00169     static PRBool IsDataInBuffer(PRUnichar* aBuffer, PRInt32 aLength);
00170 
00171 
00172     // Text management
00173     nsresult FlushText(PRBool aCreateTextNode = PR_TRUE);
00174     nsresult AddText(const PRUnichar* aText, PRInt32 aLength);
00175 
00176 
00177     nsRefPtr<nsNodeInfoManager> mNodeInfoManager;
00178     
00179     
00180     nsresult NormalizeAttributeString(const PRUnichar *aExpatName,
00181                                       nsAttrName &aName);
00182     nsresult CreateElement(nsINodeInfo *aNodeInfo, nsXULPrototypeElement** aResult);
00183 
00184     // Style sheets
00185     nsresult ProcessStyleLink(nsIContent* aElement,
00186                               const nsString& aHref,
00187                               PRBool aAlternate,
00188                               const nsString& aTitle,
00189                               const nsString& aType,
00190                               const nsString& aMedia);
00191     
00192 
00193     public:
00194     enum State { eInProlog, eInDocumentElement, eInScript, eInEpilog };
00195     protected:
00196 
00197     State mState;
00198 
00199     // content stack management
00200     class ContextStack {
00201     protected:
00202         struct Entry {
00203             nsXULPrototypeNode* mNode;
00204             // a LOT of nodes have children; preallocate for 8
00205             nsAutoVoidArray     mChildren;
00206             State               mState;
00207             Entry*              mNext;
00208         };
00209 
00210         Entry* mTop;
00211         PRInt32 mDepth;
00212 
00213     public:
00214         ContextStack();
00215         ~ContextStack();
00216 
00217         PRInt32 Depth() { return mDepth; }
00218 
00219         nsresult Push(nsXULPrototypeNode* aNode, State aState);
00220         nsresult Pop(State* aState);
00221 
00222         nsresult GetTopNode(nsXULPrototypeNode** aNode);
00223         nsresult GetTopChildren(nsVoidArray** aChildren);
00224     };
00225 
00226     friend class ContextStack;
00227     ContextStack mContextStack;
00228 
00229     nsWeakPtr              mDocument;             // [OWNER]
00230     nsCOMPtr<nsIURI>       mDocumentURL;          // [OWNER]
00231 
00232     nsCOMPtr<nsIXULPrototypeDocument> mPrototype; // [OWNER]
00233     nsIParser*             mParser;               // [OWNER] We use regular pointer b/c of funky exports on nsIParser
00234     
00235     nsString               mPreferredStyle;
00236     nsCOMPtr<nsICSSLoader> mCSSLoader;            // [OWNER]
00237     nsCOMPtr<nsICSSParser> mCSSParser;            // [OWNER]
00238     nsCOMPtr<nsIScriptSecurityManager> mSecMan;
00239 };
00240 
00241 nsrefcnt XULContentSinkImpl::gRefCnt;
00242 nsIXULPrototypeCache* XULContentSinkImpl::gXULCache;
00243 
00244 //----------------------------------------------------------------------
00245 
00246 XULContentSinkImpl::ContextStack::ContextStack()
00247     : mTop(nsnull), mDepth(0)
00248 {
00249 }
00250 
00251 XULContentSinkImpl::ContextStack::~ContextStack()
00252 {
00253     while (mTop) {
00254         Entry* doomed = mTop;
00255         mTop = mTop->mNext;
00256         delete doomed;
00257     }
00258 }
00259 
00260 nsresult
00261 XULContentSinkImpl::ContextStack::Push(nsXULPrototypeNode* aNode, State aState)
00262 {
00263     Entry* entry = new Entry;
00264     if (! entry)
00265         return NS_ERROR_OUT_OF_MEMORY;
00266 
00267     entry->mNode  = aNode;
00268     entry->mState = aState;
00269     entry->mNext  = mTop;
00270     mTop = entry;
00271 
00272     ++mDepth;
00273     return NS_OK;
00274 }
00275 
00276 nsresult
00277 XULContentSinkImpl::ContextStack::Pop(State* aState)
00278 {
00279     if (mDepth == 0)
00280         return NS_ERROR_UNEXPECTED;
00281 
00282     Entry* entry = mTop;
00283     mTop = mTop->mNext;
00284     --mDepth;
00285 
00286     *aState = entry->mState;
00287     delete entry;
00288 
00289     return NS_OK;
00290 }
00291 
00292 
00293 nsresult
00294 XULContentSinkImpl::ContextStack::GetTopNode(nsXULPrototypeNode** aNode)
00295 {
00296     if (mDepth == 0)
00297         return NS_ERROR_UNEXPECTED;
00298 
00299     *aNode = mTop->mNode;
00300     return NS_OK;
00301 }
00302 
00303 
00304 nsresult
00305 XULContentSinkImpl::ContextStack::GetTopChildren(nsVoidArray** aChildren)
00306 {
00307     if (mDepth == 0)
00308         return NS_ERROR_UNEXPECTED;
00309 
00310     *aChildren = &(mTop->mChildren);
00311     return NS_OK;
00312 }
00313 
00314 
00315 //----------------------------------------------------------------------
00316 
00317 
00318 XULContentSinkImpl::XULContentSinkImpl(nsresult& rv)
00319     : mText(nsnull),
00320       mTextLength(0),
00321       mTextSize(0),
00322       mConstrainSize(PR_TRUE),
00323       mState(eInProlog),
00324       mParser(nsnull)
00325 {
00326 
00327     if (gRefCnt++ == 0) {
00328         rv = CallGetService(kXULPrototypeCacheCID, &gXULCache);
00329     }
00330 
00331 #ifdef PR_LOGGING
00332     if (! gLog)
00333         gLog = PR_NewLogModule("nsXULContentSink");
00334 #endif
00335 
00336     rv = NS_OK;
00337 }
00338 
00339 
00340 XULContentSinkImpl::~XULContentSinkImpl()
00341 {
00342     NS_IF_RELEASE(mParser); // XXX should've been released by now, unless error.
00343 
00344     // Pop all of the elements off of the context stack, and delete
00345     // any remaining content elements. The context stack _should_ be
00346     // empty, unless something has gone wrong.
00347     while (mContextStack.Depth()) {
00348         nsresult rv;
00349 
00350         nsVoidArray* children;
00351         rv = mContextStack.GetTopChildren(&children);
00352         if (NS_SUCCEEDED(rv)) {
00353             for (PRInt32 i = children->Count() - 1; i >= 0; --i) {
00354                 nsXULPrototypeNode* child =
00355                     NS_REINTERPRET_CAST(nsXULPrototypeNode*, children->ElementAt(i));
00356 
00357                 delete child;
00358             }
00359         }
00360 
00361         nsXULPrototypeNode* node;
00362         rv = mContextStack.GetTopNode(&node);
00363         if (NS_SUCCEEDED(rv)) delete node;
00364 
00365         State state;
00366         mContextStack.Pop(&state);
00367     }
00368 
00369     PR_FREEIF(mText);
00370 
00371     if (--gRefCnt == 0) {
00372         NS_IF_RELEASE(gXULCache);
00373     }
00374 }
00375 
00376 //----------------------------------------------------------------------
00377 // nsISupports interface
00378 
00379 NS_IMPL_ISUPPORTS4(XULContentSinkImpl,
00380                    nsIXULContentSink,
00381                    nsIXMLContentSink,
00382                    nsIContentSink,
00383                    nsIExpatSink)
00384 
00385 //----------------------------------------------------------------------
00386 // nsIContentSink interface
00387 
00388 NS_IMETHODIMP 
00389 XULContentSinkImpl::WillBuildModel(void)
00390 {
00391 #if FIXME
00392     if (! mParentContentSink) {
00393         // If we're _not_ an overlay, then notify the document that
00394         // the load is beginning.
00395         mDocument->BeginLoad();
00396     }
00397 #endif
00398 
00399     return NS_OK;
00400 }
00401 
00402 NS_IMETHODIMP 
00403 XULContentSinkImpl::DidBuildModel(void)
00404 {
00405     nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
00406     if (doc) {
00407         doc->EndLoad();
00408         mDocument = nsnull;
00409     }
00410 
00411     // Drop our reference to the parser to get rid of a circular
00412     // reference.
00413     NS_IF_RELEASE(mParser);
00414     return NS_OK;
00415 }
00416 
00417 NS_IMETHODIMP 
00418 XULContentSinkImpl::WillInterrupt(void)
00419 {
00420     // XXX Notify the docshell, if necessary
00421     return NS_OK;
00422 }
00423 
00424 NS_IMETHODIMP 
00425 XULContentSinkImpl::WillResume(void)
00426 {
00427     // XXX Notify the docshell, if necessary
00428     return NS_OK;
00429 }
00430 
00431 NS_IMETHODIMP 
00432 XULContentSinkImpl::SetParser(nsIParser* aParser)
00433 {
00434     NS_IF_RELEASE(mParser);
00435     mParser = aParser;
00436     NS_IF_ADDREF(mParser);
00437     return NS_OK;
00438 }
00439 
00440 nsresult
00441 XULContentSinkImpl::ProcessStyleLink(nsIContent* aElement,
00442                                      const nsString& aHref,
00443                                      PRBool aAlternate,
00444                                      const nsString& aTitle,
00445                                      const nsString& aType,
00446                                      const nsString& aMedia)
00447 {
00448     static const char kCSSType[] = "text/css";
00449 
00450     nsresult rv = NS_OK;
00451 
00452     if (aAlternate) { // if alternate, does it have title?
00453         if (aTitle.IsEmpty()) { // alternates must have title
00454             return NS_OK; //return without error, for now
00455         }
00456     }
00457 
00458     nsAutoString mimeType;
00459     nsAutoString params;
00460     nsParserUtils::SplitMimeType(aType, mimeType, params);
00461 
00462     if ((mimeType.IsEmpty()) || mimeType.EqualsIgnoreCase(kCSSType)) {
00463         nsCOMPtr<nsIURI> url;
00464         rv = NS_NewURI(getter_AddRefs(url), aHref, nsnull, mDocumentURL);
00465         if (NS_OK != rv) {
00466             return NS_OK; // The URL is bad, move along, don't propagate the error (for now)
00467         }
00468 
00469         // Add the style sheet reference to the prototype
00470         mPrototype->AddStyleSheetReference(url);
00471 
00472         // Nope, we need to load it asynchronously
00473         PRBool blockParser = PR_FALSE;
00474         if (! aAlternate) {
00475             if (!aTitle.IsEmpty()) {  // possibly preferred sheet
00476                 if (mPreferredStyle.IsEmpty()) {
00477                     mPreferredStyle = aTitle;
00478                     mCSSLoader->SetPreferredSheet(aTitle);
00479                     nsCOMPtr<nsIAtom> defaultStyle = do_GetAtom("default-style");
00480                     if (defaultStyle) {
00481                         mPrototype->SetHeaderData(defaultStyle, aTitle);
00482                     }
00483                 }
00484             }
00485             else {  // persistent sheet, block
00486                 blockParser = PR_TRUE;
00487             }
00488         }
00489 
00490         nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
00491         if (! doc)
00492             return NS_ERROR_FAILURE; // doc went away!
00493 
00494         PRBool doneLoading;
00495         rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia,
00496                                        ((blockParser) ? mParser : nsnull),
00497                                        doneLoading, nsnull);
00498         if (NS_SUCCEEDED(rv) && blockParser && (! doneLoading)) {
00499           rv = NS_ERROR_HTMLPARSER_BLOCK;
00500         }
00501     }
00502 
00503     return rv;
00504 }
00505 
00506 NS_IMETHODIMP 
00507 XULContentSinkImpl::SetDocumentCharset(nsACString& aCharset)
00508 {
00509     nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
00510     if (doc) {
00511         doc->SetDocumentCharacterSet(aCharset);
00512     }
00513   
00514     return NS_OK;
00515 }
00516 
00517 nsISupports *
00518 XULContentSinkImpl::GetTarget()
00519 {
00520     nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
00521     return doc;    
00522 }
00523 
00524 //----------------------------------------------------------------------
00525 //
00526 // nsIXULContentSink interface
00527 //
00528 
00529 NS_IMETHODIMP
00530 XULContentSinkImpl::Init(nsIDocument* aDocument, nsIXULPrototypeDocument* aPrototype)
00531 {
00532     NS_PRECONDITION(aDocument != nsnull, "null ptr");
00533     if (! aDocument)
00534         return NS_ERROR_NULL_POINTER;
00535     
00536     nsresult rv;
00537 
00538     mDocument    = do_GetWeakReference(aDocument);
00539     mPrototype   = aPrototype;
00540 
00541     rv = mPrototype->GetURI(getter_AddRefs(mDocumentURL));
00542     if (NS_FAILED(rv)) return rv;
00543 
00544     // XXX this presumes HTTP header info is already set in document
00545     // XXX if it isn't we need to set it here...
00546     nsCOMPtr<nsIAtom> defaultStyle = do_GetAtom("default-style");
00547     if (! defaultStyle)
00548         return NS_ERROR_OUT_OF_MEMORY;
00549 
00550     rv = mPrototype->GetHeaderData(defaultStyle, mPreferredStyle);
00551     if (NS_FAILED(rv)) return rv;
00552 
00553     // Get the CSS loader from the document so we can load
00554     // stylesheets
00555     mCSSLoader = aDocument->CSSLoader();
00556 
00557     mNodeInfoManager = aPrototype->GetNodeInfoManager();
00558     if (! mNodeInfoManager)
00559         return NS_ERROR_UNEXPECTED;
00560 
00561     mState = eInProlog;
00562     return NS_OK;
00563 }
00564 
00565 
00566 //----------------------------------------------------------------------
00567 //
00568 // Text buffering
00569 //
00570 
00571 PRBool
00572 XULContentSinkImpl::IsDataInBuffer(PRUnichar* buffer, PRInt32 length)
00573 {
00574     for (PRInt32 i = 0; i < length; ++i) {
00575         if (buffer[i] == ' ' ||
00576             buffer[i] == '\t' ||
00577             buffer[i] == '\n' ||
00578             buffer[i] == '\r')
00579             continue;
00580 
00581         return PR_TRUE;
00582     }
00583     return PR_FALSE;
00584 }
00585 
00586 
00587 nsresult
00588 XULContentSinkImpl::FlushText(PRBool aCreateTextNode)
00589 {
00590     nsresult rv;
00591 
00592     do {
00593         // Don't do anything if there's no text to create a node from, or
00594         // if they've told us not to create a text node
00595         if (! mTextLength)
00596             break;
00597 
00598         if (! aCreateTextNode)
00599             break;
00600 
00601         nsXULPrototypeNode* node;
00602         rv = mContextStack.GetTopNode(&node);
00603         if (NS_FAILED(rv)) return rv;
00604 
00605         PRBool stripWhitespace = PR_FALSE;
00606         if (node->mType == nsXULPrototypeNode::eType_Element) {
00607             nsINodeInfo *nodeInfo =
00608                 NS_STATIC_CAST(nsXULPrototypeElement*, node)->mNodeInfo;
00609 
00610             if (nodeInfo->NamespaceEquals(kNameSpaceID_XUL))
00611                 stripWhitespace = !nodeInfo->Equals(nsXULAtoms::label) &&
00612                                   !nodeInfo->Equals(nsXULAtoms::description);
00613         }
00614 
00615         // Don't bother if there's nothing but whitespace.
00616         if (stripWhitespace && ! IsDataInBuffer(mText, mTextLength))
00617             break;
00618 
00619         // Don't bother if we're not in XUL document body
00620         if (mState != eInDocumentElement || mContextStack.Depth() == 0)
00621             break;
00622 
00623         nsXULPrototypeText* text = new nsXULPrototypeText();
00624         if (! text)
00625             return NS_ERROR_OUT_OF_MEMORY;
00626 
00627         text->mValue.Assign(mText, mTextLength);
00628         if (stripWhitespace)
00629             text->mValue.Trim(" \t\n\r");
00630 
00631         // hook it up
00632         nsVoidArray* children;
00633         rv = mContextStack.GetTopChildren(&children);
00634         if (NS_FAILED(rv)) return rv;
00635 
00636         // transfer ownership of 'text' to the children array
00637         children->AppendElement(text);
00638     } while (0);
00639 
00640     // Reset our text buffer
00641     mTextLength = 0;
00642     return NS_OK;
00643 }
00644 
00645 //----------------------------------------------------------------------
00646 
00647 nsresult
00648 XULContentSinkImpl::NormalizeAttributeString(const PRUnichar *aExpatName,
00649                                              nsAttrName &aName)
00650 {
00651     PRInt32 nameSpaceID;
00652     nsCOMPtr<nsIAtom> prefix, localName;
00653     nsContentUtils::SplitExpatName(aExpatName, getter_AddRefs(prefix),
00654                                    getter_AddRefs(localName), &nameSpaceID);
00655 
00656     if (nameSpaceID == kNameSpaceID_None) {
00657         aName.SetTo(localName);
00658 
00659         return NS_OK;
00660     }
00661 
00662     nsCOMPtr<nsINodeInfo> ni;
00663     nsresult rv = mNodeInfoManager->GetNodeInfo(localName, prefix,
00664                                                 nameSpaceID,
00665                                                 getter_AddRefs(ni));
00666     NS_ENSURE_SUCCESS(rv, rv);
00667 
00668     aName.SetTo(ni);
00669 
00670     return NS_OK;
00671 }
00672 
00673 nsresult
00674 XULContentSinkImpl::CreateElement(nsINodeInfo *aNodeInfo,
00675                                   nsXULPrototypeElement** aResult)
00676 {
00677     nsXULPrototypeElement* element = new nsXULPrototypeElement();
00678     if (! element)
00679         return NS_ERROR_OUT_OF_MEMORY;
00680 
00681     element->mNodeInfo    = aNodeInfo;
00682     
00683     *aResult = element;
00684     return NS_OK;
00685 }
00686 
00687 nsresult
00688 NS_NewXULContentSink(nsIXULContentSink** aResult)
00689 {
00690     NS_PRECONDITION(aResult != nsnull, "null ptr");
00691     if (! aResult)
00692         return NS_ERROR_NULL_POINTER;
00693 
00694     nsresult rv;
00695     XULContentSinkImpl* sink = new XULContentSinkImpl(rv);
00696     if (! sink)
00697         return NS_ERROR_OUT_OF_MEMORY;
00698 
00699     if (NS_FAILED(rv)) {
00700         delete sink;
00701         return rv;
00702     }
00703 
00704     NS_ADDREF(sink);
00705     *aResult = sink;
00706     return NS_OK;
00707 }
00708 
00709 /**** BEGIN NEW APIs ****/
00710 
00711 
00712 NS_IMETHODIMP 
00713 XULContentSinkImpl::HandleStartElement(const PRUnichar *aName, 
00714                                        const PRUnichar **aAtts,
00715                                        PRUint32 aAttsCount, 
00716                                        PRInt32 aIndex, 
00717                                        PRUint32 aLineNumber)
00718 { 
00719   // XXX Hopefully the parser will flag this before we get here. If
00720   // we're in the epilog, there should be no new elements
00721   NS_PRECONDITION(mState != eInEpilog, "tag in XUL doc epilog");
00722   NS_PRECONDITION(aIndex >= -1, "Bogus aIndex");
00723   NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
00724   // Adjust aAttsCount so it's the actual number of attributes
00725   aAttsCount /= 2;
00726   
00727   if (mState == eInEpilog)
00728       return NS_ERROR_UNEXPECTED;
00729 
00730   if (mState != eInScript) {
00731       FlushText();
00732   }
00733 
00734   PRInt32 nameSpaceID;
00735   nsCOMPtr<nsIAtom> prefix, localName;
00736   nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
00737                                  getter_AddRefs(localName), &nameSpaceID);
00738 
00739   nsCOMPtr<nsINodeInfo> nodeInfo;
00740   nsresult rv = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
00741                                               getter_AddRefs(nodeInfo));
00742   NS_ENSURE_SUCCESS(rv, rv);
00743 
00744   switch (mState) {
00745   case eInProlog:
00746       // We're the root document element
00747       rv = OpenRoot(aAtts, aAttsCount, nodeInfo);
00748       break;
00749 
00750   case eInDocumentElement:
00751       rv = OpenTag(aAtts, aAttsCount, aLineNumber, nodeInfo);
00752       break;
00753 
00754   case eInEpilog:
00755   case eInScript:
00756       PR_LOG(gLog, PR_LOG_WARNING,
00757              ("xul: warning: unexpected tags in epilog at line %d",
00758              aLineNumber));
00759       rv = NS_ERROR_UNEXPECTED; // XXX
00760       break;
00761   }
00762 
00763   // Set the ID attribute atom on the node info object for this node
00764   if (aIndex != -1 && NS_SUCCEEDED(rv)) {
00765     nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]);
00766 
00767     if (IDAttr) {
00768       nodeInfo->SetIDAttributeAtom(IDAttr);
00769     }
00770   }
00771 
00772   return rv;
00773 }
00774 
00775 NS_IMETHODIMP 
00776 XULContentSinkImpl::HandleEndElement(const PRUnichar *aName)
00777 {
00778     // Never EVER return anything but NS_OK or
00779     // NS_ERROR_HTMLPARSER_BLOCK from this method. Doing so will blow
00780     // the parser's little mind all over the planet.
00781     nsresult rv;
00782 
00783     nsXULPrototypeNode* node;
00784     rv = mContextStack.GetTopNode(&node);
00785 
00786     if (NS_FAILED(rv)) {
00787       return NS_OK;
00788     }
00789 
00790     switch (node->mType) {
00791     case nsXULPrototypeNode::eType_Element: {
00792         // Flush any text _now_, so that we'll get text nodes created
00793         // before popping the stack.
00794         FlushText();
00795 
00796         // Pop the context stack and do prototype hookup.
00797         nsVoidArray* children;
00798         rv = mContextStack.GetTopChildren(&children);
00799         if (NS_FAILED(rv)) return rv;
00800 
00801         nsXULPrototypeElement* element =
00802             NS_REINTERPRET_CAST(nsXULPrototypeElement*, node);
00803 
00804         PRInt32 count = children->Count();
00805         if (count) {
00806             element->mChildren = new nsXULPrototypeNode*[count];
00807             if (! element->mChildren)
00808                 return NS_ERROR_OUT_OF_MEMORY;
00809 
00810             for (PRInt32 i = count - 1; i >= 0; --i)
00811                 element->mChildren[i] =
00812                     NS_REINTERPRET_CAST(nsXULPrototypeNode*, children->ElementAt(i));
00813 
00814             element->mNumChildren = count;
00815         }
00816     }
00817     break;
00818 
00819     case nsXULPrototypeNode::eType_Script: {
00820         nsXULPrototypeScript* script =
00821             NS_STATIC_CAST(nsXULPrototypeScript*, node);
00822 
00823         // If given a src= attribute, we must ignore script tag content.
00824         if (! script->mSrcURI && ! script->mJSObject) {
00825             nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
00826 
00827             script->mOutOfLine = PR_FALSE;
00828             if (doc)
00829                 script->Compile(mText, mTextLength, mDocumentURL,
00830                                 script->mLineNo, doc, mPrototype);
00831         }
00832 
00833         FlushText(PR_FALSE);
00834     }
00835     break;
00836 
00837     default:
00838         NS_ERROR("didn't expect that");
00839         break;
00840     }
00841 
00842     rv = mContextStack.Pop(&mState);
00843     NS_ASSERTION(NS_SUCCEEDED(rv), "context stack corrupted");
00844     if (NS_FAILED(rv)) return rv;
00845 
00846     if (mContextStack.Depth() == 0) {
00847         // The root element should -always- be an element, because
00848         // it'll have been created via XULContentSinkImpl::OpenRoot().
00849         NS_ASSERTION(node->mType == nsXULPrototypeNode::eType_Element, "root is not an element");
00850         if (node->mType != nsXULPrototypeNode::eType_Element)
00851             return NS_ERROR_UNEXPECTED;
00852 
00853         // Now that we're done parsing, set the prototype document's
00854         // root element. This transfers ownership of the prototype
00855         // element tree to the prototype document.
00856         nsXULPrototypeElement* element =
00857             NS_STATIC_CAST(nsXULPrototypeElement*, node);
00858 
00859         rv = mPrototype->SetRootElement(element);
00860         NS_ASSERTION(NS_SUCCEEDED(rv), "unable to set document root");
00861         if (NS_FAILED(rv)) return rv;
00862 
00863         mState = eInEpilog;
00864     }
00865 
00866     return NS_OK;
00867 }
00868 
00869 NS_IMETHODIMP 
00870 XULContentSinkImpl::HandleComment(const PRUnichar *aName)
00871 {
00872    FlushText();
00873    return NS_OK;
00874 }
00875 
00876 NS_IMETHODIMP 
00877 XULContentSinkImpl::HandleCDataSection(const PRUnichar *aData, PRUint32 aLength)
00878 {
00879     FlushText();
00880     return AddText(aData, aLength);
00881 }
00882 
00883 NS_IMETHODIMP 
00884 XULContentSinkImpl::HandleDoctypeDecl(const nsAString & aSubset, 
00885                                       const nsAString & aName, 
00886                                       const nsAString & aSystemId, 
00887                                       const nsAString & aPublicId,
00888                                       nsISupports* aCatalogData)
00889 {
00890     return NS_OK;
00891 }
00892 
00893 NS_IMETHODIMP 
00894 XULContentSinkImpl::HandleCharacterData(const PRUnichar *aData, 
00895                                         PRUint32 aLength)
00896 {
00897   if (aData && mState != eInProlog && mState != eInEpilog) {
00898     return AddText(aData, aLength);
00899   }
00900   return NS_OK;
00901 }
00902 
00903 NS_IMETHODIMP 
00904 XULContentSinkImpl::HandleProcessingInstruction(const PRUnichar *aTarget, 
00905                                                 const PRUnichar *aData)
00906 {
00907     FlushText();
00908 
00909     // XXX For now, we don't add the PI to the content model.
00910     // We just check for a style sheet PI
00911     const nsDependentString target(aTarget);
00912     const nsDependentString data(aData);
00913 
00914     nsReadingIterator<PRUnichar> targetStart, targetEnd, tmp;
00915 
00916     target.BeginReading(targetStart);
00917     target.EndReading(targetEnd);
00918 
00919     tmp = targetStart;
00920 
00921     nsresult rv;
00922     if (FindInReadable(NS_LITERAL_STRING("xul-overlay"), targetStart, targetEnd)) {
00923       // Load a XUL overlay.
00924       nsAutoString href;
00925       nsParserUtils::GetQuotedAttributeValue(data, nsHTMLAtoms::href, href);
00926 
00927       // If there was no href, we can't do
00928       // anything with this PI
00929       if (href.IsEmpty()) {
00930         return NS_OK;
00931       }
00932 
00933       // Add the overlay to our list of overlays that need to be processed.
00934       nsCOMPtr<nsIURI> url;
00935       rv = NS_NewURI(getter_AddRefs(url), href, nsnull, mDocumentURL);
00936       if (NS_FAILED(rv)) {
00937         // XXX This is wrong, the error message could be out of memory
00938         //     or something else equally bad, which we should propagate. 
00939         //     Bad URL should probably be "success with info" value.
00940         return NS_OK; // The URL is bad, move along. Don't propagate for now.
00941       }
00942 
00943       return mPrototype->AddOverlayReference(url);
00944     }
00945 
00946     targetStart = tmp;
00947     if (!FindInReadable(NS_LITERAL_STRING("xml-stylesheet"), targetStart,
00948                         targetEnd)) {
00949         return NS_OK;
00950     }
00951 
00952     // It's a stylesheet PI...
00953     nsAutoString type;
00954     nsParserUtils::GetQuotedAttributeValue(data, nsHTMLAtoms::type, type);
00955 
00956     nsAutoString href, title, media;
00957     PRBool isAlternate = PR_FALSE;
00958     nsXMLContentSink::ParsePIData(data, href, title, media, isAlternate);
00959 
00960     // If there was no href, we can't do anything with this PI
00961     if (href.IsEmpty()) {
00962         return NS_OK;
00963     }
00964 
00965     // XXX need a node here
00966     rv = ProcessStyleLink(nsnull , href, isAlternate, title, type, media);
00967     if (rv == NS_ERROR_HTMLPARSER_BLOCK && mParser) {
00968         mParser->BlockParser();
00969     }
00970 
00971     return rv;
00972 }
00973 
00974 
00975 NS_IMETHODIMP
00976 XULContentSinkImpl::HandleXMLDeclaration(const PRUnichar *aVersion,
00977                                          const PRUnichar *aEncoding,
00978                                          PRInt32 aStandalone)
00979 {
00980   return NS_OK;
00981 }
00982 
00983 
00984 NS_IMETHODIMP
00985 XULContentSinkImpl::ReportError(const PRUnichar* aErrorText, 
00986                                 const PRUnichar* aSourceText)
00987 {
00988   nsresult rv = NS_OK;
00989 
00990   // make sure to empty the context stack so that
00991   // <parsererror> could become the root element.
00992   while (mContextStack.Depth()) {
00993     nsVoidArray* children;
00994     rv = mContextStack.GetTopChildren(&children);
00995     if (NS_SUCCEEDED(rv)) {
00996       for (PRInt32 i = children->Count() - 1; i >= 0; --i) {
00997         nsXULPrototypeNode* child =
00998             NS_REINTERPRET_CAST(nsXULPrototypeNode*, children->ElementAt(i));
00999 
01000         delete child;
01001       }
01002     }
01003 
01004     State state;
01005     mContextStack.Pop(&state);
01006   }
01007 
01008   mState = eInProlog;
01009 
01010   // Clear any buffered-up text we have.  It's enough to set the length to 0.
01011   // The buffer itself is allocated when we're created and deleted in our
01012   // destructor, so don't mess with it.
01013   mTextLength = 0;
01014 
01015   const PRUnichar* noAtts[] = { 0, 0 };
01016 
01017   NS_NAMED_LITERAL_STRING(errorNs,
01018                           "http://www.mozilla.org/newlayout/xml/parsererror.xml");
01019 
01020   nsAutoString parsererror(errorNs);
01021   parsererror.Append((PRUnichar)0xFFFF);
01022   parsererror.AppendLiteral("parsererror");
01023   
01024   rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, 0);
01025   NS_ENSURE_SUCCESS(rv,rv);
01026 
01027   rv = HandleCharacterData(aErrorText, nsCRT::strlen(aErrorText));
01028   NS_ENSURE_SUCCESS(rv,rv);  
01029   
01030   nsAutoString sourcetext(errorNs);
01031   sourcetext.Append((PRUnichar)0xFFFF);
01032   sourcetext.AppendLiteral("sourcetext");
01033 
01034   rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, 0);
01035   NS_ENSURE_SUCCESS(rv,rv);
01036   
01037   rv = HandleCharacterData(aSourceText, nsCRT::strlen(aSourceText));
01038   NS_ENSURE_SUCCESS(rv,rv);
01039   
01040   rv = HandleEndElement(sourcetext.get());
01041   NS_ENSURE_SUCCESS(rv,rv); 
01042   
01043   rv = HandleEndElement(parsererror.get());
01044   NS_ENSURE_SUCCESS(rv,rv);
01045 
01046   return rv;
01047 }
01048 
01049 
01050 nsresult
01051 XULContentSinkImpl::OpenRoot(const PRUnichar** aAttributes, 
01052                              const PRUint32 aAttrLen, 
01053                              nsINodeInfo *aNodeInfo)
01054 {
01055     NS_ASSERTION(mState == eInProlog, "how'd we get here?");
01056     if (mState != eInProlog)
01057         return NS_ERROR_UNEXPECTED;
01058 
01059     nsresult rv;
01060 
01061     if (aNodeInfo->Equals(nsHTMLAtoms::script, kNameSpaceID_XHTML) || 
01062         aNodeInfo->Equals(nsHTMLAtoms::script, kNameSpaceID_XUL)) {
01063         PR_LOG(gLog, PR_LOG_ERROR,
01064                ("xul: script tag not allowed as root content element"));
01065 
01066         return NS_ERROR_UNEXPECTED;
01067     }
01068 
01069     // Create the element
01070     nsXULPrototypeElement* element;
01071     rv = CreateElement(aNodeInfo, &element);
01072 
01073     if (NS_FAILED(rv)) {
01074 #ifdef PR_LOGGING
01075         if (PR_LOG_TEST(gLog, PR_LOG_ERROR)) {
01076             nsAutoString anodeC;
01077             aNodeInfo->GetName(anodeC);
01078             PR_LOG(gLog, PR_LOG_ERROR,
01079                    ("xul: unable to create element '%s' at line %d",
01080                     NS_ConvertUCS2toUTF8(anodeC).get(),
01081                     -1)); // XXX pass in line number
01082         }
01083 #endif
01084 
01085         return rv;
01086     }
01087 
01088     // Push the element onto the context stack, so that child
01089     // containers will hook up to us as their parent.
01090     rv = mContextStack.Push(element, mState);
01091     if (NS_FAILED(rv)) {
01092         delete element;
01093         return rv;
01094     }
01095 
01096     // Add the attributes
01097     rv = AddAttributes(aAttributes, aAttrLen, element);
01098     if (NS_FAILED(rv)) return rv;
01099 
01100     mState = eInDocumentElement;
01101     return NS_OK;
01102 }
01103 
01104 nsresult
01105 XULContentSinkImpl::OpenTag(const PRUnichar** aAttributes, 
01106                             const PRUint32 aAttrLen,
01107                             const PRUint32 aLineNumber,
01108                             nsINodeInfo *aNodeInfo)
01109 {
01110     nsresult rv;
01111 
01112     // Create the element
01113     nsXULPrototypeElement* element;
01114     rv = CreateElement(aNodeInfo, &element);
01115 
01116     if (NS_FAILED(rv)) {
01117 #ifdef PR_LOGGING
01118         if (PR_LOG_TEST(gLog, PR_LOG_ERROR)) {
01119             nsAutoString anodeC;
01120             aNodeInfo->GetName(anodeC);
01121             PR_LOG(gLog, PR_LOG_ERROR,
01122                    ("xul: unable to create element '%s' at line %d",
01123                     NS_ConvertUCS2toUTF8(anodeC).get(),
01124                     aLineNumber));
01125         }
01126 #endif
01127 
01128         return rv;
01129     }
01130 
01131     // Link this element to its parent.
01132     nsVoidArray* children;
01133     rv = mContextStack.GetTopChildren(&children);
01134     if (NS_FAILED(rv)) {
01135         delete element;
01136         return rv;
01137     }
01138 
01139     // Add the attributes
01140     rv = AddAttributes(aAttributes, aAttrLen, element);
01141     if (NS_FAILED(rv)) return rv;
01142 
01143     children->AppendElement(element);
01144 
01145     if (aNodeInfo->Equals(nsHTMLAtoms::script, kNameSpaceID_XHTML) || 
01146         aNodeInfo->Equals(nsHTMLAtoms::script, kNameSpaceID_XUL)) {
01147         // Do scripty things now.  OpenScript will push the
01148         // nsPrototypeScriptElement onto the stack, so we're done after this.
01149         return OpenScript(aAttributes, aLineNumber);
01150     }
01151 
01152     // Push the element onto the context stack, so that child
01153     // containers will hook up to us as their parent.
01154     rv = mContextStack.Push(element, mState);
01155     if (NS_FAILED(rv)) return rv;
01156 
01157     mState = eInDocumentElement;
01158     return NS_OK;
01159 }
01160 
01161 nsresult
01162 XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes,
01163                                const PRUint32 aLineNumber)
01164 {
01165   nsresult rv = NS_OK;
01166   PRBool isJavaScript = PR_TRUE;
01167   PRBool hasE4XOption = PR_TRUE;
01168   const char* jsVersionString = nsnull;
01169 
01170   // Look for SRC attribute and look for a LANGUAGE attribute
01171   nsAutoString src;
01172   while (*aAttributes) {
01173       const nsDependentString key(aAttributes[0]);
01174       if (key.EqualsLiteral("src")) {
01175           src.Assign(aAttributes[1]);
01176       }
01177       else if (key.EqualsLiteral("type")) {
01178           nsCOMPtr<nsIMIMEHeaderParam> mimeHdrParser =
01179               do_GetService("@mozilla.org/network/mime-hdrparam;1");
01180           NS_ENSURE_TRUE(mimeHdrParser, NS_ERROR_FAILURE);
01181 
01182           NS_ConvertUTF16toUTF8 typeAndParams(aAttributes[1]);
01183 
01184           nsAutoString mimeType;
01185           rv = mimeHdrParser->GetParameter(typeAndParams, nsnull,
01186                                            EmptyCString(), PR_FALSE, nsnull,
01187                                            mimeType);
01188           NS_ENSURE_SUCCESS(rv, rv);
01189 
01190           // Table ordered from most to least likely JS MIME types. For .xul
01191           // files that we host, the likeliest type is application/x-javascript.
01192           // See bug 62485, feel free to add <script type="..."> survey data to it,
01193           // or to a new bug once 62485 is closed.
01194           static const char *jsTypes[] = {
01195               "application/x-javascript",
01196               "text/javascript",
01197               "text/ecmascript",
01198               "application/javascript",
01199               "application/ecmascript",
01200               nsnull
01201           };
01202 
01203           isJavaScript = PR_FALSE;
01204           for (PRInt32 i = 0; jsTypes[i]; i++) {
01205               if (mimeType.LowerCaseEqualsASCII(jsTypes[i])) {
01206                   isJavaScript = PR_TRUE;
01207                   break;
01208               }
01209           }
01210 
01211           if (isJavaScript) {
01212               JSVersion jsVersion = JSVERSION_DEFAULT;
01213               nsAutoString value;
01214               rv = mimeHdrParser->GetParameter(typeAndParams, "version",
01215                                                EmptyCString(), PR_FALSE, nsnull,
01216                                                value);
01217               if (NS_FAILED(rv)) {
01218                   if (rv != NS_ERROR_INVALID_ARG)
01219                       return rv;
01220               } else {
01221                   if (value.Length() != 3 || value[0] != '1' || value[1] != '.')
01222                       jsVersion = JSVERSION_UNKNOWN;
01223                   else switch (value[2]) {
01224                       case '0': jsVersion = JSVERSION_1_0; break;
01225                       case '1': jsVersion = JSVERSION_1_1; break;
01226                       case '2': jsVersion = JSVERSION_1_2; break;
01227                       case '3': jsVersion = JSVERSION_1_3; break;
01228                       case '4': jsVersion = JSVERSION_1_4; break;
01229                       case '5': jsVersion = JSVERSION_1_5; break;
01230                       case '6': jsVersion = JSVERSION_1_6; break;
01231                       case '7': jsVersion = JSVERSION_1_7; break;
01232                       default:  jsVersion = JSVERSION_UNKNOWN;
01233                   }
01234               }
01235               jsVersionString = ::JS_VersionToString(jsVersion);
01236 
01237               rv = mimeHdrParser->GetParameter(typeAndParams, "e4x",
01238                                                EmptyCString(), PR_FALSE, nsnull,
01239                                                value);
01240               if (NS_FAILED(rv)) {
01241                   if (rv != NS_ERROR_INVALID_ARG)
01242                       return rv;
01243               } else {
01244                   if (value.Length() == 1 && value[0] == '0')
01245                       hasE4XOption = PR_FALSE;
01246               }
01247           }
01248       }
01249       else if (key.EqualsLiteral("language")) {
01250           nsAutoString lang(aAttributes[1]);
01251           isJavaScript =
01252               nsParserUtils::IsJavaScriptLanguage(lang, &jsVersionString);
01253       }
01254       aAttributes += 2;
01255   }
01256 
01257   // Don't process scripts that aren't JavaScript
01258   if (isJavaScript) {
01259       nsXULPrototypeScript* script =
01260           new nsXULPrototypeScript(aLineNumber, jsVersionString, hasE4XOption,
01261                                    &rv);
01262       if (! script)
01263           return NS_ERROR_OUT_OF_MEMORY;
01264       if (NS_FAILED(rv)) {
01265           delete script;
01266           return rv;
01267       }      
01268 
01269       // If there is a SRC attribute...
01270       if (! src.IsEmpty()) {
01271           // Use the SRC attribute value to load the URL
01272           rv = NS_NewURI(getter_AddRefs(script->mSrcURI), src, nsnull, mDocumentURL);
01273 
01274           // Check if this document is allowed to load a script from this source
01275           // NOTE: if we ever allow scripts added via the DOM to run, we need to
01276           // add a CheckLoadURI call for that as well.
01277           if (NS_SUCCEEDED(rv)) {
01278               if (!mSecMan)
01279                   mSecMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
01280               if (NS_SUCCEEDED(rv)) {
01281                   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument, &rv);
01282 
01283                   if (NS_SUCCEEDED(rv)) {
01284                       rv = mSecMan->
01285                           CheckLoadURIWithPrincipal(doc->GetPrincipal(),
01286                                                     script->mSrcURI,
01287                                                     nsIScriptSecurityManager::ALLOW_CHROME);
01288                   }
01289               }
01290           }
01291 
01292           if (NS_FAILED(rv)) {
01293               delete script;
01294               return rv;
01295           }
01296 
01297           // Attempt to deserialize an out-of-line script from the FastLoad
01298           // file right away.  Otherwise we'll end up reloading the script and
01299           // corrupting the FastLoad file trying to serialize it, in the case
01300           // where it's already there.
01301           nsCOMPtr<nsIDocument> doc(do_QueryReferent(mDocument));
01302           if (doc) {
01303               nsIScriptGlobalObject* globalObject = doc->GetScriptGlobalObject();
01304               if (globalObject) {
01305                   nsIScriptContext *scriptContext = globalObject->GetContext();
01306                   if (scriptContext)
01307                       script->DeserializeOutOfLine(nsnull, scriptContext);
01308               }
01309           }
01310       }
01311 
01312       nsVoidArray* children;
01313       rv = mContextStack.GetTopChildren(&children);
01314       if (NS_FAILED(rv)) {
01315           delete script;
01316           return rv;
01317       }
01318 
01319       children->AppendElement(script);
01320 
01321       mConstrainSize = PR_FALSE;
01322 
01323       mContextStack.Push(script, mState);
01324       mState = eInScript;
01325   }
01326 
01327   return NS_OK;
01328 }
01329 
01330 nsresult
01331 XULContentSinkImpl::AddAttributes(const PRUnichar** aAttributes, 
01332                                   const PRUint32 aAttrLen, 
01333                                   nsXULPrototypeElement* aElement)
01334 {
01335   // Add tag attributes to the element
01336   nsresult rv;
01337 
01338   // Create storage for the attributes
01339   nsXULPrototypeAttribute* attrs = nsnull;
01340   if (aAttrLen > 0) {
01341     attrs = new nsXULPrototypeAttribute[aAttrLen];
01342     if (! attrs)
01343       return NS_ERROR_OUT_OF_MEMORY;
01344   }
01345 
01346   aElement->mAttributes    = attrs;
01347   aElement->mNumAttributes = aAttrLen;
01348 
01349   // Copy the attributes into the prototype
01350   PRUint32 i;
01351   for (i = 0; i < aAttrLen; ++i) {
01352       rv = NormalizeAttributeString(aAttributes[i * 2], attrs[i].mName);
01353       NS_ENSURE_SUCCESS(rv, rv);
01354 
01355       rv = aElement->SetAttrAt(i, nsDependentString(aAttributes[i * 2 + 1]),
01356                                mDocumentURL);
01357       NS_ENSURE_SUCCESS(rv, rv);
01358 
01359 #ifdef PR_LOGGING
01360       if (PR_LOG_TEST(gLog, PR_LOG_DEBUG)) {
01361           nsAutoString extraWhiteSpace;
01362           PRInt32 cnt = mContextStack.Depth();
01363           while (--cnt >= 0)
01364               extraWhiteSpace.AppendLiteral("  ");
01365           nsAutoString qnameC,valueC;
01366           qnameC.Assign(aAttributes[0]);
01367           valueC.Assign(aAttributes[1]);
01368           PR_LOG(gLog, PR_LOG_DEBUG,
01369                  ("xul: %.5d. %s    %s=%s",
01370                   -1, // XXX pass in line number
01371                   NS_ConvertUCS2toUTF8(extraWhiteSpace).get(),
01372                   NS_ConvertUCS2toUTF8(qnameC).get(),
01373                   NS_ConvertUCS2toUTF8(valueC).get()));
01374       }
01375 #endif
01376   }
01377 
01378   return NS_OK;
01379 }
01380 
01381 nsresult
01382 XULContentSinkImpl::AddText(const PRUnichar* aText, 
01383                             PRInt32 aLength)
01384 {
01385   // Create buffer when we first need it
01386   if (0 == mTextSize) {
01387       mText = (PRUnichar *) PR_MALLOC(sizeof(PRUnichar) * 4096);
01388       if (nsnull == mText) {
01389           return NS_ERROR_OUT_OF_MEMORY;
01390       }
01391       mTextSize = 4096;
01392   }
01393 
01394   // Copy data from string into our buffer; flush buffer when it fills up
01395   PRInt32 offset = 0;
01396   while (0 != aLength) {
01397     PRInt32 amount = mTextSize - mTextLength;
01398     if (amount > aLength) {
01399         amount = aLength;
01400     }
01401     if (0 == amount) {
01402       if (mConstrainSize) {
01403         nsresult rv = FlushText();
01404         if (NS_OK != rv) {
01405             return rv;
01406         }
01407       }
01408       else {
01409         mTextSize += aLength;
01410         mText = (PRUnichar *) PR_REALLOC(mText, sizeof(PRUnichar) * mTextSize);
01411         if (nsnull == mText) {
01412             return NS_ERROR_OUT_OF_MEMORY;
01413         }
01414       }
01415     }
01416     memcpy(&mText[mTextLength],aText + offset, sizeof(PRUnichar) * amount);
01417     
01418     mTextLength += amount;
01419     offset += amount;
01420     aLength -= amount;
01421   }
01422 
01423   return NS_OK;
01424 }