1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
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.
21 : *
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>
27 : *
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.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 :
43 : #include "nsXULPrototypeDocument.h"
44 : #include "nsXULDocument.h"
45 :
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 "mozilla/FunctionTimer.h"
62 : #include "nsIDOMScriptObjectFactory.h"
63 : #include "nsDOMCID.h"
64 : #include "nsNodeInfoManager.h"
65 : #include "nsContentUtils.h"
66 : #include "nsCCUncollectableMarker.h"
67 : #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
68 : #include "xpcpublic.h"
69 :
70 : static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
71 : NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
72 :
73 :
74 : class nsXULPDGlobalObject : public nsIScriptGlobalObject,
75 : public nsIScriptObjectPrincipal
76 : {
77 : public:
78 : nsXULPDGlobalObject(nsXULPrototypeDocument* owner);
79 :
80 : // nsISupports interface
81 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
82 :
83 : // nsIScriptGlobalObject methods
84 : virtual void OnFinalize(JSObject* aObject);
85 : virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts);
86 :
87 : virtual JSObject* GetGlobalJSObject();
88 : virtual nsresult EnsureScriptEnvironment(PRUint32 aLangID);
89 :
90 : virtual nsIScriptContext *GetScriptContext(PRUint32 lang);
91 : virtual nsresult SetScriptContext(PRUint32 language, nsIScriptContext *ctx);
92 :
93 : // nsIScriptObjectPrincipal methods
94 : virtual nsIPrincipal* GetPrincipal();
95 :
96 1396 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULPDGlobalObject,
97 : nsIScriptGlobalObject)
98 :
99 : void ClearGlobalObjectOwner();
100 :
101 : protected:
102 : virtual ~nsXULPDGlobalObject();
103 :
104 : nsXULPrototypeDocument* mGlobalObjectOwner; // weak reference
105 :
106 : nsCOMPtr<nsIScriptContext> mContext;
107 : JSObject* mJSObject;
108 :
109 : nsCOMPtr<nsIPrincipal> mCachedPrincipal;
110 :
111 : static JSClass gSharedGlobalClass;
112 : };
113 :
114 : nsIPrincipal* nsXULPrototypeDocument::gSystemPrincipal;
115 : nsXULPDGlobalObject* nsXULPrototypeDocument::gSystemGlobal;
116 : PRUint32 nsXULPrototypeDocument::gRefCnt;
117 :
118 :
119 : void
120 0 : nsXULPDGlobalObject_finalize(JSContext *cx, JSObject *obj)
121 : {
122 0 : nsISupports *nativeThis = (nsISupports*)JS_GetPrivate(obj);
123 :
124 0 : nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeThis));
125 :
126 0 : if (sgo) {
127 0 : sgo->OnFinalize(obj);
128 : }
129 :
130 : // The addref was part of JSObject construction
131 0 : NS_RELEASE(nativeThis);
132 0 : }
133 :
134 :
135 : JSBool
136 0 : nsXULPDGlobalObject_resolve(JSContext *cx, JSObject *obj, jsid id)
137 : {
138 0 : JSBool did_resolve = JS_FALSE;
139 :
140 0 : return JS_ResolveStandardClass(cx, obj, id, &did_resolve);
141 : }
142 :
143 :
144 : JSClass nsXULPDGlobalObject::gSharedGlobalClass = {
145 : "nsXULPrototypeScript compilation scope",
146 : XPCONNECT_GLOBAL_FLAGS,
147 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
148 : JS_EnumerateStub, nsXULPDGlobalObject_resolve, JS_ConvertStub,
149 : nsXULPDGlobalObject_finalize, NULL, NULL, NULL, NULL,
150 : TraceXPCGlobal
151 : };
152 :
153 :
154 :
155 : //----------------------------------------------------------------------
156 : //
157 : // ctors, dtors, n' stuff
158 : //
159 :
160 0 : nsXULPrototypeDocument::nsXULPrototypeDocument()
161 : : mRoot(nsnull),
162 : mLoaded(false),
163 0 : mCCGeneration(0)
164 : {
165 0 : ++gRefCnt;
166 0 : }
167 :
168 :
169 : nsresult
170 0 : nsXULPrototypeDocument::Init()
171 : {
172 0 : mNodeInfoManager = new nsNodeInfoManager();
173 0 : NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
174 :
175 0 : return mNodeInfoManager->Init(nsnull);
176 : }
177 :
178 0 : nsXULPrototypeDocument::~nsXULPrototypeDocument()
179 : {
180 0 : if (mGlobalObject) {
181 : // cleaup cycles etc.
182 0 : mGlobalObject->ClearGlobalObjectOwner();
183 : }
184 :
185 0 : if (mRoot)
186 0 : mRoot->ReleaseSubtree();
187 :
188 0 : if (--gRefCnt == 0) {
189 0 : NS_IF_RELEASE(gSystemPrincipal);
190 0 : NS_IF_RELEASE(gSystemGlobal);
191 : }
192 0 : }
193 :
194 1396 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeDocument)
195 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULPrototypeDocument)
196 0 : tmp->mPrototypeWaiters.Clear();
197 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
198 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeDocument)
199 0 : if (nsCCUncollectableMarker::InGeneration(cb, tmp->mCCGeneration)) {
200 0 : return NS_SUCCESS_INTERRUPTED_TRAVERSE;
201 : }
202 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mRoot,
203 : nsXULPrototypeElement)
204 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mGlobalObject");
205 0 : cb.NoteXPCOMChild(static_cast<nsIScriptGlobalObject*>(tmp->mGlobalObject));
206 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNodeInfoManager,
207 : nsNodeInfoManager)
208 0 : for (PRUint32 i = 0; i < tmp->mPrototypeWaiters.Length(); ++i) {
209 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mPrototypeWaiters[i]");
210 0 : cb.NoteXPCOMChild(static_cast<nsINode*>(tmp->mPrototypeWaiters[i].get()));
211 : }
212 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
213 :
214 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPrototypeDocument)
215 0 : NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner)
216 0 : NS_INTERFACE_MAP_ENTRY(nsISerializable)
217 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObjectOwner)
218 0 : NS_INTERFACE_MAP_END
219 :
220 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULPrototypeDocument)
221 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULPrototypeDocument)
222 :
223 : NS_IMETHODIMP
224 0 : NS_NewXULPrototypeDocument(nsXULPrototypeDocument** aResult)
225 : {
226 0 : *aResult = new nsXULPrototypeDocument();
227 0 : if (! *aResult)
228 0 : return NS_ERROR_OUT_OF_MEMORY;
229 :
230 : nsresult rv;
231 0 : rv = (*aResult)->Init();
232 0 : if (NS_FAILED(rv)) {
233 0 : delete *aResult;
234 0 : *aResult = nsnull;
235 0 : return rv;
236 : }
237 :
238 0 : NS_ADDREF(*aResult);
239 0 : return rv;
240 : }
241 :
242 : // Helper method that shares a system global among all prototype documents
243 : // that have the system principal as their security principal. Called by
244 : // nsXULPrototypeDocument::Read and
245 : // nsXULPrototypeDocument::GetScriptGlobalObject.
246 : // This method greatly reduces the number of nsXULPDGlobalObjects and their
247 : // nsIScriptContexts in apps that load many XUL documents via chrome: URLs.
248 :
249 : nsXULPDGlobalObject *
250 0 : nsXULPrototypeDocument::NewXULPDGlobalObject()
251 : {
252 : // Now compare DocumentPrincipal() to gSystemPrincipal, in order to create
253 : // gSystemGlobal if the two pointers are equal. Thus, gSystemGlobal
254 : // implies gSystemPrincipal.
255 : nsXULPDGlobalObject *global;
256 0 : if (DocumentPrincipal() == gSystemPrincipal) {
257 0 : if (!gSystemGlobal) {
258 0 : gSystemGlobal = new nsXULPDGlobalObject(nsnull);
259 0 : if (! gSystemGlobal)
260 0 : return nsnull;
261 0 : NS_ADDREF(gSystemGlobal);
262 : }
263 0 : global = gSystemGlobal;
264 : } else {
265 0 : global = new nsXULPDGlobalObject(this); // does not refcount
266 0 : if (! global)
267 0 : return nsnull;
268 : }
269 0 : return global;
270 : }
271 :
272 : //----------------------------------------------------------------------
273 : //
274 : // nsISerializable methods
275 : //
276 :
277 : NS_IMETHODIMP
278 0 : nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
279 : {
280 : NS_TIME_FUNCTION;
281 : nsresult rv;
282 :
283 0 : rv = aStream->ReadObject(true, getter_AddRefs(mURI));
284 :
285 : PRUint32 count, i;
286 0 : nsCOMPtr<nsIURI> styleOverlayURI;
287 :
288 0 : rv |= aStream->Read32(&count);
289 0 : if (NS_FAILED(rv)) return rv;
290 :
291 0 : for (i = 0; i < count; ++i) {
292 0 : rv |= aStream->ReadObject(true, getter_AddRefs(styleOverlayURI));
293 0 : mStyleSheetReferences.AppendObject(styleOverlayURI);
294 : }
295 :
296 :
297 : // nsIPrincipal mNodeInfoManager->mPrincipal
298 0 : nsCOMPtr<nsIPrincipal> principal;
299 0 : rv |= aStream->ReadObject(true, getter_AddRefs(principal));
300 : // Better safe than sorry....
301 0 : mNodeInfoManager->SetDocumentPrincipal(principal);
302 :
303 :
304 : // nsIScriptGlobalObject mGlobalObject
305 0 : mGlobalObject = NewXULPDGlobalObject();
306 0 : if (! mGlobalObject)
307 0 : return NS_ERROR_OUT_OF_MEMORY;
308 :
309 0 : mRoot = new nsXULPrototypeElement();
310 0 : if (! mRoot)
311 0 : return NS_ERROR_OUT_OF_MEMORY;
312 :
313 : // nsINodeInfo table
314 0 : nsCOMArray<nsINodeInfo> nodeInfos;
315 :
316 0 : rv |= aStream->Read32(&count);
317 0 : nsAutoString namespaceURI, prefixStr, localName;
318 : bool prefixIsNull;
319 0 : nsCOMPtr<nsIAtom> prefix;
320 0 : for (i = 0; i < count; ++i) {
321 0 : rv |= aStream->ReadString(namespaceURI);
322 0 : rv |= aStream->ReadBoolean(&prefixIsNull);
323 0 : if (prefixIsNull) {
324 0 : prefix = nsnull;
325 : } else {
326 0 : rv |= aStream->ReadString(prefixStr);
327 0 : prefix = do_GetAtom(prefixStr);
328 : }
329 0 : rv |= aStream->ReadString(localName);
330 :
331 0 : nsCOMPtr<nsINodeInfo> nodeInfo;
332 : // Using PR_UINT16_MAX here as we don't know which nodeinfos will be
333 : // used for attributes and which for elements. And that doesn't really
334 : // matter.
335 : rv |= mNodeInfoManager->GetNodeInfo(localName, prefix, namespaceURI,
336 : PR_UINT16_MAX,
337 0 : getter_AddRefs(nodeInfo));
338 0 : if (!nodeInfos.AppendObject(nodeInfo))
339 0 : rv |= NS_ERROR_OUT_OF_MEMORY;
340 : }
341 :
342 : // Document contents
343 : PRUint32 type;
344 0 : while (NS_SUCCEEDED(rv)) {
345 0 : rv |= aStream->Read32(&type);
346 :
347 0 : if ((nsXULPrototypeNode::Type)type == nsXULPrototypeNode::eType_PI) {
348 0 : nsRefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI();
349 0 : if (! pi) {
350 0 : rv |= NS_ERROR_OUT_OF_MEMORY;
351 : break;
352 : }
353 :
354 0 : rv |= pi->Deserialize(aStream, mGlobalObject, mURI, &nodeInfos);
355 0 : rv |= AddProcessingInstruction(pi);
356 0 : } else if ((nsXULPrototypeNode::Type)type == nsXULPrototypeNode::eType_Element) {
357 0 : rv |= mRoot->Deserialize(aStream, mGlobalObject, mURI, &nodeInfos);
358 0 : break;
359 : } else {
360 0 : NS_NOTREACHED("Unexpected prototype node type");
361 0 : rv |= NS_ERROR_FAILURE;
362 0 : break;
363 : }
364 : }
365 0 : rv |= NotifyLoadDone();
366 :
367 0 : return rv;
368 : }
369 :
370 : static nsresult
371 0 : GetNodeInfos(nsXULPrototypeElement* aPrototype,
372 : nsCOMArray<nsINodeInfo>& aArray)
373 : {
374 : nsresult rv;
375 0 : if (aArray.IndexOf(aPrototype->mNodeInfo) < 0) {
376 0 : if (!aArray.AppendObject(aPrototype->mNodeInfo)) {
377 0 : return NS_ERROR_OUT_OF_MEMORY;
378 : }
379 : }
380 :
381 : // Search attributes
382 : PRUint32 i;
383 0 : for (i = 0; i < aPrototype->mNumAttributes; ++i) {
384 0 : nsCOMPtr<nsINodeInfo> ni;
385 0 : nsAttrName* name = &aPrototype->mAttributes[i].mName;
386 0 : if (name->IsAtom()) {
387 : ni = aPrototype->mNodeInfo->NodeInfoManager()->
388 : GetNodeInfo(name->Atom(), nsnull, kNameSpaceID_None,
389 0 : nsIDOMNode::ATTRIBUTE_NODE);
390 0 : NS_ENSURE_TRUE(ni, NS_ERROR_OUT_OF_MEMORY);
391 : }
392 : else {
393 0 : ni = name->NodeInfo();
394 : }
395 :
396 0 : if (aArray.IndexOf(ni) < 0) {
397 0 : if (!aArray.AppendObject(ni)) {
398 0 : return NS_ERROR_OUT_OF_MEMORY;
399 : }
400 : }
401 : }
402 :
403 : // Search children
404 0 : for (i = 0; i < aPrototype->mChildren.Length(); ++i) {
405 0 : nsXULPrototypeNode* child = aPrototype->mChildren[i];
406 0 : if (child->mType == nsXULPrototypeNode::eType_Element) {
407 : rv = GetNodeInfos(static_cast<nsXULPrototypeElement*>(child),
408 0 : aArray);
409 0 : NS_ENSURE_SUCCESS(rv, rv);
410 : }
411 : }
412 :
413 0 : return NS_OK;
414 : }
415 :
416 : NS_IMETHODIMP
417 0 : nsXULPrototypeDocument::Write(nsIObjectOutputStream* aStream)
418 : {
419 : nsresult rv;
420 :
421 0 : rv = aStream->WriteCompoundObject(mURI, NS_GET_IID(nsIURI), true);
422 :
423 : PRUint32 count;
424 :
425 0 : count = mStyleSheetReferences.Count();
426 0 : rv |= aStream->Write32(count);
427 :
428 : PRUint32 i;
429 0 : for (i = 0; i < count; ++i) {
430 0 : rv |= aStream->WriteCompoundObject(mStyleSheetReferences[i],
431 0 : NS_GET_IID(nsIURI), true);
432 : }
433 :
434 : // nsIPrincipal mNodeInfoManager->mPrincipal
435 0 : rv |= aStream->WriteObject(mNodeInfoManager->DocumentPrincipal(),
436 0 : true);
437 :
438 : #ifdef DEBUG
439 : // XXX Worrisome if we're caching things without system principal.
440 0 : if (!nsContentUtils::IsSystemPrincipal(mNodeInfoManager->DocumentPrincipal())) {
441 0 : NS_WARNING("Serializing document without system principal");
442 : }
443 : #endif
444 :
445 : // nsINodeInfo table
446 0 : nsCOMArray<nsINodeInfo> nodeInfos;
447 0 : if (mRoot)
448 0 : rv |= GetNodeInfos(mRoot, nodeInfos);
449 :
450 0 : PRUint32 nodeInfoCount = nodeInfos.Count();
451 0 : rv |= aStream->Write32(nodeInfoCount);
452 0 : for (i = 0; i < nodeInfoCount; ++i) {
453 0 : nsINodeInfo *nodeInfo = nodeInfos[i];
454 0 : NS_ENSURE_TRUE(nodeInfo, NS_ERROR_FAILURE);
455 :
456 0 : nsAutoString namespaceURI;
457 0 : rv |= nodeInfo->GetNamespaceURI(namespaceURI);
458 0 : rv |= aStream->WriteWStringZ(namespaceURI.get());
459 :
460 0 : nsAutoString prefix;
461 0 : nodeInfo->GetPrefix(prefix);
462 0 : bool nullPrefix = DOMStringIsNull(prefix);
463 0 : rv |= aStream->WriteBoolean(nullPrefix);
464 0 : if (!nullPrefix) {
465 0 : rv |= aStream->WriteWStringZ(prefix.get());
466 : }
467 :
468 0 : nsAutoString localName;
469 0 : nodeInfo->GetName(localName);
470 0 : rv |= aStream->WriteWStringZ(localName.get());
471 : }
472 :
473 : // Now serialize the document contents
474 0 : nsIScriptGlobalObject* globalObject = GetScriptGlobalObject();
475 0 : NS_ENSURE_TRUE(globalObject, NS_ERROR_UNEXPECTED);
476 :
477 0 : count = mProcessingInstructions.Length();
478 0 : for (i = 0; i < count; ++i) {
479 0 : nsXULPrototypePI* pi = mProcessingInstructions[i];
480 0 : rv |= pi->Serialize(aStream, globalObject, &nodeInfos);
481 : }
482 :
483 0 : if (mRoot)
484 0 : rv |= mRoot->Serialize(aStream, globalObject, &nodeInfos);
485 :
486 0 : return rv;
487 : }
488 :
489 :
490 : //----------------------------------------------------------------------
491 : //
492 :
493 : nsresult
494 0 : nsXULPrototypeDocument::InitPrincipal(nsIURI* aURI, nsIPrincipal* aPrincipal)
495 : {
496 0 : NS_ENSURE_ARG_POINTER(aURI);
497 :
498 0 : mURI = aURI;
499 0 : mNodeInfoManager->SetDocumentPrincipal(aPrincipal);
500 0 : return NS_OK;
501 : }
502 :
503 :
504 : nsIURI*
505 0 : nsXULPrototypeDocument::GetURI()
506 : {
507 0 : NS_ASSERTION(mURI, "null URI");
508 0 : return mURI;
509 : }
510 :
511 :
512 : nsXULPrototypeElement*
513 0 : nsXULPrototypeDocument::GetRootElement()
514 : {
515 0 : return mRoot;
516 : }
517 :
518 :
519 : void
520 0 : nsXULPrototypeDocument::SetRootElement(nsXULPrototypeElement* aElement)
521 : {
522 0 : mRoot = aElement;
523 0 : }
524 :
525 : nsresult
526 0 : nsXULPrototypeDocument::AddProcessingInstruction(nsXULPrototypePI* aPI)
527 : {
528 0 : NS_PRECONDITION(aPI, "null ptr");
529 0 : if (!mProcessingInstructions.AppendElement(aPI)) {
530 0 : return NS_ERROR_OUT_OF_MEMORY;
531 : }
532 0 : return NS_OK;
533 : }
534 :
535 : const nsTArray<nsRefPtr<nsXULPrototypePI> >&
536 0 : nsXULPrototypeDocument::GetProcessingInstructions() const
537 : {
538 0 : return mProcessingInstructions;
539 : }
540 :
541 : void
542 0 : nsXULPrototypeDocument::AddStyleSheetReference(nsIURI* aURI)
543 : {
544 0 : NS_PRECONDITION(aURI, "null ptr");
545 0 : if (!mStyleSheetReferences.AppendObject(aURI)) {
546 : NS_WARNING("mStyleSheetReferences->AppendElement() failed."
547 0 : "Stylesheet overlay dropped.");
548 : }
549 0 : }
550 :
551 : const nsCOMArray<nsIURI>&
552 0 : nsXULPrototypeDocument::GetStyleSheetReferences() const
553 : {
554 0 : return mStyleSheetReferences;
555 : }
556 :
557 : NS_IMETHODIMP
558 0 : nsXULPrototypeDocument::GetHeaderData(nsIAtom* aField, nsAString& aData) const
559 : {
560 : // XXX Not implemented
561 0 : aData.Truncate();
562 0 : return NS_OK;
563 : }
564 :
565 :
566 : NS_IMETHODIMP
567 0 : nsXULPrototypeDocument::SetHeaderData(nsIAtom* aField, const nsAString& aData)
568 : {
569 : // XXX Not implemented
570 0 : return NS_OK;
571 : }
572 :
573 :
574 :
575 : nsIPrincipal*
576 0 : nsXULPrototypeDocument::DocumentPrincipal()
577 : {
578 0 : NS_PRECONDITION(mNodeInfoManager, "missing nodeInfoManager");
579 0 : return mNodeInfoManager->DocumentPrincipal();
580 : }
581 :
582 : void
583 0 : nsXULPrototypeDocument::SetDocumentPrincipal(nsIPrincipal* aPrincipal)
584 : {
585 0 : mNodeInfoManager->SetDocumentPrincipal(aPrincipal);
586 0 : }
587 :
588 : nsNodeInfoManager*
589 0 : nsXULPrototypeDocument::GetNodeInfoManager()
590 : {
591 0 : return mNodeInfoManager;
592 : }
593 :
594 :
595 : nsresult
596 0 : nsXULPrototypeDocument::AwaitLoadDone(nsXULDocument* aDocument, bool* aResult)
597 : {
598 0 : nsresult rv = NS_OK;
599 :
600 0 : *aResult = mLoaded;
601 :
602 0 : if (!mLoaded) {
603 0 : rv = mPrototypeWaiters.AppendElement(aDocument)
604 0 : ? NS_OK : NS_ERROR_OUT_OF_MEMORY; // addrefs
605 : }
606 :
607 0 : return rv;
608 : }
609 :
610 :
611 : nsresult
612 0 : nsXULPrototypeDocument::NotifyLoadDone()
613 : {
614 : // Call back to each XUL document that raced to start the same
615 : // prototype document load, lost the race, but hit the XUL
616 : // prototype cache because the winner filled the cache with
617 : // the not-yet-loaded prototype object.
618 :
619 0 : nsresult rv = NS_OK;
620 :
621 0 : mLoaded = true;
622 :
623 0 : for (PRUint32 i = mPrototypeWaiters.Length(); i > 0; ) {
624 0 : --i;
625 : // true means that OnPrototypeLoadDone will also
626 : // call ResumeWalk().
627 0 : rv = mPrototypeWaiters[i]->OnPrototypeLoadDone(true);
628 0 : if (NS_FAILED(rv)) break;
629 : }
630 0 : mPrototypeWaiters.Clear();
631 :
632 0 : return rv;
633 : }
634 :
635 : //----------------------------------------------------------------------
636 : //
637 : // nsIScriptGlobalObjectOwner methods
638 : //
639 :
640 : nsIScriptGlobalObject*
641 0 : nsXULPrototypeDocument::GetScriptGlobalObject()
642 : {
643 0 : if (!mGlobalObject)
644 0 : mGlobalObject = NewXULPDGlobalObject();
645 :
646 0 : return mGlobalObject;
647 : }
648 :
649 : //----------------------------------------------------------------------
650 : //
651 : // nsXULPDGlobalObject
652 : //
653 :
654 0 : nsXULPDGlobalObject::nsXULPDGlobalObject(nsXULPrototypeDocument* owner)
655 : : mGlobalObjectOwner(owner)
656 0 : , mJSObject(NULL)
657 : {
658 0 : }
659 :
660 :
661 0 : nsXULPDGlobalObject::~nsXULPDGlobalObject()
662 : {
663 0 : }
664 :
665 1396 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPDGlobalObject)
666 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsXULPDGlobalObject)
667 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPDGlobalObject)
668 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
669 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
670 :
671 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULPDGlobalObject)
672 0 : NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
673 0 : NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
674 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObject)
675 0 : NS_INTERFACE_MAP_END
676 :
677 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULPDGlobalObject)
678 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULPDGlobalObject)
679 :
680 : //----------------------------------------------------------------------
681 : //
682 : // nsIScriptGlobalObject methods
683 : //
684 :
685 : nsresult
686 0 : nsXULPDGlobalObject::SetScriptContext(PRUint32 lang_id, nsIScriptContext *aScriptContext)
687 : {
688 0 : NS_ABORT_IF_FALSE(lang_id == nsIProgrammingLanguage::JAVASCRIPT,
689 : "We don't support this language ID");
690 : // almost a clone of nsGlobalWindow
691 0 : if (!aScriptContext) {
692 0 : NS_WARNING("Possibly early removal of script object, see bug #41608");
693 : } else {
694 : // should probably assert the context is clean???
695 0 : aScriptContext->WillInitializeContext();
696 0 : nsresult rv = aScriptContext->InitContext();
697 0 : NS_ENSURE_SUCCESS(rv, rv);
698 : }
699 :
700 0 : NS_ASSERTION(!aScriptContext || !mContext, "Bad call to SetContext()!");
701 :
702 0 : JSObject* global = NULL;
703 :
704 0 : if (aScriptContext) {
705 0 : aScriptContext->SetGCOnDestruction(false);
706 0 : aScriptContext->DidInitializeContext();
707 0 : global = aScriptContext->GetNativeGlobal();
708 0 : NS_ASSERTION(global, "GetNativeGlobal returned NULL!");
709 : }
710 0 : mContext = aScriptContext;
711 0 : mJSObject = global;
712 0 : return NS_OK;
713 : }
714 :
715 : nsresult
716 0 : nsXULPDGlobalObject::EnsureScriptEnvironment(PRUint32 lang_id)
717 : {
718 0 : NS_ABORT_IF_FALSE(lang_id == nsIProgrammingLanguage::JAVASCRIPT,
719 : "We don't support this language ID");
720 0 : if (mContext) {
721 0 : return NS_OK;
722 : }
723 0 : NS_ASSERTION(!mJSObject, "Have global without context?");
724 :
725 0 : nsCOMPtr<nsIScriptRuntime> languageRuntime;
726 : nsresult rv = NS_GetScriptRuntimeByID(nsIProgrammingLanguage::JAVASCRIPT,
727 0 : getter_AddRefs(languageRuntime));
728 0 : NS_ENSURE_SUCCESS(rv, NS_OK);
729 :
730 0 : nsCOMPtr<nsIScriptContext> ctxNew = languageRuntime->CreateContext();
731 : // We have to setup a special global object. We do this then
732 : // attach it as the global for this context. Then, ::SetScriptContext
733 : // will re-fetch the global and set it up in our language globals array.
734 : {
735 0 : JSContext *cx = ctxNew->GetNativeContext();
736 0 : JSAutoRequest ar(cx);
737 :
738 0 : nsIPrincipal *principal = GetPrincipal();
739 : JSObject *newGlob;
740 : JSCompartment *compartment;
741 :
742 : rv = xpc_CreateGlobalObject(cx, &gSharedGlobalClass, principal, nsnull,
743 0 : false, &newGlob, &compartment);
744 0 : NS_ENSURE_SUCCESS(rv, NS_OK);
745 :
746 0 : ::JS_SetGlobalObject(cx, newGlob);
747 :
748 : // Add an owning reference from JS back to us. This'll be
749 : // released when the JSObject is finalized.
750 0 : ::JS_SetPrivate(newGlob, this);
751 0 : NS_ADDREF(this);
752 : }
753 :
754 0 : NS_ENSURE_SUCCESS(rv, NS_OK);
755 0 : rv = SetScriptContext(lang_id, ctxNew);
756 0 : NS_ENSURE_SUCCESS(rv, NS_OK);
757 0 : return NS_OK;
758 : }
759 :
760 : nsIScriptContext*
761 0 : nsXULPDGlobalObject::GetScriptContext(PRUint32 lang_id)
762 : {
763 0 : NS_ABORT_IF_FALSE(lang_id == nsIProgrammingLanguage::JAVASCRIPT,
764 : "We don't support this language ID");
765 : // This global object creates a context on demand - do that now.
766 0 : nsresult rv = EnsureScriptEnvironment(nsIProgrammingLanguage::JAVASCRIPT);
767 0 : if (NS_FAILED(rv)) {
768 0 : NS_ERROR("Failed to setup script language");
769 0 : return NULL;
770 : }
771 : // Note that EnsureScriptEnvironment has validated lang_id
772 0 : return mContext;
773 : }
774 :
775 : JSObject*
776 0 : nsXULPDGlobalObject::GetGlobalJSObject()
777 : {
778 0 : return mJSObject;
779 : }
780 :
781 :
782 : void
783 0 : nsXULPDGlobalObject::ClearGlobalObjectOwner()
784 : {
785 0 : NS_ASSERTION(!mCachedPrincipal, "This shouldn't ever be set until now!");
786 :
787 : // Cache mGlobalObjectOwner's principal if possible.
788 0 : if (this != nsXULPrototypeDocument::gSystemGlobal)
789 0 : mCachedPrincipal = mGlobalObjectOwner->DocumentPrincipal();
790 :
791 0 : mContext = NULL;
792 0 : mGlobalObjectOwner = NULL;
793 0 : }
794 :
795 :
796 : void
797 0 : nsXULPDGlobalObject::OnFinalize(JSObject* aObject)
798 : {
799 0 : mJSObject = NULL;
800 0 : }
801 :
802 : void
803 0 : nsXULPDGlobalObject::SetScriptsEnabled(bool aEnabled, bool aFireTimeouts)
804 : {
805 : // We don't care...
806 0 : }
807 :
808 : //----------------------------------------------------------------------
809 : //
810 : // nsIScriptObjectPrincipal methods
811 : //
812 :
813 : nsIPrincipal*
814 0 : nsXULPDGlobalObject::GetPrincipal()
815 : {
816 0 : if (!mGlobalObjectOwner) {
817 : // See nsXULPrototypeDocument::NewXULPDGlobalObject, the comment
818 : // about gSystemGlobal implying gSystemPrincipal.
819 0 : if (this == nsXULPrototypeDocument::gSystemGlobal) {
820 0 : return nsXULPrototypeDocument::gSystemPrincipal;
821 : }
822 : // Return the cached principal if it exists.
823 0 : return mCachedPrincipal;
824 : }
825 :
826 0 : return mGlobalObjectOwner->DocumentPrincipal();
827 4188 : }
|