Index: source/gui/IGUIObject.h =================================================================== --- source/gui/IGUIObject.h +++ source/gui/IGUIObject.h @@ -101,9 +101,11 @@ friend class GUITooltip; // Allow getProperty to access things like GetParent() - friend bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp); - friend bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool UNUSED(strict), JS::MutableHandleValue vp); - friend bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, JS::Value* vp); + friend bool JSI_IGUIObject::getEventHandler(JSContext* cx, IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp); + friend bool JSI_IGUIObject::setEventHandler(JSContext* cx, IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp); + friend bool JSI_IGUIObject::getChildren(JSContext* cx, IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp); + friend bool JSI_IGUIObject::getParent(JSContext* cx, IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp); + friend bool JSI_IGUIObject::getComputedSize(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue rval); public: IGUIObject(CGUI* pGUI); Index: source/gui/IGUITextOwner.h =================================================================== --- source/gui/IGUITextOwner.h +++ source/gui/IGUITextOwner.h @@ -45,7 +45,7 @@ */ class IGUITextOwner : virtual public IGUIObject { - friend bool JSI_IGUITextOwner::GetTextSize(JSContext* cx, uint argc, JS::Value* vp); + friend bool JSI_IGUITextOwner::GetTextSize(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue rval); public: IGUITextOwner(CGUI* pGUI); Index: source/gui/scripting/GuiScriptConversions.cpp =================================================================== --- source/gui/scripting/GuiScriptConversions.cpp +++ source/gui/scripting/GuiScriptConversions.cpp @@ -170,6 +170,16 @@ return FromJSVal(cx, v, out); } +template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CRect& val) +{ + ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface->CreateObject( + ret, + "left", val.left, + "right", val.right, + "top", val.top, + "bottom", val.bottom); +} + template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CSize& val) { ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface->CreateObject(ret, "width", val.cx, "height", val.cy); Index: source/gui/scripting/JSInterface_IGUIObject.h =================================================================== --- source/gui/scripting/JSInterface_IGUIObject.h +++ source/gui/scripting/JSInterface_IGUIObject.h @@ -20,18 +20,34 @@ #include "scriptinterface/ScriptInterface.h" +class IGUIObject; +class CStr8; + namespace JSI_IGUIObject { extern JSClass JSI_class; extern JSFunctionSpec JSI_methods[]; - bool getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp); - bool setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool UNUSED(strict), JS::MutableHandleValue vp); - bool toString(JSContext* cx, uint argc, JS::Value* vp); - bool focus(JSContext* cx, uint argc, JS::Value* vp); - bool blur(JSContext* cx, uint argc, JS::Value* vp); - bool getComputedSize(JSContext* cx, uint argc, JS::Value* vp); - bool getTextSize(JSContext* cx, uint argc, JS::Value* vp); + + bool performOnGUIObject(JSContext* cx, JS::HandleObject thisObj, JS::MutableHandleValue vp, std::function action); + bool performObjectProperty(JSContext* cx, JS::HandleObject vp, JS::HandleId id, JS::MutableHandleValue, std::function action); + bool performObjectFunction(JSContext* cx, JS::Value* vp, std::function action); + bool getProperty(JSContext* cx, IGUIObject& obj, const CStr8& propName, JS::MutableHandleValue vp); + bool setProperty(JSContext* cx, IGUIObject& obj, const CStr8& propName, JS::MutableHandleValue vp); + bool getName(JSContext* cx, IGUIObject& obj, const CStr8& propName, JS::MutableHandleValue vp); + bool setName(JSContext* cx, IGUIObject& obj, const CStr8& propName, JS::MutableHandleValue vp); + + CStr8 getEventName(const CStr8& propName); + bool getEventHandler(JSContext* cx, IGUIObject& obj, const CStr8& propName, JS::MutableHandleValue vp); + bool setEventHandler(JSContext* cx, IGUIObject& obj, const CStr8& propName, JS::MutableHandleValue vp); + bool getParent(JSContext* cx, IGUIObject& obj, const CStr8& propName, JS::MutableHandleValue vp); + bool getChildren(JSContext* cx, IGUIObject& obj, const CStr8& propName, JS::MutableHandleValue vp); + void init(ScriptInterface& scriptInterface); + + bool toString(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue vp); + bool focus(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue vp); + bool blur(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue vp); + bool getComputedSize(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue vp); } #endif // INCLUDED_JSI_IGUIOBJECT Index: source/gui/scripting/JSInterface_IGUIObject.cpp =================================================================== --- source/gui/scripting/JSInterface_IGUIObject.cpp +++ source/gui/scripting/JSInterface_IGUIObject.cpp @@ -33,28 +33,47 @@ JSClass JSI_IGUIObject::JSI_class = { "GUIObject", JSCLASS_HAS_PRIVATE, nullptr, nullptr, - JSI_IGUIObject::getProperty, JSI_IGUIObject::setProperty, + [](JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) { return performObjectProperty(cx, obj, id, vp, getProperty); }, + [](JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool UNUSED(strict), JS::MutableHandleValue vp) { return performObjectProperty(cx, obj, id, vp, setProperty); }, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; JSFunctionSpec JSI_IGUIObject::JSI_methods[] = { - JS_FN("toString", JSI_IGUIObject::toString, 0, 0), - JS_FN("focus", JSI_IGUIObject::focus, 0, 0), - JS_FN("blur", JSI_IGUIObject::blur, 0, 0), - JS_FN("getComputedSize", JSI_IGUIObject::getComputedSize, 0, 0), + JS_FN("toString", [](JSContext* cx, uint UNUSED(argc), JS::Value* vp){ return performObjectFunction(cx, vp, toString); }, 0, 0), + JS_FN("focus", [](JSContext* cx, uint UNUSED(argc), JS::Value* vp){ return performObjectFunction(cx, vp, focus); }, 0, 0), + JS_FN("blur", [](JSContext* cx, uint UNUSED(argc), JS::Value* vp){ return performObjectFunction(cx, vp, blur); }, 0, 0), + JS_FN("getComputedSize", [](JSContext* cx, uint UNUSED(argc), JS::Value* vp){ return performObjectFunction(cx, vp, getComputedSize); }, 0, 0), JS_FS_END }; -bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) +bool JSI_IGUIObject::performOnGUIObject(JSContext* cx, JS::HandleObject thisObj, JS::MutableHandleValue vp, std::function action) { - JSAutoRequest rq(cx); - ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; + IGUIObject* obj = static_cast( + JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, nullptr)); - IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); - if (!e) + if (!obj) + { + JS_ReportError(cx, "JSI_IGUIObject could not determine the IGUIObject instance!"); return false; + } + + action(cx, *obj, vp); + return true; +} + +bool JSI_IGUIObject::performObjectFunction(JSContext* cx, JS::Value* vp, std::function action) +{ + JSAutoRequest rq(cx); + JS::CallReceiver rec = JS::CallReceiverFromVp(vp); + JS::RootedObject thisObj(cx, &rec.thisv().toObject()); + return performOnGUIObject(cx, thisObj, rec.rval(), action); +} + +bool JSI_IGUIObject::performObjectProperty(JSContext* cx, JS::HandleObject thisObj, JS::HandleId id, JS::MutableHandleValue vp, std::function action) +{ + JSAutoRequest rq(cx); JS::RootedValue idval(cx); if (!JS_IdToValue(cx, id, &idval)) @@ -64,6 +83,14 @@ if (!ScriptInterface::FromJSVal(cx, idval, propName)) return false; + return performOnGUIObject(cx, thisObj, vp, [&propName, action](JSContext* cx, IGUIObject& obj, JS::MutableHandleValue vp) + { + return action(cx, obj, propName, vp); + }); +} + +bool JSI_IGUIObject::getProperty(JSContext* cx, IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp) +{ // Skip registered functions and inherited properties // including JSInterfaces of derived classes if (propName == "constructor" || @@ -79,44 +106,20 @@ // Use onWhatever to access event handlers if (propName.substr(0, 2) == "on") - { - CStr eventName(CStr(propName.substr(2)).LowerCase()); - std::map>::iterator it = e->m_ScriptHandlers.find(eventName); - if (it == e->m_ScriptHandlers.end()) - vp.setNull(); - else - vp.setObject(*it->second.get()); - return true; - } + return getEventHandler(cx, obj, propName, vp); if (propName == "parent") - { - IGUIObject* parent = e->GetParent(); - - if (parent) - vp.set(JS::ObjectValue(*parent->GetJSObject())); - else - vp.set(JS::NullValue()); + return getParent(cx, obj, propName, vp); - return true; - } - else if (propName == "children") - { - pScriptInterface->CreateArray(vp); + if (propName == "children") + return getChildren(cx, obj, propName, vp); - for (size_t i = 0; i < e->m_Children.size(); ++i) - pScriptInterface->SetPropertyInt(vp, i, e->m_Children[i]); + if (propName == "name") + return getName(cx, obj, propName, vp); - return true; - } - else if (propName == "name") + if (obj.SettingExists(propName)) { - ScriptInterface::ToJSVal(cx, vp, e->GetName()); - return true; - } - else if (e->SettingExists(propName)) - { - e->m_Settings[propName].m_ToJSVal(cx, vp); + obj.m_Settings[propName].m_ToJSVal(cx, vp); return true; } @@ -124,51 +127,17 @@ return false; } -bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool UNUSED(strict), JS::MutableHandleValue vp) +bool JSI_IGUIObject::setProperty(JSContext* cx, IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp) { - IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); - if (!e) - return false; - - JSAutoRequest rq(cx); - JS::RootedValue idval(cx); - if (!JS_IdToValue(cx, id, &idval)) - return false; - - std::string propName; - if (!ScriptInterface::FromJSVal(cx, idval, propName)) - return false; - if (propName == "name") - { - std::string value; - if (!ScriptInterface::FromJSVal(cx, vp, value)) - return false; - e->SetName(value); - return true; - } - - JS::RootedObject vpObj(cx); - if (vp.isObject()) - vpObj = &vp.toObject(); + return setName(cx, obj, propName, vp); // Use onWhatever to set event handlers if (propName.substr(0, 2) == "on") - { - if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(cx, &vp.toObject())) - { - JS_ReportError(cx, "on- event-handlers must be functions"); - return false; - } - - CStr eventName(CStr(propName.substr(2)).LowerCase()); - e->SetScriptHandler(eventName, vpObj); - - return true; - } + return setEventHandler(cx, obj, propName, vp); - if (e->SettingExists(propName)) - return e->m_Settings[propName].m_FromJSVal(cx, vp); + if (obj.SettingExists(propName)) + return obj.m_Settings[propName].m_FromJSVal(cx, vp); JS_ReportError(cx, "Property '%s' does not exist!", propName.c_str()); return false; @@ -179,85 +148,98 @@ scriptInterface.DefineCustomObjectType(&JSI_class, nullptr, 1, nullptr, JSI_methods, nullptr, nullptr); } -bool JSI_IGUIObject::toString(JSContext* cx, uint UNUSED(argc), JS::Value* vp) +bool JSI_IGUIObject::toString(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue vp) { - JSAutoRequest rq(cx); - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); + ScriptInterface::ToJSVal(cx, vp, "[GUIObject: " + obj.GetName() + "]"); + return true; +} - JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); +bool JSI_IGUIObject::getName(JSContext* cx, IGUIObject& obj, const CStr& UNUSED(propName), JS::MutableHandleValue vp) +{ + ScriptInterface::ToJSVal(cx, vp, obj.GetName()); + return true; +} - IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); - if (!e) +bool JSI_IGUIObject::setName(JSContext* cx, IGUIObject& obj, const CStr& UNUSED(propName), JS::MutableHandleValue vp) +{ + CStr value; + if (!ScriptInterface::FromJSVal(cx, vp, value)) return false; - ScriptInterface::ToJSVal(cx, rec.rval(), "[GUIObject: " + e->GetName() + "]"); + obj.SetName(value); return true; } -bool JSI_IGUIObject::focus(JSContext* cx, uint UNUSED(argc), JS::Value* vp) +CStr JSI_IGUIObject::getEventName(const CStr& propName) { - JSAutoRequest rq(cx); - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); - - JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); + return CStr(propName.substr(2)).LowerCase(); +} - IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); - if (!e) - return false; +bool JSI_IGUIObject::getEventHandler(JSContext* UNUSED(cx), IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp) +{ + std::map>::iterator it = obj.m_ScriptHandlers.find(getEventName(propName)); - e->GetGUI()->SetFocusedObject(e); + if (it == obj.m_ScriptHandlers.end()) + vp.setNull(); + else + vp.setObject(*it->second.get()); - rec.rval().setUndefined(); return true; } -bool JSI_IGUIObject::blur(JSContext* cx, uint UNUSED(argc), JS::Value* vp) +bool JSI_IGUIObject::setEventHandler(JSContext* cx, IGUIObject& obj, const CStr& propName, JS::MutableHandleValue vp) { - JSAutoRequest rq(cx); - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); + if (!vp.isObject() || !JS_ObjectIsFunction(cx, &vp.toObject())) + { + JS_ReportError(cx, "on- event-handlers must be functions"); + return false; + } - JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); + JS::RootedObject vpObj(cx, &vp.toObject()); + obj.SetScriptHandler(getEventName(propName), vpObj); + return true; +} - IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); - if (!e) - return false; +bool JSI_IGUIObject::getParent(JSContext* UNUSED(cx), IGUIObject& obj, const CStr& UNUSED(propName), JS::MutableHandleValue vp) +{ + IGUIObject* parent = obj.GetParent(); - e->GetGUI()->SetFocusedObject(NULL); + if (parent) + vp.set(JS::ObjectValue(*parent->GetJSObject())); + else + vp.set(JS::NullValue()); - rec.rval().setUndefined(); return true; } -bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint UNUSED(argc), JS::Value* vp) +bool JSI_IGUIObject::getChildren(JSContext* cx, IGUIObject& obj, const CStr& UNUSED(propName), JS::MutableHandleValue vp) { - JSAutoRequest rq(cx); - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); + ScriptInterface& pScriptInterface = *ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; + pScriptInterface.CreateArray(vp); - JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); + for (size_t i = 0; i < obj.m_Children.size(); ++i) + pScriptInterface.SetPropertyInt(vp, i, obj.m_Children[i]); - IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); - if (!e) - return false; + return true; +} - e->UpdateCachedSize(); - CRect size = e->m_CachedActualSize; +bool JSI_IGUIObject::focus(JSContext* UNUSED(cx), IGUIObject& obj, JS::MutableHandleValue vp) +{ + obj.GetGUI()->SetFocusedObject(&obj); + vp.setUndefined(); + return true; +} - JS::RootedValue objVal(cx); - try - { - ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface->CreateObject( - &objVal, - "left", size.left, - "right", size.right, - "top", size.top, - "bottom", size.bottom); - } - catch (PSERROR_Scripting_ConversionFailed&) - { - debug_warn(L"Error creating size object!"); - return false; - } +bool JSI_IGUIObject::blur(JSContext* UNUSED(cx), IGUIObject& obj, JS::MutableHandleValue vp) +{ + obj.GetGUI()->SetFocusedObject(nullptr); + vp.setUndefined(); + return true; +} - rec.rval().set(objVal); +bool JSI_IGUIObject::getComputedSize(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue vp) +{ + obj.UpdateCachedSize(); + ScriptInterface::ToJSVal(cx, vp, obj.m_CachedActualSize); return true; } Index: source/gui/scripting/JSInterface_IGUITextOwner.h =================================================================== --- source/gui/scripting/JSInterface_IGUITextOwner.h +++ source/gui/scripting/JSInterface_IGUITextOwner.h @@ -20,13 +20,15 @@ #include "scriptinterface/ScriptInterface.h" +class IGUIObject; + namespace JSI_IGUITextOwner { extern JSFunctionSpec JSI_methods[]; void RegisterScriptFunctions(JSContext* cx, JS::HandleObject obj); - bool GetTextSize(JSContext* cx, uint argc, JS::Value* vp); + bool GetTextSize(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue rval); } #endif // INCLUDED_JSI_IGUITEXTOWNER Index: source/gui/scripting/JSInterface_IGUITextOwner.cpp =================================================================== --- source/gui/scripting/JSInterface_IGUITextOwner.cpp +++ source/gui/scripting/JSInterface_IGUITextOwner.cpp @@ -19,12 +19,14 @@ #include "JSInterface_IGUITextOwner.h" +#include "gui/IGUIObject.h" #include "gui/IGUITextOwner.h" +#include "gui/scripting/JSInterface_IGUIObject.h" #include "scriptinterface/ScriptInterface.h" JSFunctionSpec JSI_IGUITextOwner::JSI_methods[] = { - JS_FN("getTextSize", GetTextSize, 0, 0), + JS_FN("getTextSize", [](JSContext* cx, uint UNUSED(argc), JS::Value* vp){ return JSI_IGUIObject::performObjectFunction(cx, vp, GetTextSize); }, 0, 0), JS_FS_END }; @@ -33,27 +35,16 @@ JS_DefineFunctions(cx, obj, JSI_methods); } -bool JSI_IGUITextOwner::GetTextSize(JSContext* cx, uint UNUSED(argc), JS::Value* vp) +bool JSI_IGUITextOwner::GetTextSize(JSContext* cx, IGUIObject& obj, JS::MutableHandleValue rval) { - JSAutoRequest rq(cx); - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); - JS::RootedObject thisObj(cx, &rec.thisv().toObject()); - - IGUIObject* obj = static_cast(JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, nullptr)); - if (!obj) - { - JS_ReportError(cx, "This is not an IGUIObject!"); - return false; - } - // Avoid dynamic_cast for performance reasons - IGUITextOwner* objText = static_cast(obj->GetTextOwner()); + IGUITextOwner* objText = static_cast(obj.GetTextOwner()); if (!objText) { JS_ReportError(cx, "This IGUIObject is not an IGUITextOwner!"); return false; } - ScriptInterface::ToJSVal(cx, rec.rval(), objText->CalculateTextSize()); + ScriptInterface::ToJSVal(cx, rval, objText->CalculateTextSize()); return true; } Index: source/scriptinterface/NativeWrapperDefns.h =================================================================== --- source/scriptinterface/NativeWrapperDefns.h +++ source/scriptinterface/NativeWrapperDefns.h @@ -132,7 +132,7 @@ { \ JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \ JSAutoRequest rq(cx); \ - JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); \ + JS::RootedObject thisObj(cx, &args.thisv().toObject()); \ if (ScriptInterface::GetClass(thisObj) != CLS) return false; \ TC* c = static_cast(ScriptInterface::GetPrivate(thisObj)); \ if (! c) return false; \ @@ -152,7 +152,7 @@ { \ JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \ JSAutoRequest rq(cx); \ - JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); \ + JS::RootedObject thisObj(cx, &args.thisv().toObject()); \ if (ScriptInterface::GetClass(thisObj) != CLS) return false; \ TC* c = static_cast(ScriptInterface::GetPrivate(thisObj)); \ if (! c) return false; \