Index: ps/trunk/source/gui/Scripting/GuiScriptConversions.cpp =================================================================== --- ps/trunk/source/gui/Scripting/GuiScriptConversions.cpp +++ ps/trunk/source/gui/Scripting/GuiScriptConversions.cpp @@ -22,6 +22,7 @@ #include "gui/SettingTypes/CGUIList.h" #include "gui/SettingTypes/CGUISeries.h" #include "gui/SettingTypes/CGUISize.h" +#include "gui/Scripting/JSInterface_GUIProxy.h" #include "lib/external_libraries/libsdl.h" #include "maths/Size2D.h" #include "maths/Vector2D.h" @@ -136,6 +137,22 @@ ret.setObject(*val->GetJSObject()); } +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, IGUIObject*& out) +{ + if (!v.isObject()) + { + ScriptException::Raise(rq, "Value is not an IGUIObject."); + return false; + } + out = IGUIProxyObject::FromPrivateSlot(v.toObjectOrNull()); + if (!out) + { + ScriptException::Raise(rq, "Value is not an IGUIObject."); + return false; + } + return true; +} + template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CGUIString& val) { ScriptInterface::ToJSVal(rq, ret, val.GetOriginalString()); Index: ps/trunk/source/gui/Scripting/JSInterface_GUIProxy.h =================================================================== --- ps/trunk/source/gui/Scripting/JSInterface_GUIProxy.h +++ ps/trunk/source/gui/Scripting/JSInterface_GUIProxy.h @@ -55,13 +55,19 @@ } using PrivateData = IGUIObject*; + template static T* FromPrivateSlot(JSObject* obj) { + return static_cast(FromPrivateSlot(obj)); + } +protected: + template + static T* UnsafeFromPrivateSlot(JSObject* obj) + { return static_cast(static_cast(js::GetProxyPrivate(obj).toPrivate())); } -protected: IGUIProxyObject() = default; IGUIProxyObject(const IGUIProxyObject&) = delete; IGUIProxyObject(IGUIProxyObject&&) = delete; @@ -69,6 +75,8 @@ JS::PersistentRootedObject m_Object; PrivateData m_Ptr; }; +// Declare the IGUIObject* specialization - it's defined in _impl.h +template<> IGUIObject* IGUIProxyObject::FromPrivateSlot(JSObject*); /** * Proxies need to store some data whose lifetime is tied to an interface. @@ -115,9 +123,6 @@ template friend class JSI_GUIProxy; public: - // Access the js::Class of the Proxy. - static JSClass& ClassDefinition(); - // For convenience, this is the single instantiated JSI_GUIProxy. static JSI_GUIProxy& Singleton(); @@ -134,6 +139,8 @@ // This also enforces making proxy handlers dataless static variables. ~JSI_GUIProxy() {}; + static GUIObjectType* FromPrivateSlot(const ScriptRequest&, JS::CallArgs& args); + // The default implementations need to know the type of the GUIProxyProps for this proxy type. // This is done by specializing this struct's alias type. struct PropCache; Index: ps/trunk/source/gui/Scripting/JSInterface_GUIProxy_impl.h =================================================================== --- ps/trunk/source/gui/Scripting/JSInterface_GUIProxy_impl.h +++ ps/trunk/source/gui/Scripting/JSInterface_GUIProxy_impl.h @@ -30,13 +30,6 @@ #include template -JSClass& JSI_GUIProxy::ClassDefinition() -{ - static JSClass c = PROXY_CLASS_DEF("GUIObjectProxy", JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy) | JSCLASS_HAS_RESERVED_SLOTS(1)); - return c; -} - -template JSI_GUIProxy& JSI_GUIProxy::Singleton() { static JSI_GUIProxy s; @@ -56,10 +49,11 @@ // Use a common namespace to avoid duplicating the symbols un-necessarily. namespace JSInterface_GUIProxy { -template -inline T* GuiObjectGetter(const ScriptRequest&, JS::CallArgs& args) +// All proxy objects share a class definition. +JSClass& ClassDefinition() { - return IGUIProxyObject::FromPrivateSlot(args.thisv().toObjectOrNull()); + static JSClass c = PROXY_CLASS_DEF("GUIObjectProxy", JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy) | JSCLASS_HAS_RESERVED_SLOTS(1)); + return c; } // Default implementation of the cache via unordered_map @@ -89,6 +83,16 @@ }; } +template<> +IGUIObject* IGUIProxyObject::FromPrivateSlot(JSObject* obj) +{ + if (!obj) + return nullptr; + if (JS_GetClass(obj) != &JSInterface_GUIProxy::ClassDefinition()) + return nullptr; + return UnsafeFromPrivateSlot(obj); +} + // The default propcache is a MapCache. template struct JSI_GUIProxy::PropCache @@ -97,6 +101,13 @@ }; template +T* JSI_GUIProxy::FromPrivateSlot(const ScriptRequest&, JS::CallArgs& args) +{ + // Call the unsafe version - this is only ever called from actual proxy objects. + return IGUIProxyObject::UnsafeFromPrivateSlot(args.thisv().toObjectOrNull()); +} + +template bool JSI_GUIProxy::PropGetter(JS::HandleObject proxy, const std::string& propName, JS::MutableHandleValue vp) const { using PropertyCache = typename PropCache::type; @@ -130,14 +141,14 @@ template void JSI_GUIProxy::CreateFunction(const ScriptRequest& rq, GUIProxyProps* cache, const std::string& name) { - cache->setFunction(rq, name, ScriptFunction::Create>(rq, name.c_str())); + cache->setFunction(rq, name, ScriptFunction::Create(rq, name.c_str())); } template std::unique_ptr JSI_GUIProxy::CreateJSObject(const ScriptRequest& rq, T* ptr, GUIProxyProps* dataPtr) { js::ProxyOptions options; - options.setClass(&ClassDefinition()); + options.setClass(&JSInterface_GUIProxy::ClassDefinition()); auto ret = std::make_unique(); ret->m_Ptr = static_cast(ptr);