Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / content / xul / document / src / nsXULPrototypeDocument.cpp
bloba4375438e34df9402373eadd4e5f712b01073122
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Chris Waterson <waterson@netscape.com>
24 * L. David Baron <dbaron@dbaron.org>
25 * Ben Goodger <ben@netscape.com>
26 * Mark Hammond <mhammond@skippinet.com.au>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
43 #include "nsXULPrototypeDocument.h"
44 #include "nsXULDocument.h"
46 #include "nsAString.h"
47 #include "nsIObjectInputStream.h"
48 #include "nsIObjectOutputStream.h"
49 #include "nsIPrincipal.h"
50 #include "nsIScriptGlobalObject.h"
51 #include "nsIScriptObjectPrincipal.h"
52 #include "nsIScriptSecurityManager.h"
53 #include "nsIScriptRuntime.h"
54 #include "nsIServiceManager.h"
55 #include "nsIArray.h"
56 #include "nsIURI.h"
57 #include "jsapi.h"
58 #include "nsString.h"
59 #include "nsIConsoleService.h"
60 #include "nsIScriptError.h"
61 #include "nsIDOMScriptObjectFactory.h"
62 #include "nsDOMCID.h"
63 #include "nsNodeInfoManager.h"
64 #include "nsContentUtils.h"
65 #include "nsCCUncollectableMarker.h"
66 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
68 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
69 NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
72 class nsXULPDGlobalObject : public nsIScriptGlobalObject,
73 public nsIScriptObjectPrincipal
75 public:
76 nsXULPDGlobalObject(nsXULPrototypeDocument* owner);
78 // nsISupports interface
79 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
81 // nsIScriptGlobalObject methods
82 virtual void OnFinalize(PRUint32 aLangID, void *aGlobal);
83 virtual void SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts);
84 virtual nsresult SetNewArguments(nsIArray *aArguments);
86 virtual void *GetScriptGlobal(PRUint32 lang);
87 virtual nsresult EnsureScriptEnvironment(PRUint32 aLangID);
89 virtual nsIScriptContext *GetScriptContext(PRUint32 lang);
90 virtual nsresult SetScriptContext(PRUint32 language, nsIScriptContext *ctx);
92 // nsIScriptObjectPrincipal methods
93 virtual nsIPrincipal* GetPrincipal();
95 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULPDGlobalObject,
96 nsIScriptGlobalObject)
98 void ClearGlobalObjectOwner();
100 protected:
101 virtual ~nsXULPDGlobalObject();
103 nsXULPrototypeDocument* mGlobalObjectOwner; // weak reference
105 nsCOMPtr<nsIScriptContext> mScriptContexts[NS_STID_ARRAY_UBOUND];
106 void * mScriptGlobals[NS_STID_ARRAY_UBOUND];
108 nsCOMPtr<nsIPrincipal> mCachedPrincipal;
110 static JSClass gSharedGlobalClass;
113 nsIPrincipal* nsXULPrototypeDocument::gSystemPrincipal;
114 nsXULPDGlobalObject* nsXULPrototypeDocument::gSystemGlobal;
115 PRUint32 nsXULPrototypeDocument::gRefCnt;
118 void
119 nsXULPDGlobalObject_finalize(JSContext *cx, JSObject *obj)
121 nsISupports *nativeThis = (nsISupports*)JS_GetPrivate(cx, obj);
123 nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeThis));
125 if (sgo) {
126 sgo->OnFinalize(nsIProgrammingLanguage::JAVASCRIPT, obj);
129 // The addref was part of JSObject construction
130 NS_RELEASE(nativeThis);
134 JSBool
135 nsXULPDGlobalObject_resolve(JSContext *cx, JSObject *obj, jsval id)
137 JSBool did_resolve = JS_FALSE;
139 return JS_ResolveStandardClass(cx, obj, id, &did_resolve);
143 JSClass nsXULPDGlobalObject::gSharedGlobalClass = {
144 "nsXULPrototypeScript compilation scope",
145 JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_GLOBAL_FLAGS,
146 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
147 JS_EnumerateStub, nsXULPDGlobalObject_resolve, JS_ConvertStub,
148 nsXULPDGlobalObject_finalize
153 //----------------------------------------------------------------------
155 // ctors, dtors, n' stuff
158 nsXULPrototypeDocument::nsXULPrototypeDocument()
159 : mRoot(nsnull),
160 mLoaded(PR_FALSE)
162 ++gRefCnt;
166 nsresult
167 nsXULPrototypeDocument::Init()
169 mNodeInfoManager = new nsNodeInfoManager();
170 NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
172 return mNodeInfoManager->Init(nsnull);
175 nsXULPrototypeDocument::~nsXULPrototypeDocument()
177 if (mGlobalObject) {
178 // cleaup cycles etc.
179 mGlobalObject->ClearGlobalObjectOwner();
182 if (mRoot)
183 mRoot->ReleaseSubtree();
185 if (--gRefCnt == 0) {
186 NS_IF_RELEASE(gSystemPrincipal);
187 NS_IF_RELEASE(gSystemGlobal);
191 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeDocument)
192 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsXULPrototypeDocument)
193 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeDocument)
194 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mRoot,
195 nsXULPrototypeElement)
196 cb.NoteXPCOMChild(static_cast<nsIScriptGlobalObject*>(tmp->mGlobalObject));
197 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNodeInfoManager,
198 nsNodeInfoManager)
199 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
201 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPrototypeDocument)
202 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner)
203 NS_INTERFACE_MAP_ENTRY(nsISerializable)
204 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObjectOwner)
205 NS_INTERFACE_MAP_END
207 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsXULPrototypeDocument,
208 nsIScriptGlobalObjectOwner)
209 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsXULPrototypeDocument,
210 nsIScriptGlobalObjectOwner)
212 NS_IMETHODIMP
213 NS_NewXULPrototypeDocument(nsXULPrototypeDocument** aResult)
215 *aResult = new nsXULPrototypeDocument();
216 if (! *aResult)
217 return NS_ERROR_OUT_OF_MEMORY;
219 nsresult rv;
220 rv = (*aResult)->Init();
221 if (NS_FAILED(rv)) {
222 delete *aResult;
223 *aResult = nsnull;
224 return rv;
227 NS_ADDREF(*aResult);
228 return rv;
231 // Helper method that shares a system global among all prototype documents
232 // that have the system principal as their security principal. Called by
233 // nsXULPrototypeDocument::Read and nsXULPDGlobalObject::GetGlobalObject.
234 // This method greatly reduces the number of nsXULPDGlobalObjects and their
235 // nsIScriptContexts in apps that load many XUL documents via chrome: URLs.
237 nsXULPDGlobalObject *
238 nsXULPrototypeDocument::NewXULPDGlobalObject()
240 // Now compare DocumentPrincipal() to gSystemPrincipal, in order to create
241 // gSystemGlobal if the two pointers are equal. Thus, gSystemGlobal
242 // implies gSystemPrincipal.
243 nsXULPDGlobalObject *global;
244 if (DocumentPrincipal() == gSystemPrincipal) {
245 if (!gSystemGlobal) {
246 gSystemGlobal = new nsXULPDGlobalObject(nsnull);
247 if (! gSystemGlobal)
248 return nsnull;
249 NS_ADDREF(gSystemGlobal);
251 global = gSystemGlobal;
252 } else {
253 global = new nsXULPDGlobalObject(this); // does not refcount
254 if (! global)
255 return nsnull;
257 return global;
260 //----------------------------------------------------------------------
262 // nsISerializable methods
265 NS_IMETHODIMP
266 nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
268 nsresult rv;
270 rv = aStream->ReadObject(PR_TRUE, getter_AddRefs(mURI));
272 PRUint32 count, i;
273 nsCOMPtr<nsIURI> styleOverlayURI;
275 rv |= aStream->Read32(&count);
276 if (NS_FAILED(rv)) return rv;
278 for (i = 0; i < count; ++i) {
279 rv |= aStream->ReadObject(PR_TRUE, getter_AddRefs(styleOverlayURI));
280 mStyleSheetReferences.AppendObject(styleOverlayURI);
284 // nsIPrincipal mNodeInfoManager->mPrincipal
285 nsCOMPtr<nsIPrincipal> principal;
286 rv |= aStream->ReadObject(PR_TRUE, getter_AddRefs(principal));
287 // Better safe than sorry....
288 mNodeInfoManager->SetDocumentPrincipal(principal);
291 // nsIScriptGlobalObject mGlobalObject
292 mGlobalObject = NewXULPDGlobalObject();
293 if (! mGlobalObject)
294 return NS_ERROR_OUT_OF_MEMORY;
296 mRoot = new nsXULPrototypeElement();
297 if (! mRoot)
298 return NS_ERROR_OUT_OF_MEMORY;
300 // nsINodeInfo table
301 nsCOMArray<nsINodeInfo> nodeInfos;
303 rv |= aStream->Read32(&count);
304 nsAutoString namespaceURI, prefixStr, localName;
305 PRBool prefixIsNull;
306 nsCOMPtr<nsIAtom> prefix;
307 for (i = 0; i < count; ++i) {
308 rv |= aStream->ReadString(namespaceURI);
309 rv |= aStream->ReadBoolean(&prefixIsNull);
310 if (prefixIsNull) {
311 prefix = nsnull;
312 } else {
313 rv |= aStream->ReadString(prefixStr);
314 prefix = do_GetAtom(prefixStr);
316 rv |= aStream->ReadString(localName);
318 nsCOMPtr<nsINodeInfo> nodeInfo;
319 rv |= mNodeInfoManager->GetNodeInfo(localName, prefix, namespaceURI,
320 getter_AddRefs(nodeInfo));
321 if (!nodeInfos.AppendObject(nodeInfo))
322 rv |= NS_ERROR_OUT_OF_MEMORY;
325 // Document contents
326 PRUint32 type;
327 while (NS_SUCCEEDED(rv)) {
328 rv |= aStream->Read32(&type);
330 if ((nsXULPrototypeNode::Type)type == nsXULPrototypeNode::eType_PI) {
331 nsRefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI();
332 if (! pi) {
333 rv |= NS_ERROR_OUT_OF_MEMORY;
334 break;
337 rv |= pi->Deserialize(aStream, mGlobalObject, mURI, &nodeInfos);
338 rv |= AddProcessingInstruction(pi);
339 } else if ((nsXULPrototypeNode::Type)type == nsXULPrototypeNode::eType_Element) {
340 rv |= mRoot->Deserialize(aStream, mGlobalObject, mURI, &nodeInfos);
341 break;
342 } else {
343 NS_NOTREACHED("Unexpected prototype node type");
344 rv |= NS_ERROR_FAILURE;
345 break;
348 rv |= NotifyLoadDone();
350 return rv;
353 static nsresult
354 GetNodeInfos(nsXULPrototypeElement* aPrototype,
355 nsCOMArray<nsINodeInfo>& aArray)
357 nsresult rv;
358 if (aArray.IndexOf(aPrototype->mNodeInfo) < 0) {
359 if (!aArray.AppendObject(aPrototype->mNodeInfo)) {
360 return NS_ERROR_OUT_OF_MEMORY;
364 // Search attributes
365 PRUint32 i;
366 for (i = 0; i < aPrototype->mNumAttributes; ++i) {
367 nsCOMPtr<nsINodeInfo> ni;
368 nsAttrName* name = &aPrototype->mAttributes[i].mName;
369 if (name->IsAtom()) {
370 ni = aPrototype->mNodeInfo->NodeInfoManager()->
371 GetNodeInfo(name->Atom(), nsnull, kNameSpaceID_None);
372 NS_ENSURE_TRUE(ni, NS_ERROR_OUT_OF_MEMORY);
374 else {
375 ni = name->NodeInfo();
378 if (aArray.IndexOf(ni) < 0) {
379 if (!aArray.AppendObject(ni)) {
380 return NS_ERROR_OUT_OF_MEMORY;
385 // Search children
386 for (i = 0; i < aPrototype->mChildren.Length(); ++i) {
387 nsXULPrototypeNode* child = aPrototype->mChildren[i];
388 if (child->mType == nsXULPrototypeNode::eType_Element) {
389 rv = GetNodeInfos(static_cast<nsXULPrototypeElement*>(child),
390 aArray);
391 NS_ENSURE_SUCCESS(rv, rv);
395 return NS_OK;
398 NS_IMETHODIMP
399 nsXULPrototypeDocument::Write(nsIObjectOutputStream* aStream)
401 nsresult rv;
403 rv = aStream->WriteCompoundObject(mURI, NS_GET_IID(nsIURI), PR_TRUE);
405 PRUint32 count;
407 count = mStyleSheetReferences.Count();
408 rv |= aStream->Write32(count);
410 PRUint32 i;
411 for (i = 0; i < count; ++i) {
412 rv |= aStream->WriteCompoundObject(mStyleSheetReferences[i],
413 NS_GET_IID(nsIURI), PR_TRUE);
416 // nsIPrincipal mNodeInfoManager->mPrincipal
417 rv |= aStream->WriteObject(mNodeInfoManager->DocumentPrincipal(),
418 PR_TRUE);
420 // nsINodeInfo table
421 nsCOMArray<nsINodeInfo> nodeInfos;
422 if (mRoot)
423 rv |= GetNodeInfos(mRoot, nodeInfos);
425 PRUint32 nodeInfoCount = nodeInfos.Count();
426 rv |= aStream->Write32(nodeInfoCount);
427 for (i = 0; i < nodeInfoCount; ++i) {
428 nsINodeInfo *nodeInfo = nodeInfos[i];
429 NS_ENSURE_TRUE(nodeInfo, NS_ERROR_FAILURE);
431 nsAutoString namespaceURI;
432 rv |= nodeInfo->GetNamespaceURI(namespaceURI);
433 rv |= aStream->WriteWStringZ(namespaceURI.get());
435 nsAutoString prefix;
436 nodeInfo->GetPrefix(prefix);
437 PRBool nullPrefix = DOMStringIsNull(prefix);
438 rv |= aStream->WriteBoolean(nullPrefix);
439 if (!nullPrefix) {
440 rv |= aStream->WriteWStringZ(prefix.get());
443 nsAutoString localName;
444 nodeInfo->GetName(localName);
445 rv |= aStream->WriteWStringZ(localName.get());
448 // Now serialize the document contents
449 nsIScriptGlobalObject* globalObject = GetScriptGlobalObject();
450 NS_ENSURE_TRUE(globalObject, NS_ERROR_UNEXPECTED);
452 count = mProcessingInstructions.Length();
453 for (i = 0; i < count; ++i) {
454 nsXULPrototypePI* pi = mProcessingInstructions[i];
455 rv |= pi->Serialize(aStream, globalObject, &nodeInfos);
458 if (mRoot)
459 rv |= mRoot->Serialize(aStream, globalObject, &nodeInfos);
461 return rv;
465 //----------------------------------------------------------------------
468 nsresult
469 nsXULPrototypeDocument::InitPrincipal(nsIURI* aURI, nsIPrincipal* aPrincipal)
471 NS_ENSURE_ARG_POINTER(aURI);
473 mURI = aURI;
474 mNodeInfoManager->SetDocumentPrincipal(aPrincipal);
475 return NS_OK;
479 nsIURI*
480 nsXULPrototypeDocument::GetURI()
482 NS_ASSERTION(mURI, "null URI");
483 return mURI;
487 nsXULPrototypeElement*
488 nsXULPrototypeDocument::GetRootElement()
490 return mRoot;
494 void
495 nsXULPrototypeDocument::SetRootElement(nsXULPrototypeElement* aElement)
497 mRoot = aElement;
500 nsresult
501 nsXULPrototypeDocument::AddProcessingInstruction(nsXULPrototypePI* aPI)
503 NS_PRECONDITION(aPI, "null ptr");
504 if (!mProcessingInstructions.AppendElement(aPI)) {
505 return NS_ERROR_OUT_OF_MEMORY;
507 return NS_OK;
510 const nsTArray<nsRefPtr<nsXULPrototypePI> >&
511 nsXULPrototypeDocument::GetProcessingInstructions() const
513 return mProcessingInstructions;
516 void
517 nsXULPrototypeDocument::AddStyleSheetReference(nsIURI* aURI)
519 NS_PRECONDITION(aURI, "null ptr");
520 if (!mStyleSheetReferences.AppendObject(aURI)) {
521 NS_WARNING("mStyleSheetReferences->AppendElement() failed."
522 "Stylesheet overlay dropped.");
526 const nsCOMArray<nsIURI>&
527 nsXULPrototypeDocument::GetStyleSheetReferences() const
529 return mStyleSheetReferences;
532 NS_IMETHODIMP
533 nsXULPrototypeDocument::GetHeaderData(nsIAtom* aField, nsAString& aData) const
535 // XXX Not implemented
536 aData.Truncate();
537 return NS_OK;
541 NS_IMETHODIMP
542 nsXULPrototypeDocument::SetHeaderData(nsIAtom* aField, const nsAString& aData)
544 // XXX Not implemented
545 return NS_OK;
550 nsIPrincipal*
551 nsXULPrototypeDocument::DocumentPrincipal()
553 NS_PRECONDITION(mNodeInfoManager, "missing nodeInfoManager");
554 return mNodeInfoManager->DocumentPrincipal();
557 void
558 nsXULPrototypeDocument::SetDocumentPrincipal(nsIPrincipal* aPrincipal)
560 mNodeInfoManager->SetDocumentPrincipal(aPrincipal);
563 nsNodeInfoManager*
564 nsXULPrototypeDocument::GetNodeInfoManager()
566 return mNodeInfoManager;
570 nsresult
571 nsXULPrototypeDocument::AwaitLoadDone(nsXULDocument* aDocument, PRBool* aResult)
573 nsresult rv = NS_OK;
575 *aResult = mLoaded;
577 if (!mLoaded) {
578 rv = mPrototypeWaiters.AppendElement(aDocument)
579 ? NS_OK : NS_ERROR_OUT_OF_MEMORY; // addrefs
582 return rv;
586 nsresult
587 nsXULPrototypeDocument::NotifyLoadDone()
589 // Call back to each XUL document that raced to start the same
590 // prototype document load, lost the race, but hit the XUL
591 // prototype cache because the winner filled the cache with
592 // the not-yet-loaded prototype object.
594 nsresult rv = NS_OK;
596 mLoaded = PR_TRUE;
598 for (PRUint32 i = mPrototypeWaiters.Length(); i > 0; ) {
599 --i;
600 // PR_TRUE means that OnPrototypeLoadDone will also
601 // call ResumeWalk().
602 rv = mPrototypeWaiters[i]->OnPrototypeLoadDone(PR_TRUE);
603 if (NS_FAILED(rv)) break;
605 mPrototypeWaiters.Clear();
607 return rv;
610 //----------------------------------------------------------------------
612 // nsIScriptGlobalObjectOwner methods
615 nsIScriptGlobalObject*
616 nsXULPrototypeDocument::GetScriptGlobalObject()
618 if (!mGlobalObject)
619 mGlobalObject = NewXULPDGlobalObject();
621 return mGlobalObject;
624 //----------------------------------------------------------------------
626 // nsXULPDGlobalObject
629 nsXULPDGlobalObject::nsXULPDGlobalObject(nsXULPrototypeDocument* owner)
630 : mGlobalObjectOwner(owner)
632 memset(mScriptGlobals, 0, sizeof(mScriptGlobals));
636 nsXULPDGlobalObject::~nsXULPDGlobalObject()
640 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPDGlobalObject)
641 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsXULPDGlobalObject)
642 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPDGlobalObject)
644 PRUint32 lang_index;
645 NS_STID_FOR_INDEX(lang_index) {
646 cb.NoteXPCOMChild(tmp->mScriptContexts[lang_index]);
649 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
651 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPDGlobalObject)
652 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
653 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
654 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObject)
655 NS_INTERFACE_MAP_END
657 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsXULPDGlobalObject,
658 nsIScriptGlobalObject)
659 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsXULPDGlobalObject,
660 nsIScriptGlobalObject)
662 //----------------------------------------------------------------------
664 // nsIScriptGlobalObject methods
667 nsresult
668 nsXULPDGlobalObject::SetScriptContext(PRUint32 lang_id, nsIScriptContext *aScriptContext)
670 // almost a clone of nsGlobalWindow
671 nsresult rv;
673 PRBool ok = NS_STID_VALID(lang_id);
674 NS_ASSERTION(ok, "Invalid programming language ID requested");
675 NS_ENSURE_TRUE(ok, NS_ERROR_INVALID_ARG);
676 PRUint32 lang_ndx = NS_STID_INDEX(lang_id);
678 if (!aScriptContext)
679 NS_WARNING("Possibly early removal of script object, see bug #41608");
680 else {
681 // should probably assert the context is clean???
682 aScriptContext->WillInitializeContext();
683 // NOTE: We init this context with a NULL global - this is subtly
684 // different than nsGlobalWindow which passes 'this'
685 rv = aScriptContext->InitContext(nsnull);
686 NS_ENSURE_SUCCESS(rv, rv);
689 NS_ASSERTION(!aScriptContext || !mScriptContexts[lang_ndx],
690 "Bad call to SetContext()!");
692 void *script_glob = nsnull;
694 if (aScriptContext) {
695 aScriptContext->DidInitializeContext();
696 script_glob = aScriptContext->GetNativeGlobal();
697 NS_ASSERTION(script_glob, "GetNativeGlobal returned NULL!");
699 mScriptContexts[lang_ndx] = aScriptContext;
700 mScriptGlobals[lang_ndx] = script_glob;
701 return NS_OK;
704 nsresult
705 nsXULPDGlobalObject::EnsureScriptEnvironment(PRUint32 lang_id)
707 PRBool ok = NS_STID_VALID(lang_id);
708 NS_ASSERTION(ok, "Invalid programming language ID requested");
709 NS_ENSURE_TRUE(ok, NS_ERROR_INVALID_ARG);
710 PRUint32 lang_ndx = NS_STID_INDEX(lang_id);
712 if (mScriptContexts[lang_ndx] == nsnull) {
713 nsresult rv;
714 NS_ASSERTION(mScriptGlobals[lang_ndx] == nsnull, "Have global without context?");
716 nsCOMPtr<nsIScriptRuntime> languageRuntime;
717 rv = NS_GetScriptRuntimeByID(lang_id, getter_AddRefs(languageRuntime));
718 NS_ENSURE_SUCCESS(rv, nsnull);
720 nsCOMPtr<nsIScriptContext> ctxNew;
721 rv = languageRuntime->CreateContext(getter_AddRefs(ctxNew));
722 // For JS, we have to setup a special global object. We do this then
723 // attach it as the global for this context. Then, ::SetScriptContext
724 // will re-fetch the global and set it up in our language globals array.
725 if (lang_id == nsIProgrammingLanguage::JAVASCRIPT) {
726 // some special JS specific code we should abstract
727 JSContext *cx = (JSContext *)ctxNew->GetNativeContext();
728 JSAutoRequest ar(cx);
729 JSObject *newGlob = ::JS_NewObject(cx, &gSharedGlobalClass, nsnull, nsnull);
730 if (!newGlob)
731 return nsnull;
733 ::JS_SetGlobalObject(cx, newGlob);
735 // Add an owning reference from JS back to us. This'll be
736 // released when the JSObject is finalized.
737 ::JS_SetPrivate(cx, newGlob, this);
738 NS_ADDREF(this);
741 NS_ENSURE_SUCCESS(rv, nsnull);
742 rv = SetScriptContext(lang_id, ctxNew);
743 NS_ENSURE_SUCCESS(rv, nsnull);
745 return NS_OK;
748 nsIScriptContext *
749 nsXULPDGlobalObject::GetScriptContext(PRUint32 lang_id)
751 // This global object creates a context on demand - do that now.
752 nsresult rv = EnsureScriptEnvironment(lang_id);
753 if (NS_FAILED(rv)) {
754 NS_ERROR("Failed to setup script language");
755 return nsnull;
757 // Note that EnsureScriptEnvironment has validated lang_id
758 return mScriptContexts[NS_STID_INDEX(lang_id)];
761 void *
762 nsXULPDGlobalObject::GetScriptGlobal(PRUint32 lang_id)
764 PRBool ok = NS_STID_VALID(lang_id);
765 NS_ASSERTION(ok, "Invalid programming language ID requested");
766 NS_ENSURE_TRUE(ok, nsnull);
767 PRUint32 lang_ndx = NS_STID_INDEX(lang_id);
769 NS_ASSERTION(mScriptContexts[lang_ndx] != nsnull, "Querying for global before setting up context?");
770 return mScriptGlobals[lang_ndx];
774 void
775 nsXULPDGlobalObject::ClearGlobalObjectOwner()
777 NS_ASSERTION(!mCachedPrincipal, "This shouldn't ever be set until now!");
779 // Cache mGlobalObjectOwner's principal if possible.
780 if (this != nsXULPrototypeDocument::gSystemGlobal)
781 mCachedPrincipal = mGlobalObjectOwner->DocumentPrincipal();
783 PRUint32 lang_ndx;
784 NS_STID_FOR_INDEX(lang_ndx) {
785 if (mScriptContexts[lang_ndx]) {
786 mScriptContexts[lang_ndx]->FinalizeContext();
787 mScriptContexts[lang_ndx] = nsnull;
791 mGlobalObjectOwner = nsnull;
795 void
796 nsXULPDGlobalObject::OnFinalize(PRUint32 aLangID, void *aObject)
798 NS_ASSERTION(NS_STID_VALID(aLangID), "Invalid language ID");
799 NS_ASSERTION(aObject == mScriptGlobals[NS_STID_INDEX(aLangID)],
800 "Wrong object finalized!");
801 mScriptGlobals[NS_STID_INDEX(aLangID)] = nsnull;
804 void
805 nsXULPDGlobalObject::SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts)
807 // We don't care...
810 nsresult
811 nsXULPDGlobalObject::SetNewArguments(nsIArray *aArguments)
813 NS_NOTREACHED("waaah!");
814 return NS_ERROR_UNEXPECTED;
817 //----------------------------------------------------------------------
819 // nsIScriptObjectPrincipal methods
822 nsIPrincipal*
823 nsXULPDGlobalObject::GetPrincipal()
825 if (!mGlobalObjectOwner) {
826 // See nsXULPrototypeDocument::NewXULPDGlobalObject, the comment
827 // about gSystemGlobal implying gSystemPrincipal.
828 if (this == nsXULPrototypeDocument::gSystemGlobal) {
829 return nsXULPrototypeDocument::gSystemPrincipal;
831 // Return the cached principal if it exists.
832 return mCachedPrincipal;
835 return mGlobalObjectOwner->DocumentPrincipal();