diff --git a/js/src/xpconnect/idl/xpctest.idl b/js/src/xpconnect/idl/xpctest.idl index d643b0359790..eb9d8e1b71cd 100644 --- a/js/src/xpconnect/idl/xpctest.idl +++ b/js/src/xpconnect/idl/xpctest.idl @@ -131,6 +131,9 @@ interface nsIXPCTestString : nsISupports { string GetStringA(); void GetStringB(out string s); void GetStringC([shared,retval] out string s); + + void GetWStringCopied([retval] out wstring s); + void GetWStringShared([shared,retval] out wstring s); }; [scriptable, uuid(0ff4faf0-439a-11d3-988c-006008962422)] diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 22c6be0b642f..e75de63b29c3 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -229,7 +229,7 @@ nsXPConnect::IsISupportsDescendent(nsIInterfaceInfo* info) nsID* iid; if(NS_SUCCEEDED(oldest->GetIID(&iid))) { - retval = iid->Equals(nsCOMTypeInfo::GetIID()); + retval = iid->Equals(NS_GET_IID(nsISupports)); nsAllocator::Free(iid); } NS_RELEASE(oldest); diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp index 7cd08dc1df43..c97f2cf479fa 100644 --- a/js/src/xpconnect/src/xpccomponents.cpp +++ b/js/src/xpconnect/src/xpccomponents.cpp @@ -246,8 +246,8 @@ nsXPCInterfaces::CacheDynaProp(JSContext *cx, JSObject *obj, jsid id, nsXPConnect* xpc = nsXPConnect::GetXPConnect(); if(xpc) { - if(NS_SUCCEEDED(xpc->WrapNative(cx, nsid, - nsIJSIID::GetIID(), + if(NS_SUCCEEDED(xpc->WrapNative(cx, NS_STATIC_CAST(nsIJSID*,nsid), + NS_GET_IID(nsIJSIID), &nsid_wrapper))) { JSObject* idobj; @@ -789,6 +789,9 @@ nsXPCClassesByID::CacheDynaProp(JSContext *cx, JSObject *obj, jsid id, /***************************************************************************/ +// Currently the possible results do not change at runtime, so they are only +// cached once (unlike ProgIDs, CLSIDs, and IIDs) + class nsXPCResults : public nsIXPCResults, public nsIXPCScriptable { public: diff --git a/js/src/xpconnect/src/xpcjsid.cpp b/js/src/xpconnect/src/xpcjsid.cpp index 7da17ceaf81a..e31c53c57b8f 100644 --- a/js/src/xpconnect/src/xpcjsid.cpp +++ b/js/src/xpconnect/src/xpcjsid.cpp @@ -224,9 +224,31 @@ nsJSID::NewID(const char* str) /***************************************************************************/ /***************************************************************************/ -NS_IMPL_ISUPPORTS2(nsJSIID, nsIJSID, nsIJSIID) +NS_IMPL_ISUPPORTS3(nsJSIID, nsIJSID, nsIJSIID, nsIXPCScriptable) + +XPC_IMPLEMENT_FORWARD_CREATE(nsJSIID) +// XPC_IMPLEMENT_IGNORE_GETFLAGS(nsJSIID) +// XPC_IMPLEMENT_IGNORE_LOOKUPPROPERTY(nsJSIID) +XPC_IMPLEMENT_IGNORE_DEFINEPROPERTY(nsJSIID) +// XPC_IMPLEMENT_IGNORE_GETPROPERTY(nsJSIID) +XPC_IMPLEMENT_IGNORE_SETPROPERTY(nsJSIID) +XPC_IMPLEMENT_IGNORE_GETATTRIBUTES(nsJSIID) +XPC_IMPLEMENT_IGNORE_SETATTRIBUTES(nsJSIID) +XPC_IMPLEMENT_IGNORE_DELETEPROPERTY(nsJSIID) +XPC_IMPLEMENT_IGNORE_DEFAULTVALUE(nsJSIID) +// XPC_IMPLEMENT_IGNORE_ENUMERATE(nsJSIID) +XPC_IMPLEMENT_IGNORE_CHECKACCESS(nsJSIID) +XPC_IMPLEMENT_IGNORE_CALL(nsJSIID) +XPC_IMPLEMENT_IGNORE_CONSTRUCT(nsJSIID) +// XPC_IMPLEMENT_FORWARD_HASINSTANCE(nsJSIID) +XPC_IMPLEMENT_FORWARD_FINALIZE(nsJSIID) + +nsJSIID::nsJSIID() + : mCacheFilled(JS_FALSE) +{ + NS_INIT_ISUPPORTS(); +} -nsJSIID::nsJSIID() {NS_INIT_ISUPPORTS();} nsJSIID::~nsJSIID() {} NS_IMETHODIMP nsJSIID::GetName(char * *aName) @@ -297,8 +319,12 @@ nsJSIID::NewID(const char* str) nsIInterfaceInfoManager* iim; if(nsnull != (iim = nsXPConnect::GetInterfaceInfoManager())) { + nsIInterfaceInfo* iinfo; + PRBool canScript; nsID* pid; - if(NS_SUCCEEDED(iim->GetIIDForName(str, &pid)) && pid) + if(NS_SUCCEEDED(iim->GetInfoForName(str, &iinfo)) && + NS_SUCCEEDED(iinfo->IsScriptable(&canScript)) && canScript && + NS_SUCCEEDED(iinfo->GetIID(&pid)) && pid) { success = idObj->mDetails.InitWithName(*pid, str); nsAllocator::Free(pid); @@ -312,6 +338,173 @@ nsJSIID::NewID(const char* str) return idObj; } +NS_IMETHODIMP +nsJSIID::HasInstance(JSContext *cx, JSObject *obj, + jsval v, JSBool *bp, + nsIXPConnectWrappedNative* wrapper, + nsIXPCScriptable* arbitrary, + JSBool* retval) +{ + *bp = JS_FALSE; + *retval = JS_TRUE; + nsresult rv = NS_OK; + + if(!JSVAL_IS_PRIMITIVE(v)) + { + // we have a JSObject + JSObject* obj = JSVAL_TO_OBJECT(v); + + NS_ASSERTION(obj, "when is an object not an object?"); + + // is this really a native xpcom object with a wrapper? + nsXPCWrappedNative* other_wrapper = + nsXPCWrappedNativeClass::GetWrappedNativeOfJSObject(cx,obj); + + if(!other_wrapper) + return NS_OK; + + if(mDetails.GetID()->Equals(other_wrapper->GetIID())) + *bp = JS_TRUE; + else + { + // This would be so easy except for the case... + // other_wrapper might inherit from our type + nsXPCWrappedNativeClass* clazz; + nsIInterfaceInfo* prev; + if(!(clazz = other_wrapper->GetClass()) || + !(prev = clazz->GetInterfaceInfo())) + return NS_ERROR_UNEXPECTED; + + nsIInterfaceInfo* cur; + NS_ADDREF(prev); + while(NS_SUCCEEDED(prev->GetParent(&cur))) + { + NS_RELEASE(prev); + prev = cur; + + nsID* iid; + if(NS_SUCCEEDED(cur->GetIID(&iid))) + { + JSBool found = mDetails.GetID()->Equals(*iid); + nsAllocator::Free(iid); + if(found) + { + *bp = JS_TRUE; + break; + } + } + else + { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + NS_RELEASE(prev); + } + } + return rv; +} + +void +nsJSIID::FillCache(JSContext *cx, JSObject *obj, + nsIXPConnectWrappedNative *wrapper, + nsIXPCScriptable *arbitrary) +{ + nsIInterfaceInfoManager* iim = nsnull; + nsIInterfaceInfo* iinfo; + PRUint16 count; + + if(!(iim = XPTI_GetInterfaceInfoManager()) || + NS_FAILED(iim->GetInfoForIID(mDetails.GetID(), &iinfo)) || + !iinfo || + NS_FAILED(iinfo->GetConstantCount(&count))) + + { + NS_ASSERTION(0,"access to interface info is truly horked"); + NS_IF_RELEASE(iim); + ThrowException(NS_ERROR_XPC_UNEXPECTED, cx); + return; + } + NS_RELEASE(iim); + + + for(PRUint16 i = 0; i < count; i++) + { + const nsXPTConstant* constant; + jsid id; + JSString *jstrid; + jsval val; + JSBool retval; + + if(NS_FAILED(iinfo->GetConstant(i, &constant)) || + !(jstrid = JS_InternString(cx, constant->GetName())) || + !JS_ValueToId(cx, STRING_TO_JSVAL(jstrid), &id) || + !nsXPCWrappedNativeClass::GetConstantAsJSVal(cx, iinfo, i, &val) || + NS_FAILED(arbitrary->SetProperty(cx, obj, id, &val, wrapper, nsnull, &retval)) || + !retval) + { + ThrowException(NS_ERROR_XPC_UNEXPECTED, cx); + return; + } + } + + mCacheFilled = JS_TRUE; + return; +} + +NS_IMETHODIMP +nsJSIID::GetFlags(JSContext *cx, JSObject *obj, + nsIXPConnectWrappedNative* wrapper, + JSUint32* flagsp, + nsIXPCScriptable* arbitrary) +{ + NS_PRECONDITION(flagsp, "bad param"); + *flagsp = XPCSCRIPTABLE_DONT_ENUM_STATIC_PROPS; + return NS_OK; +} + +NS_IMETHODIMP +nsJSIID::LookupProperty(JSContext *cx, JSObject *obj, + jsid id, + JSObject **objp, JSProperty **propp, + nsIXPConnectWrappedNative* wrapper, + nsIXPCScriptable* arbitrary, + JSBool* retval) +{ + if(!mCacheFilled) + FillCache(cx, obj, wrapper, arbitrary); + return arbitrary->LookupProperty(cx, obj, id, objp, propp, wrapper, + nsnull, retval); +} + +NS_IMETHODIMP +nsJSIID::GetProperty(JSContext *cx, JSObject *obj, + jsid id, jsval *vp, + nsIXPConnectWrappedNative* wrapper, + nsIXPCScriptable* arbitrary, + JSBool* retval) +{ + if(!mCacheFilled) + FillCache(cx, obj, wrapper, arbitrary); + return arbitrary->GetProperty(cx, obj, id, vp, wrapper, nsnull, retval); +} + + +NS_IMETHODIMP +nsJSIID::Enumerate(JSContext *cx, JSObject *obj, + JSIterateOp enum_op, + jsval *statep, jsid *idp, + nsIXPConnectWrappedNative *wrapper, + nsIXPCScriptable *arbitrary, + JSBool *retval) +{ + if(enum_op == JSENUMERATE_INIT && !mCacheFilled) + FillCache(cx, obj, wrapper, arbitrary); + + return arbitrary->Enumerate(cx, obj, enum_op, statep, idp, wrapper, + arbitrary, retval); +} + /***************************************************************************/ /***************************************************************************/ /***************************************************************************/ diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index 1ab266d0598a..93da7d4de996 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -534,10 +534,16 @@ public: const XPCNativeMemberDescriptor* LookupMemberByID(jsid id) const; + static JSBool GetConstantAsJSVal(JSContext *cx, + nsIInterfaceInfo* iinfo, + PRUint16 index, + jsval* vp); + JSBool GetConstantAsJSVal(JSContext* cx, nsXPCWrappedNative* wrapper, const XPCNativeMemberDescriptor* desc, - jsval* vp); + jsval* vp) + {return GetConstantAsJSVal(cx, mInfo, desc->index, vp);} enum CallMode {CALL_METHOD, CALL_GETTER, CALL_SETTER}; @@ -760,7 +766,7 @@ protected: // nsJSIID -class nsJSIID : public nsIJSIID +class nsJSIID : public nsIJSIID, public nsIXPCScriptable { public: NS_DECL_ISUPPORTS @@ -770,6 +776,7 @@ public: // we implement the rest... NS_DECL_NSIJSIID + XPC_DECLARE_IXPCSCRIPTABLE static nsJSIID* NewID(const char* str); @@ -779,8 +786,13 @@ public: private: void ResolveName(); + void FillCache(JSContext *cx, JSObject *obj, + nsIXPConnectWrappedNative *wrapper, + nsIXPCScriptable *arbitrary); + private: nsJSID mDetails; + JSBool mCacheFilled; }; // nsJSCID diff --git a/js/src/xpconnect/src/xpcthrower.cpp b/js/src/xpconnect/src/xpcthrower.cpp index 230f95ae1836..0bbf2f328e76 100644 --- a/js/src/xpconnect/src/xpcthrower.cpp +++ b/js/src/xpconnect/src/xpcthrower.cpp @@ -80,7 +80,6 @@ XPCJSThrower::ThrowBadResultException(nsresult rv, char* sz; const char* format; const char* name; - JSString* str = nsnull; /* * If there is a pending exception when the native call returns and @@ -136,7 +135,6 @@ XPCJSThrower::ThrowBadParamException(nsresult rv, { char* sz; const char* format; - JSString* str = nsnull; if(!nsXPCException::NameAndFormatForNSResult(rv, nsnull, &format)) format = ""; @@ -160,7 +158,6 @@ XPCJSThrower::ThrowException(nsresult rv, { char* sz; const char* format; - JSString* str = nsnull; if(!nsXPCException::NameAndFormatForNSResult(rv, nsnull, &format)) format = ""; diff --git a/js/src/xpconnect/src/xpcwrappednativeclass.cpp b/js/src/xpconnect/src/xpcwrappednativeclass.cpp index e1fe52a072cb..f28de0706dff 100644 --- a/js/src/xpconnect/src/xpcwrappednativeclass.cpp +++ b/js/src/xpconnect/src/xpcwrappednativeclass.cpp @@ -265,21 +265,18 @@ nsXPCWrappedNativeClass::GetInterfaceName() return mName; } +// static JSBool nsXPCWrappedNativeClass::GetConstantAsJSVal(JSContext *cx, - nsXPCWrappedNative* wrapper, - const XPCNativeMemberDescriptor* desc, + nsIInterfaceInfo* iinfo, + PRUint16 index, jsval* vp) { const nsXPTConstant* constant; - NS_ASSERTION(desc->IsConstant(),"bad type"); - if(NS_FAILED(mInfo->GetConstant(desc->index, &constant))) - { - // XXX fail silently? - *vp = JSVAL_NULL; - return JS_TRUE; - } + if(NS_FAILED(iinfo->GetConstant(index, &constant))) + return JS_FALSE; + const nsXPTCMiniVariant& mv = *constant->GetValue(); // XXX Big Hack! @@ -288,7 +285,6 @@ nsXPCWrappedNativeClass::GetConstantAsJSVal(JSContext *cx, v.type = constant->GetType(); memcpy(&v.val, &mv.val, sizeof(mv.val)); - // XXX if iid consts are supported, then conditionally fill it in here return XPCConvert::NativeData2JS(cx, vp, &v.val, v.type, nsnull, nsnull); } diff --git a/js/src/xpconnect/src/xpcwrappednativejsops.cpp b/js/src/xpconnect/src/xpcwrappednativejsops.cpp index 022c5f52e96a..408dc7206237 100644 --- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp +++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp @@ -196,7 +196,11 @@ WrappedNative_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) if(desc) { if(desc->IsConstant()) - return clazz->GetConstantAsJSVal(cx, wrapper, desc, vp); + { + if(!clazz->GetConstantAsJSVal(cx, wrapper, desc, vp)) + *vp = JSVAL_NULL; //XXX silent failure? + return JS_TRUE; + } else if(desc->IsMethod()) { // allow for lazy creation of 'prototypical' function invoke object diff --git a/js/src/xpconnect/tests/TestXPC.cpp b/js/src/xpconnect/tests/TestXPC.cpp index 040388b37fc0..73d871ea2d59 100644 --- a/js/src/xpconnect/tests/TestXPC.cpp +++ b/js/src/xpconnect/tests/TestXPC.cpp @@ -824,13 +824,13 @@ int main() if(JS_GetProperty(jscontext, glob, "bar", &v) && JSVAL_IS_OBJECT(v)) { - JSObject* bar = JSVAL_TO_OBJECT(v); - nsISupports* wrapper3; +// JSObject* bar = JSVAL_TO_OBJECT(v); + nsISupports* wrapper4; if(NS_SUCCEEDED(xpc->WrapJS(jscontext, JSVAL_TO_OBJECT(v), - nsITestXPCFoo::GetIID(), &wrapper3))) + nsITestXPCFoo::GetIID(), &wrapper4))) { - nsITestXPCFoo* ptr = (nsITestXPCFoo*)wrapper3; + nsITestXPCFoo* ptr = (nsITestXPCFoo*)wrapper4; int result; JSObject* test_js_obj; ptr->Test(11, 13, &result); @@ -839,7 +839,7 @@ int main() nsIXPConnectWrappedJSMethods* methods; - wrapper3->QueryInterface(nsIXPConnectWrappedJSMethods::GetIID(), + wrapper4->QueryInterface(nsIXPConnectWrappedJSMethods::GetIID(), (void**) &methods); methods->GetJSObject(&test_js_obj); @@ -864,7 +864,7 @@ int main() // XPC_DUMP(xpc, 50); NS_RELEASE(methods); - NS_RELEASE(wrapper3); + NS_RELEASE(wrapper4); } } diff --git a/js/src/xpconnect/tests/components/xpctest_string.cpp b/js/src/xpconnect/tests/components/xpctest_string.cpp index 74a7bfb78f13..562e4e3fa63c 100644 --- a/js/src/xpconnect/tests/components/xpctest_string.cpp +++ b/js/src/xpconnect/tests/components/xpctest_string.cpp @@ -84,6 +84,58 @@ xpcstringtest::GetStringC(const char **s) return NS_OK; } +// quick and dirty!!! +static PRUnichar* GetTestWString(int* size) +{ + static PRUnichar* sWStr; + static char str[] = "This is part of a long string... "; + static const int slen = (sizeof(str)-1)/sizeof(char); + static const int rep = 1; + static const int space = (slen*rep*sizeof(PRUnichar))+sizeof(PRUnichar); + + if(!sWStr) + { + sWStr = (PRUnichar*) nsAllocator::Alloc(space); + if(sWStr) + { + PRUnichar* p = sWStr; + for(int k = 0; k < rep; k++) + for (int i = 0; i < slen; i++) + *(p++) = (PRUnichar) str[i]; + *p = 0; + } + } + if(size) + *size = space; + return sWStr; +} + +/* void GetWStringCopied ([retval] out wstring s); */ +NS_IMETHODIMP xpcstringtest::GetWStringCopied(PRUnichar **s) +{ + const char myResult[] = "result of xpcstringtest::GetStringB"; + + if(!s) + return NS_ERROR_NULL_POINTER; + + int size; + PRUnichar* str = GetTestWString(&size); + if(!str) + return NS_ERROR_OUT_OF_MEMORY; + + *s = (PRUnichar*) nsAllocator::Clone(str, size); + return *s ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/* void GetWStringShared ([shared, retval] out wstring s); */ +NS_IMETHODIMP xpcstringtest::GetWStringShared(const PRUnichar **s) +{ + if(!s) + return NS_ERROR_NULL_POINTER; + *s = GetTestWString(nsnull); + return NS_OK; +} + /***************************************************************************/ // static diff --git a/js/src/xpconnect/tests/xpctest_enum_and_sort.js b/js/src/xpconnect/tests/xpctest_enum_and_sort.js new file mode 100644 index 000000000000..aef0624e83ab --- /dev/null +++ b/js/src/xpconnect/tests/xpctest_enum_and_sort.js @@ -0,0 +1,28 @@ +function enum_and_sort(o) { + var all = []; + for(n in o) all.push(n); + all.sort(); + for(n in all) print(all[n]); + print("total count: "+all.length); +} + + +print("enum_and_sort...\n"); +print(enum_and_sort); +print(""); + +print("enum_and_sort(Components.results)...\n"); +enum_and_sort(Components.results); +print(""); + +print("enum_and_sort(Components.interfaces)...\n"); +enum_and_sort(Components.interfaces); +print(""); + +print("enum_and_sort(Components.classes)...\n"); +enum_and_sort(Components.classes); +print(""); + +print("enum_and_sort(Components.classesByID)...\n"); +enum_and_sort(Components.classesByID); +print(""); diff --git a/js/src/xpconnect/tests/xpctest_enum_constants.js b/js/src/xpconnect/tests/xpctest_enum_constants.js new file mode 100644 index 000000000000..af2bae129679 --- /dev/null +++ b/js/src/xpconnect/tests/xpctest_enum_constants.js @@ -0,0 +1,15 @@ +var iface_count = 0; +var constant_count = 0; +for(var iface_name in Components.interfaces) { + var iface = Components.interfaces[iface_name]; + print(iface_name); + var iface_name; + for(var const_name in iface) { + print(" "+const_name+" = "+iface[const_name]) + constant_count++; + } + iface_count++; +} +print("\n"+iface_count+" interfaces with "+constant_count+" constants"); + +