Back to index

lightning-sunbird  0.9+nobinonly
nsXULPrototypeDocument.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  *   L. David Baron <dbaron@dbaron.org>
00025  *   Ben Goodger <ben@netscape.com>
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   A "prototype" document that stores shared document information
00044   for the XUL cache.
00045 
00046 */
00047 
00048 #include "nsCOMPtr.h"
00049 #include "nsAString.h"
00050 #include "nsIObjectInputStream.h"
00051 #include "nsIObjectOutputStream.h"
00052 #include "nsIPrincipal.h"
00053 #include "nsIScriptGlobalObject.h"
00054 #include "nsIScriptGlobalObjectOwner.h"
00055 #include "nsIScriptObjectPrincipal.h"
00056 #include "nsIScriptSecurityManager.h"
00057 #include "nsIServiceManager.h"
00058 #include "nsISupportsArray.h"
00059 #include "nsIURI.h"
00060 #include "nsIXULDocument.h"
00061 #include "nsIXULPrototypeDocument.h"
00062 #include "jsapi.h"
00063 #include "nsString.h"
00064 #include "nsVoidArray.h"
00065 #include "nsXULElement.h"
00066 #include "nsIConsoleService.h"
00067 #include "nsIScriptError.h"
00068 #include "nsIDOMScriptObjectFactory.h"
00069 #include "nsDOMCID.h"
00070 #include "nsArray.h"
00071 #include "nsNodeInfoManager.h"
00072 #include "nsContentUtils.h"
00073 
00074 
00075 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
00076                      NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
00077 
00078 
00079 class nsXULPDGlobalObject : public nsIScriptGlobalObject,
00080                             public nsIScriptObjectPrincipal
00081 {
00082 public:
00083     nsXULPDGlobalObject();
00084 
00085     // nsISupports interface
00086     NS_DECL_ISUPPORTS
00087 
00088     // nsIScriptGlobalObject methods
00089     virtual void SetContext(nsIScriptContext *aContext);
00090     virtual nsIScriptContext *GetContext();
00091     virtual nsresult SetNewDocument(nsIDOMDocument *aDocument,
00092                                     nsISupports *aState,
00093                                     PRBool aRemoveEventListeners,
00094                                     PRBool aClearScope);
00095     virtual void SetDocShell(nsIDocShell *aDocShell);
00096     virtual nsIDocShell *GetDocShell();
00097     virtual void SetOpenerWindow(nsIDOMWindowInternal *aOpener);
00098     virtual void SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner);
00099     virtual nsIScriptGlobalObjectOwner *GetGlobalObjectOwner();
00100     virtual nsresult HandleDOMEvent(nsPresContext* aPresContext, 
00101                                     nsEvent* aEvent, 
00102                                     nsIDOMEvent** aDOMEvent,
00103                                     PRUint32 aFlags,
00104                                     nsEventStatus* aEventStatus);
00105     virtual JSObject *GetGlobalJSObject();
00106     virtual void OnFinalize(JSObject *aObject);
00107     virtual void SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts);
00108     virtual nsresult SetNewArguments(PRUint32 aArgc, void* aArgv);
00109 
00110     // nsIScriptObjectPrincipal methods
00111     virtual nsIPrincipal* GetPrincipal();
00112     
00113 protected:
00114     virtual ~nsXULPDGlobalObject();
00115 
00116     nsCOMPtr<nsIScriptContext> mScriptContext;
00117     JSObject *mJSObject;    // XXX JS language rabies bigotry badness
00118 
00119     nsIScriptGlobalObjectOwner* mGlobalObjectOwner; // weak reference
00120 
00121     static JSClass gSharedGlobalClass;
00122 };
00123 
00124 class nsXULPrototypeDocument : public nsIXULPrototypeDocument,
00125                                public nsIScriptGlobalObjectOwner
00126 {
00127 public:
00128     static nsresult
00129     Create(nsIURI* aURI, nsXULPrototypeDocument** aResult);
00130 
00131     // nsISupports interface
00132     NS_DECL_ISUPPORTS
00133 
00134     // nsISerializable interface
00135     NS_DECL_NSISERIALIZABLE
00136 
00137     // nsIXULPrototypeDocument interface
00138     NS_IMETHOD GetURI(nsIURI** aResult);
00139     NS_IMETHOD SetURI(nsIURI* aURI);
00140 
00141     NS_IMETHOD GetRootElement(nsXULPrototypeElement** aResult);
00142     NS_IMETHOD SetRootElement(nsXULPrototypeElement* aElement);
00143 
00144     NS_IMETHOD AddStyleSheetReference(nsIURI* aStyleSheet);
00145     NS_IMETHOD GetStyleSheetReferences(nsISupportsArray** aResult);
00146 
00147     NS_IMETHOD AddOverlayReference(nsIURI* aURI);
00148     NS_IMETHOD GetOverlayReferences(nsISupportsArray** aResult);
00149 
00150     NS_IMETHOD GetHeaderData(nsIAtom* aField, nsAString& aData) const;
00151     NS_IMETHOD SetHeaderData(nsIAtom* aField, const nsAString& aData);
00152 
00153     virtual nsIPrincipal *GetDocumentPrincipal();
00154     void SetDocumentPrincipal(nsIPrincipal *aPrincipal);
00155 
00156     NS_IMETHOD AwaitLoadDone(nsIXULDocument* aDocument, PRBool* aResult);
00157     NS_IMETHOD NotifyLoadDone();
00158     
00159     virtual nsNodeInfoManager *GetNodeInfoManager();
00160 
00161     // nsIScriptGlobalObjectOwner methods
00162     virtual nsIScriptGlobalObject* GetScriptGlobalObject();
00163 
00164     NS_DEFINE_STATIC_CID_ACCESSOR(NS_XULPROTOTYPEDOCUMENT_CID);
00165 
00166 protected:
00167     nsCOMPtr<nsIURI> mURI;
00168     nsXULPrototypeElement* mRoot;
00169     nsCOMPtr<nsISupportsArray> mStyleSheetReferences;
00170     nsCOMPtr<nsISupportsArray> mOverlayReferences;
00171     nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
00172 
00173     nsCOMPtr<nsIScriptGlobalObject> mGlobalObject;
00174 
00175     PRPackedBool mLoaded;
00176     nsCOMPtr<nsICollection> mPrototypeWaiters;
00177 
00178     nsRefPtr<nsNodeInfoManager> mNodeInfoManager;
00179 
00180     nsXULPrototypeDocument();
00181     virtual ~nsXULPrototypeDocument();
00182     nsresult Init();
00183 
00184     friend NS_IMETHODIMP
00185     NS_NewXULPrototypeDocument(nsISupports* aOuter, REFNSIID aIID,
00186                                void** aResult);
00187 
00188     nsresult NewXULPDGlobalObject(nsIScriptGlobalObject** aResult);
00189 
00190     static nsIPrincipal* gSystemPrincipal;
00191     static nsIScriptGlobalObject* gSystemGlobal;
00192     static PRUint32 gRefCnt;
00193 
00194     friend class nsXULPDGlobalObject;
00195 };
00196 
00197 nsIPrincipal* nsXULPrototypeDocument::gSystemPrincipal;
00198 nsIScriptGlobalObject* nsXULPrototypeDocument::gSystemGlobal;
00199 PRUint32 nsXULPrototypeDocument::gRefCnt;
00200 
00201 
00202 void PR_CALLBACK
00203 nsXULPDGlobalObject_finalize(JSContext *cx, JSObject *obj)
00204 {
00205     nsISupports *nativeThis = (nsISupports*)JS_GetPrivate(cx, obj);
00206 
00207     nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeThis));
00208 
00209     if (sgo) {
00210         sgo->OnFinalize(obj);
00211     }
00212 
00213     // The addref was part of JSObject construction
00214     NS_RELEASE(nativeThis);
00215 }
00216 
00217 
00218 JSBool PR_CALLBACK
00219 nsXULPDGlobalObject_resolve(JSContext *cx, JSObject *obj, jsval id)
00220 {
00221     JSBool did_resolve = JS_FALSE;
00222 
00223     return JS_ResolveStandardClass(cx, obj, id, &did_resolve);
00224 }
00225 
00226 
00227 JSClass nsXULPDGlobalObject::gSharedGlobalClass = {
00228     "nsXULPrototypeScript compilation scope",
00229     JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_GLOBAL_FLAGS,
00230     JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
00231     JS_EnumerateStub, nsXULPDGlobalObject_resolve,  JS_ConvertStub,
00232     nsXULPDGlobalObject_finalize
00233 };
00234 
00235 
00236 
00237 //----------------------------------------------------------------------
00238 //
00239 // ctors, dtors, n' stuff
00240 //
00241 
00242 nsXULPrototypeDocument::nsXULPrototypeDocument()
00243     : mRoot(nsnull),
00244       mGlobalObject(nsnull),
00245       mLoaded(PR_FALSE)
00246 {
00247     ++gRefCnt;
00248 }
00249 
00250 
00251 nsresult
00252 nsXULPrototypeDocument::Init()
00253 {
00254     nsresult rv;
00255 
00256     rv = NS_NewISupportsArray(getter_AddRefs(mStyleSheetReferences));
00257     NS_ENSURE_SUCCESS(rv, rv);
00258 
00259     rv = NS_NewISupportsArray(getter_AddRefs(mOverlayReferences));
00260     NS_ENSURE_SUCCESS(rv, rv);
00261 
00262     mNodeInfoManager = new nsNodeInfoManager();
00263     NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
00264 
00265     return mNodeInfoManager->Init(nsnull);
00266 }
00267 
00268 nsXULPrototypeDocument::~nsXULPrototypeDocument()
00269 {
00270     if (mGlobalObject) {
00271         mGlobalObject->SetContext(nsnull); // remove circular reference
00272         mGlobalObject->SetGlobalObjectOwner(nsnull); // just in case
00273     }
00274     
00275     if (mRoot)
00276         mRoot->ReleaseSubtree();
00277 
00278     if (--gRefCnt == 0) {
00279         NS_IF_RELEASE(gSystemPrincipal);
00280         NS_IF_RELEASE(gSystemGlobal);
00281     }
00282 }
00283 
00284 NS_IMPL_ISUPPORTS3(nsXULPrototypeDocument,
00285                    nsIXULPrototypeDocument,
00286                    nsIScriptGlobalObjectOwner,
00287                    nsISerializable)
00288 
00289 NS_IMETHODIMP
00290 NS_NewXULPrototypeDocument(nsISupports* aOuter, REFNSIID aIID, void** aResult)
00291 {
00292     NS_PRECONDITION(aOuter == nsnull, "no aggregation");
00293     if (aOuter)
00294         return NS_ERROR_NO_AGGREGATION;
00295 
00296     nsXULPrototypeDocument* result = new nsXULPrototypeDocument();
00297     if (! result)
00298         return NS_ERROR_OUT_OF_MEMORY;
00299 
00300     nsresult rv;
00301     rv = result->Init();
00302     if (NS_FAILED(rv)) {
00303         delete result;
00304         return rv;
00305     }
00306 
00307     NS_ADDREF(result);
00308     rv = result->QueryInterface(aIID, aResult);
00309     NS_RELEASE(result);
00310 
00311     return rv;
00312 }
00313 
00314 // Helper method that shares a system global among all prototype documents
00315 // that have the system principal as their security principal.   Called by
00316 // nsXULPrototypeDocument::Read and nsXULPDGlobalObject::GetGlobalObject.
00317 // This method greatly reduces the number of nsXULPDGlobalObjects and their
00318 // nsIScriptContexts in apps that load many XUL documents via chrome: URLs.
00319 
00320 nsresult
00321 nsXULPrototypeDocument::NewXULPDGlobalObject(nsIScriptGlobalObject** aResult)
00322 {
00323     nsIPrincipal *principal = GetDocumentPrincipal();
00324     if (!principal)
00325         return NS_ERROR_FAILURE;
00326 
00327     // Now that GetDocumentPrincipal has succeeded, we can safely compare its
00328     // result to gSystemPrincipal, in order to create gSystemGlobal if the two
00329     // pointers are equal.  Thus, gSystemGlobal implies gSystemPrincipal.
00330     nsCOMPtr<nsIScriptGlobalObject> global;
00331     if (principal == gSystemPrincipal) {
00332         if (!gSystemGlobal) {
00333             gSystemGlobal = new nsXULPDGlobalObject();
00334             if (! gSystemGlobal)
00335                 return NS_ERROR_OUT_OF_MEMORY;
00336             NS_ADDREF(gSystemGlobal);
00337         }
00338         global = gSystemGlobal;
00339     } else {
00340         global = new nsXULPDGlobalObject();
00341         if (! global)
00342             return NS_ERROR_OUT_OF_MEMORY;
00343         global->SetGlobalObjectOwner(this); // does not refcount
00344     }
00345     *aResult = global;
00346     NS_ADDREF(*aResult);
00347     return NS_OK;
00348 }
00349 
00350 //----------------------------------------------------------------------
00351 //
00352 // nsISerializable methods
00353 //
00354 
00355 NS_IMETHODIMP
00356 nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
00357 {
00358     nsresult rv;
00359 
00360     rv = aStream->ReadObject(PR_TRUE, getter_AddRefs(mURI));
00361 
00362     PRUint32 referenceCount;
00363     nsCOMPtr<nsIURI> referenceURI;
00364 
00365     PRUint32 i;
00366     // nsISupportsArray mStyleSheetReferences
00367     rv |= aStream->Read32(&referenceCount);
00368     if (NS_FAILED(rv)) return rv;
00369     for (i = 0; i < referenceCount; ++i) {
00370         rv |= aStream->ReadObject(PR_TRUE, getter_AddRefs(referenceURI));
00371         
00372         mStyleSheetReferences->AppendElement(referenceURI);
00373     }
00374 
00375     // nsISupportsArray mOverlayReferences
00376     rv |= aStream->Read32(&referenceCount);
00377     for (i = 0; i < referenceCount; ++i) {
00378         rv |= aStream->ReadObject(PR_TRUE, getter_AddRefs(referenceURI));
00379         
00380         mOverlayReferences->AppendElement(referenceURI);
00381     }
00382 
00383     // nsIPrincipal mDocumentPrincipal
00384     nsCOMPtr<nsIPrincipal> principal;
00385     rv |= NS_ReadOptionalObject(aStream, PR_TRUE, getter_AddRefs(principal));
00386     if (! principal) {
00387         principal = GetDocumentPrincipal();
00388         if (!principal)
00389             rv |= NS_ERROR_FAILURE;
00390     } else {
00391         mNodeInfoManager->SetDocumentPrincipal(principal);
00392         mDocumentPrincipal = principal;
00393     }
00394 
00395     // nsIScriptGlobalObject mGlobalObject
00396     NewXULPDGlobalObject(getter_AddRefs(mGlobalObject));
00397     if (! mGlobalObject)
00398         return NS_ERROR_OUT_OF_MEMORY;
00399 
00400     mRoot = new nsXULPrototypeElement();
00401     if (! mRoot)
00402        return NS_ERROR_OUT_OF_MEMORY;
00403 
00404     nsIScriptContext *scriptContext = mGlobalObject->GetContext();
00405     NS_ASSERTION(scriptContext != nsnull,
00406                  "no prototype script context!");
00407 
00408     // nsINodeInfo table
00409     nsCOMArray<nsINodeInfo> nodeInfos;
00410 
00411     rv |= aStream->Read32(&referenceCount);
00412     nsAutoString namespaceURI, qualifiedName;
00413     for (i = 0; i < referenceCount; ++i) {
00414         rv |= aStream->ReadString(namespaceURI);
00415         rv |= aStream->ReadString(qualifiedName);
00416 
00417         nsCOMPtr<nsINodeInfo> nodeInfo;
00418         rv |= mNodeInfoManager->GetNodeInfo(qualifiedName, namespaceURI, getter_AddRefs(nodeInfo));
00419         if (!nodeInfos.AppendObject(nodeInfo))
00420             rv |= NS_ERROR_OUT_OF_MEMORY;
00421     }
00422 
00423     // Document contents
00424     PRUint32 type;
00425     rv |= aStream->Read32(&type);
00426 
00427     if ((nsXULPrototypeNode::Type)type != nsXULPrototypeNode::eType_Element)
00428         return NS_ERROR_FAILURE;
00429 
00430     rv |= mRoot->Deserialize(aStream, scriptContext, mURI, &nodeInfos);
00431     rv |= NotifyLoadDone();
00432 
00433     return rv;
00434 }
00435 
00436 static nsresult
00437 GetNodeInfos(nsXULPrototypeElement* aPrototype,
00438              nsCOMArray<nsINodeInfo>& aArray)
00439 {
00440     nsresult rv;
00441     if (aArray.IndexOf(aPrototype->mNodeInfo) < 0) {
00442         if (!aArray.AppendObject(aPrototype->mNodeInfo)) {
00443             return NS_ERROR_OUT_OF_MEMORY;
00444         }
00445     }
00446 
00447     // Search attributes
00448     PRUint32 i;
00449     for (i = 0; i < aPrototype->mNumAttributes; ++i) {
00450         nsCOMPtr<nsINodeInfo> ni;
00451         nsAttrName* name = &aPrototype->mAttributes[i].mName;
00452         if (name->IsAtom()) {
00453             rv = aPrototype->mNodeInfo->NodeInfoManager()->
00454                 GetNodeInfo(name->Atom(), nsnull, kNameSpaceID_None,
00455                             getter_AddRefs(ni));
00456             NS_ENSURE_SUCCESS(rv, rv);
00457         }
00458         else {
00459             ni = name->NodeInfo();
00460         }
00461 
00462         if (aArray.IndexOf(ni) < 0) {
00463             if (!aArray.AppendObject(ni)) {
00464                 return NS_ERROR_OUT_OF_MEMORY;
00465             }
00466         }
00467     }
00468 
00469     // Search children
00470     for (i = 0; i < aPrototype->mNumChildren; ++i) {
00471         nsXULPrototypeNode* child = aPrototype->mChildren[i];
00472         if (child->mType == nsXULPrototypeNode::eType_Element) {
00473             rv = GetNodeInfos(NS_STATIC_CAST(nsXULPrototypeElement*, child),
00474                               aArray);
00475             NS_ENSURE_SUCCESS(rv, rv);
00476         }
00477     }
00478 
00479     return NS_OK;
00480 }
00481 
00482 NS_IMETHODIMP
00483 nsXULPrototypeDocument::Write(nsIObjectOutputStream* aStream)
00484 {
00485     nsresult rv;
00486 
00487     rv = aStream->WriteCompoundObject(mURI, NS_GET_IID(nsIURI), PR_TRUE);
00488     
00489     PRUint32 referenceCount;
00490     nsCOMPtr<nsIURI> referenceURI;
00491 
00492     PRUint32 i;
00493 
00494     // nsISupportsArray mStyleSheetReferences
00495     mStyleSheetReferences->Count(&referenceCount);
00496     rv |= aStream->Write32(referenceCount);
00497     
00498     for (i = 0; i < referenceCount; ++i) {
00499         mStyleSheetReferences->QueryElementAt(i, NS_GET_IID(nsIURI), getter_AddRefs(referenceURI));
00500         
00501         rv |= aStream->WriteCompoundObject(referenceURI, NS_GET_IID(nsIURI), PR_TRUE);
00502     }
00503 
00504     // nsISupportsArray mOverlayReferences
00505     mOverlayReferences->Count(&referenceCount);
00506     rv |= aStream->Write32(referenceCount);
00507     
00508     for (i = 0; i < referenceCount; ++i) {
00509         mOverlayReferences->QueryElementAt(i, NS_GET_IID(nsIURI), getter_AddRefs(referenceURI));
00510         
00511         rv |= aStream->WriteCompoundObject(referenceURI, NS_GET_IID(nsIURI), PR_TRUE);
00512     }
00513 
00514     // nsIPrincipal mDocumentPrincipal
00515     rv |= NS_WriteOptionalObject(aStream, mDocumentPrincipal, PR_TRUE);
00516     
00517     // nsINodeInfo table
00518     nsCOMArray<nsINodeInfo> nodeInfos;
00519     if (mRoot)
00520         rv |= GetNodeInfos(mRoot, nodeInfos);
00521 
00522     PRInt32 nodeInfoCount = nodeInfos.Count();
00523     rv |= aStream->Write32(nodeInfoCount);
00524     for (PRInt32 j = 0; j < nodeInfoCount; ++j) {
00525         nsINodeInfo *nodeInfo = nodeInfos[j];
00526         NS_ENSURE_TRUE(nodeInfo, NS_ERROR_FAILURE);
00527 
00528         nsAutoString namespaceURI;
00529         rv |= nodeInfo->GetNamespaceURI(namespaceURI);
00530         rv |= aStream->WriteWStringZ(namespaceURI.get());
00531 
00532         nsAutoString qualifiedName;
00533         nodeInfo->GetQualifiedName(qualifiedName);
00534         rv |= aStream->WriteWStringZ(qualifiedName.get());
00535     }
00536 
00537     // Now serialize the document contents
00538     nsIScriptGlobalObject* globalObject = GetScriptGlobalObject();
00539     NS_ENSURE_TRUE(globalObject, NS_ERROR_UNEXPECTED);
00540 
00541     nsIScriptContext *scriptContext = globalObject->GetContext();
00542 
00543     if (mRoot)
00544         rv |= mRoot->Serialize(aStream, scriptContext, &nodeInfos);
00545  
00546     return rv;
00547 }
00548 
00549 
00550 //----------------------------------------------------------------------
00551 //
00552 // nsIXULPrototypeDocument methods
00553 //
00554 
00555 NS_IMETHODIMP
00556 nsXULPrototypeDocument::GetURI(nsIURI** aResult)
00557 {
00558     *aResult = mURI;
00559     NS_IF_ADDREF(*aResult);
00560     return NS_OK;
00561 }
00562 
00563 
00564 NS_IMETHODIMP
00565 nsXULPrototypeDocument::SetURI(nsIURI* aURI)
00566 {
00567     NS_ASSERTION(!mURI, "Can't change the uri of a xul prototype document");
00568     if (mURI)
00569         return NS_ERROR_ALREADY_INITIALIZED;
00570 
00571     mURI = aURI;
00572     if (!mDocumentPrincipal) {
00573         // If the document doesn't have a principal yet we'll force the creation of one
00574         // so that mNodeInfoManager properly gets one.
00575         GetDocumentPrincipal();
00576     }
00577     return NS_OK;
00578 }
00579 
00580 
00581 NS_IMETHODIMP
00582 nsXULPrototypeDocument::GetRootElement(nsXULPrototypeElement** aResult)
00583 {
00584     *aResult = mRoot;
00585     return NS_OK;
00586 }
00587 
00588 
00589 NS_IMETHODIMP
00590 nsXULPrototypeDocument::SetRootElement(nsXULPrototypeElement* aElement)
00591 {
00592     mRoot = aElement;
00593     return NS_OK;
00594 }
00595 
00596 
00597 NS_IMETHODIMP
00598 nsXULPrototypeDocument::AddStyleSheetReference(nsIURI* aURI)
00599 {
00600     NS_PRECONDITION(aURI != nsnull, "null ptr");
00601     if (! aURI)
00602         return NS_ERROR_NULL_POINTER;
00603 
00604     mStyleSheetReferences->AppendElement(aURI);
00605     return NS_OK;
00606 }
00607 
00608 
00609 NS_IMETHODIMP
00610 nsXULPrototypeDocument::GetStyleSheetReferences(nsISupportsArray** aResult)
00611 {
00612     *aResult = mStyleSheetReferences;
00613     NS_ADDREF(*aResult);
00614     return NS_OK;
00615 }
00616 
00617 
00618 
00619 NS_IMETHODIMP
00620 nsXULPrototypeDocument::AddOverlayReference(nsIURI* aURI)
00621 {
00622     NS_PRECONDITION(aURI != nsnull, "null ptr");
00623     if (! aURI)
00624         return NS_ERROR_NULL_POINTER;
00625 
00626     mOverlayReferences->AppendElement(aURI);
00627     return NS_OK;
00628 }
00629 
00630 
00631 NS_IMETHODIMP
00632 nsXULPrototypeDocument::GetOverlayReferences(nsISupportsArray** aResult)
00633 {
00634     *aResult = mOverlayReferences;
00635     NS_ADDREF(*aResult);
00636     return NS_OK;
00637 }
00638 
00639 
00640 NS_IMETHODIMP
00641 nsXULPrototypeDocument::GetHeaderData(nsIAtom* aField, nsAString& aData) const
00642 {
00643     // XXX Not implemented
00644     aData.Truncate();
00645     return NS_OK;
00646 }
00647 
00648 
00649 NS_IMETHODIMP
00650 nsXULPrototypeDocument::SetHeaderData(nsIAtom* aField, const nsAString& aData)
00651 {
00652     // XXX Not implemented
00653     return NS_OK;
00654 }
00655 
00656 
00657 
00658 nsIPrincipal*
00659 nsXULPrototypeDocument::GetDocumentPrincipal()
00660 {
00661     NS_PRECONDITION(mNodeInfoManager, "missing nodeInfoManager");
00662     if (!mDocumentPrincipal) {
00663         nsIScriptSecurityManager *securityManager =
00664             nsContentUtils::GetSecurityManager();
00665         nsresult rv = NS_OK;
00666 
00667         // XXX This should be handled by the security manager, see bug 160042
00668         PRBool isChrome = PR_FALSE;
00669         if (NS_SUCCEEDED(mURI->SchemeIs("chrome", &isChrome)) && isChrome) {
00670             if (gSystemPrincipal) {
00671                 mDocumentPrincipal = gSystemPrincipal;
00672             } else {
00673                 rv = securityManager->
00674                      GetSystemPrincipal(getter_AddRefs(mDocumentPrincipal));
00675                 NS_IF_ADDREF(gSystemPrincipal = mDocumentPrincipal);
00676             }
00677         } else {
00678             rv = securityManager->
00679                  GetCodebasePrincipal(mURI, getter_AddRefs(mDocumentPrincipal));
00680         }
00681 
00682         if (NS_FAILED(rv))
00683             return nsnull;
00684 
00685         mNodeInfoManager->SetDocumentPrincipal(mDocumentPrincipal);
00686     }
00687 
00688     return mDocumentPrincipal;
00689 }
00690 
00691 
00692 void
00693 nsXULPrototypeDocument::SetDocumentPrincipal(nsIPrincipal *aPrincipal)
00694 {
00695     NS_PRECONDITION(mNodeInfoManager, "missing nodeInfoManager");
00696     mDocumentPrincipal = aPrincipal;
00697     mNodeInfoManager->SetDocumentPrincipal(aPrincipal);
00698 }
00699 
00700 nsNodeInfoManager*
00701 nsXULPrototypeDocument::GetNodeInfoManager()
00702 {
00703     return mNodeInfoManager;
00704 }
00705 
00706 
00707 NS_IMETHODIMP
00708 nsXULPrototypeDocument::AwaitLoadDone(nsIXULDocument* aDocument, PRBool* aResult)
00709 {
00710     nsresult rv = NS_OK;
00711 
00712     *aResult = mLoaded;
00713 
00714     if (!mLoaded) {
00715         if (!mPrototypeWaiters) {
00716             nsCOMPtr<nsISupportsArray> supportsArray;
00717             rv = NS_NewISupportsArray(getter_AddRefs(supportsArray));
00718             if (NS_FAILED(rv)) return rv;
00719 
00720             mPrototypeWaiters = do_QueryInterface(supportsArray);
00721         }
00722 
00723         rv = mPrototypeWaiters->AppendElement(aDocument);
00724     }
00725 
00726     return rv;
00727 }
00728 
00729 
00730 NS_IMETHODIMP
00731 nsXULPrototypeDocument::NotifyLoadDone()
00732 {
00733     nsresult rv = NS_OK;
00734 
00735     mLoaded = PR_TRUE;
00736 
00737     if (mPrototypeWaiters) {
00738         PRUint32 n;
00739         rv = mPrototypeWaiters->Count(&n);
00740         if (NS_SUCCEEDED(rv)) {
00741             for (PRUint32 i = 0; i < n; i++) {
00742                 nsCOMPtr<nsIXULDocument> doc;
00743                 rv = mPrototypeWaiters->GetElementAt(i, getter_AddRefs(doc));
00744                 if (NS_FAILED(rv)) break;
00745 
00746                 rv = doc->OnPrototypeLoadDone();
00747                 if (NS_FAILED(rv)) break;
00748             }
00749         }
00750 
00751         mPrototypeWaiters = nsnull;
00752     }
00753 
00754     return rv;
00755 }
00756 
00757 //----------------------------------------------------------------------
00758 //
00759 // nsIScriptGlobalObjectOwner methods
00760 //
00761 
00762 nsIScriptGlobalObject*
00763 nsXULPrototypeDocument::GetScriptGlobalObject()
00764 {
00765     if (!mGlobalObject)
00766         NewXULPDGlobalObject(getter_AddRefs(mGlobalObject));
00767 
00768     return mGlobalObject;
00769 }
00770 
00771 //----------------------------------------------------------------------
00772 //
00773 // nsXULPDGlobalObject
00774 //
00775 
00776 nsXULPDGlobalObject::nsXULPDGlobalObject()
00777     : mJSObject(nsnull),
00778       mGlobalObjectOwner(nsnull)
00779 {
00780 }
00781 
00782 
00783 nsXULPDGlobalObject::~nsXULPDGlobalObject()
00784 {
00785 }
00786 
00787 NS_IMPL_ADDREF(nsXULPDGlobalObject)
00788 NS_IMPL_RELEASE(nsXULPDGlobalObject)
00789 
00790 NS_INTERFACE_MAP_BEGIN(nsXULPDGlobalObject)
00791     NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
00792     NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
00793     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObject)
00794 NS_INTERFACE_MAP_END
00795 
00796 //----------------------------------------------------------------------
00797 //
00798 // nsIScriptGlobalObject methods
00799 //
00800 
00801 void
00802 nsXULPDGlobalObject::SetContext(nsIScriptContext *aContext)
00803 {
00804     mScriptContext = aContext;
00805 }
00806 
00807 
00808 nsIScriptContext *
00809 nsXULPDGlobalObject::GetContext()
00810 {
00811     // This whole fragile mess is predicated on the fact that
00812     // GetContext() will be called before GetScriptObject() is.
00813     if (! mScriptContext) {
00814         nsCOMPtr<nsIDOMScriptObjectFactory> factory =
00815             do_GetService(kDOMScriptObjectFactoryCID);
00816         NS_ENSURE_TRUE(factory, nsnull);
00817 
00818         nsresult rv =
00819             factory->NewScriptContext(nsnull, getter_AddRefs(mScriptContext));
00820         if (NS_FAILED(rv))
00821             return nsnull;
00822 
00823         JSContext *cx = (JSContext *)mScriptContext->GetNativeContext();
00824 
00825         mJSObject = ::JS_NewObject(cx, &gSharedGlobalClass, nsnull, nsnull);
00826         if (!mJSObject)
00827             return nsnull;
00828 
00829         ::JS_SetGlobalObject(cx, mJSObject);
00830 
00831         // Add an owning reference from JS back to us. This'll be
00832         // released when the JSObject is finalized.
00833         ::JS_SetPrivate(cx, mJSObject, this);
00834         NS_ADDREF(this);
00835     }
00836 
00837     return mScriptContext;
00838 }
00839 
00840 
00841 nsresult
00842 nsXULPDGlobalObject::SetNewDocument(nsIDOMDocument *aDocument,
00843                                     nsISupports *aState,
00844                                     PRBool aRemoveEventListeners,
00845                                     PRBool aClearScope)
00846 {
00847     NS_NOTREACHED("waaah!");
00848     return NS_ERROR_UNEXPECTED;
00849 }
00850 
00851 
00852 void
00853 nsXULPDGlobalObject::SetDocShell(nsIDocShell *aDocShell)
00854 {
00855     NS_NOTREACHED("waaah!");
00856 }
00857 
00858 
00859 nsIDocShell *
00860 nsXULPDGlobalObject::GetDocShell()
00861 {
00862     NS_WARNING("waaah!");
00863 
00864     return nsnull;
00865 }
00866 
00867 
00868 void
00869 nsXULPDGlobalObject::SetOpenerWindow(nsIDOMWindowInternal *aOpener)
00870 {
00871     NS_NOTREACHED("waaah!");
00872 }
00873 
00874 
00875 void
00876 nsXULPDGlobalObject::SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner)
00877 {
00878     mGlobalObjectOwner = aOwner; // weak reference
00879 }
00880 
00881 
00882 nsIScriptGlobalObjectOwner *
00883 nsXULPDGlobalObject::GetGlobalObjectOwner()
00884 {
00885     return mGlobalObjectOwner;
00886 }
00887 
00888 
00889 nsresult
00890 nsXULPDGlobalObject::HandleDOMEvent(nsPresContext* aPresContext, 
00891                                        nsEvent* aEvent, 
00892                                        nsIDOMEvent** aDOMEvent,
00893                                        PRUint32 aFlags,
00894                                        nsEventStatus* aEventStatus)
00895 {
00896     NS_NOTREACHED("waaah!");
00897     return NS_ERROR_UNEXPECTED;
00898 }
00899 
00900 JSObject *
00901 nsXULPDGlobalObject::GetGlobalJSObject()
00902 {
00903     // The prototype document has its own special secret script object
00904     // that can be used to compile scripts and event handlers.
00905 
00906     if (!mScriptContext)
00907         return nsnull;
00908 
00909     JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
00910                                         mScriptContext->GetNativeContext());
00911     if (!cx)
00912         return nsnull;
00913 
00914     return ::JS_GetGlobalObject(cx);
00915 }
00916 
00917 void
00918 nsXULPDGlobalObject::OnFinalize(JSObject *aObject)
00919 {
00920     NS_ASSERTION(aObject == mJSObject, "Wrong object finalized!");
00921 
00922     mJSObject = nsnull;
00923 }
00924 
00925 void
00926 nsXULPDGlobalObject::SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts)
00927 {
00928     // We don't care...
00929 }
00930 
00931 nsresult
00932 nsXULPDGlobalObject::SetNewArguments(PRUint32 aArgc, void* aArgv)
00933 {
00934     NS_NOTREACHED("waaah!");
00935     return NS_ERROR_UNEXPECTED;
00936 }
00937 
00938 //----------------------------------------------------------------------
00939 //
00940 // nsIScriptObjectPrincipal methods
00941 //
00942 
00943 nsIPrincipal*
00944 nsXULPDGlobalObject::GetPrincipal()
00945 {
00946     if (!mGlobalObjectOwner) {
00947         // See nsXULPrototypeDocument::NewXULPDGlobalObject, the comment
00948         // about gSystemGlobal implying gSystemPrincipal.
00949         if (this == nsXULPrototypeDocument::gSystemGlobal) {
00950             return nsXULPrototypeDocument::gSystemPrincipal;
00951         }
00952         return nsnull;
00953     }
00954     nsCOMPtr<nsIXULPrototypeDocument> protoDoc
00955       = do_QueryInterface(mGlobalObjectOwner);
00956 
00957     return protoDoc->GetDocumentPrincipal();
00958 }
00959