зеркало из https://github.com/mozilla/pjs.git
NOT PART OF THE BUILD YET.
Adding new interface for xbl brutal sharing. Bug #70647
This commit is contained in:
Родитель
12e7bd8482
Коммит
09345030fd
|
@ -0,0 +1,58 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Original Author: Scott MacGregor (mscott@netscape.com)
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Private interface to the XBL PrototypeProperty
|
||||
|
||||
*/
|
||||
|
||||
#ifndef nsIXBLPrototypeProperty_h__
|
||||
#define nsIXBLPrototypeProperty_h__
|
||||
|
||||
class nsIContent;
|
||||
class nsIScriptContext;
|
||||
class nsIXBLPrototypeBinding;
|
||||
|
||||
// {FDDD1C5C-F47C-4b10-9CBC-34E087D1279A}
|
||||
#define NS_IXBLPROTOTYPEPROPERTY_IID \
|
||||
{ 0xfddd1c5c, 0xf47c, 0x4b10, { 0x9c, 0xbc, 0x34, 0xe0, 0x87, 0xd1, 0x27, 0x9a } }
|
||||
|
||||
class nsIXBLPrototypeProperty : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IXBLPROTOTYPEPROPERTY_IID)
|
||||
|
||||
NS_IMETHOD GetNextProperty(nsIXBLPrototypeProperty** aProperty) = 0;
|
||||
NS_IMETHOD SetNextProperty(nsIXBLPrototypeProperty* aProperty) = 0;
|
||||
|
||||
NS_IMETHOD ConstructProperty(nsIContent * aInterfaceElement, nsIContent* aPropertyElement) = 0;
|
||||
NS_IMETHOD InstallProperty(nsIScriptContext * aContext, nsIContent *aBoundElement, void * aScriptObject, void * aTargetClassObject) = 0;
|
||||
NS_IMETHOD InitTargetObjects(nsIScriptContext * aContext, nsIContent * aBoundElement, void ** aScriptObject, void ** aTargetClassObject) = 0;
|
||||
};
|
||||
|
||||
extern nsresult
|
||||
NS_NewXBLPrototypeProperty(nsIXBLPrototypeBinding * aPrototypeBinding, nsIXBLPrototypeProperty ** aResult);
|
||||
|
||||
#endif // nsIXBLPrototypeProperty_h__
|
|
@ -0,0 +1,645 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Original Author: Scott MacGregor (mscott@netscape.com)
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsXBLPrototypeProperty.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIScriptGlobalObjectOwner.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIPref.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsXULAtoms.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIDOMScriptObjectFactory.h"
|
||||
#include "nsINameSpaceManager.h"
|
||||
#include "nsXBLService.h"
|
||||
#include "nsIXBLDocumentInfo.h"
|
||||
#include "nsIDOMText.h"
|
||||
|
||||
PRUint32 nsXBLPrototypeProperty::gRefCnt = 0;
|
||||
|
||||
nsIAtom* nsXBLPrototypeProperty::kMethodAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeProperty::kParameterAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeProperty::kBodyAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeProperty::kPropertyAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeProperty::kOnSetAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeProperty::kOnGetAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeProperty::kGetterAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeProperty::kSetterAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeProperty::kNameAtom = nsnull;
|
||||
nsIAtom* nsXBLPrototypeProperty::kReadOnlyAtom = nsnull;
|
||||
|
||||
#include "nsIJSRuntimeService.h"
|
||||
static nsIJSRuntimeService* gJSRuntimeService = nsnull;
|
||||
static JSRuntime* gScriptRuntime = nsnull;
|
||||
static PRInt32 gScriptRuntimeRefcnt = 0;
|
||||
|
||||
static nsresult
|
||||
AddJSGCRoot(void* aScriptObjectRef, const char* aName)
|
||||
{
|
||||
if (++gScriptRuntimeRefcnt == 1 || !gScriptRuntime) {
|
||||
CallGetService("@mozilla.org/js/xpc/RuntimeService;1",
|
||||
&gJSRuntimeService);
|
||||
if (! gJSRuntimeService) {
|
||||
NS_NOTREACHED("couldn't add GC root");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
gJSRuntimeService->GetRuntime(&gScriptRuntime);
|
||||
if (! gScriptRuntime) {
|
||||
NS_NOTREACHED("couldn't add GC root");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool ok;
|
||||
ok = ::JS_AddNamedRootRT(gScriptRuntime, aScriptObjectRef, aName);
|
||||
if (! ok) {
|
||||
NS_NOTREACHED("couldn't add GC root");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
RemoveJSGCRoot(void* aScriptObjectRef)
|
||||
{
|
||||
if (! gScriptRuntime) {
|
||||
NS_NOTREACHED("couldn't remove GC root");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
::JS_RemoveRootRT(gScriptRuntime, aScriptObjectRef);
|
||||
|
||||
if (--gScriptRuntimeRefcnt == 0) {
|
||||
NS_RELEASE(gJSRuntimeService);
|
||||
gScriptRuntime = nsnull;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsXBLPrototypeProperty::nsXBLPrototypeProperty(nsIXBLPrototypeBinding * aPrototypeBinding)
|
||||
: mJSMethod(nsnull), mJSGetterObject(nsnull), mJSSetterObject(nsnull), mPropertyIsCompiled(PR_FALSE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mClassObject = nsnull;
|
||||
gRefCnt++;
|
||||
if (gRefCnt == 1)
|
||||
{
|
||||
kMethodAtom = NS_NewAtom("method");
|
||||
kParameterAtom = NS_NewAtom("parameter");
|
||||
kBodyAtom = NS_NewAtom("body");
|
||||
kPropertyAtom = NS_NewAtom("property");
|
||||
kOnSetAtom = NS_NewAtom("onset");
|
||||
kOnGetAtom = NS_NewAtom("onget");
|
||||
kGetterAtom = NS_NewAtom("getter");
|
||||
kSetterAtom = NS_NewAtom("setter");
|
||||
kNameAtom = NS_NewAtom("name");
|
||||
kReadOnlyAtom = NS_NewAtom("readonly");
|
||||
|
||||
}
|
||||
|
||||
mPrototypeBinding = do_GetWeakReference(aPrototypeBinding);
|
||||
}
|
||||
|
||||
nsXBLPrototypeProperty::~nsXBLPrototypeProperty()
|
||||
{
|
||||
if (mJSMethod)
|
||||
RemoveJSGCRoot(&mJSMethod);
|
||||
if (mJSGetterObject)
|
||||
RemoveJSGCRoot(&mJSGetterObject);
|
||||
if (mJSSetterObject)
|
||||
RemoveJSGCRoot(&mJSSetterObject);
|
||||
|
||||
gRefCnt--;
|
||||
if (gRefCnt == 0)
|
||||
{
|
||||
NS_RELEASE(kMethodAtom);
|
||||
NS_RELEASE(kParameterAtom);
|
||||
NS_RELEASE(kBodyAtom);
|
||||
NS_RELEASE(kPropertyAtom);
|
||||
NS_RELEASE(kOnSetAtom);
|
||||
NS_RELEASE(kOnGetAtom);
|
||||
NS_RELEASE(kGetterAtom);
|
||||
NS_RELEASE(kSetterAtom);
|
||||
NS_RELEASE(kNameAtom);
|
||||
NS_RELEASE(kReadOnlyAtom);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsXBLPrototypeProperty, nsIXBLPrototypeProperty)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeProperty::GetNextProperty(nsIXBLPrototypeProperty** aResult)
|
||||
{
|
||||
*aResult = mNextProperty;
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeProperty::SetNextProperty(nsIXBLPrototypeProperty* aProperty)
|
||||
{
|
||||
mNextProperty = aProperty;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Assumes the class object has already been initialized!!
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeProperty::InitTargetObjects(nsIScriptContext * aContext, nsIContent * aBoundElement, void ** aScriptObject, void ** aTargetClassObject)
|
||||
{
|
||||
if (!mClassObject)
|
||||
{
|
||||
DelayedPropertyConstruction();
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(mClassObject, NS_ERROR_FAILURE);
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
JSContext* jscontext = (JSContext*)aContext->GetNativeContext();
|
||||
JSObject* global = ::JS_GetGlobalObject(jscontext);
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
|
||||
|
||||
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = xpc->WrapNative(jscontext, global, aBoundElement,
|
||||
NS_GET_IID(nsISupports), getter_AddRefs(wrapper));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JSObject * object = nsnull;
|
||||
|
||||
rv = wrapper->GetJSObject(&object);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aScriptObject = object;
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> binding = do_QueryReferent(mPrototypeBinding);
|
||||
if (binding)
|
||||
{
|
||||
binding->InitClass(mClassStr, aContext, (void *) object, aTargetClassObject);
|
||||
|
||||
// Root mBoundElement so that it doesn't loose it's binding
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
aBoundElement->GetDocument(*getter_AddRefs(doc));
|
||||
|
||||
if (doc)
|
||||
{
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> native_wrapper = do_QueryInterface(wrapper);
|
||||
if (native_wrapper)
|
||||
doc->AddReference(aBoundElement, native_wrapper);
|
||||
}
|
||||
} // if binding
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeProperty::InstallProperty(nsIScriptContext * aContext, nsIContent * aBoundElement, void * aScriptObject, void * aTargetClassObject)
|
||||
{
|
||||
if (!mPropertyIsCompiled)
|
||||
{
|
||||
DelayedPropertyConstruction();
|
||||
}
|
||||
|
||||
JSContext* cx = (JSContext*) aContext->GetNativeContext();
|
||||
JSObject * scriptObject = (JSObject *) aScriptObject;
|
||||
JSObject * targetClassObject = (JSObject *) aTargetClassObject;
|
||||
|
||||
// now we want to re-evaluate our property using aContext and the script object for this window...
|
||||
|
||||
if (mJSMethod && targetClassObject)
|
||||
{
|
||||
JSObject * method = ::JS_CloneFunctionObject(cx, (JSObject *) mJSMethod, JS_GetGlobalObject(cx));
|
||||
::JS_DefineUCProperty(cx, targetClassObject, NS_REINTERPRET_CAST(const jschar*, mName.get()), mName.Length(), OBJECT_TO_JSVAL(method),
|
||||
NULL, NULL, JSPROP_ENUMERATE);
|
||||
|
||||
|
||||
}
|
||||
else if ((mJSGetterObject || mJSSetterObject) && targetClassObject)
|
||||
{
|
||||
// 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.
|
||||
|
||||
JSObject * getter = nsnull;
|
||||
if (mJSGetterObject)
|
||||
getter = ::JS_CloneFunctionObject(cx, (JSObject *) mJSGetterObject, JS_GetGlobalObject(cx));
|
||||
|
||||
JSObject * setter = nsnull;
|
||||
if (mJSSetterObject)
|
||||
setter = ::JS_CloneFunctionObject(cx, (JSObject *) mJSSetterObject, JS_GetGlobalObject(cx));
|
||||
|
||||
::JS_DefineUCProperty(cx, targetClassObject, NS_REINTERPRET_CAST(const jschar*, mName.get()),
|
||||
mName.Length(), JSVAL_VOID, (JSPropertyOp) getter,
|
||||
(JSPropertyOp) setter, mJSAttributes);
|
||||
}
|
||||
else if (!mLiteralPropertyString.IsEmpty())
|
||||
{
|
||||
// compile the literal string
|
||||
jsval result = nsnull;
|
||||
PRBool undefined;
|
||||
aContext->EvaluateStringWithValue(mLiteralPropertyString,
|
||||
scriptObject,
|
||||
nsnull, nsnull, 0, nsnull,
|
||||
(void*) &result, &undefined);
|
||||
|
||||
if (!undefined)
|
||||
{
|
||||
// Define that value as a property
|
||||
::JS_DefineUCProperty(cx, scriptObject, NS_REINTERPRET_CAST(const jschar*, mName.get()),
|
||||
mName.Length(), result,nsnull, nsnull, mJSAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsXBLPrototypeProperty::DelayedPropertyConstruction()
|
||||
{
|
||||
// FIRST: get the name attribute on the property!!! need to pass in the property tag
|
||||
// into here in order to do that.
|
||||
|
||||
// See if we're a property or a method.
|
||||
nsCOMPtr<nsIAtom> tagName;
|
||||
mPropertyElement->GetTag(*getter_AddRefs(tagName));
|
||||
|
||||
// We want to pre-compile the properties against a "special context". Then when we actual bind
|
||||
// the proto type to a real xbl instance, we'll resolve the pre-compiled JS against the file context.
|
||||
// right now this special context is attached to the xbl document info....
|
||||
|
||||
nsCOMPtr<nsIXBLDocumentInfo> docInfo;
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> binding = do_QueryReferent(mPrototypeBinding);
|
||||
NS_ENSURE_TRUE(binding, NS_ERROR_FAILURE);
|
||||
|
||||
binding->GetXBLDocumentInfo(nsnull, getter_AddRefs(docInfo));
|
||||
NS_ENSURE_TRUE(docInfo, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObjectOwner> globalOwner (do_QueryInterface(docInfo));
|
||||
nsCOMPtr<nsIScriptGlobalObject> globalObject;
|
||||
globalOwner->GetScriptGlobalObject(getter_AddRefs(globalObject));
|
||||
|
||||
nsCOMPtr<nsIScriptContext> context;
|
||||
globalObject->GetContext(getter_AddRefs(context));
|
||||
|
||||
void * classObject;
|
||||
JSObject * scopeObject = globalObject->GetGlobalJSObject();
|
||||
binding->GetCompiledClassObject(mClassStr, context, (void *) scopeObject, &classObject);
|
||||
mClassObject = (JSObject *) classObject;
|
||||
|
||||
if (tagName.get() == kMethodAtom /* && mClassObject */)
|
||||
{
|
||||
ParseMethod(context, mPropertyElement, mClassStr);
|
||||
}
|
||||
else if (tagName.get() == kPropertyAtom)
|
||||
{
|
||||
ParseProperty(context, mPropertyElement, mClassStr);
|
||||
}
|
||||
|
||||
mPropertyIsCompiled = PR_TRUE;
|
||||
mInterfaceElement = nsnull;
|
||||
mPropertyElement = nsnull;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXBLPrototypeProperty::ConstructProperty(nsIContent * aInterfaceElement, nsIContent* aPropertyElement)
|
||||
{
|
||||
NS_ENSURE_ARG(aPropertyElement);
|
||||
NS_ENSURE_ARG(aInterfaceElement);
|
||||
|
||||
mInterfaceElement = aInterfaceElement;
|
||||
mPropertyElement = aPropertyElement;
|
||||
|
||||
// Init our class and insert it into the prototype chain.
|
||||
nsAutoString className;
|
||||
mInterfaceElement->GetAttr(kNameSpaceID_None, kNameAtom, className);
|
||||
|
||||
if (!className.IsEmpty()) {
|
||||
mClassStr.AssignWithConversion(className);
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIXBLPrototypeBinding> binding = do_QueryReferent(mPrototypeBinding);
|
||||
NS_ENSURE_TRUE(binding, NS_ERROR_FAILURE);
|
||||
binding->GetBindingURI(mClassStr);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const char* gPropertyArgs[] = { "val" };
|
||||
|
||||
nsresult nsXBLPrototypeProperty::ParseProperty(nsIScriptContext * aContext, nsIContent* aPropertyElement, const char * aClassStr)
|
||||
{
|
||||
// Obtain our name attribute.
|
||||
nsAutoString name;
|
||||
nsresult rv = NS_OK;
|
||||
aPropertyElement->GetAttr(kNameSpaceID_None, kNameAtom, mName);
|
||||
|
||||
if (!mName.IsEmpty())
|
||||
{
|
||||
// We have a property.
|
||||
nsAutoString getter, setter, readOnly;
|
||||
aPropertyElement->GetAttr(kNameSpaceID_None, kOnGetAtom, getter);
|
||||
aPropertyElement->GetAttr(kNameSpaceID_None, kOnSetAtom, setter);
|
||||
aPropertyElement->GetAttr(kNameSpaceID_None, kReadOnlyAtom, readOnly);
|
||||
|
||||
mJSAttributes = JSPROP_ENUMERATE;
|
||||
|
||||
if (readOnly == NS_LITERAL_STRING("true"))
|
||||
mJSAttributes |= JSPROP_READONLY;
|
||||
|
||||
// try for first <getter> tag
|
||||
if (getter.IsEmpty())
|
||||
{
|
||||
PRInt32 childCount;
|
||||
aPropertyElement->ChildCount(childCount);
|
||||
|
||||
nsCOMPtr<nsIContent> getterElement;
|
||||
for (PRInt32 j=0; j<childCount; j++)
|
||||
{
|
||||
aPropertyElement->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
|
||||
}
|
||||
} // for each childCount
|
||||
} // if getter is empty
|
||||
|
||||
|
||||
if (!getter.IsEmpty() && mClassObject)
|
||||
{
|
||||
nsCAutoString functionUri;
|
||||
functionUri.Assign(aClassStr);
|
||||
functionUri += ".";
|
||||
functionUri.AppendWithConversion(mName.get());
|
||||
functionUri += " (getter)";
|
||||
rv = aContext->CompileFunction(mClassObject,
|
||||
nsCAutoString("onget"),
|
||||
0,
|
||||
nsnull,
|
||||
getter,
|
||||
functionUri.get(),
|
||||
0,
|
||||
PR_FALSE,
|
||||
&mJSGetterObject);
|
||||
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
||||
mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
|
||||
if (mJSGetterObject)
|
||||
{
|
||||
// Root the compiled prototype script object.
|
||||
JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
|
||||
aContext->GetNativeContext());
|
||||
if (!cx) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
rv = AddJSGCRoot(&mJSGetterObject, "nsXBLPrototypeProperty::mJSGetterObject");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
} // if getter is not empty
|
||||
|
||||
// try for first <setter> tag
|
||||
if (setter.IsEmpty())
|
||||
{
|
||||
PRInt32 childCount;
|
||||
aPropertyElement->ChildCount(childCount);
|
||||
|
||||
nsCOMPtr<nsIContent> setterElement;
|
||||
for (PRInt32 j=0; j<childCount; j++)
|
||||
{
|
||||
aPropertyElement->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 is empty
|
||||
|
||||
if (!setter.IsEmpty() && mClassObject)
|
||||
{
|
||||
nsCAutoString functionUri (aClassStr);
|
||||
functionUri += ".";
|
||||
functionUri.AppendWithConversion(mName.get());
|
||||
functionUri += " (setter)";
|
||||
rv = aContext->CompileFunction(mClassObject,
|
||||
nsCAutoString("onset"),
|
||||
1,
|
||||
gPropertyArgs,
|
||||
setter,
|
||||
functionUri.get(),
|
||||
0,
|
||||
PR_FALSE,
|
||||
&mJSSetterObject);
|
||||
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
||||
mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
|
||||
if (mJSSetterObject)
|
||||
{
|
||||
// Root the compiled prototype script object.
|
||||
JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
|
||||
aContext->GetNativeContext());
|
||||
if (!cx) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
rv = AddJSGCRoot(&mJSSetterObject, "nsXBLPrototypeProperty::mJSSetterObject");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
} // if setter wasn't empty....
|
||||
|
||||
// if we came through all of this without a getter or setter, look for a raw
|
||||
// literal property string...
|
||||
if (mJSSetterObject || mJSGetterObject)
|
||||
return NS_OK;
|
||||
|
||||
return ParseLiteral(aContext, aPropertyElement);
|
||||
} // if name isn't empty
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsXBLPrototypeProperty::ParseLiteral(nsIScriptContext * aContext, nsIContent* aPropertyElement)
|
||||
{
|
||||
// Look for a normal value and just define that.
|
||||
nsCOMPtr<nsIContent> textChild;
|
||||
PRInt32 textCount;
|
||||
aPropertyElement->ChildCount(textCount);
|
||||
for (PRInt32 j = 0; j < textCount; j++)
|
||||
{
|
||||
// Get the child.
|
||||
aPropertyElement->ChildAt(j, *getter_AddRefs(textChild));
|
||||
nsCOMPtr<nsIDOMText> text(do_QueryInterface(textChild));
|
||||
if (text)
|
||||
{
|
||||
nsAutoString data;
|
||||
text->GetData(data);
|
||||
mLiteralPropertyString += data;
|
||||
}
|
||||
} // for each element
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsXBLPrototypeProperty::ParseMethod(nsIScriptContext * aContext, nsIContent* aPropertyElement, const char * aClassStr)
|
||||
{
|
||||
// TO DO: fix up class name and class object
|
||||
|
||||
// Obtain our name attribute.
|
||||
nsAutoString body;
|
||||
nsresult rv = NS_OK;
|
||||
aPropertyElement->GetAttr(kNameSpaceID_None, kNameAtom, mName);
|
||||
|
||||
// Now walk all of our args.
|
||||
// XXX I'm lame. 32 max args allowed.
|
||||
char* args[32];
|
||||
PRUint32 argCount = 0;
|
||||
PRInt32 kidCount;
|
||||
aPropertyElement->ChildCount(kidCount);
|
||||
for (PRInt32 j = 0; j < kidCount; j++)
|
||||
{
|
||||
nsCOMPtr<nsIContent> arg;
|
||||
aPropertyElement->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;
|
||||
}
|
||||
} // for each body line
|
||||
} // if we have a body atom
|
||||
} // for each node in the method
|
||||
|
||||
// Now that we have a body and args, compile the function
|
||||
// and then define it as a property.....
|
||||
if (!body.IsEmpty())
|
||||
{
|
||||
nsCAutoString cname; cname.AssignWithConversion(mName.get());
|
||||
nsCAutoString functionUri (aClassStr);
|
||||
functionUri += ".";
|
||||
functionUri += cname;
|
||||
functionUri += "()";
|
||||
|
||||
rv = aContext->CompileFunction(mClassObject,
|
||||
cname,
|
||||
argCount,
|
||||
(const char**)args,
|
||||
body,
|
||||
functionUri.get(),
|
||||
0,
|
||||
PR_FALSE,
|
||||
&mJSMethod);
|
||||
|
||||
if (mJSMethod)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
for (PRUint32 l = 0; l < argCount; l++)
|
||||
nsMemory::Free(args[l]);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXBLPrototypeProperty::GetTextData(nsIContent *aParent, nsString& aResult)
|
||||
{
|
||||
aResult.Truncate(0);
|
||||
|
||||
nsCOMPtr<nsIContent> textChild;
|
||||
PRInt32 textCount;
|
||||
aParent->ChildCount(textCount);
|
||||
nsAutoString answer;
|
||||
for (PRInt32 j = 0; j < textCount; j++) {
|
||||
// Get the child.
|
||||
aParent->ChildAt(j, *getter_AddRefs(textChild));
|
||||
nsCOMPtr<nsIDOMText> text(do_QueryInterface(textChild));
|
||||
if (text)
|
||||
{
|
||||
nsAutoString data;
|
||||
text->GetData(data);
|
||||
aResult += data;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
NS_NewXBLPrototypeProperty(nsIXBLPrototypeBinding * aPrototypeBinding, nsIXBLPrototypeProperty ** aResult)
|
||||
{
|
||||
*aResult = new nsXBLPrototypeProperty(aPrototypeBinding);
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Original Author: Scott MacGregor (mscott@netscape.com)
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef nsXBLPrototypeProperty_h__
|
||||
#define nsXBLPrototypeProperty_h__
|
||||
|
||||
#include "nsIXBLPrototypeProperty.h"
|
||||
#include "nsIXBLPrototypeBinding.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsString.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsString.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
class nsIXBLBinding;
|
||||
class nsIDocument;
|
||||
class nsIXBLPrototypeBinding;
|
||||
|
||||
class nsXBLPrototypeProperty : public nsIXBLPrototypeProperty
|
||||
{
|
||||
public:
|
||||
nsXBLPrototypeProperty(nsIXBLPrototypeBinding * aPrototypeBinding);
|
||||
virtual ~nsXBLPrototypeProperty();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD GetNextProperty(nsIXBLPrototypeProperty** aProperty);
|
||||
NS_IMETHOD SetNextProperty(nsIXBLPrototypeProperty* aProperty);
|
||||
NS_IMETHOD ConstructProperty(nsIContent * aInterfaceElement, nsIContent* aPropertyElement);
|
||||
|
||||
NS_IMETHOD InstallProperty(nsIScriptContext * aContext, nsIContent * aBoundElement, void * aScopeObject, void * aTargetClassObject);
|
||||
NS_IMETHOD InitTargetObjects(nsIScriptContext * aContext, nsIContent * aBoundElement, void ** aScriptObject, void ** aTargetClassObject);
|
||||
static PRUint32 gRefCnt;
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIXBLPrototypeProperty> mNextProperty; // Prototype properties are chained. We own the next handler in the chain.
|
||||
|
||||
static nsIAtom* kMethodAtom;
|
||||
static nsIAtom* kParameterAtom;
|
||||
static nsIAtom* kBodyAtom;
|
||||
static nsIAtom* kPropertyAtom;
|
||||
static nsIAtom* kOnSetAtom;
|
||||
static nsIAtom* kOnGetAtom;
|
||||
static nsIAtom* kGetterAtom;
|
||||
static nsIAtom* kSetterAtom;
|
||||
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
|
||||
nsString mLiteralPropertyString; // the property is just a literal string
|
||||
|
||||
JSObject* mClassObject;
|
||||
|
||||
nsString mName; // name of the property
|
||||
|
||||
uintN mJSAttributes;
|
||||
nsWeakPtr mPrototypeBinding; // weak reference back to the proto type binding which owns us.
|
||||
|
||||
nsCOMPtr<nsIContent> mInterfaceElement;
|
||||
nsCOMPtr<nsIContent> mPropertyElement;
|
||||
PRBool mPropertyIsCompiled;
|
||||
nsCString mClassStr;
|
||||
|
||||
protected:
|
||||
nsresult GetTextData(nsIContent *aParent, nsString& aResult);
|
||||
nsresult ParseMethod(nsIScriptContext * aContext, nsIContent * aNode, const char * aClassStr);
|
||||
nsresult ParseProperty(nsIScriptContext * aContext, nsIContent * aNode, const char * aClassStr);
|
||||
nsresult ParseLiteral(nsIScriptContext * aContext, nsIContent* aPropertyElement);
|
||||
|
||||
nsresult DelayedPropertyConstruction();
|
||||
};
|
||||
|
||||
extern nsresult
|
||||
NS_NewXBLPrototypeProperty(nsIXBLPrototypeBinding * aProtoTypeBinding, nsIXBLPrototypeProperty** aResult);
|
||||
|
||||
#endif // nsXBLPrototypeProperty_h__
|
Загрузка…
Ссылка в новой задаче