diff --git a/source/gui/IGUIObject.cpp b/source/gui/IGUIObject.cpp index e7de78a35e..d37e9533d9 100644 --- a/source/gui/IGUIObject.cpp +++ b/source/gui/IGUIObject.cpp @@ -518,11 +518,11 @@ JSObject* IGUIObject::GetJSObject() // not have these objects hang around forever using up memory, though. if (m_JSObject.uninitialised()) { - JSObject* obj = JS_NewObject(cx, &JSI_IGUIObject::JSI_class, NULL, NULL); - m_JSObject = CScriptValRooted(cx, OBJECT_TO_JSVAL(obj)); - JS_SetPrivate(JSVAL_TO_OBJECT(m_JSObject.get()), this); + JS::RootedObject obj(cx, m_pGUI->GetScriptInterface()->CreateCustomObject("GUIObject")); + m_JSObject = CScriptValRooted(cx, JS::ObjectValue(*obj)); + JS_SetPrivate(obj, this); } - return JSVAL_TO_OBJECT(m_JSObject.get());; + return &m_JSObject.get().toObject(); } CStr IGUIObject::GetPresentableName() const diff --git a/source/gui/scripting/JSInterface_GUITypes.cpp b/source/gui/scripting/JSInterface_GUITypes.cpp index 65fbac5d68..735c1571a8 100644 --- a/source/gui/scripting/JSInterface_GUITypes.cpp +++ b/source/gui/scripting/JSInterface_GUITypes.cpp @@ -51,8 +51,11 @@ JSFunctionSpec JSI_GUISize::JSI_methods[] = JSBool JSI_GUISize::construct(JSContext* cx, uint argc, jsval* vp) { + JSAutoRequest rq(cx); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - JSObject* obj = JS_NewObject(cx, &JSI_GUISize::JSI_class, NULL, NULL); + + ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; + JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUISize")); if (args.length() == 8) { @@ -166,9 +169,12 @@ JSFunctionSpec JSI_GUIColor::JSI_methods[] = JSBool JSI_GUIColor::construct(JSContext* cx, uint argc, jsval* vp) { + JSAutoRequest rq(cx); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - JSObject* obj = JS_NewObject(cx, &JSI_GUIColor::JSI_class, NULL, NULL); - + + ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; + JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUIColor")); + if (args.length() == 4) { JS_SetProperty(cx, obj, "r", &args[0]); @@ -243,7 +249,9 @@ JSBool JSI_GUIMouse::construct(JSContext* cx, uint argc, jsval* vp) { JSAutoRequest rq(cx); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - JSObject* obj = JS_NewObject(cx, &JSI_GUIMouse::JSI_class, NULL, NULL); + + ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; + JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUIMouse")); if (args.length() == 3) { diff --git a/source/gui/scripting/JSInterface_IGUIObject.cpp b/source/gui/scripting/JSInterface_IGUIObject.cpp index f5b0213db8..0d0cb9ccf6 100644 --- a/source/gui/scripting/JSInterface_IGUIObject.cpp +++ b/source/gui/scripting/JSInterface_IGUIObject.cpp @@ -56,6 +56,8 @@ JSFunctionSpec JSI_IGUIObject::JSI_methods[] = JSBool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) { JSAutoRequest rq(cx); + ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; + IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); if (!e) return JS_FALSE; @@ -161,8 +163,8 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::Hand { CColor colour; GUI::GetSetting(e, propName, colour); - JS::RootedObject obj(cx, JS_NewObject(cx, &JSI_GUIColor::JSI_class, NULL, NULL)); - vp.set(JS::ObjectValue(*obj)); + JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUIColor")); + vp.setObject(*obj); JS::RootedValue c(cx); // Attempt to minimise ugliness through macrosity #define P(x) c = JS::NumberValue(colour.x); \ @@ -183,7 +185,8 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::Hand CClientArea area; GUI::GetSetting(e, propName, area); - vp.set(JS::ObjectValue(*JS_NewObject(cx, &JSI_GUISize::JSI_class, NULL, NULL))); + JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUISize")); + vp.setObject(*obj); try { ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; @@ -595,14 +598,17 @@ JSBool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::Hand JSBool JSI_IGUIObject::construct(JSContext* cx, uint argc, jsval* vp) { + JSAutoRequest rq(cx); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; + if (args.length() == 0) { JS_ReportError(cx, "GUIObject has no default constructor"); return JS_FALSE; } - JS::RootedObject obj(cx, JS_NewObject(cx, &JSI_IGUIObject::JSI_class, NULL, NULL)); + JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUIObject")); // Store the IGUIObject in the JS object's 'private' area IGUIObject* guiObject = (IGUIObject*)JSVAL_TO_PRIVATE(args[0]); diff --git a/source/scriptinterface/ScriptInterface.cpp b/source/scriptinterface/ScriptInterface.cpp index 3b728e830d..86d7727ff1 100644 --- a/source/scriptinterface/ScriptInterface.cpp +++ b/source/scriptinterface/ScriptInterface.cpp @@ -946,7 +946,7 @@ void ScriptInterface::DefineCustomObjectType(JSClass *clasp, JSNative constructo CustomType type; - type.m_Object = obj; + type.m_Prototype = obj; type.m_Class = clasp; type.m_Constructor = constructor; @@ -960,12 +960,10 @@ JSObject* ScriptInterface::CreateCustomObject(const std::string & typeName) if (it == m_CustomObjectTypes.end()) throw PSERROR_Scripting_TypeDoesNotExist(); - JSFunction* ctor = JS_NewFunction(m->m_cx, (*it).second.m_Constructor, 0, 0, - NULL, "ctor_fun"); - return JS_New(m->m_cx, JS_GetFunctionObject(ctor), 0, NULL); + JS::RootedObject prototype(m->m_cx, (*it).second.m_Prototype); + return JS_NewObject(m->m_cx, (*it).second.m_Class, prototype, NULL); } - bool ScriptInterface::CallFunctionVoid(jsval val, const char* name) { JSAutoRequest rq(m->m_cx); diff --git a/source/scriptinterface/ScriptInterface.h b/source/scriptinterface/ScriptInterface.h index d17ce6295f..699945543a 100644 --- a/source/scriptinterface/ScriptInterface.h +++ b/source/scriptinterface/ScriptInterface.h @@ -413,8 +413,8 @@ private: class CustomType { public: - JSObject * m_Object; - JSClass * m_Class; + JSObject* m_Prototype; + JSClass* m_Class; JSNative m_Constructor; }; void Register(const char* name, JSNative fptr, size_t nargs); diff --git a/source/simulation2/scripting/EngineScriptConversions.cpp b/source/simulation2/scripting/EngineScriptConversions.cpp index 71d4166e8d..f38a6c465a 100644 --- a/source/simulation2/scripting/EngineScriptConversions.cpp +++ b/source/simulation2/scripting/EngineScriptConversions.cpp @@ -51,8 +51,8 @@ template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::Value& // Otherwise we need to construct a wrapper object // (TODO: cache wrapper objects?) - JSClass* cls = val->GetJSClass(); - if (!cls) + JS::RootedObject obj(cx); + if (!val->NewJSObject(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface, &obj)) { // Report as an error, since scripts really shouldn't try to use unscriptable interfaces LOGERROR(L"IComponent does not have a scriptable interface"); @@ -60,15 +60,7 @@ template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::Value& return; } - JS::RootedObject obj(cx, JS_NewObject(cx, cls, NULL, NULL)); - if (!obj) - { - LOGERROR(L"Failed to construct IComponent script object"); - ret = JS::UndefinedValue(); - return; - } JS_SetPrivate(obj, static_cast(val)); - ret = JS::ObjectValue(*obj); } diff --git a/source/simulation2/system/IComponent.cpp b/source/simulation2/system/IComponent.cpp index 2aca346322..cfa852b5a8 100644 --- a/source/simulation2/system/IComponent.cpp +++ b/source/simulation2/system/IComponent.cpp @@ -33,9 +33,9 @@ void IComponent::HandleMessage(const CMessage& UNUSED(msg), bool UNUSED(global)) { } -JSClass* IComponent::GetJSClass() const +bool IComponent::NewJSObject(ScriptInterface& UNUSED(scriptInterface), JS::MutableHandleObject UNUSED(out)) const { - return NULL; + return false; } jsval IComponent::GetJSInstance() const diff --git a/source/simulation2/system/IComponent.h b/source/simulation2/system/IComponent.h index 7e1b29a935..06873d0b28 100644 --- a/source/simulation2/system/IComponent.h +++ b/source/simulation2/system/IComponent.h @@ -56,7 +56,11 @@ public: virtual void Serialize(ISerializer& serialize) = 0; virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) = 0; - virtual JSClass* GetJSClass() const; + /** + * Returns false by default, indicating that a scripted wrapper of this IComponent is not supported. + * Derrived classes should return true if they implement such a wrapper. + */ + virtual bool NewJSObject(ScriptInterface& scriptInterface, JS::MutableHandleObject out) const; virtual jsval GetJSInstance() const; virtual int GetComponentTypeId() const = 0; diff --git a/source/simulation2/system/Interface.h b/source/simulation2/system/Interface.h index 9d1283877b..4308b4825e 100644 --- a/source/simulation2/system/Interface.h +++ b/source/simulation2/system/Interface.h @@ -21,7 +21,7 @@ #include "simulation2/system/IComponent.h" #define DECLARE_INTERFACE_TYPE(iname) \ - virtual JSClass* GetJSClass() const; \ + virtual bool NewJSObject(ScriptInterface& scriptInterface, JS::MutableHandleObject out) const; \ static void InterfaceInit(ScriptInterface& scriptInterface); \ static int GetInterfaceId() { return IID_##iname; } diff --git a/source/simulation2/system/InterfaceScripted.h b/source/simulation2/system/InterfaceScripted.h index f589849284..6c814f6ec8 100644 --- a/source/simulation2/system/InterfaceScripted.h +++ b/source/simulation2/system/InterfaceScripted.h @@ -32,12 +32,13 @@ { NULL } \ }; \ void ICmp##iname::InterfaceInit(ScriptInterface& scriptInterface) { \ - JSContext* cx = scriptInterface.GetContext(); \ - JSAutoRequest rq(cx); \ - JSObject* global = JS_GetGlobalForScopeChain(cx); \ - JS_InitClass(cx, global, NULL, &class_ICmp##iname, NULL, 0, NULL, methods_ICmp##iname, NULL, NULL); \ + scriptInterface.DefineCustomObjectType(&class_ICmp##iname, NULL, 0, NULL, methods_ICmp##iname, NULL, NULL); \ + } \ + bool ICmp##iname::NewJSObject(ScriptInterface& scriptInterface, JS::MutableHandleObject out) const\ + { \ + out.set(scriptInterface.CreateCustomObject("ICmp" #iname)); \ + return true; \ } \ - JSClass* ICmp##iname::GetJSClass() const { return &class_ICmp##iname; } \ void RegisterComponentInterface_##iname(ScriptInterface& scriptInterface) { \ ICmp##iname::InterfaceInit(scriptInterface); \ }