diff --git a/source/gui/GUIManager.cpp b/source/gui/GUIManager.cpp index 4e22da8b6c..06bbe85231 100644 --- a/source/gui/GUIManager.cpp +++ b/source/gui/GUIManager.cpp @@ -261,11 +261,14 @@ Status CGUIManager::ReloadChangedFile(const VfsPath& path) CScriptVal CGUIManager::GetSavedGameData(ScriptInterface*& pPageScriptInterface) { - CScriptVal data; - if (!top()->GetScriptInterface()->CallFunction(top()->GetGlobalObject(), "getSavedGameData", data)) + JSContext* cx = top()->GetScriptInterface()->GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue data(cx); + if (!top()->GetScriptInterface()->CallFunction(top()->GetGlobalObject(), "getSavedGameData", &data)) LOGERROR(L"Failed to call getSavedGameData() on the current GUI page"); pPageScriptInterface = GetScriptInterface().get(); - return data; + return CScriptVal(data); } std::string CGUIManager::GetSavedGameData() diff --git a/source/scriptinterface/NativeWrapperDecls.h b/source/scriptinterface/NativeWrapperDecls.h index a14c0afc33..54ea534d09 100644 --- a/source/scriptinterface/NativeWrapperDecls.h +++ b/source/scriptinterface/NativeWrapperDecls.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2014 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,6 +26,7 @@ #define NUMBERED_LIST_BALANCED(z, i, data) BOOST_PP_COMMA_IF(i) data##i // Some other things #define TYPED_ARGS(z, i, data) , T##i a##i +#define TYPED_ARGS_CONST_REF(z, i, data) const T##i& a##i, #define CONVERT_ARG(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal(cx, i < args.length() ? args.handleAt(i) : JS::UndefinedHandleValue, a##i)) return false; // List-generating macros, named roughly after their first list item @@ -35,6 +36,7 @@ #define T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, T) // "T0, T1, " #define T0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, T) // ", T0, T1" #define T0_A0(z, i) BOOST_PP_REPEAT_##z (i, TYPED_ARGS, ~) // "T0 a0, T1 a1" +#define T0_A0_CONST_REF(z, i) BOOST_PP_REPEAT_##z (i, TYPED_ARGS_CONST_REF, ~) // " const T0 a0, const T1 a1, " #define A0(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_BALANCED, a) // "a0, a1" #define A0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, a) // ", a0, a1" @@ -68,3 +70,19 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) static size_t nargs() { return i; } BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS + +// Call the named property on the given object +#define OVERLOADS(z, i, data) \ + template \ + bool CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) R& ret); +BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) +#undef OVERLOADS + +// The trick is using JS::Rooted* and converting that to a JS::MutableHandle explicitly in the function body. +// Normally the function would take JS::MutableHandle and that conversion would happen implicitly. However, implicit +// conversion does not work with template argument deduction (only exact type matches allowed). +#define OVERLOADS(z, i, data) \ + template \ + bool CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) JS::Rooted* ret); +BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) +#undef OVERLOADS diff --git a/source/scriptinterface/NativeWrapperDefns.h b/source/scriptinterface/NativeWrapperDefns.h index dc0aa37ebb..d84bd93ee3 100644 --- a/source/scriptinterface/NativeWrapperDefns.h +++ b/source/scriptinterface/NativeWrapperDefns.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2014 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -123,11 +123,52 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS +#define TO_JS_VAL(z, i, data) ToJSVal(cx, argv.handleAt(i), a##i); + +#define OVERLOADS(z, i, data) \ +template \ +bool ScriptInterface::CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) R& ret) \ +{ \ + JSContext* cx = GetContext(); \ + JSAutoRequest rq(cx); \ + JS::RootedValue jsRet(cx); \ + JS::RootedValue val1(cx, val); \ + JS::AutoValueVector argv(cx); \ + argv.resize(i); \ + BOOST_PP_REPEAT_##z (i, TO_JS_VAL, ~) \ + bool ok = CallFunction_(val1, name, argv.length(), argv.begin(), &jsRet); \ + if (!ok) \ + return false; \ + return FromJSVal(cx, jsRet, ret); \ +} +BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) +#undef OVERLOADS + +#define OVERLOADS(z, i, data) \ +template \ +bool ScriptInterface::CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) JS::Rooted* ret) \ +{ \ + JSContext* cx = GetContext(); \ + JSAutoRequest rq(cx); \ + JS::MutableHandle jsRet(ret); \ + JS::RootedValue val1(cx, val); \ + JS::AutoValueVector argv(cx); \ + argv.resize(i); \ + BOOST_PP_REPEAT_##z (i, TO_JS_VAL, ~) \ + bool ok = CallFunction_(val1, name, argv.length(), argv.begin(), jsRet); \ + if (!ok) \ + return false; \ + return true; \ +} +BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) +#undef OVERLOADS + // Clean up our mess #undef SCRIPT_PROFILE #undef NUMBERED_LIST_HEAD #undef NUMBERED_LIST_TAIL #undef NUMBERED_LIST_BALANCED +#undef TYPED_ARGS_CONST_REF #undef TYPED_ARGS #undef CONVERT_ARG #undef TYPENAME_T0_HEAD @@ -135,6 +176,7 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef T0 #undef T0_HEAD #undef T0_TAIL +#undef T0_A0_CONST_REF #undef T0_A0 #undef A0 #undef A0_TAIL diff --git a/source/scriptinterface/ScriptInterface.h b/source/scriptinterface/ScriptInterface.h index b18e890c77..ff64d2f1d6 100644 --- a/source/scriptinterface/ScriptInterface.h +++ b/source/scriptinterface/ScriptInterface.h @@ -170,36 +170,6 @@ public: template bool CallFunctionVoid(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2); - /** - * Call the named property on the given object, with return type R and 0 arguments - */ - template - bool CallFunction(jsval val, const char* name, R& ret); - - /** - * Call the named property on the given object, with return type R and 1 argument - */ - template - bool CallFunction(jsval val, const char* name, const T0& a0, R& ret); - - /** - * Call the named property on the given object, with return type R and 2 arguments - */ - template - bool CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, R& ret); - - /** - * Call the named property on the given object, with return type R and 3 arguments - */ - template - bool CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, R& ret); - - /** - * Call the named property on the given object, with return type R and 4 arguments - */ - template - bool CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, const T3& a3, R& ret); - JSObject* CreateCustomObject(const std::string & typeName); void DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs); @@ -444,19 +414,6 @@ public: // Implement those declared functions #include "NativeWrapperDefns.h" -template -bool ScriptInterface::CallFunction(jsval val, const char* name, R& ret) -{ - JSContext* cx = GetContext(); - JSAutoRequest rq(cx); - JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); - bool ok = CallFunction_(val1, name, 0, NULL, &jsRet); - if (!ok) - return false; - return FromJSVal(GetContext(), jsRet, ret); -} - template bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0) { @@ -499,76 +456,6 @@ bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0 return CallFunction_(val1, name, 3, argv.begin(), &jsRet); } -template -bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, R& ret) -{ - JSContext* cx = GetContext(); - JSAutoRequest rq(cx); - JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); - JS::AutoValueVector argv(cx); - argv.resize(1); - ToJSVal(cx, argv.handleAt(0), a0); - bool ok = CallFunction_(val1, name, 1, argv.begin(), &jsRet); - if (!ok) - return false; - return FromJSVal(cx, jsRet, ret); -} - -template -bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, R& ret) -{ - JSContext* cx = GetContext(); - JSAutoRequest rq(cx); - JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); - JS::AutoValueVector argv(cx); - argv.resize(2); - ToJSVal(cx, argv.handleAt(0), a0); - ToJSVal(cx, argv.handleAt(1), a1); - bool ok = CallFunction_(val1, name, 2, argv.begin(), &jsRet); - if (!ok) - return false; - return FromJSVal(cx, jsRet, ret); -} - -template -bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, R& ret) -{ - JSContext* cx = GetContext(); - JSAutoRequest rq(cx); - JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); - JS::AutoValueVector argv(cx); - argv.resize(3); - ToJSVal(cx, argv.handleAt(0), a0); - ToJSVal(cx, argv.handleAt(1), a1); - ToJSVal(cx, argv.handleAt(2), a2); - bool ok = CallFunction_(val1, name, 3, argv.begin(), &jsRet); - if (!ok) - return false; - return FromJSVal(cx, jsRet, ret); -} - -template -bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, const T3& a3, R& ret) -{ - JSContext* cx = GetContext(); - JSAutoRequest rq(cx); - JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); - JS::AutoValueVector argv(cx); - argv.resize(4); - ToJSVal(cx, argv.handleAt(0), a0); - ToJSVal(cx, argv.handleAt(1), a1); - ToJSVal(cx, argv.handleAt(2), a2); - ToJSVal(cx, argv.handleAt(3), a3); - bool ok = CallFunction_(val1, name, 4, argv.begin(), &jsRet); - if (!ok) - return false; - return FromJSVal(cx, jsRet, ret); -} - template bool ScriptInterface::SetGlobal(const char* name, const T& value, bool replace) {