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