diff --git a/content/xbl/public/Makefile.in b/content/xbl/public/Makefile.in index 7a3543e85a0..b4aff9109e1 100644 --- a/content/xbl/public/Makefile.in +++ b/content/xbl/public/Makefile.in @@ -36,6 +36,7 @@ EXPORTS = \ nsIXBLInsertionPoint.h \ nsIXBLPrototypeBinding.h \ nsIXBLPrototypeHandler.h \ + nsIXBLPrototypeProperty.h \ nsIXBLService.h \ $(NULL) diff --git a/content/xbl/public/makefile.win b/content/xbl/public/makefile.win index 97d3f7ffe7d..71b5d97c21b 100644 --- a/content/xbl/public/makefile.win +++ b/content/xbl/public/makefile.win @@ -26,10 +26,11 @@ EXPORTS = \ nsIXBLBinding.h \ nsIXBLBindingAttachedHandler.h \ nsIXBLDocumentInfo.h \ - nsIXBLInsertionPoint.h \ + nsIXBLInsertionPoint.h \ nsIXBLPrototypeBinding.h \ nsIXBLPrototypeHandler.h \ nsIXBLService.h \ + nsIXBLPrototypeProperty.h \ $(NULL) MODULE=raptor diff --git a/content/xbl/public/nsIXBLPrototypeBinding.h b/content/xbl/public/nsIXBLPrototypeBinding.h index 40355d55ad8..0193f20d91e 100644 --- a/content/xbl/public/nsIXBLPrototypeBinding.h +++ b/content/xbl/public/nsIXBLPrototypeBinding.h @@ -32,8 +32,11 @@ class nsIDocument; class nsIDOMEventReceiver; class nsIXBLDocumentInfo; class nsIXBLPrototypeHandler; +class nsIXBLPrototypeProperty; class nsIXBLBinding; class nsISupportsArray; +class nsCString; +class nsIScriptContext; // {34D700F5-C1A2-4408-A0B1-DD8F891DD1FE} #define NS_IXBLPROTOTYPEBINDING_IID \ @@ -63,6 +66,12 @@ public: NS_IMETHOD GetPrototypeHandlers(nsIXBLPrototypeHandler** aHandler)=0; NS_IMETHOD SetPrototypeHandlers(nsIXBLPrototypeHandler* aHandler)=0; + NS_IMETHOD GetPrototypeProperties(nsIXBLPrototypeProperty** aResult) = 0; + NS_IMETHOD SetProtoTypeProperties(nsIXBLPrototypeProperty* aResult) = 0; + NS_IMETHOD GetCompiledClassObject(const nsCString& aClassName, nsIScriptContext * aContext, void * aScriptObject, void ** aClassObject) = 0; + + NS_IMETHOD InitClass(const nsCString& aClassName, nsIScriptContext * aContext, void * aScriptObject, void ** aClassObject) = 0; + NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag, nsIContent* aChangedElement, nsIContent* aAnonymousContent)=0; diff --git a/content/xbl/src/Makefile.in b/content/xbl/src/Makefile.in index eba7233648c..787ea72cd26 100644 --- a/content/xbl/src/Makefile.in +++ b/content/xbl/src/Makefile.in @@ -33,6 +33,7 @@ REQUIRES = xpcom string js dom widget caps htmlparser necko xpconnect pref docsh CPPSRCS = \ nsXBLBinding.cpp \ nsXBLPrototypeBinding.cpp \ + nsXBLPrototypeProperty.cpp \ nsXBLEventHandler.cpp \ nsXBLWindowHandler.cpp \ nsXBLWindowKeyHandler.cpp \ diff --git a/content/xbl/src/makefile.win b/content/xbl/src/makefile.win index 617f3ad4bf5..03cf74a47c8 100644 --- a/content/xbl/src/makefile.win +++ b/content/xbl/src/makefile.win @@ -48,6 +48,7 @@ CPPSRCS= \ nsXBLPrototypeHandler.cpp \ nsBindingManager.cpp \ nsXBLInsertionPoint.cpp \ + nsXBLPrototypeProperty.cpp \ $(NULL) CPP_OBJS= \ @@ -72,6 +73,7 @@ CPP_OBJS= \ .\$(OBJDIR)\nsXBLService.obj \ .\$(OBJDIR)\nsBindingManager.obj \ .\$(OBJDIR)\nsXBLInsertionPoint.obj \ + .\$(OBJDIR)\nsXBLPrototypeProperty.obj \ $(NULL) EXPORTS = \ diff --git a/content/xbl/src/nsBindingManager.cpp b/content/xbl/src/nsBindingManager.cpp index dbddd546495..34acbdc0871 100644 --- a/content/xbl/src/nsBindingManager.cpp +++ b/content/xbl/src/nsBindingManager.cpp @@ -66,6 +66,15 @@ #include "jsapi.h" #include "nsIXPConnect.h" +#include "nsDOMCID.h" +#include "nsIDOMScriptObjectFactory.h" +#include "nsIPrincipal.h" +#include "nsIScriptGlobalObject.h" +#include "nsIScriptGlobalObjectOwner.h" +#include "nsIScriptObjectPrincipal.h" +#include "nsIConsoleService.h" +#include "nsIScriptError.h" + #include "nsIScriptContext.h" // Static IIDs/CIDs. Try to minimize these. @@ -73,7 +82,260 @@ static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID); static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID); static NS_DEFINE_CID(kParserCID, NS_PARSER_CID); -class nsXBLDocumentInfo : public nsIXBLDocumentInfo, public nsSupportsWeakReference +// an XBLDocumentInfo object has a special context associated with it which we can use to pre-compile properties and methods +// of XBL widgets against..... + + +static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); + + +class nsXBLDocGlobalObject : public nsIScriptGlobalObject, + public nsIScriptObjectPrincipal +{ +public: + nsXBLDocGlobalObject(); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsIScriptGlobalObject methods + NS_IMETHOD SetContext(nsIScriptContext *aContext); + NS_IMETHOD GetContext(nsIScriptContext **aContext); + NS_IMETHOD SetNewDocument(nsIDOMDocument *aDocument); + NS_IMETHOD SetDocShell(nsIDocShell *aDocShell); + NS_IMETHOD GetDocShell(nsIDocShell **aDocShell); + NS_IMETHOD SetOpenerWindow(nsIDOMWindowInternal *aOpener); + NS_IMETHOD SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner); + NS_IMETHOD GetGlobalObjectOwner(nsIScriptGlobalObjectOwner** aOwner); + NS_IMETHOD HandleDOMEvent(nsIPresContext* aPresContext, + nsEvent* aEvent, + nsIDOMEvent** aDOMEvent, + PRUint32 aFlags, + nsEventStatus* aEventStatus); + NS_IMETHOD_(JSObject *) GetGlobalJSObject(); + NS_IMETHOD OnFinalize(JSObject *aObject); + + // nsIScriptObjectPrincipal methods + NS_IMETHOD GetPrincipal(nsIPrincipal** aPrincipal); + +protected: + virtual ~nsXBLDocGlobalObject(); + + nsCOMPtr mScriptContext; + JSObject *mJSObject; // XXX JS language rabies bigotry badness + + nsIScriptGlobalObjectOwner* mGlobalObjectOwner; // weak reference + static JSClass gSharedGlobalClass; +}; + +void PR_CALLBACK nsXBLDocGlobalObject_finalize(JSContext *cx, JSObject *obj) +{ + nsISupports *nativeThis = (nsISupports*)JS_GetPrivate(cx, obj); + + nsCOMPtr sgo(do_QueryInterface(nativeThis)); + + if (sgo) + sgo->OnFinalize(obj); + + // The addref was part of JSObject construction + NS_RELEASE(nativeThis); +} + + +JSBool PR_CALLBACK nsXBLDocGlobalObject_resolve(JSContext *cx, JSObject *obj, jsval id) +{ + JSBool did_resolve = JS_FALSE; + return JS_ResolveStandardClass(cx, obj, id, &did_resolve); +} + + +JSClass nsXBLDocGlobalObject::gSharedGlobalClass = { + "nsXBLPrototypeScript compilation scope", + JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, nsXBLDocGlobalObject_resolve, JS_ConvertStub, + nsXBLDocGlobalObject_finalize +}; + +//---------------------------------------------------------------------- +// +// nsXBLDocGlobalObject +// + +nsXBLDocGlobalObject::nsXBLDocGlobalObject() + : mJSObject(nsnull), + mGlobalObjectOwner(nsnull) +{ + NS_INIT_REFCNT(); +} + + +nsXBLDocGlobalObject::~nsXBLDocGlobalObject() +{} + + +NS_IMPL_ISUPPORTS2(nsXBLDocGlobalObject, nsIScriptGlobalObject, nsIScriptObjectPrincipal) + +//---------------------------------------------------------------------- +// +// nsIScriptGlobalObject methods +// + +NS_IMETHODIMP +nsXBLDocGlobalObject::SetContext(nsIScriptContext *aContext) +{ + mScriptContext = aContext; + return NS_OK; +} + + +NS_IMETHODIMP +nsXBLDocGlobalObject::GetContext(nsIScriptContext **aContext) +{ + // This whole fragile mess is predicated on the fact that + // GetContext() will be called before GetScriptObject() is. + if (! mScriptContext) { + nsCOMPtr factory = do_GetService(kDOMScriptObjectFactoryCID); + NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE); + + nsresult rv = factory->NewScriptContext(nsnull, getter_AddRefs(mScriptContext)); + if (NS_FAILED(rv)) + return rv; + + JSContext *cx = (JSContext *)mScriptContext->GetNativeContext(); + + mJSObject = ::JS_NewObject(cx, &gSharedGlobalClass, nsnull, nsnull); + if (!mJSObject) + return NS_ERROR_OUT_OF_MEMORY; + + ::JS_SetGlobalObject(cx, mJSObject); + + // Add an owning reference from JS back to us. This'll be + // released when the JSObject is finalized. + ::JS_SetPrivate(cx, mJSObject, this); + NS_ADDREF(this); + } + + *aContext = mScriptContext; + NS_IF_ADDREF(*aContext); + return NS_OK; +} + + +NS_IMETHODIMP +nsXBLDocGlobalObject::SetNewDocument(nsIDOMDocument *aDocument) +{ + NS_NOTREACHED("waaah!"); + return NS_ERROR_UNEXPECTED; +} + + +NS_IMETHODIMP +nsXBLDocGlobalObject::SetDocShell(nsIDocShell *aDocShell) +{ + NS_NOTREACHED("waaah!"); + return NS_ERROR_UNEXPECTED; +} + + +NS_IMETHODIMP +nsXBLDocGlobalObject::GetDocShell(nsIDocShell **aDocShell) +{ + NS_WARNING("waaah!"); + return NS_ERROR_UNEXPECTED; +} + + +NS_IMETHODIMP +nsXBLDocGlobalObject::SetOpenerWindow(nsIDOMWindowInternal *aOpener) +{ + NS_NOTREACHED("waaah!"); + return NS_ERROR_UNEXPECTED; +} + + +NS_IMETHODIMP +nsXBLDocGlobalObject::SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner) +{ + mGlobalObjectOwner = aOwner; // weak reference + return NS_OK; +} + + +NS_IMETHODIMP +nsXBLDocGlobalObject::GetGlobalObjectOwner(nsIScriptGlobalObjectOwner** aOwner) +{ + *aOwner = mGlobalObjectOwner; + NS_IF_ADDREF(*aOwner); + return NS_OK; +} + + +NS_IMETHODIMP +nsXBLDocGlobalObject::HandleDOMEvent(nsIPresContext* aPresContext, + nsEvent* aEvent, + nsIDOMEvent** aDOMEvent, + PRUint32 aFlags, + nsEventStatus* aEventStatus) +{ + NS_NOTREACHED("waaah!"); + return NS_ERROR_UNEXPECTED; +} + +NS_IMETHODIMP_(JSObject *) +nsXBLDocGlobalObject::GetGlobalJSObject() +{ + // The prototype document has its own special secret script object + // that can be used to compile scripts and event handlers. + + if (!mScriptContext) + return nsnull; + + JSContext* cx = NS_REINTERPRET_CAST(JSContext*, + mScriptContext->GetNativeContext()); + if (!cx) + return nsnull; + + return ::JS_GetGlobalObject(cx); +} + +NS_IMETHODIMP +nsXBLDocGlobalObject::OnFinalize(JSObject *aObject) +{ + NS_ASSERTION(aObject == mJSObject, "Wrong object finalized!"); + + mJSObject = nsnull; + + return NS_OK; +} + +//---------------------------------------------------------------------- +// +// nsIScriptObjectPrincipal methods +// + +NS_IMETHODIMP +nsXBLDocGlobalObject::GetPrincipal(nsIPrincipal** aPrincipal) +{ + nsresult rv = NS_OK; + if (!mGlobalObjectOwner) { + *aPrincipal = nsnull; + return NS_ERROR_FAILURE; + } + + nsCOMPtr docInfo = do_QueryInterface(mGlobalObjectOwner, &rv); + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + + nsCOMPtr document; + rv = docInfo->GetDocument(getter_AddRefs(document)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + + return document->GetPrincipal(aPrincipal); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// + +class nsXBLDocumentInfo : public nsIXBLDocumentInfo, public nsIScriptGlobalObjectOwner, public nsSupportsWeakReference { public: NS_DECL_ISUPPORTS @@ -91,15 +353,20 @@ public: NS_IMETHOD GetPrototypeBinding(const nsAReadableCString& aRef, nsIXBLPrototypeBinding** aResult); NS_IMETHOD SetPrototypeBinding(const nsAReadableCString& aRef, nsIXBLPrototypeBinding* aBinding); + // nsIScriptGlobalObjectOwner methods + NS_DECL_NSISCRIPTGLOBALOBJECTOWNER + private: nsCOMPtr mDocument; nsCString mDocURI; PRBool mScriptAccess; nsSupportsHashtable* mBindingTable; + + nsCOMPtr mGlobalObject; }; /* Implementation file */ -NS_IMPL_ISUPPORTS2(nsXBLDocumentInfo, nsIXBLDocumentInfo, nsISupportsWeakReference) +NS_IMPL_ISUPPORTS3(nsXBLDocumentInfo, nsIXBLDocumentInfo, nsIScriptGlobalObjectOwner, nsISupportsWeakReference) nsXBLDocumentInfo::nsXBLDocumentInfo(const char* aDocURI, nsIDocument* aDocument) { @@ -114,6 +381,10 @@ nsXBLDocumentInfo::nsXBLDocumentInfo(const char* aDocURI, nsIDocument* aDocument nsXBLDocumentInfo::~nsXBLDocumentInfo() { /* destructor code */ + if (mGlobalObject) { + mGlobalObject->SetContext(nsnull); // remove circular reference + mGlobalObject->SetGlobalObjectOwner(nsnull); // just in case + } delete mBindingTable; } @@ -144,6 +415,45 @@ nsXBLDocumentInfo::SetPrototypeBinding(const nsAReadableCString& aRef, nsIXBLPro return NS_OK; } +//---------------------------------------------------------------------- +// +// nsIScriptGlobalObjectOwner methods +// + +NS_IMETHODIMP +nsXBLDocumentInfo::GetScriptGlobalObject(nsIScriptGlobalObject** _result) +{ + if (!mGlobalObject) { + + mGlobalObject = new nsXBLDocGlobalObject(); + + if (!mGlobalObject) { + *_result = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + mGlobalObject->SetGlobalObjectOwner(this); // does not refcount + } + + *_result = mGlobalObject; + NS_ADDREF(*_result); + return NS_OK; +} + +NS_IMETHODIMP +nsXBLDocumentInfo::ReportScriptError(nsIScriptError *errorObject) +{ + if (errorObject == nsnull) + return NS_ERROR_NULL_POINTER; + + // Get the console service, where we're going to register the error. + nsCOMPtr consoleService (do_GetService("@mozilla.org/consoleservice;1")); + + if (!consoleService) + return NS_ERROR_NOT_AVAILABLE; + return consoleService->LogMessage(errorObject); +} + nsresult NS_NewXBLDocumentInfo(nsIDocument* aDocument, nsIXBLDocumentInfo** aResult) { nsCOMPtr url; diff --git a/content/xbl/src/nsXBLBinding.cpp b/content/xbl/src/nsXBLBinding.cpp index 23d9c767835..c3561d98c81 100644 --- a/content/xbl/src/nsXBLBinding.cpp +++ b/content/xbl/src/nsXBLBinding.cpp @@ -20,6 +20,7 @@ * Original Author: David W. Hyatt (hyatt@netscape.com) * * Contributor(s): Brendan Eich (brendan@mozilla.org) + * Scott MacGregor (mscott@netscape.com) */ #include "nsCOMPtr.h" @@ -53,6 +54,7 @@ #include "nsXBLService.h" #include "nsIXBLInsertionPoint.h" #include "nsIXPConnect.h" +#include "nsIScriptGlobalObjectOwner.h" #include "nsIScriptContext.h" // Event listeners @@ -73,6 +75,7 @@ #include "nsIDOMNamedNodeMap.h" #include "nsIXBLPrototypeHandler.h" +#include "nsIXBLPrototypeProperty.h" #include "nsXBLKeyHandler.h" #include "nsXBLFocusHandler.h" @@ -1054,281 +1057,47 @@ nsXBLBinding::InstallEventHandlers() return NS_OK; } -const char* gPropertyArg[] = { "val" }; - NS_IMETHODIMP nsXBLBinding::InstallProperties() { // Always install the base class properties first, so that // derived classes can reference the base class properties. + if (mNextBinding) mNextBinding->InstallProperties(); - // Fetch the interface element for this binding. - nsCOMPtr interfaceElement; - GetImmediateChild(kImplementationAtom, getter_AddRefs(interfaceElement)); + // iterate through each property in the prototype's list and install the property. + if (AllowScripts()) { + nsCOMPtr propertyChain; + mPrototypeBinding->GetPrototypeProperties(getter_AddRefs(propertyChain)); + + if (!propertyChain) return NS_OK; // kick out if our list is empty - if (interfaceElement && AllowScripts()) { - // Get our bound element's script context. - nsresult rv; nsCOMPtr document; mBoundElement->GetDocument(*getter_AddRefs(document)); - if (!document) - return NS_OK; + if (!document) return NS_OK; nsCOMPtr global; document->GetScriptGlobalObject(getter_AddRefs(global)); - - if (!global) - return NS_OK; + if (!global) return NS_OK; nsCOMPtr context; - rv = global->GetContext(getter_AddRefs(context)); - if (NS_FAILED(rv)) return rv; + nsresult rv = global->GetContext(getter_AddRefs(context)); + NS_ENSURE_SUCCESS(rv, rv); if (!context) return NS_OK; - // Init our class and insert it into the prototype chain. - nsAutoString className; - nsCAutoString classStr; - interfaceElement->GetAttr(kNameSpaceID_None, kNameAtom, className); - if (!className.IsEmpty()) { - classStr.AssignWithConversion(className); - } - else { - GetBindingURI(classStr); - } + void * targetScriptObject = nsnull; + void * targetClassObject = nsnull; + rv = propertyChain->InitTargetObjects(context, mBoundElement, &targetScriptObject, &targetClassObject); + NS_ENSURE_SUCCESS(rv, rv); // kick out if we were unable to properly intialize our target objects - JSObject* scriptObject; - JSObject* classObject; - if (NS_FAILED(rv = InitClass(classStr, context, document, (void**)&scriptObject, (void**)&classObject))) - return rv; - - JSContext* cx = (JSContext*)context->GetNativeContext(); - - // Do a walk. - PRInt32 childCount; - interfaceElement->ChildCount(childCount); - for (PRInt32 i = 0; i < childCount; i++) { - nsCOMPtr child; - interfaceElement->ChildAt(i, *getter_AddRefs(child)); - - // See if we're a property or a method. - nsCOMPtr tagName; - child->GetTag(*getter_AddRefs(tagName)); - - if (tagName.get() == kMethodAtom && classObject) { - // Obtain our name attribute. - nsAutoString name, body; - child->GetAttr(kNameSpaceID_None, kNameAtom, name); - - // Now walk all of our args. - // XXX I'm lame. 32 max args allowed. - char* args[32]; - PRUint32 argCount = 0; - PRInt32 kidCount; - child->ChildCount(kidCount); - for (PRInt32 j = 0; j < kidCount; j++) - { - nsCOMPtr arg; - child->ChildAt(j, *getter_AddRefs(arg)); - nsCOMPtr kidTagName; - arg->GetTag(*getter_AddRefs(kidTagName)); - if (kidTagName.get() == kParameterAtom) { - // Get the argname and add it to the array. - nsAutoString argName; - arg->GetAttr(kNameSpaceID_None, kNameAtom, argName); - char* argStr = argName.ToNewCString(); - args[argCount] = argStr; - argCount++; - } - else if (kidTagName.get() == kBodyAtom) { - PRInt32 textCount; - arg->ChildCount(textCount); - - for (PRInt32 k = 0; k < textCount; k++) { - // Get the child. - nsCOMPtr textChild; - arg->ChildAt(k, *getter_AddRefs(textChild)); - nsCOMPtr text(do_QueryInterface(textChild)); - if (text) { - nsAutoString data; - text->GetData(data); - body += data; - } - } - } - } - - // Now that we have a body and args, compile the function - // and then define it as a property. - if (!body.IsEmpty()) { - void* myFunc; - nsCAutoString cname; cname.AssignWithConversion(name.get()); - nsCAutoString functionUri = classStr; - functionUri += "."; - functionUri += cname; - functionUri += "()"; - - rv = context->CompileFunction(classObject, - cname, - argCount, - (const char**)args, - body, - functionUri.get(), - 0, - PR_FALSE, - &myFunc); - } - for (PRUint32 l = 0; l < argCount; l++) { - nsMemory::Free(args[l]); - } - } - else if (tagName.get() == kPropertyAtom) { - // Obtain our name attribute. - nsAutoString name; - child->GetAttr(kNameSpaceID_None, kNameAtom, name); - - if (!name.IsEmpty()) { - // We have a property. - nsAutoString getter, setter, readOnly; - child->GetAttr(kNameSpaceID_None, kOnGetAtom, getter); - child->GetAttr(kNameSpaceID_None, kOnSetAtom, setter); - child->GetAttr(kNameSpaceID_None, kReadOnlyAtom, readOnly); - - void* getFunc = nsnull; - void* setFunc = nsnull; - uintN attrs = JSPROP_ENUMERATE; - - if (readOnly == NS_LITERAL_STRING("true")) - attrs |= JSPROP_READONLY; - - // try for first tag - if (getter.IsEmpty()) { - PRInt32 childCount; - child->ChildCount(childCount); - - nsCOMPtr getterElement; - for (PRInt32 j=0; jChildAt(j, *getter_AddRefs(getterElement)); - - if (!getterElement) continue; - - nsCOMPtr getterTag; - getterElement->GetTag(*getter_AddRefs(getterTag)); - - if (getterTag.get() == kGetterAtom) { - GetTextData(getterElement, getter); - break; // stop at first tag - } - } - - } - - if (!getter.IsEmpty() && classObject) { - nsCAutoString functionUri = classStr; - functionUri += "."; - functionUri.AppendWithConversion(name.get()); - functionUri += " (getter)"; - rv = context->CompileFunction(classObject, - nsCAutoString("onget"), - 0, - nsnull, - getter, - functionUri.get(), - 0, - PR_FALSE, - &getFunc); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - attrs |= JSPROP_GETTER | JSPROP_SHARED; - } - - // try for first tag - if (setter.IsEmpty()) { - PRInt32 childCount; - child->ChildCount(childCount); - - nsCOMPtr setterElement; - for (PRInt32 j=0; jChildAt(j, *getter_AddRefs(setterElement)); - - if (!setterElement) continue; - - nsCOMPtr setterTag; - setterElement->GetTag(*getter_AddRefs(setterTag)); - if (setterTag.get() == kSetterAtom) { - GetTextData(setterElement, setter); - break; // stop at first tag - } - } - } - - if (!setter.IsEmpty() && classObject) { - nsCAutoString functionUri = classStr; - functionUri += "."; - functionUri.AppendWithConversion(name.get()); - functionUri += " (setter)"; - rv = context->CompileFunction(classObject, - nsCAutoString("onset"), - 1, - gPropertyArg, - setter, - functionUri.get(), - 0, - PR_FALSE, - &setFunc); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - attrs |= JSPROP_SETTER | JSPROP_SHARED; - } - - if ((getFunc || setFunc) && classObject) { - // Having either a getter or setter results in the - // destruction of any initial value that might be set. - // This means we only have to worry about defining the getter - // or setter. - ::JS_DefineUCProperty(cx, (JSObject*)classObject, NS_REINTERPRET_CAST(const jschar*, name.get()), - name.Length(), JSVAL_VOID, - (JSPropertyOp) getFunc, - (JSPropertyOp) setFunc, - attrs); - } else { - // Look for a normal value and just define that. - nsCOMPtr textChild; - PRInt32 textCount; - child->ChildCount(textCount); - nsAutoString answer; - for (PRInt32 j = 0; j < textCount; j++) { - // Get the child. - child->ChildAt(j, *getter_AddRefs(textChild)); - nsCOMPtr text(do_QueryInterface(textChild)); - if (text) { - nsAutoString data; - text->GetData(data); - answer += data; - } - } - - if (!answer.IsEmpty()) { - // Evaluate our script and obtain a value. - jsval result = nsnull; - PRBool undefined; - rv = context->EvaluateStringWithValue(answer, - scriptObject, - nsnull, nsnull, 0, nsnull, - (void*) &result, &undefined); - - if (!undefined) { - // Define that value as a property - ::JS_DefineUCProperty(cx, (JSObject*)scriptObject, NS_REINTERPRET_CAST(const jschar*, name.get()), - name.Length(), result, - nsnull, nsnull, - attrs); - } - } - } - } - } - } + nsCOMPtr curr = propertyChain; + do { + curr->InstallProperty(context, mBoundElement, targetScriptObject, targetClassObject); + curr->GetNextProperty(getter_AddRefs(propertyChain)); + curr = propertyChain; + } while (curr); } return NS_OK; @@ -1441,8 +1210,11 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen // XXX Sanity check to make sure our class name matches // Pull ourselves out of the proto chain. JSObject* ourProto = ::JS_GetPrototype(jscontext, scriptObject); - JSObject* grandProto = ::JS_GetPrototype(jscontext, ourProto); - ::JS_SetPrototype(jscontext, scriptObject, grandProto); + if (ourProto) + { + JSObject* grandProto = ::JS_GetPrototype(jscontext, ourProto); + ::JS_SetPrototype(jscontext, scriptObject, grandProto); + } // Don't remove the reference from the document to the // wrapper here since it'll be removed by the element diff --git a/content/xbl/src/nsXBLPrototypeBinding.cpp b/content/xbl/src/nsXBLPrototypeBinding.cpp index 97bacf79ec4..ee9deb8a999 100644 --- a/content/xbl/src/nsXBLPrototypeBinding.cpp +++ b/content/xbl/src/nsXBLPrototypeBinding.cpp @@ -58,6 +58,8 @@ #include "nsHTMLAtoms.h" #include "nsXULAtoms.h" +#include "nsIScriptContext.h" + #include "nsICSSLoader.h" #include "nsIStyleRuleProcessor.h" @@ -250,11 +252,10 @@ static const PRInt32 kInsInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLInsertionPoi // Implementation ///////////////////////////////////////////////////////////////// // Implement our nsISupports methods -NS_IMPL_ISUPPORTS2(nsXBLPrototypeBinding, nsIXBLPrototypeBinding, nsICSSLoaderObserver) +NS_IMPL_ISUPPORTS3(nsXBLPrototypeBinding, nsIXBLPrototypeBinding, nsICSSLoaderObserver, nsISupportsWeakReference) // Constructors/Destructors -nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIContent* aElement, - nsIXBLDocumentInfo* aInfo) +nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIXBLDocumentInfo* aInfo) : mID(aID), mInheritStyle(PR_TRUE), mHasBaseProto(PR_TRUE), @@ -264,7 +265,8 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIC mAttributeTable(nsnull), mInsertionPointTable(nsnull), mInterfaceTable(nsnull), - mStyleSheetList(nsnull) + mStyleSheetList(nsnull), + mClassObject(nsnull) { NS_INIT_REFCNT(); @@ -297,7 +299,10 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIC kImplementationAtom = NS_NewAtom("implementation"); kImplementsAtom = NS_NewAtom("implements"); } +} +void nsXBLPrototypeBinding::Initialize(nsIContent * aElement, nsIXBLDocumentInfo* aInfo) +{ // These all use atoms, so we have to do these ops last to ensure // the atoms exist. SetBindingElement(aElement); @@ -306,6 +311,7 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIC aInfo->GetScriptAccess(&allowScripts); if (allowScripts) { ConstructHandlers(); + ConstructProperties(); } nsCOMPtr content; @@ -321,7 +327,6 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIC ConstructInterfaceTable(impl); } - nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void) { delete mAttributeTable; @@ -617,6 +622,21 @@ nsXBLPrototypeBinding::SetPrototypeHandlers(nsIXBLPrototypeHandler* aHandler) return NS_OK; } +NS_IMETHODIMP +nsXBLPrototypeBinding::GetPrototypeProperties(nsIXBLPrototypeProperty ** aResult) +{ + *aResult = mPrototypeProperty; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsXBLPrototypeBinding::SetProtoTypeProperties(nsIXBLPrototypeProperty* aResult) +{ + mPrototypeProperty = aResult; + return NS_OK; +} + NS_IMETHODIMP nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag, nsIContent* aChangedElement, nsIContent* aAnonymousContent) @@ -933,6 +953,120 @@ nsXBLPrototypeBinding::GetImmediateChild(nsIAtom* aTag, nsIContent** aResult) return; } +void +nsXBLPrototypeBinding::ConstructProperties() +{ + nsCOMPtr properties; + GetImmediateChild(kImplementationAtom, getter_AddRefs(properties)); + if (properties && mBinding) { + nsXBLService::BuildPropertyChain(this, properties, getter_AddRefs(mPrototypeProperty)); + } +} + +NS_IMETHODIMP +nsXBLPrototypeBinding::GetCompiledClassObject(const nsCString& aClassName, nsIScriptContext * aContext, void * aScriptObject, void ** aClassObject) +{ + if (mClassObject) { + *aClassObject = mClassObject; + return NS_OK; + } + + InitClass(aClassName, aContext, aScriptObject, &mClassObject); + *aClassObject = mClassObject; + + return NS_OK; +} + +NS_IMETHODIMP +nsXBLPrototypeBinding::InitClass(const nsCString& aClassName, nsIScriptContext * aContext, void * aScriptObject, void ** aClassObject) +{ + NS_ENSURE_ARG_POINTER (aClassObject); + + *aClassObject = nsnull; + + JSContext* jscontext = (JSContext*)aContext->GetNativeContext(); + JSObject* global = ::JS_GetGlobalObject(jscontext); + JSObject* scriptObject = (JSObject*) aScriptObject; + + // First ensure our JS class is initialized. + jsval vp; + JSObject* proto; + + if ((! ::JS_LookupProperty(jscontext, global, aClassName, &vp)) || JSVAL_IS_PRIMITIVE(vp)) { + // We need to initialize the class. + nsXBLJSClass* c; + void* classObject; + nsCStringKey key(aClassName); + classObject = (nsXBLService::gClassTable)->Get(&key); + + if (classObject) { + c = NS_STATIC_CAST(nsXBLJSClass*, classObject); + // If c is on the LRU list (i.e., not linked to itself), remove it now! + JSCList* link = NS_STATIC_CAST(JSCList*, c); + if (c->next != link) { + JS_REMOVE_AND_INIT_LINK(link); + nsXBLService::gClassLRUListLength--; + } + } + else { + if (JS_CLIST_IS_EMPTY(&nsXBLService::gClassLRUList)) { + // We need to create a struct for this class. + c = new nsXBLJSClass(aClassName); + if (!c) + return NS_ERROR_OUT_OF_MEMORY; + } + else { + // Pull the least recently used class struct off the list. + JSCList* lru = (nsXBLService::gClassLRUList).next; + JS_REMOVE_AND_INIT_LINK(lru); + nsXBLService::gClassLRUListLength--; + + // Remove any mapping from the old name to the class struct. + c = NS_STATIC_CAST(nsXBLJSClass*, lru); + nsCStringKey oldKey(c->name); + (nsXBLService::gClassTable)->Remove(&oldKey); + + // Change the class name and we're done. + nsMemory::Free((void*) c->name); + c->name = aClassName.ToNewCString(); + } + + // Add c to our table. + (nsXBLService::gClassTable)->Put(&key, (void*)c); + } + + // Retrieve the current prototype of the JS object. + JSObject* parent_proto = ::JS_GetPrototype(jscontext, scriptObject); + + // Make a new object prototyped by parent_proto and parented by global. + proto = ::JS_InitClass(jscontext, // context + global, // global object + parent_proto, // parent proto + c, // JSClass + NULL, // JSNative ctor + 0, // ctor args + nsnull, // proto props + nsnull, // proto funcs + nsnull, // ctor props (static) + nsnull); // ctor funcs (static) + if (!proto) { + (nsXBLService::gClassTable)->Remove(&key); + delete c; + return NS_ERROR_OUT_OF_MEMORY; + } + + // The prototype holds a strong reference to its class struct. + c->Hold(); + *aClassObject = (void *) proto; + } + else + proto = JSVAL_TO_OBJECT(vp); + + ::JS_SetPrototype(jscontext, scriptObject, proto); + + return NS_OK; +} + void nsXBLPrototypeBinding::ConstructHandlers() { @@ -1520,10 +1654,13 @@ nsresult NS_NewXBLPrototypeBinding(const nsAReadableCString& aRef, nsIContent* aElement, nsIXBLDocumentInfo* aInfo, nsIXBLPrototypeBinding** aResult) { - *aResult = new nsXBLPrototypeBinding(aRef, aElement, aInfo); - if (!*aResult) + nsXBLPrototypeBinding * binding = new nsXBLPrototypeBinding(aRef, aInfo); + if (!binding) return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(*aResult); + + binding->QueryInterface(NS_GET_IID(nsIXBLPrototypeBinding), (void **) aResult); + binding->Initialize(aElement, aInfo); + return NS_OK; } diff --git a/content/xbl/src/nsXBLPrototypeBinding.h b/content/xbl/src/nsXBLPrototypeBinding.h index e5cd712dd60..f25a78032c4 100644 --- a/content/xbl/src/nsXBLPrototypeBinding.h +++ b/content/xbl/src/nsXBLPrototypeBinding.h @@ -25,8 +25,10 @@ #include "nsCOMPtr.h" #include "nsIXBLPrototypeBinding.h" #include "nsIXBLPrototypeHandler.h" +#include "nsIXBLPrototypeProperty.h" #include "nsICSSStyleSheet.h" #include "nsICSSLoaderObserver.h" +#include "nsWeakReference.h" class nsIContent; class nsIAtom; @@ -40,7 +42,7 @@ class nsFixedSizeAllocator; // *********************************************************************/ // The XBLPrototypeBinding class -class nsXBLPrototypeBinding: public nsIXBLPrototypeBinding, public nsICSSLoaderObserver +class nsXBLPrototypeBinding: public nsIXBLPrototypeBinding, public nsICSSLoaderObserver, public nsSupportsWeakReference { NS_DECL_ISUPPORTS @@ -67,6 +69,11 @@ class nsXBLPrototypeBinding: public nsIXBLPrototypeBinding, public nsICSSLoaderO NS_IMETHOD GetPrototypeHandlers(nsIXBLPrototypeHandler** aHandler); NS_IMETHOD SetPrototypeHandlers(nsIXBLPrototypeHandler* aHandler); + NS_IMETHOD GetPrototypeProperties(nsIXBLPrototypeProperty** aResult); + NS_IMETHOD SetProtoTypeProperties(nsIXBLPrototypeProperty* aResult); + NS_IMETHOD GetCompiledClassObject(const nsCString& aClassName, nsIScriptContext * aContext, void * aScriptObject, void ** aClassObject); + NS_IMETHOD InitClass(const nsCString& aClassName, nsIScriptContext * aContext, void * aScriptObject, void ** aClassObject); + NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag, nsIContent* aChangedElement, nsIContent* aAnonymousContent); @@ -108,10 +115,11 @@ class nsXBLPrototypeBinding: public nsIXBLPrototypeBinding, public nsICSSLoaderO NS_IMETHOD GetConstructor(nsIXBLPrototypeHandler** aResult) { *aResult = mConstructor; NS_IF_ADDREF(*aResult); return NS_OK; }; public: - nsXBLPrototypeBinding(const nsAReadableCString& aRef, nsIContent* aElement, - nsIXBLDocumentInfo* aInfo); + nsXBLPrototypeBinding(const nsAReadableCString& aRef, nsIXBLDocumentInfo* aInfo); virtual ~nsXBLPrototypeBinding(); + void Initialize(nsIContent * aElement, nsIXBLDocumentInfo* aInfo); + // Static members static PRUint32 gRefCnt; static nsIAtom* kInheritStyleAtom; @@ -143,6 +151,7 @@ public: protected: void ConstructHandlers(); + void ConstructProperties(); void ConstructAttributeTable(nsIContent* aElement); void ConstructInsertionTable(nsIContent* aElement); void ConstructInterfaceTable(nsIContent* aElement); @@ -182,6 +191,8 @@ protected: nsCOMPtr mConstructor; // Strong. Our constructor. nsCOMPtr mDestructor; // Strong. Our destructor. + nsCOMPtr mPrototypeProperty; + nsCOMPtr mBaseBinding; // Strong. We own the base binding in our explicit inheritance chain. PRPackedBool mInheritStyle; PRPackedBool mHasBaseProto; @@ -206,4 +217,6 @@ protected: PRInt32 mBaseNameSpaceID; // If we extend a tagname/namespace, then that information will nsCOMPtr mBaseTag; // be stored in here. + + void * mClassObject; // the class object for the binding. We'll use this to pre-compile properties and methods for the binding. }; diff --git a/content/xbl/src/nsXBLPrototypeProperty.cpp b/content/xbl/src/nsXBLPrototypeProperty.cpp index 73e30bf25aa..6527a07668f 100644 --- a/content/xbl/src/nsXBLPrototypeProperty.cpp +++ b/content/xbl/src/nsXBLPrototypeProperty.cpp @@ -107,7 +107,7 @@ RemoveJSGCRoot(void* aScriptObjectRef) } nsXBLPrototypeProperty::nsXBLPrototypeProperty(nsIXBLPrototypeBinding * aPrototypeBinding) -: mJSMethod(nsnull), mJSGetterObject(nsnull), mJSSetterObject(nsnull), mPropertyIsCompiled(PR_FALSE) +: mJSMethodObject(nsnull), mJSGetterObject(nsnull), mJSSetterObject(nsnull), mPropertyIsCompiled(PR_FALSE) { NS_INIT_REFCNT(); mClassObject = nsnull; @@ -132,8 +132,8 @@ nsXBLPrototypeProperty::nsXBLPrototypeProperty(nsIXBLPrototypeBinding * aPrototy nsXBLPrototypeProperty::~nsXBLPrototypeProperty() { - if (mJSMethod) - RemoveJSGCRoot(&mJSMethod); + if (mJSMethodObject) + RemoveJSGCRoot(&mJSMethodObject); if (mJSGetterObject) RemoveJSGCRoot(&mJSGetterObject); if (mJSSetterObject) @@ -232,13 +232,16 @@ nsXBLPrototypeProperty::InstallProperty(nsIScriptContext * aContext, nsIContent JSContext* cx = (JSContext*) aContext->GetNativeContext(); JSObject * scriptObject = (JSObject *) aScriptObject; + NS_ASSERTION(scriptObject, "uhoh, script Object should NOT be null or bad things will happen"); + JSObject * targetClassObject = (JSObject *) aTargetClassObject; + JSObject * globalObject = ::JS_GetGlobalObject(cx); // now we want to re-evaluate our property using aContext and the script object for this window... - if (mJSMethod && targetClassObject) + if (mJSMethodObject && targetClassObject) { - JSObject * method = ::JS_CloneFunctionObject(cx, (JSObject *) mJSMethod, JS_GetGlobalObject(cx)); + JSObject * method = ::JS_CloneFunctionObject(cx, mJSMethodObject, globalObject); ::JS_DefineUCProperty(cx, targetClassObject, NS_REINTERPRET_CAST(const jschar*, mName.get()), mName.Length(), OBJECT_TO_JSVAL(method), NULL, NULL, JSPROP_ENUMERATE); @@ -253,11 +256,11 @@ nsXBLPrototypeProperty::InstallProperty(nsIScriptContext * aContext, nsIContent JSObject * getter = nsnull; if (mJSGetterObject) - getter = ::JS_CloneFunctionObject(cx, (JSObject *) mJSGetterObject, JS_GetGlobalObject(cx)); + getter = ::JS_CloneFunctionObject(cx, mJSGetterObject, globalObject); JSObject * setter = nsnull; if (mJSSetterObject) - setter = ::JS_CloneFunctionObject(cx, (JSObject *) mJSSetterObject, JS_GetGlobalObject(cx)); + setter = ::JS_CloneFunctionObject(cx, mJSSetterObject, globalObject); ::JS_DefineUCProperty(cx, targetClassObject, NS_REINTERPRET_CAST(const jschar*, mName.get()), mName.Length(), JSVAL_VOID, (JSPropertyOp) getter, @@ -269,9 +272,9 @@ nsXBLPrototypeProperty::InstallProperty(nsIScriptContext * aContext, nsIContent jsval result = nsnull; PRBool undefined; aContext->EvaluateStringWithValue(mLiteralPropertyString, - scriptObject, - nsnull, nsnull, 0, nsnull, - (void*) &result, &undefined); + scriptObject, + nsnull, nsnull, 0, nsnull, + (void*) &result, &undefined); if (!undefined) { @@ -419,7 +422,7 @@ nsresult nsXBLPrototypeProperty::ParseProperty(nsIScriptContext * aContext, nsIC functionUri.get(), 0, PR_FALSE, - &mJSGetterObject); + (void **) &mJSGetterObject); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED; if (mJSGetterObject) @@ -471,7 +474,7 @@ nsresult nsXBLPrototypeProperty::ParseProperty(nsIScriptContext * aContext, nsIC functionUri.get(), 0, PR_FALSE, - &mJSSetterObject); + (void **) &mJSSetterObject); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED; if (mJSSetterObject) @@ -589,17 +592,16 @@ nsresult nsXBLPrototypeProperty::ParseMethod(nsIScriptContext * aContext, nsICon functionUri.get(), 0, PR_FALSE, - &mJSMethod); + (void **) &mJSMethodObject); - if (mJSMethod) + if (mJSMethodObject) { // Root the compiled prototype script object. JSContext* cx = NS_REINTERPRET_CAST(JSContext*, aContext->GetNativeContext()); if (!cx) return NS_ERROR_UNEXPECTED; - rv = AddJSGCRoot(&mJSMethod, "nsXBLPrototypeProperty::mJSMethod"); - if (NS_FAILED(rv)) return rv; + rv = AddJSGCRoot(&mJSMethodObject, "nsXBLPrototypeProperty::mJSMethod"); } } diff --git a/content/xbl/src/nsXBLPrototypeProperty.h b/content/xbl/src/nsXBLPrototypeProperty.h index 96f3c797ff5..11aee568c60 100644 --- a/content/xbl/src/nsXBLPrototypeProperty.h +++ b/content/xbl/src/nsXBLPrototypeProperty.h @@ -68,9 +68,9 @@ protected: static nsIAtom* kNameAtom; static nsIAtom* kReadOnlyAtom; - void * mJSMethod; // precompiled JS for a method - void * mJSGetterObject; // precompiled JS for a getter property - void * mJSSetterObject; // precompiled JS for a setter property + JSObject * mJSMethodObject; // precompiled JS for a method + JSObject * mJSGetterObject; // precompiled JS for a getter property + JSObject * mJSSetterObject; // precompiled JS for a setter property nsString mLiteralPropertyString; // the property is just a literal string JSObject* mClassObject; diff --git a/content/xbl/src/nsXBLService.cpp b/content/xbl/src/nsXBLService.cpp index 57fa7b077b0..1c2c7513c3f 100644 --- a/content/xbl/src/nsXBLService.cpp +++ b/content/xbl/src/nsXBLService.cpp @@ -62,6 +62,7 @@ #include "nsIXBLDocumentInfo.h" #include "nsIXBLPrototypeHandler.h" +#include "nsIXBLPrototypeProperty.h" #include "nsIChromeRegistry.h" #include "nsIPref.h" @@ -1398,6 +1399,40 @@ static void GetImmediateChild(nsIAtom* aTag, nsIContent* aParent, nsIContent** a } } +nsresult +nsXBLService::BuildPropertyChain(nsIXBLPrototypeBinding * aPrototypeBinding, nsIContent * aContent, nsIXBLPrototypeProperty ** aResult) +{ + nsCOMPtr firstProperty; + nsCOMPtr currProperty; + PRInt32 propertyCount = 0; + aContent->ChildCount(propertyCount); + + for (PRInt32 j = 0; j < propertyCount; j++) { + nsCOMPtr property; + aContent->ChildAt(j, *getter_AddRefs(property)); + + nsCOMPtr newProperty; + NS_NewXBLPrototypeProperty(aPrototypeBinding, getter_AddRefs(newProperty)); + + if (!newProperty) return NS_ERROR_FAILURE; + + newProperty->ConstructProperty(aContent, property); + + if (newProperty) { + if (currProperty) + currProperty->SetNextProperty(newProperty); + else + firstProperty = newProperty; + currProperty = newProperty; + } + } + + *aResult = firstProperty; + NS_IF_ADDREF(*aResult); + + return NS_OK; +} + nsresult nsXBLService::BuildHandlerChain(nsIContent* aContent, nsIXBLPrototypeHandler** aResult) { diff --git a/content/xbl/src/nsXBLService.h b/content/xbl/src/nsXBLService.h index b7429c597fc..64fb7935545 100644 --- a/content/xbl/src/nsXBLService.h +++ b/content/xbl/src/nsXBLService.h @@ -36,6 +36,8 @@ class nsIXBLBinding; class nsIXBLDocumentInfo; class nsIXBLPrototypeHandler; +class nsIXBLPrototypeBinding; +class nsIXBLPrototypeProperty; class nsINameSpaceManager; class nsIContent; class nsIDocument; @@ -102,6 +104,7 @@ public: // that contain only whitespace. static nsresult StripWhitespaceNodes(nsIContent* aContent); static nsresult BuildHandlerChain(nsIContent* aContent, nsIXBLPrototypeHandler** aResult); + static nsresult BuildPropertyChain(nsIXBLPrototypeBinding * aPrototypeBinding, nsIContent * aContent, nsIXBLPrototypeProperty ** aResult); // MEMBER VARIABLES public: