Landing XBL brutal sharing from mscott's machine. This is hyatt. The bug has r/sr=hyatt,brendan.

This commit is contained in:
mscott%netscape.com 2001-09-05 07:36:55 +00:00
Родитель 4e50521155
Коммит dfd15deec1
13 изменённых файлов: 576 добавлений и 290 удалений

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

@ -36,6 +36,7 @@ EXPORTS = \
nsIXBLInsertionPoint.h \
nsIXBLPrototypeBinding.h \
nsIXBLPrototypeHandler.h \
nsIXBLPrototypeProperty.h \
nsIXBLService.h \
$(NULL)

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

@ -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

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

@ -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;

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

@ -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 \

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

@ -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 = \

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

@ -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<nsIScriptContext> 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<nsIScriptGlobalObject> 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<nsIDOMScriptObjectFactory> 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<nsIXBLDocumentInfo> docInfo = do_QueryInterface(mGlobalObjectOwner, &rv);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsCOMPtr<nsIDocument> 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<nsIDocument> mDocument;
nsCString mDocURI;
PRBool mScriptAccess;
nsSupportsHashtable* mBindingTable;
nsCOMPtr<nsIScriptGlobalObject> 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<nsIConsoleService> 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<nsIURI> url;

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

@ -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<nsIContent> interfaceElement;
GetImmediateChild(kImplementationAtom, getter_AddRefs(interfaceElement));
// iterate through each property in the prototype's list and install the property.
if (AllowScripts()) {
nsCOMPtr<nsIXBLPrototypeProperty> 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<nsIDocument> document;
mBoundElement->GetDocument(*getter_AddRefs(document));
if (!document)
return NS_OK;
if (!document) return NS_OK;
nsCOMPtr<nsIScriptGlobalObject> global;
document->GetScriptGlobalObject(getter_AddRefs(global));
if (!global)
return NS_OK;
if (!global) return NS_OK;
nsCOMPtr<nsIScriptContext> 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<nsIContent> child;
interfaceElement->ChildAt(i, *getter_AddRefs(child));
// See if we're a property or a method.
nsCOMPtr<nsIAtom> 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<nsIContent> arg;
child->ChildAt(j, *getter_AddRefs(arg));
nsCOMPtr<nsIAtom> 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<nsIContent> textChild;
arg->ChildAt(k, *getter_AddRefs(textChild));
nsCOMPtr<nsIDOMText> 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 <getter> tag
if (getter.IsEmpty()) {
PRInt32 childCount;
child->ChildCount(childCount);
nsCOMPtr<nsIContent> getterElement;
for (PRInt32 j=0; j<childCount; j++) {
child->ChildAt(j, *getter_AddRefs(getterElement));
if (!getterElement) continue;
nsCOMPtr<nsIAtom> 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 <setter> tag
if (setter.IsEmpty()) {
PRInt32 childCount;
child->ChildCount(childCount);
nsCOMPtr<nsIContent> setterElement;
for (PRInt32 j=0; j<childCount; j++) {
child->ChildAt(j, *getter_AddRefs(setterElement));
if (!setterElement) continue;
nsCOMPtr<nsIAtom> 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<nsIContent> 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<nsIDOMText> 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<nsIXBLPrototypeProperty> 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

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

@ -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<nsIContent> 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<nsIContent> 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;
}

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

@ -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<nsIXBLPrototypeHandler> mConstructor; // Strong. Our constructor.
nsCOMPtr<nsIXBLPrototypeHandler> mDestructor; // Strong. Our destructor.
nsCOMPtr<nsIXBLPrototypeProperty> mPrototypeProperty;
nsCOMPtr<nsIXBLPrototypeBinding> 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<nsIAtom> 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.
};

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

@ -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");
}
}

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

@ -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;

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

@ -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<nsIXBLPrototypeProperty> firstProperty;
nsCOMPtr<nsIXBLPrototypeProperty> currProperty;
PRInt32 propertyCount = 0;
aContent->ChildCount(propertyCount);
for (PRInt32 j = 0; j < propertyCount; j++) {
nsCOMPtr<nsIContent> property;
aContent->ChildAt(j, *getter_AddRefs(property));
nsCOMPtr<nsIXBLPrototypeProperty> 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)
{

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

@ -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: