Bugs 18127, 20677, 23905. Partial fix. Give the nsXULPrototypeDocument it's own JSContext to use for compiling scripts and event handlers. Modify script and event handler code to compile shared scripts using this context, if appropriate. r=brendan

This commit is contained in:
waterson%netscape.com 2000-01-22 22:00:35 +00:00
Родитель 146f7bdd8e
Коммит d100985675
18 изменённых файлов: 866 добавлений и 234 удалений

Просмотреть файл

@ -553,13 +553,17 @@ nsEventListenerManager::AddScriptEventListener(nsIScriptContext* aContext,
}
if (!done) {
if (handlerOwner) {
// Always let the handler owner compile the event handler, as
// it may want to use a special context or scope object.
rv = handlerOwner->CompileEventHandler(aContext, scriptObject, aName, aBody, &handler);
}
else {
rv = aContext->CompileEventHandler(scriptObject, aName, aBody,
(handlerOwner != nsnull),
&handler);
if (NS_FAILED(rv))
return rv;
if (handlerOwner)
handlerOwner->SetCompiledEventHandler(aName, handler);
}
if (NS_FAILED(rv)) return rv;
}
}
return SetJSEventListener(aContext, aScriptObjectOwner, aName, aIID, aDeferCompilation);
@ -621,12 +625,19 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
nsAutoString handlerBody;
result = content->GetAttribute(kNameSpaceID_None, atom, handlerBody);
if (NS_SUCCEEDED(result)) {
if (handlerOwner) {
// Always let the handler owner compile the event
// handler, as it may want to use a special
// context or scope object.
result = handlerOwner->CompileEventHandler(scriptCX, jsobj, atom, handlerBody, &handler);
}
else {
result = scriptCX->CompileEventHandler(jsobj, atom, handlerBody,
(handlerOwner != nsnull),
&handler);
}
if (NS_SUCCEEDED(result))
aListenerStruct->mHandlerIsString &= ~aSubType;
if (handlerOwner)
handlerOwner->SetCompiledEventHandler(atom, handler);
}
}
}

Просмотреть файл

@ -1594,14 +1594,18 @@ nsXULElement::GetScriptObject(nsIScriptContext* aContext, void** aScriptObject)
// tag...
nsresult (*fn)(nsIScriptContext* aContext, nsISupports* aSupports, nsISupports* aParent, void** aReturn);
const char* rootname;
if (Tag() == kTreeAtom) {
fn = NS_NewScriptXULTreeElement;
rootname = "nsXULTreeElement::mScriptObject";
}
else if (Tag() == kEditorAtom) {
fn = NS_NewScriptXULEditorElement;
rootname = "nsXULEditorElement::mScriptObject";
}
else {
fn = NS_NewScriptXULElement;
rootname = "nsXULElement::mScriptObject";
}
// Create the script object; N.B. that if |mDocument| is null,
@ -1611,7 +1615,7 @@ nsXULElement::GetScriptObject(nsIScriptContext* aContext, void** aScriptObject)
rv = fn(aContext, (nsIDOMXULElement*) this, mDocument, (void**) &mScriptObject);
// Ensure that a reference exists to this element
aContext->AddNamedReference((void*) &mScriptObject, mScriptObject, "nsXULElement::mScriptObject");
aContext->AddNamedReference((void*) &mScriptObject, mScriptObject, rootname);
}
*aScriptObject = mScriptObject;
@ -1651,29 +1655,85 @@ nsXULElement::GetCompiledEventHandler(nsIAtom *aName, void** aHandler)
}
NS_IMETHODIMP
nsXULElement::SetCompiledEventHandler(nsIAtom *aName, void* aHandler)
nsXULElement::CompileEventHandler(nsIScriptContext* aContext,
void* aTarget,
nsIAtom *aName,
const nsString& aBody,
void** aHandler)
{
nsresult rv;
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheSets);
nsCOMPtr<nsIScriptContext> context;
JSObject* scopeObject;
PRBool shared;
if (mPrototype) {
// It'll be shared amonst the instances of the prototype
shared = PR_TRUE;
// Use the prototype document's special context
nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mDocument);
NS_ASSERTION(xuldoc != nsnull, "mDocument is not an nsIXULDocument");
if (! xuldoc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIXULPrototypeDocument> protodoc;
rv = xuldoc->GetMasterPrototype(getter_AddRefs(protodoc));
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(protodoc != nsnull, "xul document has no prototype");
if (! protodoc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(protodoc);
NS_ASSERTION(global != nsnull, "prototype doc is not a script global");
if (! global)
return NS_ERROR_UNEXPECTED;
rv = global->GetContext(getter_AddRefs(context));
if (NS_FAILED(rv)) return rv;
// Use the prototype script's special scope object
nsCOMPtr<nsIScriptObjectOwner> owner = do_QueryInterface(protodoc);
if (! owner)
return NS_ERROR_UNEXPECTED;
rv = owner->GetScriptObject(context, (void**) &scopeObject);
if (NS_FAILED(rv)) return rv;
}
else {
// We don't have a prototype; do a one-off compile.
shared = PR_FALSE;
context = aContext;
scopeObject = NS_STATIC_CAST(JSObject*, aTarget);
}
NS_ASSERTION(context != nsnull, "no script context");
if (! context)
return NS_ERROR_UNEXPECTED;
// Compile the event handler
rv = context->CompileEventHandler(scopeObject, aName, aBody, shared, aHandler);
if (NS_FAILED(rv)) return rv;
if (shared) {
// If it's a shared handler, we need to bind the shared
// function object to the real target.
rv = aContext->BindCompiledEventHandler(aTarget, aName, *aHandler);
if (NS_FAILED(rv)) return rv;
}
if (mPrototype) {
// Remember the compiled event handler
for (PRInt32 i = 0; i < mPrototype->mNumAttributes; ++i) {
nsXULPrototypeAttribute* attr = &(mPrototype->mAttributes[i]);
if ((attr->mNameSpaceID == kNameSpaceID_None) &&
(attr->mName.get() == aName)) {
nsresult rv;
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheFills);
attr->mEventHandler = aHandler;
nsCOMPtr<nsIScriptGlobalObject> global;
mDocument->GetScriptGlobalObject(getter_AddRefs(global));
NS_ASSERTION(global != nsnull, "no script global object");
if (! global)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIScriptContext> context;
rv = global->GetContext(getter_AddRefs(context));
if (NS_FAILED(rv)) return rv;
attr->mEventHandler = *aHandler;
JSContext *cx = (JSContext*) context->GetNativeContext();
if (!cx)
@ -1686,6 +1746,7 @@ nsXULElement::SetCompiledEventHandler(nsIAtom *aName, void* aHandler)
}
}
}
return NS_OK;
}
@ -1926,7 +1987,10 @@ nsXULElement::InsertChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify)
if (insertOk) {
aKid->SetParent(NS_STATIC_CAST(nsIStyledContent*, this));
//nsRange::OwnerChildInserted(this, aIndex);
//XXXwaterson this should be shallow
aKid->SetDocument(mDocument, PR_TRUE);
if (aNotify && ElementIsInDocument()) {
mDocument->ContentInserted(NS_STATIC_CAST(nsIStyledContent*, this), aKid, aIndex);
}
@ -1965,10 +2029,21 @@ nsXULElement::ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify)
if (replaceOk) {
aKid->SetParent(NS_STATIC_CAST(nsIStyledContent*, this));
//nsRange::OwnerChildReplaced(this, aIndex, oldKid);
//XXXwaterson this should be shallow
aKid->SetDocument(mDocument, PR_TRUE);
if (aNotify && ElementIsInDocument()) {
mDocument->ContentReplaced(NS_STATIC_CAST(nsIStyledContent*, this), oldKid, aKid, aIndex);
}
#if 0 //XXXwaterson put this in eventually.
// This will cause the script object to be unrooted for each
// element in the subtree.
oldKid->SetDocument(nsnull, PR_TRUE);
#endif
// We've got no mo' parent.
oldKid->SetParent(nsnull);
}
return NS_OK;
@ -1992,7 +2067,10 @@ nsXULElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
if (appendOk) {
aKid->SetParent(NS_STATIC_CAST(nsIStyledContent*, this));
// ranges don't need adjustment since new child is at end of list
//XXXwaterson this should be shallow
aKid->SetDocument(mDocument, PR_TRUE);
if (aNotify && ElementIsInDocument()) {
PRUint32 cnt;
rv = mChildren->Count(&cnt);
@ -2097,6 +2175,14 @@ nsXULElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
if (aNotify && removeOk && ElementIsInDocument()) {
doc->ContentRemoved(NS_STATIC_CAST(nsIStyledContent*, this), oldKid, aIndex);
}
#if 0 //XXXwaterson put this in eventually
// This will cause the script object to be unrooted for each
// element in the subtree.
oldKid->SetDocument(nsnull, PR_TRUE);
#endif
// We've got no mo' parent.
oldKid->SetParent(nsnull);
}
@ -3921,33 +4007,13 @@ nsXULPrototypeScript::~nsXULPrototypeScript()
}
nsresult
nsXULPrototypeScript::Compile(const PRUnichar* aText, PRInt32 aTextLength,
nsIURI* aURI, PRInt32 aLineNo,
nsXULPrototypeScript::Compile(const PRUnichar* aText,
PRInt32 aTextLength,
nsIURI* aURI,
PRInt32 aLineNo,
nsIDocument* aDocument,
nsIXULPrototypeDocument* aPrototypeDocument)
{
nsresult rv;
nsCOMPtr<nsIScriptGlobalObject> global;
aDocument->GetScriptGlobalObject(getter_AddRefs(global));
NS_ASSERTION(global != nsnull, "no script global object");
if (! global)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIScriptContext> context;
rv = global->GetContext(getter_AddRefs(context));
if (NS_FAILED(rv)) return rv;
JSContext *cx = (JSContext*) context->GetNativeContext();
if (!cx)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIPrincipal> principal =
dont_AddRef(aDocument->GetDocumentPrincipal());
nsXPIDLCString urlspec;
aURI->GetSpec(getter_Copies(urlspec));
// We'll compile the script using the prototype document's special
// script object as the parent. This ensures that we won't end up
// with an uncollectable reference.
@ -3959,18 +4025,62 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText, PRInt32 aTextLength,
// and the first document would indirectly reference the prototype
// document because it keeps the prototype cache
// alive. Circularity!
void * scopeObject;
nsCOMPtr<nsIScriptObjectOwner> owner= do_QueryInterface(aPrototypeDocument, &rv);
if (NS_FAILED(rv)) return rv;
nsresult rv;
rv = owner->GetScriptObject(context, &scopeObject);
if (NS_FAILED(rv)) return rv;
// Use the prototype document's special context
nsCOMPtr<nsIScriptContext> context;
rv = context->CompileScript(aText, aTextLength, (JSObject *)scopeObject,
principal, urlspec, aLineNo, mLangVersion,
{
nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(aPrototypeDocument);
NS_ASSERTION(global != nsnull, "prototype doc is not a script global");
if (! global)
return NS_ERROR_UNEXPECTED;
rv = global->GetContext(getter_AddRefs(context));
if (NS_FAILED(rv)) return rv;
}
NS_ASSERTION(context != nsnull, "no context for script global");
if (! context)
return NS_ERROR_UNEXPECTED;
// Use the prototype script's special scope object
JSObject* scopeObject;
{
nsCOMPtr<nsIScriptObjectOwner> owner = do_QueryInterface(aPrototypeDocument);
if (! owner)
return NS_ERROR_UNEXPECTED;
rv = owner->GetScriptObject(context, (void**) &scopeObject);
if (NS_FAILED(rv)) return rv;
}
// Use the enclosing document's principal
// XXX is this right? or should we use the protodoc's?
nsCOMPtr<nsIPrincipal> principal =
dont_AddRef(aDocument->GetDocumentPrincipal());
nsXPIDLCString urlspec;
aURI->GetSpec(getter_Copies(urlspec));
// Ok, compile it to create a prototype script object!
rv = context->CompileScript(aText,
aTextLength,
scopeObject,
principal,
urlspec,
aLineNo,
mLangVersion,
(void**) &mScriptObject);
if (NS_FAILED(rv)) return rv;
// Root the compiled prototype script object.
JSContext* cx = NS_STATIC_CAST(JSContext*, context->GetNativeContext());
if (!cx)
return NS_ERROR_UNEXPECTED;
rv = AddJSGCRoot(cx, &mScriptObject, "nsXULPrototypeScript::mScriptObject");
return rv;
}

Просмотреть файл

@ -463,8 +463,12 @@ public:
NS_IMETHOD SetScriptObject(void *aScriptObject);
// nsIScriptEventHandlerOwner
NS_IMETHOD CompileEventHandler(nsIScriptContext* aContext,
void* aTarget,
nsIAtom *aName,
const nsString& aBody,
void** aHandler);
NS_IMETHOD GetCompiledEventHandler(nsIAtom *aName, void** aHandler);
NS_IMETHOD SetCompiledEventHandler(nsIAtom *aName, void* aHandler);
// nsIJSScriptObject
virtual PRBool AddProperty(JSContext *aContext, JSObject *aObj,

Просмотреть файл

@ -113,6 +113,11 @@ public:
*/
NS_IMETHOD SetMasterPrototype(nsIXULPrototypeDocument* aDocument) = 0;
/**
* Get the master prototype.
*/
NS_IMETHOD GetMasterPrototype(nsIXULPrototypeDocument** aPrototypeDocument) = 0;
/**
* Set the current prototype
*/

Просмотреть файл

@ -33,8 +33,8 @@
class nsIAtom;
class nsIPrincipal;
class nsIURI;
class nsIStyleSheet;
class nsIURI;
class nsString;
class nsVoidArray;
class nsXULPrototypeElement;

Просмотреть файл

@ -2108,6 +2108,14 @@ nsXULDocument::SetMasterPrototype(nsIXULPrototypeDocument* aDocument)
return NS_OK;
}
NS_IMETHODIMP
nsXULDocument::GetMasterPrototype(nsIXULPrototypeDocument** aDocument)
{
*aDocument = mMasterPrototype;
NS_IF_ADDREF(*aDocument);
return NS_OK;
}
NS_IMETHODIMP
nsXULDocument::SetCurrentPrototype(nsIXULPrototypeDocument* aDocument)
{
@ -2683,7 +2691,7 @@ nsXULDocument::AddSubtreeToDocument(nsIContent* aElement)
if (NS_FAILED(rv)) return rv;
}
// Finally, recurse to children.
// 4. Recurse to children.
PRInt32 count;
nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(aElement);
rv = xulcontent ? xulcontent->PeekChildCount(count) : aElement->ChildCount(count);
@ -2708,6 +2716,7 @@ nsXULDocument::RemoveSubtreeFromDocument(nsIContent* aElement)
// document.
nsresult rv;
// 1. Remove any children from the document.
PRInt32 count;
nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(aElement);
rv = xulcontent ? xulcontent->PeekChildCount(count) : aElement->ChildCount(count);
@ -2722,11 +2731,11 @@ nsXULDocument::RemoveSubtreeFromDocument(nsIContent* aElement)
if (NS_FAILED(rv)) return rv;
}
// 1. Remove the element from the resource-to-element map
// 2. Remove the element from the resource-to-element map
rv = RemoveElementFromMap(aElement);
if (NS_FAILED(rv)) return rv;
// 2. If the element is a 'command updater', then remove the
// 3. If the element is a 'command updater', then remove the
// element from the document's command dispatcher.
nsAutoString value;
rv = aElement->GetAttribute(kNameSpaceID_None, kCommandUpdaterAtom, value);
@ -3951,10 +3960,9 @@ nsXULDocument::CreateElement(PRInt32 aNameSpaceID,
return NS_ERROR_UNEXPECTED;
}
rv = result->SetDocument(this, PR_FALSE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to set element's document");
if (NS_FAILED(rv)) return rv;
#if 1 // XXXwaterson remove this eventually
result->SetDocument(this, PR_FALSE);
#endif
result->SetContentID(mNextContentID++);
*aResult = result;

Просмотреть файл

@ -285,6 +285,7 @@ public:
NS_IMETHOD AddForwardReference(nsForwardReference* aRef);
NS_IMETHOD ResolveForwardReferences();
NS_IMETHOD SetMasterPrototype(nsIXULPrototypeDocument* aDocument);
NS_IMETHOD GetMasterPrototype(nsIXULPrototypeDocument** aDocument);
NS_IMETHOD SetCurrentPrototype(nsIXULPrototypeDocument* aDocument);
NS_IMETHOD SetDocumentURL(nsIURI* anURL);
NS_IMETHOD PrepareStyleSheets(nsIURI* anURL);

Просмотреть файл

@ -27,19 +27,23 @@
*/
#include "nsCOMPtr.h"
#include "nsString2.h"
#include "nsVoidArray.h"
#include "nsIPrincipal.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptGlobalObjectData.h"
#include "nsIScriptSecurityManager.h"
#include "nsIServiceManager.h"
#include "nsISupportsArray.h"
#include "nsIURI.h"
#include "nsIServiceManager.h"
#include "nsIScriptSecurityManager.h"
#include "nsIXULPrototypeDocument.h"
#include "nsString2.h"
#include "nsVoidArray.h"
#include "nsXULElement.h"
#include "nsIJSRuntimeService.h"
class nsXULPrototypeDocument : public nsIXULPrototypeDocument,
public nsIScriptObjectOwner
public nsIScriptObjectOwner,
public nsIScriptGlobalObject,
public nsIScriptGlobalObjectData
{
public:
static nsresult
@ -71,12 +75,33 @@ public:
NS_IMETHOD GetScriptObject(nsIScriptContext *aContext, void **aObject);
NS_IMETHOD SetScriptObject(void *aObject);
// nsIScriptGlobalObject methods
NS_IMETHOD SetContext(nsIScriptContext *aContext);
NS_IMETHOD GetContext(nsIScriptContext **aContext);
NS_IMETHOD SetNewDocument(nsIDOMDocument *aDocument);
NS_IMETHOD SetWebShell(nsIWebShell *aWebShell);
NS_IMETHOD GetWebShell(nsIWebShell **aWebShell);
NS_IMETHOD SetOpenerWindow(nsIDOMWindow *aOpener);
NS_IMETHOD SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner);
NS_IMETHOD GetGlobalObjectOwner(nsIScriptGlobalObjectOwner** aOwner);
NS_IMETHOD HandleDOMEvent(nsIPresContext* aPresContext,
nsEvent* aEvent,
nsIDOMEvent** aDOMEvent,
PRUint32 aFlags,
nsEventStatus* aEventStatus);
// nsIScriptGlobalObjectData methods
NS_IMETHOD GetPrincipal(nsIPrincipal** aPrincipal);
protected:
nsCOMPtr<nsIURI> mURI;
nsXULPrototypeElement* mRoot;
nsCOMPtr<nsISupportsArray> mStyleSheetReferences;
nsCOMPtr<nsISupportsArray> mOverlayReferences;
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
nsCOMPtr<nsIScriptContext> mScriptContext;
JSObject *mScriptObject; // XXX JS language rabies bigotry badness
nsXULPrototypeDocument();
@ -85,13 +110,30 @@ protected:
friend NS_IMETHODIMP
NS_NewXULPrototypeDocument(nsISupports* aOuter, REFNSIID aIID, void** aResult);
static JSClass gSharedGlobalClass;
static void PR_CALLBACK
FinalizeScriptObject(JSContext* cx, JSObject* obj);
};
JSClass nsXULPrototypeDocument::gSharedGlobalClass = {
"nsXULPrototypeScript compilation scope",
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nsXULPrototypeDocument::FinalizeScriptObject
};
//----------------------------------------------------------------------
//
// ctors, dtors, n' stuff
//
nsXULPrototypeDocument::nsXULPrototypeDocument()
: mRoot(nsnull), mScriptObject(nsnull)
: mRoot(nsnull),
mScriptObject(nsnull)
{
NS_INIT_REFCNT();
}
@ -115,19 +157,14 @@ nsXULPrototypeDocument::Init()
nsXULPrototypeDocument::~nsXULPrototypeDocument()
{
delete mRoot;
nsresult rv;
NS_WITH_SERVICE(nsIJSRuntimeService, rtsvc, "nsJSRuntimeService", &rv);
if (NS_SUCCEEDED(rv)) {
JSRuntime *rt;
rv = rtsvc->GetRuntime(&rt);
if (NS_SUCCEEDED(rv) && rt)
JS_RemoveRootRT(rt, &mScriptObject);
}
}
NS_IMPL_ISUPPORTS2(nsXULPrototypeDocument, nsIXULPrototypeDocument, nsIScriptObjectOwner);
NS_IMPL_ISUPPORTS4(nsXULPrototypeDocument,
nsIXULPrototypeDocument,
nsIScriptObjectOwner,
nsIScriptGlobalObject,
nsIScriptGlobalObjectData);
NS_IMETHODIMP
NS_NewXULPrototypeDocument(nsISupports* aOuter, REFNSIID aIID, void** aResult)
@ -156,6 +193,9 @@ NS_NewXULPrototypeDocument(nsISupports* aOuter, REFNSIID aIID, void** aResult)
//----------------------------------------------------------------------
//
// nsIXULPrototypeDocument methods
//
NS_IMETHODIMP
nsXULPrototypeDocument::GetURI(nsIURI** aResult)
@ -169,7 +209,7 @@ nsXULPrototypeDocument::GetURI(nsIURI** aResult)
NS_IMETHODIMP
nsXULPrototypeDocument::SetURI(nsIURI* aURI)
{
mURI = aURI;
mURI = dont_QueryInterface(aURI);
return NS_OK;
}
@ -257,14 +297,20 @@ nsXULPrototypeDocument::GetDocumentPrincipal(nsIPrincipal** aResult)
{
if (!mDocumentPrincipal) {
nsresult rv;
NS_WITH_SERVICE(nsIScriptSecurityManager, securityManager,
NS_SCRIPTSECURITYMANAGER_PROGID, &rv);
NS_WITH_SERVICE(nsIScriptSecurityManager,
securityManager,
NS_SCRIPTSECURITYMANAGER_PROGID,
&rv);
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
rv = securityManager->GetCodebasePrincipal(mURI, getter_AddRefs(mDocumentPrincipal));
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
}
*aResult = mDocumentPrincipal;
NS_ADDREF(*aResult);
return NS_OK;
@ -278,40 +324,43 @@ nsXULPrototypeDocument::SetDocumentPrincipal(nsIPrincipal* aPrincipal)
return NS_OK;
}
JSClass null_class = {
"nsXULPrototypeScript compilation scope", 0,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
};
//----------------------------------------------------------------------
//
// nsIScriptObjectOwner methods
//
NS_IMETHODIMP
nsXULPrototypeDocument::GetScriptObject(nsIScriptContext *aContext, void **aObject)
{
// The prototype document will have its own special secret script
// object that can be used to compile scripts and event handlers.
if (!mScriptObject) {
JSContext *cx = (JSContext *)aContext->GetNativeContext();
if (!cx)
return NS_ERROR_UNEXPECTED;
// The prototype document has its own special secret script object
// that can be used to compile scripts and event handlers.
nsresult rv;
mScriptObject = JS_NewObject(cx, &null_class, nsnull, nsnull);
nsCOMPtr<nsIScriptContext> context;
if (mScriptContext && aContext != mScriptContext.get()) {
rv = GetContext(getter_AddRefs(context));
if (NS_FAILED(rv)) return rv;
}
else {
context = aContext;
}
if (! mScriptObject) {
JSContext* cx = NS_STATIC_CAST(JSContext*, context->GetNativeContext());
if (! cx)
return NS_ERROR_OUT_OF_MEMORY;
mScriptObject = JS_NewObject(cx, &gSharedGlobalClass, nsnull, nsnull);
if (! mScriptObject)
return NS_ERROR_OUT_OF_MEMORY;
// Be sure to unlink the script object from the parent global
// object. This ensures that we don't end up with a circular
// reference back to the first document.
JS_SetPrototype(cx, mScriptObject, nsnull);
JS_SetParent(cx, mScriptObject, nsnull);
JS_AddNamedRoot(cx, &mScriptObject, "nsXULPrototypeDocument::mScriptObject");
// We need standard classes, in particular RegExp, to compile JS.
if (!JS_InitStandardClasses(cx, mScriptObject))
return NS_ERROR_FAILURE;
// Add an owning reference from JS back to us. This'll be
// released when the JSObject is finalized.
::JS_SetPrivate(cx, mScriptObject, this);
NS_ADDREF(this);
}
*aObject = mScriptObject;
return NS_OK;
}
@ -322,3 +371,120 @@ nsXULPrototypeDocument::SetScriptObject(void *aObject)
mScriptObject = (JSObject *)aObject;
return NS_OK;
}
//----------------------------------------------------------------------
//
// nsIScriptGlobalObject methods
//
NS_IMETHODIMP
nsXULPrototypeDocument::SetContext(nsIScriptContext *aContext)
{
mScriptContext = aContext;
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeDocument::GetContext(nsIScriptContext **aContext)
{
if (! mScriptContext) {
nsresult rv;
rv = NS_CreateScriptContext(this, getter_AddRefs(mScriptContext));
if (NS_FAILED(rv)) return rv;
}
*aContext = mScriptContext;
NS_IF_ADDREF(*aContext);
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeDocument::SetNewDocument(nsIDOMDocument *aDocument)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsXULPrototypeDocument::SetWebShell(nsIWebShell *aWebShell)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsXULPrototypeDocument::GetWebShell(nsIWebShell **aWebShell)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsXULPrototypeDocument::SetOpenerWindow(nsIDOMWindow *aOpener)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsXULPrototypeDocument::SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsXULPrototypeDocument::GetGlobalObjectOwner(nsIScriptGlobalObjectOwner** aOwner)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsXULPrototypeDocument::HandleDOMEvent(nsIPresContext* aPresContext,
nsEvent* aEvent,
nsIDOMEvent** aDOMEvent,
PRUint32 aFlags,
nsEventStatus* aEventStatus)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
//----------------------------------------------------------------------
//
// nsIScriptGlobalObjectData methods
//
NS_IMETHODIMP
nsXULPrototypeDocument::GetPrincipal(nsIPrincipal** aPrincipal)
{
return GetDocumentPrincipal(aPrincipal);
}
//----------------------------------------------------------------------
//
// Implementation methods
//
void PR_CALLBACK
nsXULPrototypeDocument::FinalizeScriptObject(JSContext* cx, JSObject* obj)
{
nsXULPrototypeDocument* native =
NS_STATIC_CAST(nsXULPrototypeDocument*, ::JS_GetPrivate(cx, obj));
if (native) {
// Clear the native object's reference back to us, and release
// our ownership of it.
native->SetScriptObject(nsnull);
NS_RELEASE(native);
}
}

Просмотреть файл

@ -90,9 +90,30 @@ class nsIScriptEventHandlerOwner : public nsISupports
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISCRIPTEVENTHANDLEROWNER_IID)
NS_IMETHOD GetCompiledEventHandler(nsIAtom *aName, void** aHandler) = 0;
/**
* Compile the specified event handler, and bind it to aTarget using
* aContext.
*
* @param aContext the context to use when creating event handler
* @param aTarget the object to which to bind the event handler
* @param aName the name of the handler
* @param aBody the handler script body
* @param aHandler the compiled, bound handler object
*/
NS_IMETHOD CompileEventHandler(nsIScriptContext* aContext,
void* aTarget,
nsIAtom *aName,
const nsString& aBody,
void** aHandler) = 0;
NS_IMETHOD SetCompiledEventHandler(nsIAtom *aName, void* aHandler) = 0;
/**
* Retrieve an already-compiled event handler that can be bound to a
* target object using a script context.
*
* @param aName the name of the event handler to retrieve
* @param aHandler the compiled event handler
*/
NS_IMETHOD GetCompiledEventHandler(nsIAtom *aName, void** aHandler) = 0;
};
#endif // nsIScriptObjectOwner_h__

Просмотреть файл

@ -553,13 +553,17 @@ nsEventListenerManager::AddScriptEventListener(nsIScriptContext* aContext,
}
if (!done) {
if (handlerOwner) {
// Always let the handler owner compile the event handler, as
// it may want to use a special context or scope object.
rv = handlerOwner->CompileEventHandler(aContext, scriptObject, aName, aBody, &handler);
}
else {
rv = aContext->CompileEventHandler(scriptObject, aName, aBody,
(handlerOwner != nsnull),
&handler);
if (NS_FAILED(rv))
return rv;
if (handlerOwner)
handlerOwner->SetCompiledEventHandler(aName, handler);
}
if (NS_FAILED(rv)) return rv;
}
}
return SetJSEventListener(aContext, aScriptObjectOwner, aName, aIID, aDeferCompilation);
@ -621,12 +625,19 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
nsAutoString handlerBody;
result = content->GetAttribute(kNameSpaceID_None, atom, handlerBody);
if (NS_SUCCEEDED(result)) {
if (handlerOwner) {
// Always let the handler owner compile the event
// handler, as it may want to use a special
// context or scope object.
result = handlerOwner->CompileEventHandler(scriptCX, jsobj, atom, handlerBody, &handler);
}
else {
result = scriptCX->CompileEventHandler(jsobj, atom, handlerBody,
(handlerOwner != nsnull),
&handler);
}
if (NS_SUCCEEDED(result))
aListenerStruct->mHandlerIsString &= ~aSubType;
if (handlerOwner)
handlerOwner->SetCompiledEventHandler(atom, handler);
}
}
}

Просмотреть файл

@ -113,6 +113,11 @@ public:
*/
NS_IMETHOD SetMasterPrototype(nsIXULPrototypeDocument* aDocument) = 0;
/**
* Get the master prototype.
*/
NS_IMETHOD GetMasterPrototype(nsIXULPrototypeDocument** aPrototypeDocument) = 0;
/**
* Set the current prototype
*/

Просмотреть файл

@ -33,8 +33,8 @@
class nsIAtom;
class nsIPrincipal;
class nsIURI;
class nsIStyleSheet;
class nsIURI;
class nsString;
class nsVoidArray;
class nsXULPrototypeElement;

Просмотреть файл

@ -2108,6 +2108,14 @@ nsXULDocument::SetMasterPrototype(nsIXULPrototypeDocument* aDocument)
return NS_OK;
}
NS_IMETHODIMP
nsXULDocument::GetMasterPrototype(nsIXULPrototypeDocument** aDocument)
{
*aDocument = mMasterPrototype;
NS_IF_ADDREF(*aDocument);
return NS_OK;
}
NS_IMETHODIMP
nsXULDocument::SetCurrentPrototype(nsIXULPrototypeDocument* aDocument)
{
@ -2683,7 +2691,7 @@ nsXULDocument::AddSubtreeToDocument(nsIContent* aElement)
if (NS_FAILED(rv)) return rv;
}
// Finally, recurse to children.
// 4. Recurse to children.
PRInt32 count;
nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(aElement);
rv = xulcontent ? xulcontent->PeekChildCount(count) : aElement->ChildCount(count);
@ -2708,6 +2716,7 @@ nsXULDocument::RemoveSubtreeFromDocument(nsIContent* aElement)
// document.
nsresult rv;
// 1. Remove any children from the document.
PRInt32 count;
nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(aElement);
rv = xulcontent ? xulcontent->PeekChildCount(count) : aElement->ChildCount(count);
@ -2722,11 +2731,11 @@ nsXULDocument::RemoveSubtreeFromDocument(nsIContent* aElement)
if (NS_FAILED(rv)) return rv;
}
// 1. Remove the element from the resource-to-element map
// 2. Remove the element from the resource-to-element map
rv = RemoveElementFromMap(aElement);
if (NS_FAILED(rv)) return rv;
// 2. If the element is a 'command updater', then remove the
// 3. If the element is a 'command updater', then remove the
// element from the document's command dispatcher.
nsAutoString value;
rv = aElement->GetAttribute(kNameSpaceID_None, kCommandUpdaterAtom, value);
@ -3951,10 +3960,9 @@ nsXULDocument::CreateElement(PRInt32 aNameSpaceID,
return NS_ERROR_UNEXPECTED;
}
rv = result->SetDocument(this, PR_FALSE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to set element's document");
if (NS_FAILED(rv)) return rv;
#if 1 // XXXwaterson remove this eventually
result->SetDocument(this, PR_FALSE);
#endif
result->SetContentID(mNextContentID++);
*aResult = result;

Просмотреть файл

@ -285,6 +285,7 @@ public:
NS_IMETHOD AddForwardReference(nsForwardReference* aRef);
NS_IMETHOD ResolveForwardReferences();
NS_IMETHOD SetMasterPrototype(nsIXULPrototypeDocument* aDocument);
NS_IMETHOD GetMasterPrototype(nsIXULPrototypeDocument** aDocument);
NS_IMETHOD SetCurrentPrototype(nsIXULPrototypeDocument* aDocument);
NS_IMETHOD SetDocumentURL(nsIURI* anURL);
NS_IMETHOD PrepareStyleSheets(nsIURI* anURL);

Просмотреть файл

@ -1594,14 +1594,18 @@ nsXULElement::GetScriptObject(nsIScriptContext* aContext, void** aScriptObject)
// tag...
nsresult (*fn)(nsIScriptContext* aContext, nsISupports* aSupports, nsISupports* aParent, void** aReturn);
const char* rootname;
if (Tag() == kTreeAtom) {
fn = NS_NewScriptXULTreeElement;
rootname = "nsXULTreeElement::mScriptObject";
}
else if (Tag() == kEditorAtom) {
fn = NS_NewScriptXULEditorElement;
rootname = "nsXULEditorElement::mScriptObject";
}
else {
fn = NS_NewScriptXULElement;
rootname = "nsXULElement::mScriptObject";
}
// Create the script object; N.B. that if |mDocument| is null,
@ -1611,7 +1615,7 @@ nsXULElement::GetScriptObject(nsIScriptContext* aContext, void** aScriptObject)
rv = fn(aContext, (nsIDOMXULElement*) this, mDocument, (void**) &mScriptObject);
// Ensure that a reference exists to this element
aContext->AddNamedReference((void*) &mScriptObject, mScriptObject, "nsXULElement::mScriptObject");
aContext->AddNamedReference((void*) &mScriptObject, mScriptObject, rootname);
}
*aScriptObject = mScriptObject;
@ -1651,29 +1655,85 @@ nsXULElement::GetCompiledEventHandler(nsIAtom *aName, void** aHandler)
}
NS_IMETHODIMP
nsXULElement::SetCompiledEventHandler(nsIAtom *aName, void* aHandler)
nsXULElement::CompileEventHandler(nsIScriptContext* aContext,
void* aTarget,
nsIAtom *aName,
const nsString& aBody,
void** aHandler)
{
nsresult rv;
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheSets);
nsCOMPtr<nsIScriptContext> context;
JSObject* scopeObject;
PRBool shared;
if (mPrototype) {
// It'll be shared amonst the instances of the prototype
shared = PR_TRUE;
// Use the prototype document's special context
nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mDocument);
NS_ASSERTION(xuldoc != nsnull, "mDocument is not an nsIXULDocument");
if (! xuldoc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIXULPrototypeDocument> protodoc;
rv = xuldoc->GetMasterPrototype(getter_AddRefs(protodoc));
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(protodoc != nsnull, "xul document has no prototype");
if (! protodoc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(protodoc);
NS_ASSERTION(global != nsnull, "prototype doc is not a script global");
if (! global)
return NS_ERROR_UNEXPECTED;
rv = global->GetContext(getter_AddRefs(context));
if (NS_FAILED(rv)) return rv;
// Use the prototype script's special scope object
nsCOMPtr<nsIScriptObjectOwner> owner = do_QueryInterface(protodoc);
if (! owner)
return NS_ERROR_UNEXPECTED;
rv = owner->GetScriptObject(context, (void**) &scopeObject);
if (NS_FAILED(rv)) return rv;
}
else {
// We don't have a prototype; do a one-off compile.
shared = PR_FALSE;
context = aContext;
scopeObject = NS_STATIC_CAST(JSObject*, aTarget);
}
NS_ASSERTION(context != nsnull, "no script context");
if (! context)
return NS_ERROR_UNEXPECTED;
// Compile the event handler
rv = context->CompileEventHandler(scopeObject, aName, aBody, shared, aHandler);
if (NS_FAILED(rv)) return rv;
if (shared) {
// If it's a shared handler, we need to bind the shared
// function object to the real target.
rv = aContext->BindCompiledEventHandler(aTarget, aName, *aHandler);
if (NS_FAILED(rv)) return rv;
}
if (mPrototype) {
// Remember the compiled event handler
for (PRInt32 i = 0; i < mPrototype->mNumAttributes; ++i) {
nsXULPrototypeAttribute* attr = &(mPrototype->mAttributes[i]);
if ((attr->mNameSpaceID == kNameSpaceID_None) &&
(attr->mName.get() == aName)) {
nsresult rv;
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheFills);
attr->mEventHandler = aHandler;
nsCOMPtr<nsIScriptGlobalObject> global;
mDocument->GetScriptGlobalObject(getter_AddRefs(global));
NS_ASSERTION(global != nsnull, "no script global object");
if (! global)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIScriptContext> context;
rv = global->GetContext(getter_AddRefs(context));
if (NS_FAILED(rv)) return rv;
attr->mEventHandler = *aHandler;
JSContext *cx = (JSContext*) context->GetNativeContext();
if (!cx)
@ -1686,6 +1746,7 @@ nsXULElement::SetCompiledEventHandler(nsIAtom *aName, void* aHandler)
}
}
}
return NS_OK;
}
@ -1926,7 +1987,10 @@ nsXULElement::InsertChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify)
if (insertOk) {
aKid->SetParent(NS_STATIC_CAST(nsIStyledContent*, this));
//nsRange::OwnerChildInserted(this, aIndex);
//XXXwaterson this should be shallow
aKid->SetDocument(mDocument, PR_TRUE);
if (aNotify && ElementIsInDocument()) {
mDocument->ContentInserted(NS_STATIC_CAST(nsIStyledContent*, this), aKid, aIndex);
}
@ -1965,10 +2029,21 @@ nsXULElement::ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify)
if (replaceOk) {
aKid->SetParent(NS_STATIC_CAST(nsIStyledContent*, this));
//nsRange::OwnerChildReplaced(this, aIndex, oldKid);
//XXXwaterson this should be shallow
aKid->SetDocument(mDocument, PR_TRUE);
if (aNotify && ElementIsInDocument()) {
mDocument->ContentReplaced(NS_STATIC_CAST(nsIStyledContent*, this), oldKid, aKid, aIndex);
}
#if 0 //XXXwaterson put this in eventually.
// This will cause the script object to be unrooted for each
// element in the subtree.
oldKid->SetDocument(nsnull, PR_TRUE);
#endif
// We've got no mo' parent.
oldKid->SetParent(nsnull);
}
return NS_OK;
@ -1992,7 +2067,10 @@ nsXULElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
if (appendOk) {
aKid->SetParent(NS_STATIC_CAST(nsIStyledContent*, this));
// ranges don't need adjustment since new child is at end of list
//XXXwaterson this should be shallow
aKid->SetDocument(mDocument, PR_TRUE);
if (aNotify && ElementIsInDocument()) {
PRUint32 cnt;
rv = mChildren->Count(&cnt);
@ -2097,6 +2175,14 @@ nsXULElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
if (aNotify && removeOk && ElementIsInDocument()) {
doc->ContentRemoved(NS_STATIC_CAST(nsIStyledContent*, this), oldKid, aIndex);
}
#if 0 //XXXwaterson put this in eventually
// This will cause the script object to be unrooted for each
// element in the subtree.
oldKid->SetDocument(nsnull, PR_TRUE);
#endif
// We've got no mo' parent.
oldKid->SetParent(nsnull);
}
@ -3921,33 +4007,13 @@ nsXULPrototypeScript::~nsXULPrototypeScript()
}
nsresult
nsXULPrototypeScript::Compile(const PRUnichar* aText, PRInt32 aTextLength,
nsIURI* aURI, PRInt32 aLineNo,
nsXULPrototypeScript::Compile(const PRUnichar* aText,
PRInt32 aTextLength,
nsIURI* aURI,
PRInt32 aLineNo,
nsIDocument* aDocument,
nsIXULPrototypeDocument* aPrototypeDocument)
{
nsresult rv;
nsCOMPtr<nsIScriptGlobalObject> global;
aDocument->GetScriptGlobalObject(getter_AddRefs(global));
NS_ASSERTION(global != nsnull, "no script global object");
if (! global)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIScriptContext> context;
rv = global->GetContext(getter_AddRefs(context));
if (NS_FAILED(rv)) return rv;
JSContext *cx = (JSContext*) context->GetNativeContext();
if (!cx)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIPrincipal> principal =
dont_AddRef(aDocument->GetDocumentPrincipal());
nsXPIDLCString urlspec;
aURI->GetSpec(getter_Copies(urlspec));
// We'll compile the script using the prototype document's special
// script object as the parent. This ensures that we won't end up
// with an uncollectable reference.
@ -3959,18 +4025,62 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText, PRInt32 aTextLength,
// and the first document would indirectly reference the prototype
// document because it keeps the prototype cache
// alive. Circularity!
void * scopeObject;
nsCOMPtr<nsIScriptObjectOwner> owner= do_QueryInterface(aPrototypeDocument, &rv);
if (NS_FAILED(rv)) return rv;
nsresult rv;
rv = owner->GetScriptObject(context, &scopeObject);
if (NS_FAILED(rv)) return rv;
// Use the prototype document's special context
nsCOMPtr<nsIScriptContext> context;
rv = context->CompileScript(aText, aTextLength, (JSObject *)scopeObject,
principal, urlspec, aLineNo, mLangVersion,
{
nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(aPrototypeDocument);
NS_ASSERTION(global != nsnull, "prototype doc is not a script global");
if (! global)
return NS_ERROR_UNEXPECTED;
rv = global->GetContext(getter_AddRefs(context));
if (NS_FAILED(rv)) return rv;
}
NS_ASSERTION(context != nsnull, "no context for script global");
if (! context)
return NS_ERROR_UNEXPECTED;
// Use the prototype script's special scope object
JSObject* scopeObject;
{
nsCOMPtr<nsIScriptObjectOwner> owner = do_QueryInterface(aPrototypeDocument);
if (! owner)
return NS_ERROR_UNEXPECTED;
rv = owner->GetScriptObject(context, (void**) &scopeObject);
if (NS_FAILED(rv)) return rv;
}
// Use the enclosing document's principal
// XXX is this right? or should we use the protodoc's?
nsCOMPtr<nsIPrincipal> principal =
dont_AddRef(aDocument->GetDocumentPrincipal());
nsXPIDLCString urlspec;
aURI->GetSpec(getter_Copies(urlspec));
// Ok, compile it to create a prototype script object!
rv = context->CompileScript(aText,
aTextLength,
scopeObject,
principal,
urlspec,
aLineNo,
mLangVersion,
(void**) &mScriptObject);
if (NS_FAILED(rv)) return rv;
// Root the compiled prototype script object.
JSContext* cx = NS_STATIC_CAST(JSContext*, context->GetNativeContext());
if (!cx)
return NS_ERROR_UNEXPECTED;
rv = AddJSGCRoot(cx, &mScriptObject, "nsXULPrototypeScript::mScriptObject");
return rv;
}

Просмотреть файл

@ -463,8 +463,12 @@ public:
NS_IMETHOD SetScriptObject(void *aScriptObject);
// nsIScriptEventHandlerOwner
NS_IMETHOD CompileEventHandler(nsIScriptContext* aContext,
void* aTarget,
nsIAtom *aName,
const nsString& aBody,
void** aHandler);
NS_IMETHOD GetCompiledEventHandler(nsIAtom *aName, void** aHandler);
NS_IMETHOD SetCompiledEventHandler(nsIAtom *aName, void* aHandler);
// nsIJSScriptObject
virtual PRBool AddProperty(JSContext *aContext, JSObject *aObj,

Просмотреть файл

@ -403,7 +403,6 @@ nsXULKeyListenerImpl::Init(
nsIDOMElement * aElement,
nsIDOMDocument * aDocument)
{
printf("nsXULKeyListenerImpl::Init()\n");
element = aElement; // Weak reference. Don't addref it.
nsCOMPtr<nsIDOMXULDocument> xulDoc = do_QueryInterface(aDocument);
@ -1552,12 +1551,14 @@ nsXULKeyListenerImpl::HandleEventUsingKeyset(nsIDOMElement* aKeysetElement, nsID
nsAutoString value;
keyContent->GetAttribute(kNameSpaceID_None, eventName, value);
if (value != "") {
if (handlerOwner) {
handlerOwner->CompileEventHandler(context, scriptObject, eventName, value, &handler);
}
else {
context->CompileEventHandler(scriptObject, eventName, value,
PR_TRUE, &handler);
}
if (handler)
handlerOwner->SetCompiledEventHandler(eventName, handler);
}
}
if (handler) {

Просмотреть файл

@ -27,19 +27,23 @@
*/
#include "nsCOMPtr.h"
#include "nsString2.h"
#include "nsVoidArray.h"
#include "nsIPrincipal.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptGlobalObjectData.h"
#include "nsIScriptSecurityManager.h"
#include "nsIServiceManager.h"
#include "nsISupportsArray.h"
#include "nsIURI.h"
#include "nsIServiceManager.h"
#include "nsIScriptSecurityManager.h"
#include "nsIXULPrototypeDocument.h"
#include "nsString2.h"
#include "nsVoidArray.h"
#include "nsXULElement.h"
#include "nsIJSRuntimeService.h"
class nsXULPrototypeDocument : public nsIXULPrototypeDocument,
public nsIScriptObjectOwner
public nsIScriptObjectOwner,
public nsIScriptGlobalObject,
public nsIScriptGlobalObjectData
{
public:
static nsresult
@ -71,12 +75,33 @@ public:
NS_IMETHOD GetScriptObject(nsIScriptContext *aContext, void **aObject);
NS_IMETHOD SetScriptObject(void *aObject);
// nsIScriptGlobalObject methods
NS_IMETHOD SetContext(nsIScriptContext *aContext);
NS_IMETHOD GetContext(nsIScriptContext **aContext);
NS_IMETHOD SetNewDocument(nsIDOMDocument *aDocument);
NS_IMETHOD SetWebShell(nsIWebShell *aWebShell);
NS_IMETHOD GetWebShell(nsIWebShell **aWebShell);
NS_IMETHOD SetOpenerWindow(nsIDOMWindow *aOpener);
NS_IMETHOD SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner);
NS_IMETHOD GetGlobalObjectOwner(nsIScriptGlobalObjectOwner** aOwner);
NS_IMETHOD HandleDOMEvent(nsIPresContext* aPresContext,
nsEvent* aEvent,
nsIDOMEvent** aDOMEvent,
PRUint32 aFlags,
nsEventStatus* aEventStatus);
// nsIScriptGlobalObjectData methods
NS_IMETHOD GetPrincipal(nsIPrincipal** aPrincipal);
protected:
nsCOMPtr<nsIURI> mURI;
nsXULPrototypeElement* mRoot;
nsCOMPtr<nsISupportsArray> mStyleSheetReferences;
nsCOMPtr<nsISupportsArray> mOverlayReferences;
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
nsCOMPtr<nsIScriptContext> mScriptContext;
JSObject *mScriptObject; // XXX JS language rabies bigotry badness
nsXULPrototypeDocument();
@ -85,13 +110,30 @@ protected:
friend NS_IMETHODIMP
NS_NewXULPrototypeDocument(nsISupports* aOuter, REFNSIID aIID, void** aResult);
static JSClass gSharedGlobalClass;
static void PR_CALLBACK
FinalizeScriptObject(JSContext* cx, JSObject* obj);
};
JSClass nsXULPrototypeDocument::gSharedGlobalClass = {
"nsXULPrototypeScript compilation scope",
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nsXULPrototypeDocument::FinalizeScriptObject
};
//----------------------------------------------------------------------
//
// ctors, dtors, n' stuff
//
nsXULPrototypeDocument::nsXULPrototypeDocument()
: mRoot(nsnull), mScriptObject(nsnull)
: mRoot(nsnull),
mScriptObject(nsnull)
{
NS_INIT_REFCNT();
}
@ -115,19 +157,14 @@ nsXULPrototypeDocument::Init()
nsXULPrototypeDocument::~nsXULPrototypeDocument()
{
delete mRoot;
nsresult rv;
NS_WITH_SERVICE(nsIJSRuntimeService, rtsvc, "nsJSRuntimeService", &rv);
if (NS_SUCCEEDED(rv)) {
JSRuntime *rt;
rv = rtsvc->GetRuntime(&rt);
if (NS_SUCCEEDED(rv) && rt)
JS_RemoveRootRT(rt, &mScriptObject);
}
}
NS_IMPL_ISUPPORTS2(nsXULPrototypeDocument, nsIXULPrototypeDocument, nsIScriptObjectOwner);
NS_IMPL_ISUPPORTS4(nsXULPrototypeDocument,
nsIXULPrototypeDocument,
nsIScriptObjectOwner,
nsIScriptGlobalObject,
nsIScriptGlobalObjectData);
NS_IMETHODIMP
NS_NewXULPrototypeDocument(nsISupports* aOuter, REFNSIID aIID, void** aResult)
@ -156,6 +193,9 @@ NS_NewXULPrototypeDocument(nsISupports* aOuter, REFNSIID aIID, void** aResult)
//----------------------------------------------------------------------
//
// nsIXULPrototypeDocument methods
//
NS_IMETHODIMP
nsXULPrototypeDocument::GetURI(nsIURI** aResult)
@ -169,7 +209,7 @@ nsXULPrototypeDocument::GetURI(nsIURI** aResult)
NS_IMETHODIMP
nsXULPrototypeDocument::SetURI(nsIURI* aURI)
{
mURI = aURI;
mURI = dont_QueryInterface(aURI);
return NS_OK;
}
@ -257,14 +297,20 @@ nsXULPrototypeDocument::GetDocumentPrincipal(nsIPrincipal** aResult)
{
if (!mDocumentPrincipal) {
nsresult rv;
NS_WITH_SERVICE(nsIScriptSecurityManager, securityManager,
NS_SCRIPTSECURITYMANAGER_PROGID, &rv);
NS_WITH_SERVICE(nsIScriptSecurityManager,
securityManager,
NS_SCRIPTSECURITYMANAGER_PROGID,
&rv);
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
rv = securityManager->GetCodebasePrincipal(mURI, getter_AddRefs(mDocumentPrincipal));
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
}
*aResult = mDocumentPrincipal;
NS_ADDREF(*aResult);
return NS_OK;
@ -278,40 +324,43 @@ nsXULPrototypeDocument::SetDocumentPrincipal(nsIPrincipal* aPrincipal)
return NS_OK;
}
JSClass null_class = {
"nsXULPrototypeScript compilation scope", 0,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
};
//----------------------------------------------------------------------
//
// nsIScriptObjectOwner methods
//
NS_IMETHODIMP
nsXULPrototypeDocument::GetScriptObject(nsIScriptContext *aContext, void **aObject)
{
// The prototype document will have its own special secret script
// object that can be used to compile scripts and event handlers.
if (!mScriptObject) {
JSContext *cx = (JSContext *)aContext->GetNativeContext();
if (!cx)
return NS_ERROR_UNEXPECTED;
// The prototype document has its own special secret script object
// that can be used to compile scripts and event handlers.
nsresult rv;
mScriptObject = JS_NewObject(cx, &null_class, nsnull, nsnull);
nsCOMPtr<nsIScriptContext> context;
if (mScriptContext && aContext != mScriptContext.get()) {
rv = GetContext(getter_AddRefs(context));
if (NS_FAILED(rv)) return rv;
}
else {
context = aContext;
}
if (! mScriptObject) {
JSContext* cx = NS_STATIC_CAST(JSContext*, context->GetNativeContext());
if (! cx)
return NS_ERROR_OUT_OF_MEMORY;
mScriptObject = JS_NewObject(cx, &gSharedGlobalClass, nsnull, nsnull);
if (! mScriptObject)
return NS_ERROR_OUT_OF_MEMORY;
// Be sure to unlink the script object from the parent global
// object. This ensures that we don't end up with a circular
// reference back to the first document.
JS_SetPrototype(cx, mScriptObject, nsnull);
JS_SetParent(cx, mScriptObject, nsnull);
JS_AddNamedRoot(cx, &mScriptObject, "nsXULPrototypeDocument::mScriptObject");
// We need standard classes, in particular RegExp, to compile JS.
if (!JS_InitStandardClasses(cx, mScriptObject))
return NS_ERROR_FAILURE;
// Add an owning reference from JS back to us. This'll be
// released when the JSObject is finalized.
::JS_SetPrivate(cx, mScriptObject, this);
NS_ADDREF(this);
}
*aObject = mScriptObject;
return NS_OK;
}
@ -322,3 +371,120 @@ nsXULPrototypeDocument::SetScriptObject(void *aObject)
mScriptObject = (JSObject *)aObject;
return NS_OK;
}
//----------------------------------------------------------------------
//
// nsIScriptGlobalObject methods
//
NS_IMETHODIMP
nsXULPrototypeDocument::SetContext(nsIScriptContext *aContext)
{
mScriptContext = aContext;
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeDocument::GetContext(nsIScriptContext **aContext)
{
if (! mScriptContext) {
nsresult rv;
rv = NS_CreateScriptContext(this, getter_AddRefs(mScriptContext));
if (NS_FAILED(rv)) return rv;
}
*aContext = mScriptContext;
NS_IF_ADDREF(*aContext);
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeDocument::SetNewDocument(nsIDOMDocument *aDocument)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsXULPrototypeDocument::SetWebShell(nsIWebShell *aWebShell)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsXULPrototypeDocument::GetWebShell(nsIWebShell **aWebShell)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsXULPrototypeDocument::SetOpenerWindow(nsIDOMWindow *aOpener)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsXULPrototypeDocument::SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsXULPrototypeDocument::GetGlobalObjectOwner(nsIScriptGlobalObjectOwner** aOwner)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsXULPrototypeDocument::HandleDOMEvent(nsIPresContext* aPresContext,
nsEvent* aEvent,
nsIDOMEvent** aDOMEvent,
PRUint32 aFlags,
nsEventStatus* aEventStatus)
{
NS_NOTREACHED("waaah!");
return NS_ERROR_UNEXPECTED;
}
//----------------------------------------------------------------------
//
// nsIScriptGlobalObjectData methods
//
NS_IMETHODIMP
nsXULPrototypeDocument::GetPrincipal(nsIPrincipal** aPrincipal)
{
return GetDocumentPrincipal(aPrincipal);
}
//----------------------------------------------------------------------
//
// Implementation methods
//
void PR_CALLBACK
nsXULPrototypeDocument::FinalizeScriptObject(JSContext* cx, JSObject* obj)
{
nsXULPrototypeDocument* native =
NS_STATIC_CAST(nsXULPrototypeDocument*, ::JS_GetPrivate(cx, obj));
if (native) {
// Clear the native object's reference back to us, and release
// our ownership of it.
native->SetScriptObject(nsnull);
NS_RELEASE(native);
}
}