mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-10-09 22:35:23 +00:00
[engine] [cocos2d-x] [jsb-adapter] 适配引擎 v2.4.12 版本
This commit is contained in:
238
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/Class.cpp
Normal file
238
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/Class.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "Class.h"
|
||||
#include <string>
|
||||
#include "CommonHeader.h"
|
||||
#include "ScriptEngine.h"
|
||||
#include "Utils.h"
|
||||
|
||||
namespace se {
|
||||
|
||||
napi_value *Class::_exports = nullptr;
|
||||
std::vector<Class *> __allClasses;
|
||||
|
||||
Class::Class() {
|
||||
__allClasses.push_back(this);
|
||||
};
|
||||
|
||||
Class::~Class() {
|
||||
}
|
||||
|
||||
/* static */
|
||||
Class *Class::create(const std::string &clsName, se::Object *parent, Object *parentProto, napi_callback ctor) {
|
||||
Class *cls = new Class();
|
||||
if (cls != nullptr && !cls->init(clsName, parent, parentProto, ctor)) {
|
||||
delete cls;
|
||||
cls = nullptr;
|
||||
}
|
||||
return cls;
|
||||
}
|
||||
|
||||
Class* Class::create(const std::initializer_list<const char *> &classPath, se::Object *parent, Object *parentProto, napi_callback ctor) {
|
||||
se::AutoHandleScope scope;
|
||||
se::Object *currentParent = parent;
|
||||
se::Value tmp;
|
||||
for (auto i = 0; i < classPath.size() - 1; i++) {
|
||||
bool ok = currentParent->getProperty(*(classPath.begin() + i), &tmp);
|
||||
assert(ok); // class or namespace in path is not defined
|
||||
currentParent = tmp.toObject();
|
||||
}
|
||||
return create(*(classPath.end() - 1), currentParent, parentProto, ctor);
|
||||
}
|
||||
|
||||
bool Class::init(const std::string &clsName, Object *parent, Object *parentProto, napi_callback ctor) {
|
||||
_name = clsName;
|
||||
_parent = parent;
|
||||
if (_parent != nullptr)
|
||||
_parent->incRef();
|
||||
_parentProto = parentProto;
|
||||
|
||||
if (_parentProto != nullptr)
|
||||
_parentProto->incRef();
|
||||
if (ctor) {
|
||||
_ctorFunc = ctor;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
napi_value Class::_defaultCtor(napi_env env, napi_callback_info info) {
|
||||
LOGE("check default ctor called");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Class::defineProperty(const char* name, napi_callback g, napi_callback s) {
|
||||
_properties.push_back({name, nullptr, nullptr, g, s, 0, napi_default_jsproperty, 0});
|
||||
}
|
||||
|
||||
void Class::defineProperty(const std::initializer_list<const char *> &names, napi_callback g, napi_callback s) {
|
||||
for (const auto *name : names) {
|
||||
defineProperty(name, g, s);
|
||||
}
|
||||
}
|
||||
|
||||
void Class::defineStaticProperty(const char* name, napi_callback g, napi_callback s) {
|
||||
if(g != nullptr && s != nullptr)
|
||||
_properties.push_back({name, nullptr, nullptr, g, s, 0, napi_static, 0});
|
||||
}
|
||||
|
||||
void Class::defineFunction(const char* name, napi_callback func) {
|
||||
// When Napi defines a function, it needs to add the enum attribute, otherwise JS cannot traverse the function
|
||||
_properties.push_back({name, nullptr, func, nullptr, nullptr, nullptr, napi_default_jsproperty, nullptr});
|
||||
}
|
||||
|
||||
void Class::defineStaticFunction(const char* name, napi_callback func) {
|
||||
_properties.push_back({name, nullptr, func, nullptr, nullptr, 0, napi_property_attributes((int)napi_static|(int)napi_writable), 0});
|
||||
}
|
||||
|
||||
void Class::defineFinalizeFunction(napi_finalize func) {
|
||||
assert(func != nullptr);
|
||||
_finalizeFunc = func;
|
||||
}
|
||||
|
||||
napi_finalize Class::_getFinalizeFunction() const {
|
||||
return _finalizeFunc;
|
||||
}
|
||||
|
||||
bool Class::install() {
|
||||
napi_value cons;
|
||||
napi_status status;
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_define_class(ScriptEngine::getEnv(), _name.c_str(), -1, _ctorFunc, nullptr, _properties.size(), _properties.data(), &cons));
|
||||
if (_parentProto) {
|
||||
inherit(ScriptEngine::getEnv(), cons, _parentProto->_getJSObject());
|
||||
}
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(),
|
||||
napi_create_reference(ScriptEngine::getEnv(), cons, 1, &_constructor));
|
||||
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(),
|
||||
napi_set_named_property(ScriptEngine::getEnv(), _parent->_getJSObject(), _name.c_str(), cons));
|
||||
|
||||
napi_value proto;
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_named_property(ScriptEngine::getEnv(), cons, "prototype", &proto));
|
||||
|
||||
if (status == napi_ok) {
|
||||
_proto = Object::_createJSObject(ScriptEngine::getEnv(), proto, nullptr);
|
||||
_proto->root();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
napi_status Class::inherit(napi_env env, napi_value subclass, napi_value superProto) {
|
||||
napi_value global, objectClass, setProto;
|
||||
napi_value argv[2];
|
||||
napi_value callbackResult = nullptr;
|
||||
|
||||
napi_get_global(env, &global);
|
||||
napi_status status = napi_get_named_property(env, global, "Object", &objectClass);
|
||||
if (status != napi_ok) {
|
||||
return napi_ok;
|
||||
}
|
||||
status = napi_get_named_property(env, objectClass, "setPrototypeOf", &setProto);
|
||||
if (status != napi_ok) {
|
||||
return napi_ok;
|
||||
}
|
||||
|
||||
status = napi_get_named_property(env, subclass, "prototype", &argv[0]);
|
||||
if (status != napi_ok) {
|
||||
return napi_ok;
|
||||
}
|
||||
argv[1] = superProto;
|
||||
status = napi_call_function(env, objectClass, setProto, 2, argv, &callbackResult);
|
||||
if (status != napi_ok) {
|
||||
return napi_ok;
|
||||
}
|
||||
|
||||
return napi_ok;
|
||||
}
|
||||
|
||||
napi_value Class::_createJSObjectWithClass(Class *cls) {
|
||||
napi_value obj = nullptr;
|
||||
napi_status status;
|
||||
assert(cls);
|
||||
napi_value clsCtor = cls->_getCtorFunc();
|
||||
if (!clsCtor) {
|
||||
LOGE("get ctor func err");
|
||||
return nullptr;
|
||||
}
|
||||
se::ScriptEngine::getInstance()->_setNeedCallConstructor(false);
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_new_instance( ScriptEngine::getEnv(), clsCtor, 0, nullptr, &obj));
|
||||
se::ScriptEngine::getInstance()->_setNeedCallConstructor(true);
|
||||
return obj;
|
||||
}
|
||||
|
||||
Object *Class::getProto() const {
|
||||
//not impl
|
||||
return _proto;
|
||||
}
|
||||
|
||||
napi_ref Class::_getCtorRef() const {
|
||||
return _constructor;
|
||||
}
|
||||
|
||||
napi_value Class::_getCtorFunc() const {
|
||||
assert(_constructor);
|
||||
napi_value result = nullptr;
|
||||
napi_status status;
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_reference_value(ScriptEngine::getEnv(), _constructor, &result));
|
||||
return result;
|
||||
}
|
||||
|
||||
void Class::_setCtor(Object *obj) {
|
||||
assert(!_ctor.has_value());
|
||||
_ctor = obj;
|
||||
if (obj != nullptr) {
|
||||
obj->root();
|
||||
obj->incRef();
|
||||
}
|
||||
}
|
||||
|
||||
void Class::destroy() {
|
||||
SAFE_DEC_REF(_parent);
|
||||
SAFE_DEC_REF(_proto);
|
||||
SAFE_DEC_REF(_parentProto);
|
||||
if (_ctor.has_value()) {
|
||||
if (_ctor.value() != nullptr) {
|
||||
_ctor.value()->unroot();
|
||||
_ctor.value()->decRef();
|
||||
}
|
||||
_ctor.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Class::cleanup() {
|
||||
for (auto cls : __allClasses) {
|
||||
cls->destroy();
|
||||
}
|
||||
|
||||
se::ScriptEngine::getInstance()->addAfterCleanupHook([]() {
|
||||
for (auto cls : __allClasses) {
|
||||
delete cls;
|
||||
}
|
||||
__allClasses.clear();
|
||||
});
|
||||
}
|
||||
}; // namespace se
|
81
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/Class.h
Normal file
81
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/Class.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include "CommonHeader.h"
|
||||
#include "Object.h"
|
||||
|
||||
namespace se {
|
||||
class Class {
|
||||
public:
|
||||
static Class *create(const std::string &clsName, se::Object *parent, Object *parentProto, napi_callback ctor = nullptr);
|
||||
static Class *create(const std::initializer_list<const char *> &classPath, se::Object *parent, Object *parentProto, napi_callback ctor = nullptr);
|
||||
|
||||
void defineFunction(const char* name, napi_callback func);
|
||||
void defineProperty(const char* name, napi_callback g, napi_callback s);
|
||||
void defineProperty(const std::initializer_list<const char *> &names, napi_callback g, napi_callback s);
|
||||
|
||||
void defineStaticFunction(const char* name, napi_callback func);
|
||||
void defineStaticProperty(const char* name, napi_callback g, napi_callback s);
|
||||
|
||||
static napi_value _createJSObjectWithClass(Class *cls);
|
||||
|
||||
void defineFinalizeFunction(napi_finalize func);
|
||||
napi_finalize _getFinalizeFunction() const;
|
||||
|
||||
|
||||
Object * getProto() const;
|
||||
bool install();
|
||||
napi_status inherit(napi_env env, napi_value subclass, napi_value superclass);
|
||||
napi_ref _getCtorRef() const;
|
||||
napi_value _getCtorFunc() const;
|
||||
const char * getName() const { return _name.c_str(); }
|
||||
static void setExports(napi_value *expPtr) { _exports = expPtr; }
|
||||
static void cleanup();
|
||||
// Private API used in wrapper
|
||||
void _setCtor(Object *obj); // NOLINT(readability-identifier-naming)
|
||||
inline const std::optional<Object *> &_getCtor() const { return _ctor; } // NOLINT(readability-identifier-naming)
|
||||
private:
|
||||
Class();
|
||||
~Class();
|
||||
bool init(const std::string &clsName, Object *parent, Object *parentProto, napi_callback ctor = nullptr);
|
||||
void destroy();
|
||||
static napi_value _defaultCtor(napi_env env, napi_callback_info info);
|
||||
|
||||
private:
|
||||
std::optional<Object *> _ctor;
|
||||
static napi_value * _exports;
|
||||
std::string _name;
|
||||
Object * _parent = nullptr;
|
||||
Object * _proto = nullptr;
|
||||
Object * _parentProto = nullptr;
|
||||
napi_callback _ctorFunc = Class::_defaultCtor;
|
||||
napi_ref _constructor = nullptr;
|
||||
std::vector<napi_property_descriptor> _properties;
|
||||
napi_finalize _finalizeFunc = nullptr;
|
||||
};
|
||||
}; // namespace se
|
@@ -0,0 +1,74 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <napi/native_api.h>
|
||||
#include "native_common.h"
|
||||
|
||||
// Empty value so that macros here are able to return NULL or void
|
||||
#define NODE_API_RETVAL_NOTHING // Intentionally blank #define
|
||||
|
||||
// Returns NULL on failed assertion.
|
||||
// This is meant to be used inside napi_callback methods.
|
||||
#define NODE_API_ASSERT(env, assertion, message) \
|
||||
NODE_API_ASSERT_BASE(env, assertion, message, NULL)
|
||||
|
||||
// Returns empty on failed assertion.
|
||||
// This is meant to be used inside functions with void return type.
|
||||
#define NODE_API_ASSERT_RETURN_VOID(env, assertion, message) \
|
||||
NODE_API_ASSERT_BASE(env, assertion, message, NODE_API_RETVAL_NOTHING)
|
||||
|
||||
#define NODE_API_CALL_BASE(env, the_call, ret_val) \
|
||||
do { \
|
||||
if ((the_call) != napi_ok) { \
|
||||
assert(false); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Returns nullptr if the_call doesn't return napi_ok.
|
||||
#define NODE_API_CALL(status, env, the_call) \
|
||||
status = the_call; \
|
||||
if (status != napi_ok) \
|
||||
LOGI("error:%d", status); \
|
||||
NODE_API_CALL_BASE(env, status, nullptr)
|
||||
|
||||
// Returns empty if the_call doesn't return napi_ok.
|
||||
#define NODE_API_CALL_RETURN_VOID(env, the_call) \
|
||||
NODE_API_CALL_BASE(env, the_call, NODE_API_RETVAL_NOTHING)
|
||||
|
||||
#define DECLARE_NODE_API_PROPERTY(name, func) \
|
||||
{ (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr }
|
||||
|
||||
#define DECLARE_NODE_API_GETTER(name, func) \
|
||||
{ (name), nullptr, nullptr, (func), nullptr, nullptr, napi_default, nullptr }
|
||||
|
||||
void add_returned_status(napi_env env,
|
||||
const char* key,
|
||||
napi_value object,
|
||||
char* expected_message,
|
||||
napi_status expected_status,
|
||||
napi_status actual_status);
|
||||
|
||||
void add_last_status(napi_env env, const char* key, napi_value return_value);
|
@@ -0,0 +1,145 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "HelperMacros.h"
|
||||
#include "../State.hpp"
|
||||
#include "Class.h"
|
||||
#include "Object.h"
|
||||
#include "ScriptEngine.h"
|
||||
#include "Utils.h"
|
||||
|
||||
SE_HOT napi_value jsbFunctionWrapper(napi_env env, napi_callback_info info, se_function_ptr func, const char *funcName) {
|
||||
napi_status status;
|
||||
bool ret = false;
|
||||
napi_value _this;
|
||||
se::ValueArray seArgs;
|
||||
seArgs.reserve(15);
|
||||
size_t argc = 15;
|
||||
napi_value args[15];
|
||||
NODE_API_CALL(status, env, napi_get_cb_info(env, info, &argc, args, &_this, NULL));
|
||||
|
||||
void* nativeThisObject = nullptr;
|
||||
status = napi_unwrap(env, _this, &nativeThisObject);
|
||||
se::internal::jsToSeArgs(argc, args, &seArgs);
|
||||
se::State state(nativeThisObject, seArgs);
|
||||
ret = func(state);
|
||||
if (!ret) {
|
||||
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", funcName, __FILE__, __LINE__);
|
||||
return nullptr;
|
||||
}
|
||||
napi_value retVal;
|
||||
if (se::internal::setReturnValue(state.rval(), retVal))
|
||||
return retVal;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SE_HOT void jsbFinalizeWrapper(void *thisObject, se_function_ptr func, const char *funcName) {
|
||||
se::State state(reinterpret_cast<se::Object *>(thisObject));
|
||||
bool ret = func(state);
|
||||
if (!ret) {
|
||||
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", funcName, __FILE__, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
SE_HOT napi_value jsbConstructorWrapper(napi_env env, napi_callback_info info, se_function_ptr func, se_finalize_ptr finalizeCb, se::Class *cls, const char *funcName) {
|
||||
napi_status status;
|
||||
bool ret = false;
|
||||
napi_value _this;
|
||||
se::ValueArray seArgs;
|
||||
seArgs.reserve(10);
|
||||
size_t argc = 10;
|
||||
napi_value args[10];
|
||||
NODE_API_CALL(status, env, napi_get_cb_info(env, info, &argc, args, &_this, NULL));
|
||||
if (!se::ScriptEngine::getInstance()->_needCallConstructor()) {
|
||||
return _this;
|
||||
}
|
||||
se::internal::jsToSeArgs(argc, args, &seArgs);
|
||||
se::Object *thisObject = se::Object::_createJSObject(env, _this, cls);
|
||||
thisObject->_setFinalizeCallback(finalizeCb);
|
||||
se::State state(thisObject, seArgs);
|
||||
ret = func(state);
|
||||
if (!ret) {
|
||||
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", funcName, __FILE__, __LINE__);
|
||||
}
|
||||
se::Value property;
|
||||
bool foundCtor = false;
|
||||
if (!cls->_getCtor().has_value()) {
|
||||
foundCtor = thisObject->getProperty("_ctor", &property, true);
|
||||
if (foundCtor) {
|
||||
cls->_setCtor(property.toObject());
|
||||
} else {
|
||||
cls->_setCtor(nullptr);
|
||||
}
|
||||
} else {
|
||||
auto *ctorObj = cls->_getCtor().value();
|
||||
if (ctorObj != nullptr) {
|
||||
property.setObject(ctorObj);
|
||||
foundCtor = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundCtor) {
|
||||
property.toObject()->call(seArgs, thisObject);
|
||||
}
|
||||
return _this;
|
||||
}
|
||||
|
||||
SE_HOT napi_value jsbGetterWrapper(napi_env env, napi_callback_info info, se_function_ptr func, const char *funcName) {
|
||||
napi_value _this;
|
||||
napi_status status;
|
||||
NODE_API_CALL(status, env,
|
||||
napi_get_cb_info(env, info, nullptr, nullptr, &_this, nullptr));
|
||||
void* obj = nullptr;
|
||||
status = napi_unwrap(env, _this, &obj);
|
||||
se::State state(obj);
|
||||
bool ret = func(state);
|
||||
if (!ret) {
|
||||
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", funcName, __FILE__, __LINE__);
|
||||
return nullptr;
|
||||
}
|
||||
napi_value retVal;
|
||||
se::internal::setReturnValue(state.rval(), retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
SE_HOT napi_value jsbSetterWrapper(napi_env env, napi_callback_info info, se_function_ptr func, const char *funcName) {
|
||||
napi_status status;
|
||||
size_t argc = 1;
|
||||
napi_value args[1];
|
||||
napi_value _this;
|
||||
se::Value data;
|
||||
NODE_API_CALL(status, env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
|
||||
se::internal::jsToSeValue(args[0], &data);
|
||||
se::ValueArray args2;
|
||||
args2.reserve(10);
|
||||
args2.push_back(std::move(data));
|
||||
void* nativeThisObject = nullptr;
|
||||
status = napi_unwrap(env, _this, &nativeThisObject);
|
||||
se::State state(nativeThisObject, args2);
|
||||
bool ret = func(state);
|
||||
if (!ret) {
|
||||
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", funcName, __FILE__, __LINE__);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
@@ -0,0 +1,153 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CommonHeader.h"
|
||||
#if !defined(_WIN)
|
||||
#include <hilog/log.h>
|
||||
|
||||
#ifndef LOGI
|
||||
#define LOGI(...) ((void) OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "HMG_LOG", __VA_ARGS__))
|
||||
#define LOGW(...) ((void) OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, "HMG_LOG", __VA_ARGS__))
|
||||
#define LOGE(...) ((void) OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "HMG_LOG", __VA_ARGS__))
|
||||
#define LOGD(...) ((void) OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, "HMG_LOG", __VA_ARGS__))
|
||||
#endif
|
||||
#else
|
||||
#define LOGI
|
||||
#define LOGW
|
||||
#define LOGE
|
||||
#endif
|
||||
namespace se {
|
||||
class Class;
|
||||
class Object;
|
||||
class State;
|
||||
} // namespace se
|
||||
using se_function_ptr = bool (*)(se::State &state);
|
||||
using se_finalize_ptr = void (*)(napi_env env, void *nativeObject, void *hint);
|
||||
|
||||
napi_value jsbFunctionWrapper(napi_env, napi_callback_info,
|
||||
se_function_ptr,
|
||||
const char *);
|
||||
void jsbFinalizeWrapper(void *thisObject,
|
||||
se_function_ptr,
|
||||
const char *);
|
||||
napi_value jsbConstructorWrapper(napi_env, napi_callback_info,
|
||||
se_function_ptr,
|
||||
se_finalize_ptr finalizeCb,
|
||||
se::Class *,
|
||||
const char *);
|
||||
napi_value jsbGetterWrapper(napi_env, napi_callback_info,
|
||||
se_function_ptr,
|
||||
const char *);
|
||||
napi_value jsbSetterWrapper(napi_env, napi_callback_info,
|
||||
se_function_ptr,
|
||||
const char *);
|
||||
#ifdef __GNUC__
|
||||
#define SE_UNUSED __attribute__((unused))
|
||||
#define SE_HOT __attribute__((hot))
|
||||
#else
|
||||
#define SE_UNUSED
|
||||
#define SE_HOT
|
||||
#endif
|
||||
|
||||
template <typename T, typename STATE>
|
||||
constexpr inline T *SE_THIS_OBJECT(STATE &s) { // NOLINT(readability-identifier-naming)
|
||||
return reinterpret_cast<T *>(s.nativeThisObject());
|
||||
}
|
||||
|
||||
#define SAFE_INC_REF(obj) \
|
||||
if (obj != nullptr) obj->incRef()
|
||||
#define SAFE_DEC_REF(obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
(obj)->decRef(); \
|
||||
(obj) = nullptr; \
|
||||
}
|
||||
#define _SE(name) name##Registry // NOLINT(readability-identifier-naming, bugprone-reserved-identifier)
|
||||
|
||||
#define SE_QUOTEME_(x) #x // NOLINT(readability-identifier-naming)
|
||||
#define SE_QUOTEME(x) SE_QUOTEME_(x)
|
||||
#define SE_REPORT_ERROR(fmt, ...) SE_LOGE("[ERROR] (" __FILE__ ", " SE_QUOTEME(__LINE__) "): " fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
#define SE_BIND_PROP_GET_IMPL(funcName, postFix) \
|
||||
napi_value funcName##postFix##Registry(napi_env env, napi_callback_info info) { \
|
||||
return jsbGetterWrapper(env, info, funcName, #funcName); \
|
||||
}
|
||||
|
||||
#define SE_BIND_PROP_GET(funcName) SE_BIND_PROP_GET_IMPL(funcName, )
|
||||
#define SE_BIND_FUNC_AS_PROP_GET(funcName) SE_BIND_PROP_GET_IMPL(funcName, _asGetter)
|
||||
|
||||
#define SE_BIND_PROP_SET_IMPL(funcName, postFix) \
|
||||
napi_value funcName##postFix##Registry(napi_env env, napi_callback_info info) { \
|
||||
return jsbSetterWrapper(env, info, funcName, #funcName); \
|
||||
}
|
||||
|
||||
#define SE_BIND_PROP_SET(funcName) SE_BIND_PROP_SET_IMPL(funcName, )
|
||||
#define SE_BIND_FUNC_AS_PROP_SET(funcName) SE_BIND_PROP_SET_IMPL(funcName, _asSetter)
|
||||
|
||||
#define SE_DECLARE_FUNC(funcName) \
|
||||
napi_value funcName##Registry(napi_env env, napi_callback_info info)
|
||||
|
||||
#define SE_BIND_FUNC(funcName) \
|
||||
napi_value funcName##Registry( \
|
||||
napi_env env, napi_callback_info info) { \
|
||||
return jsbFunctionWrapper(env, info, funcName, #funcName); \
|
||||
}
|
||||
|
||||
#define SE_BIND_FUNC_FAST(funcName) \
|
||||
napi_value funcName##Registry(napi_env env, napi_callback_info info) { \
|
||||
napi_status status; \
|
||||
napi_value _this; \
|
||||
size_t argc = 10; \
|
||||
napi_value args[10]; \
|
||||
void* nativeThisObject = nullptr; \
|
||||
NODE_API_CALL(status, env, napi_get_cb_info(env, info, &argc, args, &_this, NULL)); \
|
||||
status = napi_unwrap(env, _this, &nativeThisObject); \
|
||||
auto *nativeObject = nativeThisObject != nullptr ? nativeThisObject->getPrivateData() : nullptr; \
|
||||
funcName(nativeObject); \
|
||||
return nullptr; \
|
||||
}
|
||||
|
||||
#define SE_BIND_CTOR(funcName, cls, finalizeCb) \
|
||||
napi_value funcName##Registry( \
|
||||
napi_env env, napi_callback_info info) { \
|
||||
return jsbConstructorWrapper(env, info, funcName, _SE(finalizeCb), cls, #funcName); \
|
||||
}
|
||||
|
||||
#define SE_BIND_SUB_CLS_CTOR SE_BIND_CTOR
|
||||
|
||||
#define SE_DECLARE_FINALIZE_FUNC(funcName) \
|
||||
void funcName##Registry( \
|
||||
napi_env env, void *nativeObject, void * /*finalize_hint*/);
|
||||
|
||||
#define SE_BIND_FINALIZE_FUNC(funcName) \
|
||||
void funcName##Registry( \
|
||||
napi_env env, void *nativeObject, void *hint /*finalize_hint*/) { \
|
||||
if (nativeObject == nullptr) { \
|
||||
return; \
|
||||
} \
|
||||
jsbFinalizeWrapper(nativeObject, funcName, #funcName); \
|
||||
}
|
||||
|
738
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/Object.cpp
Normal file
738
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/Object.cpp
Normal file
@@ -0,0 +1,738 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "Object.h"
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include "../MappingUtils.hpp"
|
||||
#include "Class.h"
|
||||
#include "ScriptEngine.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#define MAX_STRING_LEN 512
|
||||
namespace se {
|
||||
std::unique_ptr<std::unordered_map<Object*, void*>> __objectMap; // Currently, the value `void*` is always nullptr
|
||||
|
||||
Object::Object() {}
|
||||
Object::~Object() {
|
||||
if (__objectMap) {
|
||||
__objectMap->erase(this);
|
||||
}
|
||||
}
|
||||
|
||||
Object* Object::createObjectWithClass(Class* cls) {
|
||||
napi_value jsobj = Class::_createJSObjectWithClass(cls);
|
||||
Object* obj = Object::_createJSObject(ScriptEngine::getEnv(), jsobj, cls);
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool Object::setProperty(const char* name, const Value& data) {
|
||||
napi_status status;
|
||||
napi_value jsVal;
|
||||
internal::seToJsValue(data, &jsVal);
|
||||
NODE_API_CALL(status, _env, napi_set_named_property(_env, _objRef.getValue(_env), name, jsVal));
|
||||
return status == napi_ok;
|
||||
}
|
||||
|
||||
bool Object::getProperty(const char* name, Value* d) {
|
||||
napi_status status;
|
||||
napi_value jsVal;
|
||||
Value data;
|
||||
NODE_API_CALL(status, _env, napi_get_named_property(_env, _objRef.getValue(_env), name, &jsVal));
|
||||
if (status == napi_ok) {
|
||||
internal::jsToSeValue(jsVal, &data);
|
||||
*d = data;
|
||||
if (data.isUndefined()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Object::deleteProperty(const char *name) {
|
||||
napi_status status;
|
||||
napi_value key;
|
||||
NODE_API_CALL(status, _env, napi_get_named_property(_env, _objRef.getValue(_env), name, &key));
|
||||
if (status != napi_ok) {
|
||||
return false;
|
||||
}
|
||||
bool ret = false;
|
||||
NODE_API_CALL(status, _env, napi_delete_property(_env, _objRef.getValue(_env), key, &ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Object::isArray() const {
|
||||
napi_status status;
|
||||
bool ret = false;
|
||||
NODE_API_CALL(status, _env, napi_is_array(_env, _objRef.getValue(_env), &ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Object::getArrayLength(uint32_t* length) const {
|
||||
napi_status status;
|
||||
uint32_t len = 0;
|
||||
NODE_API_CALL(status, _env, napi_get_array_length(_env, _objRef.getValue(_env), &len));
|
||||
if (length) {
|
||||
*length = len;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Object::getArrayElement(uint32_t index, Value* data) const {
|
||||
napi_status status;
|
||||
napi_value val;
|
||||
NODE_API_CALL(status, _env, napi_get_element(_env, _objRef.getValue(_env), index, &val));
|
||||
internal::jsToSeValue(val, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Object::setArrayElement(uint32_t index, const Value& data) {
|
||||
napi_status status;
|
||||
napi_value val;
|
||||
internal::seToJsValue(data, &val);
|
||||
NODE_API_CALL(status, _env, napi_set_element(_env, _objRef.getValue(_env), index, val));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Object::isTypedArray() const {
|
||||
napi_status status;
|
||||
bool ret = false;
|
||||
NODE_API_CALL(status, _env, napi_is_typedarray(_env, _objRef.getValue(_env), &ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Object::isProxy() const {
|
||||
//return const_cast<Object *>(this)->_obj.handle(__isolate)->IsProxy();
|
||||
// todo:
|
||||
return false;
|
||||
}
|
||||
|
||||
Object::TypedArrayType Object::getTypedArrayType() const {
|
||||
napi_status status;
|
||||
napi_typedarray_type type;
|
||||
napi_value inputBuffer;
|
||||
size_t byteOffset;
|
||||
size_t length;
|
||||
NODE_API_CALL(status, _env, napi_get_typedarray_info(_env, _objRef.getValue(_env), &type, &length, NULL, &inputBuffer, &byteOffset));
|
||||
|
||||
TypedArrayType ret = TypedArrayType::NONE;
|
||||
switch (type) {
|
||||
case napi_int8_array:
|
||||
ret = TypedArrayType::INT8;
|
||||
break;
|
||||
case napi_uint8_array:
|
||||
ret = TypedArrayType::UINT8;
|
||||
break;
|
||||
case napi_uint8_clamped_array:
|
||||
ret = TypedArrayType::UINT8_CLAMPED;
|
||||
break;
|
||||
case napi_int16_array:
|
||||
ret = TypedArrayType::INT16;
|
||||
break;
|
||||
case napi_uint16_array:
|
||||
ret = TypedArrayType::UINT16;
|
||||
break;
|
||||
case napi_int32_array:
|
||||
ret = TypedArrayType::INT32;
|
||||
break;
|
||||
case napi_uint32_array:
|
||||
ret = TypedArrayType::UINT32;
|
||||
break;
|
||||
case napi_float32_array:
|
||||
ret = TypedArrayType::FLOAT32;
|
||||
break;
|
||||
case napi_float64_array:
|
||||
ret = TypedArrayType::FLOAT64;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Object::getTypedArrayData(uint8_t** ptr, size_t* length) const {
|
||||
napi_status status;
|
||||
napi_typedarray_type type;
|
||||
napi_value inputBuffer;
|
||||
size_t byteOffset;
|
||||
size_t byteLength;
|
||||
void* data = nullptr;
|
||||
NODE_API_CALL(status, _env, napi_get_typedarray_info(_env, _objRef.getValue(_env), &type, &byteLength, &data, &inputBuffer, &byteOffset));
|
||||
*ptr = (uint8_t*)(data);
|
||||
if (length) {
|
||||
*length = byteLength;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Object::isArrayBuffer() const {
|
||||
bool ret = false;
|
||||
napi_status status;
|
||||
NODE_API_CALL(status, _env, napi_is_arraybuffer(_env, _objRef.getValue(_env), &ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Object::getArrayBufferData(uint8_t** ptr, size_t* length) const {
|
||||
napi_status status;
|
||||
size_t len = 0;
|
||||
NODE_API_CALL(status, _env, napi_get_arraybuffer_info(_env, _objRef.getValue(_env), reinterpret_cast<void**>(ptr), &len));
|
||||
if (length) {
|
||||
*length = len;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Object* Object::createTypedArray(Object::TypedArrayType type, const void* data, size_t byteLength) {
|
||||
napi_status status;
|
||||
if (type == TypedArrayType::NONE) {
|
||||
SE_LOGE("Don't pass se::Object::TypedArrayType::NONE to createTypedArray API!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (type == TypedArrayType::UINT8_CLAMPED) {
|
||||
SE_LOGE("Doesn't support to create Uint8ClampedArray with Object::createTypedArray API!");
|
||||
return nullptr;
|
||||
}
|
||||
napi_typedarray_type napiType;
|
||||
napi_value outputBuffer;
|
||||
void* outputPtr = nullptr;
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_arraybuffer(ScriptEngine::getEnv(), byteLength, &outputPtr, &outputBuffer));
|
||||
if (outputPtr && data && byteLength > 0) {
|
||||
memcpy(outputPtr, data, byteLength);
|
||||
}
|
||||
size_t sizeOfEle = 0;
|
||||
switch (type) {
|
||||
case TypedArrayType::INT8:
|
||||
napiType = napi_int8_array;
|
||||
sizeOfEle = 1;
|
||||
break;
|
||||
case TypedArrayType::UINT8:
|
||||
napiType = napi_uint8_array;
|
||||
sizeOfEle = 1;
|
||||
break;
|
||||
case TypedArrayType::INT16:
|
||||
napiType = napi_int16_array;
|
||||
sizeOfEle = 2;
|
||||
break;
|
||||
case TypedArrayType::UINT16:
|
||||
napiType = napi_uint16_array;
|
||||
sizeOfEle = 2;
|
||||
break;
|
||||
case TypedArrayType::INT32:
|
||||
napiType = napi_int32_array;
|
||||
sizeOfEle = 4;
|
||||
break;
|
||||
case TypedArrayType::UINT32:
|
||||
napiType = napi_uint32_array;
|
||||
sizeOfEle = 4;
|
||||
break;
|
||||
case TypedArrayType::FLOAT32:
|
||||
napiType = napi_float32_array;
|
||||
sizeOfEle = 4;
|
||||
break;
|
||||
case TypedArrayType::FLOAT64:
|
||||
napiType = napi_float64_array;
|
||||
sizeOfEle = 8;
|
||||
break;
|
||||
default:
|
||||
assert(false); // Should never go here.
|
||||
break;
|
||||
}
|
||||
size_t eleCounts = byteLength / sizeOfEle;
|
||||
napi_value outputArray;
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_typedarray(ScriptEngine::getEnv(), napiType, eleCounts, outputBuffer, 0, &outputArray));
|
||||
|
||||
Object* obj = Object::_createJSObject(ScriptEngine::getEnv(), outputArray, nullptr);
|
||||
return obj;
|
||||
}
|
||||
|
||||
Object* Object::createTypedArrayWithBuffer(TypedArrayType type, const Object *obj) {
|
||||
return Object::createTypedArrayWithBuffer(type, obj, 0);
|
||||
}
|
||||
|
||||
Object* Object::createTypedArrayWithBuffer(TypedArrayType type, const Object *obj, size_t offset) {
|
||||
size_t byteLength{0};
|
||||
uint8_t *skip{nullptr};
|
||||
|
||||
if (obj->getArrayBufferData(&skip, &byteLength)) {
|
||||
return Object::createTypedArrayWithBuffer(type, obj, offset, byteLength - offset);
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Object* Object::createTypedArrayWithBuffer(TypedArrayType type, const Object *obj, size_t offset, size_t byteLength) {
|
||||
if (type == TypedArrayType::NONE) {
|
||||
SE_LOGE("Don't pass se::Object::TypedArrayType::NONE to createTypedArray API!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (type == TypedArrayType::UINT8_CLAMPED) {
|
||||
SE_LOGE("Doesn't support to create Uint8ClampedArray with Object::createTypedArray API!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
assert(obj->isArrayBuffer());
|
||||
napi_status status;
|
||||
napi_value outputBuffer = obj->_getJSObject();
|
||||
napi_typedarray_type napiType;
|
||||
|
||||
size_t sizeOfEle = 0;
|
||||
switch (type) {
|
||||
case TypedArrayType::INT8:
|
||||
napiType = napi_int8_array;
|
||||
sizeOfEle = 1;
|
||||
break;
|
||||
case TypedArrayType::UINT8:
|
||||
napiType = napi_uint8_array;
|
||||
sizeOfEle = 1;
|
||||
break;
|
||||
case TypedArrayType::INT16:
|
||||
napiType = napi_int8_array;
|
||||
sizeOfEle = 2;
|
||||
case TypedArrayType::UINT16:
|
||||
napiType = napi_uint8_array;
|
||||
sizeOfEle = 2;
|
||||
break;
|
||||
case TypedArrayType::INT32:
|
||||
napiType = napi_int32_array;
|
||||
sizeOfEle = 4;
|
||||
case TypedArrayType::UINT32:
|
||||
napiType = napi_uint32_array;
|
||||
sizeOfEle = 4;
|
||||
case TypedArrayType::FLOAT32:
|
||||
napiType = napi_float32_array;
|
||||
sizeOfEle = 4;
|
||||
break;
|
||||
case TypedArrayType::FLOAT64:
|
||||
napiType = napi_float64_array;
|
||||
sizeOfEle = 8;
|
||||
break;
|
||||
default:
|
||||
assert(false); // Should never go here.
|
||||
break;
|
||||
}
|
||||
size_t eleCounts = byteLength / sizeOfEle;
|
||||
napi_value outputArray;
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_typedarray(ScriptEngine::getEnv(), napiType, eleCounts, outputBuffer, offset, &outputArray));
|
||||
|
||||
return Object::_createJSObject(ScriptEngine::getEnv(), outputArray, nullptr);
|
||||
}
|
||||
|
||||
Object* Object::createExternalArrayBufferObject(void *contents, size_t byteLength, BufferContentsFreeFunc freeFunc, void *freeUserData) {
|
||||
napi_status status;
|
||||
napi_value result;
|
||||
if (freeFunc) {
|
||||
struct ExternalArrayBufferCallbackParams* param = new (struct ExternalArrayBufferCallbackParams);
|
||||
param->func = freeFunc;
|
||||
param->contents = contents;
|
||||
param->byteLength = byteLength;
|
||||
param->userData = freeUserData;
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_external_arraybuffer(
|
||||
ScriptEngine::getEnv(), contents, byteLength, [](napi_env env, void* finalize_data, void* finalize_hint) {
|
||||
if (finalize_hint) {
|
||||
struct ExternalArrayBufferCallbackParams* param = reinterpret_cast<struct ExternalArrayBufferCallbackParams *>(finalize_hint);
|
||||
param->func(param->contents, param->byteLength, param->userData);
|
||||
delete param;
|
||||
}
|
||||
},
|
||||
reinterpret_cast<void*>(param), &result));
|
||||
} else {
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_external_arraybuffer(
|
||||
ScriptEngine::getEnv(), contents, byteLength, nullptr,
|
||||
freeUserData, &result));
|
||||
}
|
||||
|
||||
Object* obj = Object::_createJSObject(ScriptEngine::getEnv(), result, nullptr);
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool Object::isFunction() const {
|
||||
napi_valuetype valuetype0;
|
||||
napi_status status;
|
||||
NODE_API_CALL(status, _env, napi_typeof(_env, _objRef.getValue(_env), &valuetype0));
|
||||
return (valuetype0 == napi_function);
|
||||
}
|
||||
|
||||
bool Object::defineFunction(const char* funcName, napi_callback func) {
|
||||
napi_value fn;
|
||||
napi_status status;
|
||||
NODE_API_CALL(status, _env, napi_create_function(_env, funcName, NAPI_AUTO_LENGTH, func, NULL, &fn));
|
||||
NODE_API_CALL(status, _env, napi_set_named_property(_env, _objRef.getValue(_env), funcName, fn));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Object::defineProperty(const char* name, napi_callback getter, napi_callback setter) {
|
||||
napi_status status;
|
||||
napi_property_descriptor properties[] = {{name, nullptr, nullptr, getter, setter, 0, napi_default, 0}};
|
||||
status = napi_define_properties(_env, _objRef.getValue(_env), sizeof(properties) / sizeof(napi_property_descriptor), properties);
|
||||
if (status == napi_ok) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Object* Object::_createJSObject(napi_env env, napi_value js_object, Class* cls) { // NOLINT(readability-identifier-naming)
|
||||
Object* ret = new Object();
|
||||
if (!ret->init(env, js_object, cls)) {
|
||||
delete ret;
|
||||
ret = nullptr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Object* Object::createPlainObject() {
|
||||
napi_value result;
|
||||
napi_status status;
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_object(ScriptEngine::getEnv(), &result));
|
||||
Object* obj = _createJSObject(ScriptEngine::getEnv(), result, nullptr);
|
||||
return obj;
|
||||
}
|
||||
|
||||
Object* Object::createArrayObject(size_t length) {
|
||||
napi_value result;
|
||||
napi_status status;
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_array_with_length(ScriptEngine::getEnv(), length, &result));
|
||||
Object* obj = _createJSObject(ScriptEngine::getEnv(), result, nullptr);
|
||||
return obj;
|
||||
}
|
||||
|
||||
Object* Object::createArrayBufferObject(const void* data, size_t byteLength) {
|
||||
napi_value result;
|
||||
napi_status status;
|
||||
void* retData;
|
||||
Object* obj = nullptr;
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_arraybuffer(ScriptEngine::getEnv(), byteLength, &retData, &result));
|
||||
if (status == napi_ok) {
|
||||
if (data) {
|
||||
memcpy(retData, data, byteLength);
|
||||
}
|
||||
obj = _createJSObject(ScriptEngine::getEnv(), result, nullptr);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool Object::getAllKeys(std::vector<std::string>* allKeys) const {
|
||||
napi_status status;
|
||||
napi_value names;
|
||||
|
||||
NODE_API_CALL(status, _env, napi_get_property_names(_env, _objRef.getValue(_env), &names));
|
||||
if (status != napi_ok) {
|
||||
return false;
|
||||
}
|
||||
uint32_t name_len = 0;
|
||||
NODE_API_CALL(status, _env, napi_get_array_length(_env, names, &name_len));
|
||||
for (uint32_t i = 0; i < name_len; i++) {
|
||||
napi_value val;
|
||||
NODE_API_CALL(status, _env, napi_get_element(_env, names, i, &val));
|
||||
if (status == napi_ok) {
|
||||
char buffer[MAX_STRING_LEN];
|
||||
size_t result = 0;
|
||||
NODE_API_CALL(status, _env, napi_get_value_string_utf8(_env, val, buffer, MAX_STRING_LEN, &result));
|
||||
if (result > 0) {
|
||||
allKeys->push_back(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Object::init(napi_env env, napi_value js_object, Class* cls) {
|
||||
assert(env);
|
||||
_cls = cls;
|
||||
_env = env;
|
||||
_objRef.initWeakref(env, js_object);
|
||||
|
||||
if (__objectMap) {
|
||||
assert(__objectMap->find(this) == __objectMap->end());
|
||||
__objectMap->emplace(this, nullptr);
|
||||
}
|
||||
|
||||
napi_status status;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Object::call(const ValueArray& args, Object* thisObject, Value* rval) {
|
||||
size_t argc = 0;
|
||||
std::vector<napi_value> argv;
|
||||
argv.reserve(10);
|
||||
argc = args.size();
|
||||
internal::seToJsArgs(_env, args, &argv);
|
||||
napi_value return_val;
|
||||
napi_status status;
|
||||
assert(isFunction());
|
||||
napi_value thisObj = thisObject ? thisObject->_getJSObject() : nullptr;
|
||||
status =
|
||||
napi_call_function(_env, thisObj, _getJSObject(), argc, argv.data(), &return_val);
|
||||
if (rval) {
|
||||
internal::jsToSeValue(return_val, rval);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Object::_setFinalizeCallback(napi_finalize finalizeCb) {
|
||||
assert(finalizeCb != nullptr);
|
||||
_finalizeCb = finalizeCb;
|
||||
}
|
||||
|
||||
void Object::setPrivateData(void* data){
|
||||
assert(_privateData == nullptr);
|
||||
assert(NativePtrToObjectMap::find(data) == NativePtrToObjectMap::end());
|
||||
napi_status status;
|
||||
NativePtrToObjectMap::emplace(data, this);
|
||||
_privateData = data;
|
||||
//issue https://github.com/nodejs/node/issues/23999
|
||||
auto tmpThis = _objRef.getValue(_env);
|
||||
//_objRef.deleteRef();
|
||||
napi_ref result = nullptr;
|
||||
NODE_API_CALL(status, _env,
|
||||
napi_wrap(_env, tmpThis, data, weakCallback,
|
||||
(void*)this /* finalize_hint */, &result));
|
||||
//_objRef.setWeakref(_env, result);
|
||||
setProperty("__native_ptr__", se::Value(static_cast<long>(reinterpret_cast<uintptr_t>(data))));
|
||||
}
|
||||
|
||||
void* Object::getPrivateData() const{
|
||||
napi_status status;
|
||||
void* data;
|
||||
auto tmpThis = _objRef.getValue(_env);
|
||||
status = napi_unwrap(_env, tmpThis, &data);
|
||||
const_cast<Object*>(this)->_privateData = data;
|
||||
return _privateData;
|
||||
}
|
||||
|
||||
bool Object::attachObject(Object* obj) {
|
||||
assert(obj);
|
||||
|
||||
Object* global = ScriptEngine::getInstance()->getGlobalObject();
|
||||
Value jsbVal;
|
||||
if (!global->getProperty("jsb", &jsbVal)) {
|
||||
return false;
|
||||
}
|
||||
Object* jsbObj = jsbVal.toObject();
|
||||
|
||||
Value func;
|
||||
|
||||
if (!jsbObj->getProperty("registerNativeRef", &func)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ValueArray args;
|
||||
args.push_back(Value(this));
|
||||
args.push_back(Value(obj));
|
||||
func.toObject()->call(args, global);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Object::detachObject(Object* obj) {
|
||||
assert(obj);
|
||||
|
||||
Object* global = ScriptEngine::getInstance()->getGlobalObject();
|
||||
Value jsbVal;
|
||||
if (!global->getProperty("jsb", &jsbVal)) {
|
||||
return false;
|
||||
}
|
||||
Object* jsbObj = jsbVal.toObject();
|
||||
|
||||
Value func;
|
||||
|
||||
if (!jsbObj->getProperty("unregisterNativeRef", &func)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ValueArray args;
|
||||
args.push_back(Value(this));
|
||||
args.push_back(Value(obj));
|
||||
func.toObject()->call(args, global);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Object::toString() const {
|
||||
std::string ret;
|
||||
napi_status status;
|
||||
if (isFunction() || isArray() || isTypedArray()) {
|
||||
napi_value result;
|
||||
NODE_API_CALL(status, _env, napi_coerce_to_string(_env, _objRef.getValue(_env), &result));
|
||||
char buffer[MAX_STRING_LEN];
|
||||
size_t result_t = 0;
|
||||
NODE_API_CALL(status, _env, napi_get_value_string_utf8(_env, result, buffer, MAX_STRING_LEN, &result_t));
|
||||
ret = buffer;
|
||||
} else if (isArrayBuffer()) {
|
||||
ret = "[object ArrayBuffer]";
|
||||
} else {
|
||||
ret = "[object Object]";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Object::root() {
|
||||
napi_status status;
|
||||
if (_rootCount == 0) {
|
||||
uint32_t result = 0;
|
||||
_objRef.incRef(_env);
|
||||
//NODE_API_CALL(status, _env, napi_reference_ref(_env, _wrapper, &result));
|
||||
}
|
||||
++_rootCount;
|
||||
}
|
||||
|
||||
void Object::unroot() {
|
||||
napi_status status;
|
||||
if (_rootCount > 0) {
|
||||
--_rootCount;
|
||||
if (_rootCount == 0) {
|
||||
_objRef.decRef(_env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Object::isRooted() const {
|
||||
return _rootCount > 0;
|
||||
}
|
||||
|
||||
Class* Object::_getClass() const {
|
||||
return _cls;
|
||||
}
|
||||
|
||||
Object* Object::getObjectWithPtr(void* ptr) {
|
||||
Object* obj = nullptr;
|
||||
auto iter = NativePtrToObjectMap::find(ptr);
|
||||
if (iter != NativePtrToObjectMap::end()) {
|
||||
obj = iter->second;
|
||||
obj->incRef();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
napi_value Object::_getJSObject() const {
|
||||
return _objRef.getValue(_env);
|
||||
}
|
||||
|
||||
void Object::weakCallback(napi_env env, void* nativeObject, void* finalizeHint /*finalize_hint*/) {
|
||||
if (finalizeHint) {
|
||||
if (nativeObject == nullptr) {
|
||||
return;
|
||||
}
|
||||
void *rawPtr = reinterpret_cast<Object*>(finalizeHint)->_privateData;
|
||||
Object* seObj = reinterpret_cast<Object*>(finalizeHint);
|
||||
if (seObj->_onCleaingPrivateData) { //called by cleanPrivateData, not release seObj;
|
||||
return;
|
||||
}
|
||||
if (seObj->_clearMappingInFinalizer && rawPtr != nullptr) {
|
||||
auto iter = NativePtrToObjectMap::find(rawPtr);
|
||||
if (iter != NativePtrToObjectMap::end()) {
|
||||
NativePtrToObjectMap::erase(iter);
|
||||
} else {
|
||||
SE_LOGE("not find ptr in NativePtrToObjectMap");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove test code before releasing.
|
||||
const char* clsName = seObj->_getClass()->getName();
|
||||
SE_LOGE("weakCallback class name:%s, ptr:%p", clsName, rawPtr);
|
||||
|
||||
if (seObj->_finalizeCb != nullptr) {
|
||||
seObj->_finalizeCb(env, finalizeHint, finalizeHint);
|
||||
} else {
|
||||
assert(seObj->_getClass() != nullptr);
|
||||
if (seObj->_getClass()->_getFinalizeFunction() != nullptr) {
|
||||
seObj->_getClass()->_getFinalizeFunction()(env, finalizeHint, finalizeHint);
|
||||
}
|
||||
}
|
||||
seObj->decRef();
|
||||
}
|
||||
}
|
||||
|
||||
void Object::setup() {
|
||||
__objectMap = std::make_unique<std::unordered_map<Object*, void*>>();
|
||||
}
|
||||
|
||||
void Object::cleanup() {
|
||||
void* nativeObj = nullptr;
|
||||
Object* obj = nullptr;
|
||||
Class* cls = nullptr;
|
||||
|
||||
const auto& nativePtrToObjectMap = NativePtrToObjectMap::instance();
|
||||
for (const auto& e : nativePtrToObjectMap) {
|
||||
nativeObj = e.first;
|
||||
obj = e.second;
|
||||
|
||||
if (obj->_finalizeCb != nullptr) {
|
||||
obj->_finalizeCb(ScriptEngine::getEnv(), nativeObj, nullptr);
|
||||
} else {
|
||||
if (obj->_getClass() != nullptr) {
|
||||
if (obj->_getClass()->_getFinalizeFunction() != nullptr) {
|
||||
obj->_getClass()->_getFinalizeFunction()(ScriptEngine::getEnv(), nativeObj, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
obj->decRef();
|
||||
}
|
||||
|
||||
NativePtrToObjectMap::clear();
|
||||
|
||||
if (__objectMap) {
|
||||
for (const auto& e : *__objectMap) {
|
||||
obj = e.first;
|
||||
cls = obj->_getClass();
|
||||
obj->_rootCount = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
__objectMap.reset();
|
||||
}
|
||||
|
||||
Object* Object::createJSONObject(const std::string& jsonStr) {
|
||||
//not impl
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Object::clearPrivateData(bool clearMapping) {
|
||||
if (_privateData != nullptr) {
|
||||
napi_status status;
|
||||
void* result = nullptr;
|
||||
auto tmpThis = _objRef.getValue(_env);
|
||||
_onCleaingPrivateData = true;
|
||||
if (clearMapping) {
|
||||
NativePtrToObjectMap::erase(_privateData);
|
||||
}
|
||||
NODE_API_CALL(status, _env, napi_remove_wrap(_env, tmpThis, &result));
|
||||
_privateData = nullptr;
|
||||
_onCleaingPrivateData = false;
|
||||
}
|
||||
}
|
||||
|
||||
Object* Object::createUTF8String(const std::string& str) {
|
||||
napi_status status;
|
||||
napi_value result;
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_string_utf8(ScriptEngine::getEnv(),str.c_str(),NAPI_AUTO_LENGTH,&result));
|
||||
Object* obj = _createJSObject(ScriptEngine::getEnv(), result, nullptr);
|
||||
return obj;
|
||||
}
|
||||
|
||||
} // namespace se
|
431
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/Object.h
Normal file
431
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/Object.h
Normal file
@@ -0,0 +1,431 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <cassert>
|
||||
#include "../RefCounter.hpp"
|
||||
#include "../Value.hpp"
|
||||
#include "../config.hpp"
|
||||
#include "CommonHeader.h"
|
||||
#include "HelperMacros.h"
|
||||
|
||||
namespace se {
|
||||
class Class;
|
||||
namespace internal {
|
||||
struct PrivateData;
|
||||
}
|
||||
|
||||
class ObjectRef {
|
||||
private:
|
||||
napi_ref _ref = nullptr;
|
||||
int _refCounts = 0;
|
||||
napi_env _env = nullptr;
|
||||
napi_value _obj = nullptr;
|
||||
|
||||
public:
|
||||
~ObjectRef() {
|
||||
deleteRef();
|
||||
}
|
||||
napi_value getValue(napi_env env) const {
|
||||
napi_value result;
|
||||
napi_status status;
|
||||
NODE_API_CALL(status, env, napi_get_reference_value(env, _ref, &result));
|
||||
assert(status == napi_ok);
|
||||
assert(result != nullptr);
|
||||
return result;
|
||||
}
|
||||
void initWeakref(napi_env env, napi_value obj) {
|
||||
assert(_ref == nullptr);
|
||||
_obj = obj;
|
||||
_env = env;
|
||||
napi_create_reference(env, obj, 0, &_ref);
|
||||
}
|
||||
void setWeakref(napi_env env, napi_ref ref) {
|
||||
assert(_ref == nullptr);
|
||||
_ref = ref;
|
||||
}
|
||||
void initStrongRef(napi_env env, napi_value obj) {
|
||||
assert(_ref == nullptr);
|
||||
_refCounts = 1;
|
||||
_obj = obj;
|
||||
napi_create_reference(env, obj, _refCounts, &_ref);
|
||||
_env = env;
|
||||
}
|
||||
void incRef(napi_env env) {
|
||||
assert(_refCounts == 0);
|
||||
if (_refCounts == 0) {
|
||||
uint32_t result = 0;
|
||||
_refCounts = 1;
|
||||
napi_reference_ref(env, _ref, &result);
|
||||
}
|
||||
}
|
||||
void decRef(napi_env env) {
|
||||
assert(_refCounts == 1);
|
||||
uint32_t result = 0;
|
||||
if (_refCounts > 0) {
|
||||
_refCounts--;
|
||||
if (_refCounts == 0) {
|
||||
napi_reference_unref(env, _ref, &result);
|
||||
}
|
||||
}
|
||||
}
|
||||
void deleteRef() {
|
||||
_refCounts = 0;
|
||||
if (!_ref) {
|
||||
return;
|
||||
}
|
||||
napi_delete_reference(_env, _ref);
|
||||
_ref = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
class Object;
|
||||
|
||||
class Object : public RefCounter {
|
||||
public:
|
||||
enum class TypedArrayType {
|
||||
NONE,
|
||||
INT8,
|
||||
INT16,
|
||||
INT32,
|
||||
UINT8,
|
||||
UINT8_CLAMPED,
|
||||
UINT16,
|
||||
UINT32,
|
||||
FLOAT32,
|
||||
FLOAT64
|
||||
};
|
||||
|
||||
using BufferContentsFreeFunc = void (*)(void *contents, size_t byteLength, void *userData);
|
||||
|
||||
struct ExternalArrayBufferCallbackParams {
|
||||
BufferContentsFreeFunc func{nullptr};
|
||||
void *contents{nullptr};
|
||||
size_t byteLength{0};
|
||||
void *userData{0};
|
||||
};
|
||||
|
||||
Object();
|
||||
~Object();
|
||||
/**
|
||||
* @brief Sets a property to an object.
|
||||
* @param[in] name A utf-8 string containing the property's name.
|
||||
* @param[in] value A value to be used as the property's value.
|
||||
* @return true if the property is set successfully, otherwise false.
|
||||
*/
|
||||
bool setProperty(const char *name, const Value &data);
|
||||
|
||||
inline bool setProperty(const std::string &name, const Value &value) {
|
||||
return setProperty(name.c_str(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a property from an object.
|
||||
* @param[in] name A utf-8 string containing the property's name.
|
||||
* @param[out] value The property's value if object has the property, otherwise the undefined value.
|
||||
* @return true if object has the property, otherwise false.
|
||||
*/
|
||||
bool getProperty(const char *name, Value *data);
|
||||
|
||||
inline bool getProperty(const char *name, Value *data, bool cachePropertyName) {
|
||||
return getProperty(name, data);
|
||||
}
|
||||
|
||||
inline bool getProperty(const std::string &name, Value *value) {
|
||||
return getProperty(name.c_str(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delete a property of an object.
|
||||
* @param[in] name A utf-8 string containing the property's name.
|
||||
* @return true if the property is deleted successfully, otherwise false.
|
||||
*/
|
||||
bool deleteProperty(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Gets an object's private data.
|
||||
* @return A void* that is the object's private data, if the object has private data, otherwise nullptr.
|
||||
*/
|
||||
void* getPrivateData() const;
|
||||
|
||||
/**
|
||||
* @brief Sets a pointer to private data on an object.
|
||||
* @param[in] data A void* to set as the object's private data.
|
||||
* @note This method will associate private data with se::Object by std::unordered_map::emplace.
|
||||
* It's used for search a se::Object via a void* private data.
|
||||
*/
|
||||
void setPrivateData(void* data);
|
||||
|
||||
/**
|
||||
* @brief Clears private data of an object.
|
||||
* @param clearMapping Whether to clear the mapping of native object & se::Object.
|
||||
*/
|
||||
void clearPrivateData(bool clearMapping = true);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets whether to clear the mapping of native object & se::Object in finalizer
|
||||
*/
|
||||
void setClearMappingInFinalizer(bool v) { _clearMappingInFinalizer = v; }
|
||||
|
||||
/**
|
||||
* @brief Tests whether an object is an array.
|
||||
* @return true if object is an array, otherwise false.
|
||||
*/
|
||||
bool isArray() const;
|
||||
|
||||
/**
|
||||
* @brief Gets array length of an array object.
|
||||
* @param[out] length The array length to be stored. It's set to 0 if there is an error.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool getArrayLength(uint32_t *length) const;
|
||||
|
||||
/**
|
||||
* @brief Gets an element from an array object by numeric index.
|
||||
* @param[in] index An integer value for index.
|
||||
* @param[out] data The se::Value to be stored for the element in certain index.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool getArrayElement(uint32_t index, Value *data) const;
|
||||
|
||||
/**
|
||||
* @brief Sets an element to an array object by numeric index.
|
||||
* @param[in] index An integer value for index.
|
||||
* @param[in] data The se::Value to be set to array with certain index.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool setArrayElement(uint32_t index, const Value &data);
|
||||
|
||||
/** @brief Tests whether an object is a typed array.
|
||||
* @return true if object is a typed array, otherwise false.
|
||||
*/
|
||||
bool isTypedArray() const;
|
||||
|
||||
/** @brief Tests whether an object is a proxy object.
|
||||
* @return true if object is a proxy object, otherwise false.
|
||||
*/
|
||||
bool isProxy() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the type of a typed array object.
|
||||
* @return The type of a typed array object.
|
||||
*/
|
||||
TypedArrayType getTypedArrayType() const;
|
||||
|
||||
/**
|
||||
* @brief Gets backing store of a typed array object.
|
||||
* @param[out] ptr A temporary pointer to the backing store of a JavaScript Typed Array object.
|
||||
* @param[out] length The byte length of a JavaScript Typed Array object.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool getTypedArrayData(uint8_t **ptr, size_t *length) const;
|
||||
/**
|
||||
* @brief Tests whether an object is an array buffer object.
|
||||
* @return true if object is an array buffer object, otherwise false.
|
||||
*/
|
||||
bool isArrayBuffer() const;
|
||||
|
||||
/**
|
||||
* @brief Gets buffer data of an array buffer object.
|
||||
* @param[out] ptr A pointer to the data buffer that serves as the backing store for a JavaScript Typed Array object.
|
||||
* @param[out] length The number of bytes in a JavaScript data object.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool getArrayBufferData(uint8_t **ptr, size_t *length) const;
|
||||
|
||||
/**
|
||||
* @brief Creates a JavaScript Typed Array Object with specified format from an existing pointer,
|
||||
if provide a null pointer,then will create a empty JavaScript Typed Array Object.
|
||||
* @param[in] type The format of typed array.
|
||||
* @param[in] data A pointer to the byte buffer to be used as the backing store of the Typed Array object.
|
||||
* @param[in] byteLength The number of bytes pointed to by the parameter bytes.
|
||||
* @return A JavaScript Typed Array Object whose backing store is the same as the one pointed data, or nullptr if there is an error.
|
||||
* @note The return value (non-null) has to be released manually.
|
||||
*/
|
||||
static Object *createTypedArray(TypedArrayType type, const void *data, size_t byteLength);
|
||||
|
||||
static Object *createTypedArrayWithBuffer(TypedArrayType type, const Object *obj);
|
||||
static Object *createTypedArrayWithBuffer(TypedArrayType type, const Object *obj, size_t offset);
|
||||
static Object *createTypedArrayWithBuffer(TypedArrayType type, const Object *obj, size_t offset, size_t byteLength);
|
||||
|
||||
static Object *createExternalArrayBufferObject(void *contents, size_t byteLength, BufferContentsFreeFunc freeFunc, void *freeUserData = nullptr);
|
||||
/**
|
||||
* @brief Tests whether an object can be called as a function.
|
||||
* @return true if object can be called as a function, otherwise false.
|
||||
*/
|
||||
bool isFunction() const;
|
||||
|
||||
/**
|
||||
* @brief Defines a function with a native callback for an object.
|
||||
* @param[in] funcName A utf-8 string containing the function name.
|
||||
* @param[in] func The native callback triggered by JavaScript code.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool defineFunction(const char *funcName, napi_callback func);
|
||||
|
||||
/**
|
||||
* @brief Defines a property with native accessor callbacks for an object.
|
||||
* @param[in] name A utf-8 string containing the property's name.
|
||||
* @param[in] getter The native callback for getter.
|
||||
* @param[in] setter The native callback for setter.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool defineProperty(const char *name, napi_callback getter, napi_callback setter);
|
||||
|
||||
bool attachObject(Object *obj);
|
||||
|
||||
/**
|
||||
* @brief Detaches an object from current object.
|
||||
* @param[in] obj The object to be detached.
|
||||
* @return true if succeed, otherwise false.
|
||||
* @note The attached object will not be released if current object is not garbage collected.
|
||||
*/
|
||||
bool detachObject(Object *obj);
|
||||
|
||||
/**
|
||||
* @brief Calls an object as a function.
|
||||
* @param[in] args A se::Value array of arguments to pass to the function. Pass se::EmptyValueArray if argumentCount is 0.
|
||||
* @param[in] thisObject The object to use as "this," or NULL to use the global object as "this."
|
||||
* @param[out] rval The se::Value that results from calling object as a function, passing nullptr if return value is ignored.
|
||||
* @return true if object is a function and there isn't any errors, otherwise false.
|
||||
*/
|
||||
bool call(const ValueArray &args, Object *thisObject, Value *rval = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Creates a JavaScript Native Binding Object from an existing se::Class instance.
|
||||
* @param[in] cls The se::Class instance which stores native callback informations.
|
||||
* @return A JavaScript Native Binding Object, or nullptr if there is an error.
|
||||
* @note The return value (non-null) has to be released manually.
|
||||
*/
|
||||
static Object *createObjectWithClass(Class *cls);
|
||||
|
||||
static Object *_createJSObject(napi_env env, napi_value js_object, Class *cls);
|
||||
|
||||
/**
|
||||
* @brief Creates a JavaScript Object like `{} or new Object()`.
|
||||
* @return A JavaScript Object, or nullptr if there is an error.
|
||||
* @note The return value (non-null) has to be released manually.
|
||||
*/
|
||||
static Object *createPlainObject();
|
||||
|
||||
/**
|
||||
* @brief Creates a JavaScript Array Object like `[] or new Array()`.
|
||||
* @param[in] length The initical length of array.
|
||||
* @return A JavaScript Array Object, or nullptr if there is an error.
|
||||
* @note The return value (non-null) has to be released manually.
|
||||
*/
|
||||
static Object *createArrayObject(size_t length);
|
||||
|
||||
/**
|
||||
* @brief Creates a JavaScript Array Buffer object from an existing pointer.
|
||||
* @param[in] bytes A pointer to the byte buffer to be used as the backing store of the Typed Array object.
|
||||
* @param[in] byteLength The number of bytes pointed to by the parameter bytes.
|
||||
* @return A Array Buffer Object whose backing store is the same as the one pointed to data, or nullptr if there is an error.
|
||||
* @note The return value (non-null) has to be released manually.
|
||||
*/
|
||||
static Object *createArrayBufferObject(const void *data, size_t byteLength);
|
||||
/**
|
||||
* Gets the Proxy Target object
|
||||
* @param proxy The JavaScript Proxy object.
|
||||
* @return The target JavaScript object of the parameter.
|
||||
*/
|
||||
static Object *createProxyTarget(se::Object *proxy);
|
||||
/**
|
||||
* @brief Roots an object from garbage collection.
|
||||
* @note Use this method when you want to store an object in a global or on the heap, where the garbage collector will not be able to discover your reference to it.
|
||||
* An object may be rooted multiple times and must be unrooted an equal number of times before becoming eligible for garbage collection.
|
||||
*/
|
||||
void root();
|
||||
|
||||
/**
|
||||
* @brief Unroots an object from garbage collection.
|
||||
* @note An object may be rooted multiple times and must be unrooted an equal number of times before becoming eligible for garbage collection.
|
||||
*/
|
||||
void unroot();
|
||||
|
||||
/**
|
||||
* @brief Tests whether an object is rooted.
|
||||
* @return true if it has been already rooted, otherwise false.
|
||||
*/
|
||||
bool isRooted() const;
|
||||
|
||||
/**
|
||||
* @brief Creates a JavaScript Object from a JSON formatted string.
|
||||
* @param[in] jsonStr The utf-8 string containing the JSON string to be parsed.
|
||||
* @return A JavaScript Object containing the parsed value, or nullptr if the input is invalid.
|
||||
* @note The return value (non-null) has to be released manually.
|
||||
*/
|
||||
static Object *createJSONObject(const std::string &jsonStr);
|
||||
|
||||
/**
|
||||
* @brief Gets all property names of an object.
|
||||
* @param[out] allKeys A string vector to store all property names.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool getAllKeys(std::vector<std::string> *allKeys) const;
|
||||
|
||||
/**
|
||||
* @brief Gets a se::Object from an existing native object pointer.
|
||||
* @param[in] ptr The native object pointer associated with the se::Object
|
||||
* @return A JavaScript Native Binding Object, or nullptr if there is an error.
|
||||
* @note The return value (non-null) has to be released manually.
|
||||
*/
|
||||
static Object *getObjectWithPtr(void *ptr);
|
||||
|
||||
Class * _getClass() const; // NOLINT(readability-identifier-naming)
|
||||
napi_value _getJSObject() const;
|
||||
void _setFinalizeCallback(napi_finalize finalizeCb); // NOLINT(readability-identifier-naming)
|
||||
/**
|
||||
* @brief Returns the string for describing current object.
|
||||
* @return The string for describing current object.
|
||||
*/
|
||||
std::string toString() const;
|
||||
|
||||
bool init(napi_env env, napi_value js_object, Class *cls);
|
||||
|
||||
static Object *createUTF8String(const std::string& str);
|
||||
|
||||
private:
|
||||
// Object();
|
||||
// virtual ~Object();
|
||||
static void weakCallback(napi_env env, void *nativeObject, void * /*finalize_hint*/);
|
||||
static void setup();
|
||||
static void cleanup();
|
||||
|
||||
private:
|
||||
ObjectRef _objRef;
|
||||
napi_finalize _finalizeCb = nullptr;
|
||||
bool _clearMappingInFinalizer = true;
|
||||
void* _privateData = nullptr;
|
||||
napi_env _env = nullptr;
|
||||
Class * _cls = nullptr;
|
||||
uint32_t _rootCount = 0;
|
||||
bool _onCleaingPrivateData = false;
|
||||
internal::PrivateData* _internalData;
|
||||
|
||||
friend class ScriptEngine;
|
||||
};
|
||||
}; // namespace se
|
@@ -0,0 +1,315 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "ScriptEngine.h"
|
||||
#include <sstream>
|
||||
#include "../MappingUtils.hpp"
|
||||
#include "Class.h"
|
||||
#include "Utils.h"
|
||||
#include "CommonHeader.h"
|
||||
#include <napi/native_api.h>
|
||||
|
||||
namespace se {
|
||||
AutoHandleScope::AutoHandleScope() {
|
||||
napi_open_handle_scope(ScriptEngine::getEnv(), &_handleScope);
|
||||
}
|
||||
|
||||
AutoHandleScope::~AutoHandleScope() {
|
||||
napi_close_handle_scope(ScriptEngine::getEnv(), _handleScope);
|
||||
}
|
||||
|
||||
ScriptEngine *gSriptEngineInstance = nullptr;
|
||||
|
||||
ScriptEngine::ScriptEngine() {};
|
||||
|
||||
ScriptEngine::~ScriptEngine() = default;
|
||||
|
||||
void ScriptEngine::setFileOperationDelegate(const FileOperationDelegate &delegate) {
|
||||
_fileOperationDelegate = delegate;
|
||||
}
|
||||
|
||||
const ScriptEngine::FileOperationDelegate &ScriptEngine::getFileOperationDelegate() const {
|
||||
return _fileOperationDelegate;
|
||||
}
|
||||
|
||||
ScriptEngine *ScriptEngine::getInstance() {
|
||||
if (gSriptEngineInstance == nullptr) {
|
||||
gSriptEngineInstance = new ScriptEngine();
|
||||
}
|
||||
|
||||
return gSriptEngineInstance;
|
||||
}
|
||||
|
||||
void ScriptEngine::destroyInstance() {
|
||||
if (gSriptEngineInstance) {
|
||||
gSriptEngineInstance->cleanup();
|
||||
delete gSriptEngineInstance;
|
||||
gSriptEngineInstance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptEngine::runScript(const std::string &path, Value *ret /* = nullptr */) {
|
||||
assert(!path.empty());
|
||||
napi_status status;
|
||||
napi_value result = nullptr;
|
||||
LOGD("napi runScript path=%{public}s.",path.c_str());
|
||||
//NODE_API_CALL(status, ScriptEngine::getEnv(), napi_run_script_path(ScriptEngine::getEnv(), path.c_str(), &result));
|
||||
if (ret && result) {
|
||||
internal::jsToSeValue(result, ret);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScriptEngine::evalString(const char *scriptStr, ssize_t length, Value *ret, const char *fileName) {
|
||||
napi_status status;
|
||||
napi_value script;
|
||||
napi_value result;
|
||||
length = length < 0 ? NAPI_AUTO_LENGTH : length;
|
||||
status = napi_create_string_utf8(ScriptEngine::getEnv(), scriptStr, length, &script);
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_run_script(ScriptEngine::getEnv(), script, &result));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptEngine::init() {
|
||||
napi_status status;
|
||||
napi_value result;
|
||||
|
||||
for (const auto &hook : _beforeInitHookArray) {
|
||||
hook();
|
||||
}
|
||||
|
||||
Object::setup();
|
||||
NativePtrToObjectMap::init();
|
||||
NonRefNativePtrCreatedByCtorMap::init();
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_global(ScriptEngine::getEnv(), &result));
|
||||
_globalObj = Object::_createJSObject(ScriptEngine::getEnv(), result, nullptr);
|
||||
_globalObj->root();
|
||||
_globalObj->setProperty("window", Value(_globalObj));
|
||||
_globalObj->setProperty("scriptEngineType", se::Value("napi"));
|
||||
|
||||
_isValid = true;
|
||||
|
||||
for (const auto &hook : _afterInitHookArray) {
|
||||
hook();
|
||||
}
|
||||
_afterInitHookArray.clear();
|
||||
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
Object *ScriptEngine::getGlobalObject() const {
|
||||
return _globalObj;
|
||||
}
|
||||
|
||||
bool ScriptEngine::start() {
|
||||
bool ok = true;
|
||||
if (!init()) {
|
||||
return false;
|
||||
}
|
||||
_startTime = std::chrono::steady_clock::now();
|
||||
for (auto cb : _permRegisterCallbackArray) {
|
||||
ok = cb(_globalObj);
|
||||
assert(ok);
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto cb : _registerCallbackArray) {
|
||||
ok = cb(_globalObj);
|
||||
assert(ok);
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// After ScriptEngine is started, _registerCallbackArray isn't needed. Therefore, clear it here.
|
||||
_registerCallbackArray.clear();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void ScriptEngine::cleanup() {
|
||||
if (!_isValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
SE_LOGD("ScriptEngine::cleanup begin ...\n");
|
||||
_isInCleanup = true;
|
||||
|
||||
for (const auto &hook : _beforeCleanupHookArray) {
|
||||
hook();
|
||||
}
|
||||
_beforeCleanupHookArray.clear();
|
||||
|
||||
SAFE_DEC_REF(_globalObj);
|
||||
Object::cleanup();
|
||||
Class::cleanup();
|
||||
garbageCollect();
|
||||
|
||||
_globalObj = nullptr;
|
||||
_isValid = false;
|
||||
|
||||
_registerCallbackArray.clear();
|
||||
|
||||
for (const auto &hook : _afterCleanupHookArray) {
|
||||
hook();
|
||||
}
|
||||
_afterCleanupHookArray.clear();
|
||||
|
||||
_isInCleanup = false;
|
||||
NativePtrToObjectMap::destroy();
|
||||
SE_LOGD("ScriptEngine::cleanup end ...\n");
|
||||
}
|
||||
|
||||
void ScriptEngine::addBeforeCleanupHook(const std::function<void()> &hook) {
|
||||
_beforeCleanupHookArray.push_back(hook);
|
||||
return;
|
||||
}
|
||||
|
||||
void ScriptEngine::addBeforeInitHook(const std::function<void()> &hook) {
|
||||
_beforeInitHookArray.push_back(hook);
|
||||
}
|
||||
|
||||
void ScriptEngine::addAfterCleanupHook(const std::function<void()> &hook) {
|
||||
_afterCleanupHookArray.push_back(hook);
|
||||
return;
|
||||
}
|
||||
|
||||
void ScriptEngine::addRegisterCallback(RegisterCallback cb) {
|
||||
assert(std::find(_registerCallbackArray.begin(), _registerCallbackArray.end(), cb) == _registerCallbackArray.end());
|
||||
_registerCallbackArray.push_back(cb);
|
||||
}
|
||||
|
||||
napi_env ScriptEngine::getEnv() {
|
||||
return getInstance()->_env;
|
||||
}
|
||||
|
||||
void ScriptEngine::setEnv(napi_env env) {
|
||||
getInstance()->_env = env;
|
||||
}
|
||||
|
||||
// void ScriptEngine::addPermanentRegisterCallback(RegisterCallback cb) {
|
||||
// if (std::find(_permRegisterCallbackArray.begin(), _permRegisterCallbackArray.end(), cb) == _permRegisterCallbackArray.end()) {
|
||||
// _permRegisterCallbackArray.push_back(cb);
|
||||
// }
|
||||
// }
|
||||
|
||||
void ScriptEngine::setExceptionCallback(const ExceptionCallback &cb) {
|
||||
//not impl
|
||||
return;
|
||||
}
|
||||
|
||||
const std::chrono::steady_clock::time_point &ScriptEngine::getStartTime() const {
|
||||
return _startTime;
|
||||
}
|
||||
|
||||
bool ScriptEngine::isValid() const {
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
void ScriptEngine::enableDebugger(const std::string &serverAddr, uint32_t port, bool isWait) {
|
||||
//not impl
|
||||
return;
|
||||
}
|
||||
|
||||
bool ScriptEngine::saveByteCodeToFile(const std::string &path, const std::string &pathBc) {
|
||||
//not impl
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptEngine::clearException() {
|
||||
//not impl
|
||||
return;
|
||||
}
|
||||
|
||||
void ScriptEngine::garbageCollect() {
|
||||
//not impl
|
||||
return;
|
||||
}
|
||||
|
||||
bool ScriptEngine::isGarbageCollecting() const {
|
||||
return _isGarbageCollecting;
|
||||
}
|
||||
|
||||
void ScriptEngine::_setGarbageCollecting(bool isGarbageCollecting) { //NOLINT(readability-identifier-naming)
|
||||
_isGarbageCollecting = isGarbageCollecting;
|
||||
}
|
||||
|
||||
void ScriptEngine::setJSExceptionCallback(const ExceptionCallback &cb) {
|
||||
//not impl
|
||||
return;
|
||||
}
|
||||
|
||||
void ScriptEngine::addAfterInitHook(const std::function<void()> &hook) {
|
||||
_afterInitHookArray.push_back(hook);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string ScriptEngine::getCurrentStackTrace() {
|
||||
//not impl
|
||||
return "";
|
||||
}
|
||||
|
||||
void ScriptEngine::_setNeedCallConstructor(bool need) {
|
||||
_isneedCallConstructor = need;
|
||||
}
|
||||
|
||||
bool ScriptEngine::_needCallConstructor() {
|
||||
return _isneedCallConstructor;
|
||||
}
|
||||
|
||||
bool ScriptEngine::callFunction(Object *targetObj, const char *funcName, uint32_t argc, Value *args, Value *rval) {
|
||||
Value objFunc;
|
||||
if (!targetObj->getProperty(funcName, &objFunc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ValueArray argv;
|
||||
|
||||
for (size_t i = 0; i < argc; ++i) {
|
||||
argv.push_back(args[i]);
|
||||
}
|
||||
|
||||
objFunc.toObject()->call(argv, targetObj, rval);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptEngine::handlePromiseExceptions() {
|
||||
//not impl
|
||||
assert(true);
|
||||
return;
|
||||
}
|
||||
|
||||
void ScriptEngine::mainLoopUpdate() {
|
||||
// empty implementation
|
||||
}
|
||||
|
||||
void ScriptEngine::throwException(const std::string &errorMessage) {
|
||||
napi_status status;
|
||||
NODE_API_CALL_RETURN_VOID(getEnv(), napi_throw_error(getEnv(), nullptr, errorMessage.c_str()));
|
||||
}
|
||||
}; // namespace se
|
@@ -0,0 +1,307 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include "../Value.hpp"
|
||||
#include "../config.hpp"
|
||||
#include "CommonHeader.h"
|
||||
|
||||
using HandleScope = napi_handle_scope;
|
||||
namespace se {
|
||||
class AutoHandleScope {
|
||||
public:
|
||||
// This interface needs to be implemented in NAPI, similar to V8.
|
||||
// Ref:https://nodejs.org/docs/latest-v17.x/api/n-api.html#object-lifetime-management
|
||||
AutoHandleScope();
|
||||
~AutoHandleScope();
|
||||
|
||||
private:
|
||||
HandleScope _handleScope;
|
||||
};
|
||||
// using RegisterCallback = bool (*)(Object *);
|
||||
using ExceptionCallback = std::function<void(const char *, const char *, const char *)>; // location, message, stack
|
||||
|
||||
class ScriptEngine {
|
||||
public:
|
||||
/**
|
||||
* Delegate class for file operation
|
||||
*/
|
||||
class FileOperationDelegate {
|
||||
public:
|
||||
FileOperationDelegate()
|
||||
: onGetDataFromFile(nullptr),
|
||||
onGetStringFromFile(nullptr),
|
||||
onCheckFileExist(nullptr),
|
||||
onGetFullPath(nullptr) {}
|
||||
|
||||
/**
|
||||
* @brief Tests whether delegate is valid.
|
||||
*/
|
||||
bool isValid() const {
|
||||
return onGetDataFromFile != nullptr && onGetStringFromFile != nullptr && onCheckFileExist != nullptr && onGetFullPath != nullptr;
|
||||
}
|
||||
|
||||
// path, buffer, buffer size
|
||||
std::function<void(const std::string &, const std::function<void(const uint8_t *, size_t)> &)> onGetDataFromFile;
|
||||
// path, return file string content.
|
||||
std::function<std::string(const std::string &)> onGetStringFromFile;
|
||||
// path
|
||||
std::function<bool(const std::string &)> onCheckFileExist;
|
||||
// path, return full path
|
||||
std::function<std::string(const std::string &)> onGetFullPath;
|
||||
};
|
||||
ScriptEngine();
|
||||
~ScriptEngine();
|
||||
/**
|
||||
* @brief Sets the delegate for file operation.
|
||||
* @param delegate[in] The delegate instance for file operation.
|
||||
*/
|
||||
void setFileOperationDelegate(const FileOperationDelegate &delegate);
|
||||
|
||||
/**
|
||||
* @brief Compile script file into v8::ScriptCompiler::CachedData and save to file.
|
||||
* @param[in] path The path of script file.
|
||||
* @param[in] pathBc The location where bytecode file should be written to. The path should be ends with ".bc", which indicates a bytecode file.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool saveByteCodeToFile(const std::string &path, const std::string &pathBc);
|
||||
|
||||
/**
|
||||
* @brief Gets the delegate for file operation.
|
||||
* @return The delegate for file operation
|
||||
*/
|
||||
const FileOperationDelegate &getFileOperationDelegate() const;
|
||||
|
||||
static ScriptEngine *getInstance();
|
||||
|
||||
/**
|
||||
* @brief Destroys the instance of script engine.
|
||||
*/
|
||||
static void destroyInstance();
|
||||
|
||||
/**
|
||||
* @brief Clears all exceptions.
|
||||
*/
|
||||
void clearException();
|
||||
|
||||
/**
|
||||
* @brief Sets the callback function while an exception is fired in JS.
|
||||
* @param[in] cb The callback function to notify that an exception is fired.
|
||||
*/
|
||||
void setJSExceptionCallback(const ExceptionCallback &cb);
|
||||
|
||||
/**
|
||||
* @brief Sets the callback function while an exception is fired.
|
||||
* @param[in] cb The callback function to notify that an exception is fired.
|
||||
*/
|
||||
void setExceptionCallback(const ExceptionCallback &cb);
|
||||
|
||||
/**
|
||||
* @brief Grab a snapshot of the current JavaScript execution stack.
|
||||
* @return current stack trace string
|
||||
*/
|
||||
std::string getCurrentStackTrace();
|
||||
/**
|
||||
* @brief Executes a utf-8 string buffer which contains JavaScript code.
|
||||
* @param[in] script A utf-8 string buffer, if it isn't null-terminated, parameter `length` should be assigned and > 0.
|
||||
* @param[in] length The length of parameter `scriptStr`, it will be set to string length internally if passing < 0 and parameter `scriptStr` is null-terminated.
|
||||
* @param[in] ret The se::Value that results from evaluating script. Passing nullptr if you don't care about the result.
|
||||
* @param[in] fileName A string containing a URL for the script's source file. This is used by debuggers and when reporting exceptions. Pass NULL if you do not care to include source file information.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool evalString(const char *script, ssize_t length = -1, Value *ret = nullptr, const char *fileName = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Adds a callback for registering a native binding module, which will not be removed by ScriptEngine::cleanup.
|
||||
* @param[in] cb A callback for registering a native binding module.
|
||||
* @note This method just add a callback to a vector, callbacks is invoked in `start` method.
|
||||
*/
|
||||
// void addPermanentRegisterCallback(RegisterCallback cb);
|
||||
|
||||
/**
|
||||
* @brief Starts the script engine.
|
||||
* @return true if succeed, otherwise false.
|
||||
* @note This method will invoke all callbacks of native binding modules by the order of registration.
|
||||
*/
|
||||
bool start();
|
||||
|
||||
/**
|
||||
* @brief Initializes script engine.
|
||||
* @return true if succeed, otherwise false.
|
||||
* @note This method will create JavaScript context and global object.
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/**
|
||||
* @brief Adds a hook function before initializing script engine.
|
||||
* @param[in] hook A hook function to be invoked before initializing script engine.
|
||||
* @note Multiple hook functions could be added, they will be invoked by the order of adding.
|
||||
*/
|
||||
void addBeforeInitHook(const std::function<void()> &hook);
|
||||
|
||||
/**
|
||||
* @brief Adds a hook function after initializing script engine.
|
||||
* @param[in] hook A hook function to be invoked before initializing script engine.
|
||||
* @note Multiple hook functions could be added, they will be invoked by the order of adding.
|
||||
*/
|
||||
void addAfterInitHook(const std::function<void()> &hook);
|
||||
|
||||
/**
|
||||
* @brief Cleanups script engine.
|
||||
* @note This method will removes all objects in JavaScript VM even whose are rooted, then shutdown JavaScript VMf.
|
||||
*/
|
||||
void cleanup();
|
||||
|
||||
/**
|
||||
* @brief Adds a hook function before cleanuping script engine.
|
||||
* @param[in] hook A hook function to be invoked before cleanuping script engine.
|
||||
* @note Multiple hook functions could be added, they will be invoked by the order of adding.
|
||||
*/
|
||||
void addBeforeCleanupHook(const std::function<void()> &hook);
|
||||
|
||||
/**
|
||||
* @brief Adds a hook function after cleanuping script engine.
|
||||
* @param[in] hook A hook function to be invoked after cleanuping script engine.
|
||||
* @note Multiple hook functions could be added, they will be invoked by the order of adding.
|
||||
*/
|
||||
void addAfterCleanupHook(const std::function<void()> &hook);
|
||||
/**
|
||||
* @brief Gets the global object of JavaScript VM.
|
||||
* @return The se::Object stores the global JavaScript object.
|
||||
*/
|
||||
Object *getGlobalObject() const;
|
||||
|
||||
typedef bool (*RegisterCallback)(Object*);
|
||||
|
||||
static napi_env getEnv();
|
||||
static void setEnv(napi_env env);
|
||||
|
||||
/**
|
||||
* @brief Adds a callback for registering a native binding module.
|
||||
* @param[in] cb A callback for registering a native binding module.
|
||||
* @note This method just add a callback to a vector, callbacks is invoked in `start` method.
|
||||
*/
|
||||
void addRegisterCallback(RegisterCallback cb);
|
||||
|
||||
const std::chrono::steady_clock::time_point &getStartTime() const;
|
||||
|
||||
/**
|
||||
* @brief Tests whether script engine is doing garbage collection.
|
||||
* @return true if it's in garbage collection, otherwise false.
|
||||
*/
|
||||
bool isGarbageCollecting() const;
|
||||
|
||||
/**
|
||||
* @brief Performs a JavaScript garbage collection.
|
||||
*/
|
||||
void garbageCollect();
|
||||
|
||||
/**
|
||||
* @brief Tests whether script engine is being cleaned up.
|
||||
* @return true if it's in cleaning up, otherwise false.
|
||||
*/
|
||||
bool isInCleanup() const { return _isInCleanup; }
|
||||
/**
|
||||
* @brief Executes a file which contains JavaScript code.
|
||||
* @param[in] path Script file path.
|
||||
* @param[in] ret The se::Value that results from evaluating script. Passing nullptr if you don't care about the result.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool runScript(const std::string &path, Value *ret = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Tests whether script engine is valid.
|
||||
* @return true if it's valid, otherwise false.
|
||||
*/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* @brief Enables JavaScript debugger
|
||||
* @param[in] serverAddr The address of debugger server.
|
||||
* @param[in] isWait Whether wait debugger attach when loading.
|
||||
*/
|
||||
void enableDebugger(const std::string &serverAddr, uint32_t port, bool isWait = false);
|
||||
|
||||
/**
|
||||
* @brief Tests whether JavaScript debugger is enabled
|
||||
* @return true if JavaScript debugger is enabled, otherwise false.
|
||||
*/
|
||||
bool isDebuggerEnabled() const;
|
||||
|
||||
/**
|
||||
* @brief Main loop update trigger, it's need to invoked in main thread every frame.
|
||||
*/
|
||||
void mainLoopUpdate();
|
||||
|
||||
bool runByteCodeFile(const std::string &pathBc, Value *ret /* = nullptr */);
|
||||
|
||||
/**
|
||||
* @brief Throw JS exception
|
||||
*/
|
||||
void throwException(const std::string &errorMessage);
|
||||
|
||||
/**
|
||||
* @brief for napi_new_instance, skip constructor.
|
||||
*/
|
||||
void _setNeedCallConstructor(bool need);
|
||||
|
||||
/**
|
||||
* @brief for napi_new_instance, skip constructor.
|
||||
*/
|
||||
bool _needCallConstructor();
|
||||
|
||||
/**
|
||||
* @brief Fast version of call script function, faster than Object::call
|
||||
*/
|
||||
bool callFunction(Object *targetObj, const char *funcName, uint32_t argc, Value *args, Value *rval = nullptr);
|
||||
|
||||
void _setGarbageCollecting(bool isGarbageCollecting); // NOLINT(readability-identifier-naming)
|
||||
|
||||
void handlePromiseExceptions();
|
||||
|
||||
private:
|
||||
FileOperationDelegate _fileOperationDelegate;
|
||||
std::vector<RegisterCallback> _registerCallbackArray;
|
||||
std::vector<RegisterCallback> _permRegisterCallbackArray;
|
||||
|
||||
std::vector<std::function<void()>> _beforeInitHookArray;
|
||||
std::vector<std::function<void()>> _afterInitHookArray;
|
||||
std::vector<std::function<void()>> _beforeCleanupHookArray;
|
||||
std::vector<std::function<void()>> _afterCleanupHookArray;
|
||||
|
||||
Object * _globalObj = nullptr;
|
||||
napi_env _env = nullptr;
|
||||
|
||||
bool _isValid{false};
|
||||
bool _isGarbageCollecting{false};
|
||||
bool _isInCleanup{false};
|
||||
bool _isErrorHandleWorking{false};
|
||||
bool _isneedCallConstructor{true};
|
||||
std::chrono::steady_clock::time_point _startTime;
|
||||
};
|
||||
}; // namespace se
|
32
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/SeApi.h
Normal file
32
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/SeApi.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Class.h"
|
||||
#include "HelperMacros.h"
|
||||
#include "Object.h"
|
||||
#include "ScriptEngine.h"
|
||||
#include "Utils.h"
|
195
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/Utils.cpp
Normal file
195
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/Utils.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "Utils.h"
|
||||
#include "CommonHeader.h"
|
||||
#include "ScriptEngine.h"
|
||||
#include "Class.h"
|
||||
#include "cocos/scripting/js-bindings/manual/jsb_global.h"
|
||||
|
||||
#define MAX_STRING_LENS 1024
|
||||
|
||||
namespace se {
|
||||
namespace internal {
|
||||
void jsToSeValue(const target_value& value, Value* v) {
|
||||
assert(v != nullptr);
|
||||
napi_status status;
|
||||
napi_valuetype valType;
|
||||
int64_t iRet = 0;
|
||||
double dRet = 0.0;
|
||||
bool bRet = false;
|
||||
bool lossless = false;
|
||||
size_t len = 0;
|
||||
void* privateObjPtr = nullptr;
|
||||
void* nativePtr = nullptr;
|
||||
void* privateData = nullptr;
|
||||
Object* obj = nullptr;
|
||||
|
||||
if (!value) {
|
||||
valType = napi_valuetype::napi_undefined;
|
||||
}else {
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_typeof(ScriptEngine::getEnv(), value, &valType));
|
||||
}
|
||||
|
||||
switch (valType) {
|
||||
case napi_valuetype::napi_undefined:
|
||||
v->setUndefined();
|
||||
break;
|
||||
case napi_valuetype::napi_null:
|
||||
v->setNull();
|
||||
break;
|
||||
case napi_valuetype::napi_number:
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_value_double(ScriptEngine::getEnv(), value, &dRet));
|
||||
if (status == napi_ok) {
|
||||
v->setDouble(dRet);
|
||||
} else {
|
||||
v->setUndefined();
|
||||
}
|
||||
break;
|
||||
case napi_valuetype::napi_bigint:
|
||||
//NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_value_bigint_int64(ScriptEngine::getEnv(), value, &iRet, &lossless));
|
||||
if (lossless) {
|
||||
v->setInt64(iRet);
|
||||
} else {
|
||||
v->setUndefined();
|
||||
}
|
||||
|
||||
break;
|
||||
case napi_valuetype::napi_string:
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_value_string_utf8(ScriptEngine::getEnv(), value, nullptr, 0, &len));
|
||||
if (status == napi_ok) {
|
||||
std::string valueStr;
|
||||
len += 1;
|
||||
valueStr.resize(len);
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_value_string_utf8(ScriptEngine::getEnv(), value, const_cast<char*>(valueStr.data()), valueStr.size(), &len));
|
||||
if (valueStr.length() != len) {
|
||||
valueStr.resize(len);
|
||||
}
|
||||
v->setString(valueStr);
|
||||
} else {
|
||||
v->setUndefined();
|
||||
}
|
||||
break;
|
||||
case napi_valuetype::napi_boolean:
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_value_bool(ScriptEngine::getEnv(), value, &bRet));
|
||||
if (status == napi_ok) {
|
||||
v->setBoolean(bRet);
|
||||
} else {
|
||||
v->setUndefined();
|
||||
}
|
||||
break;
|
||||
case napi_valuetype::napi_object:
|
||||
case napi_valuetype::napi_function:
|
||||
status = napi_unwrap(ScriptEngine::getEnv(), value, &privateData);
|
||||
if (privateData) {
|
||||
obj = Object::getObjectWithPtr(privateData);
|
||||
}
|
||||
if (obj == nullptr) {
|
||||
obj = Object::_createJSObject(ScriptEngine::getEnv(), value, nullptr);
|
||||
}
|
||||
if (obj) {
|
||||
v->setObject(obj, true);
|
||||
obj->decRef();
|
||||
} else {
|
||||
v->setUndefined();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void jsToSeArgs(size_t argc, target_value* argv, ValueArray* outArr) {
|
||||
assert(outArr != nullptr);
|
||||
for (int i = 0; i < argc; i++) {
|
||||
Value v;
|
||||
jsToSeValue(argv[i], &v);
|
||||
outArr->push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
bool seToJsValue(const Value& v, target_value* outJsVal) {
|
||||
assert(outJsVal != nullptr);
|
||||
bool ret = false;
|
||||
napi_status status = napi_ok;
|
||||
switch (v.getType()) {
|
||||
case Value::Type::Number:
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_double(ScriptEngine::getEnv(), v.toDouble(), outJsVal));
|
||||
ret = (status == napi_ok);
|
||||
break;
|
||||
case Value::Type::String: {
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_string_utf8(ScriptEngine::getEnv(), v.toString().c_str(), v.toString().length(), outJsVal));
|
||||
ret = (status == napi_ok);
|
||||
} break;
|
||||
case Value::Type::Boolean:
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_boolean(ScriptEngine::getEnv(), v.toBoolean(), outJsVal));
|
||||
ret = (status == napi_ok);
|
||||
break;
|
||||
case Value::Type::Object:
|
||||
*outJsVal = v.toObject()->_getJSObject();
|
||||
ret = (outJsVal != nullptr);
|
||||
break;
|
||||
case Value::Type::Null:
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_null(ScriptEngine::getEnv(), outJsVal));
|
||||
ret = (status == napi_ok);
|
||||
break;
|
||||
case Value::Type::Undefined:
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_undefined(ScriptEngine::getEnv(), outJsVal));
|
||||
ret = (status == napi_ok);
|
||||
break;
|
||||
case Value::Type::BigInt:
|
||||
//NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_bigint_int64(ScriptEngine::getEnv(), v.toInt64(), outJsVal));
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_double(ScriptEngine::getEnv(), v.toDouble(), outJsVal));
|
||||
ret = (status == napi_ok);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
//LOGI("type :%d", v.getType());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void seToJsArgs(napi_env env, const ValueArray& args, std::vector<target_value>* outArr) {
|
||||
assert(outArr != nullptr);
|
||||
for (const auto& data : args) {
|
||||
napi_value jsval;
|
||||
seToJsValue(data, &jsval);
|
||||
outArr->push_back(jsval);
|
||||
}
|
||||
}
|
||||
|
||||
bool setReturnValue(const Value& data, target_value& argv) {
|
||||
if (data.getType() == Value::Type::BigInt) {
|
||||
// TODO: fix 'TypeError: Cannot mix BigInt and other types, use explicit conversions' for spine & dragonbones
|
||||
napi_status status;
|
||||
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_double(ScriptEngine::getEnv(), data.toDouble(), &argv));
|
||||
return true;
|
||||
}
|
||||
|
||||
return seToJsValue(data, &argv);
|
||||
}
|
||||
} // namespace internal
|
||||
}; // namespace se
|
46
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/Utils.h
Normal file
46
cocos2d-x/cocos/scripting/js-bindings/jswrapper/napi/Utils.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../config.hpp"
|
||||
#include "Object.h"
|
||||
namespace se {
|
||||
|
||||
namespace internal {
|
||||
|
||||
using target_value = napi_value;
|
||||
struct PrivateData {
|
||||
void * data;
|
||||
Object *seObj;
|
||||
};
|
||||
|
||||
bool setReturnValue(const Value &data, target_value &argv);
|
||||
void jsToSeValue(const target_value &value, Value *v);
|
||||
void jsToSeArgs(size_t argc, target_value *argv, ValueArray *outArr);
|
||||
bool seToJsValue(const Value &v, target_value *jsval);
|
||||
void seToJsArgs(napi_env env, const ValueArray &args, std::vector<target_value> *outArr);
|
||||
} // namespace internal
|
||||
} // namespace se
|
@@ -0,0 +1,115 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#ifndef FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_COMMON_H
|
||||
#define FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_COMMON_H
|
||||
|
||||
#define DEPRECATED __attribute__((__deprecated__))
|
||||
|
||||
#ifndef NAPI_VERSION
|
||||
#define NAPI_VERSION 8
|
||||
#endif
|
||||
|
||||
#define NAPI_RETVAL_NOTHING
|
||||
|
||||
#define GET_AND_THROW_LAST_ERROR(env) \
|
||||
do { \
|
||||
const napi_extended_error_info* errorInfo = nullptr; \
|
||||
napi_get_last_error_info((env), &errorInfo); \
|
||||
bool isPending = false; \
|
||||
napi_is_exception_pending((env), &isPending); \
|
||||
if (!isPending && errorInfo != nullptr) { \
|
||||
const char* errorMessage = \
|
||||
errorInfo->error_message != nullptr ? errorInfo->error_message : "empty error message"; \
|
||||
napi_throw_error((env), nullptr, errorMessage); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define NAPI_ASSERT_BASE(env, assertion, message, retVal) \
|
||||
do { \
|
||||
if (!(assertion)) { \
|
||||
napi_throw_error((env), nullptr, "assertion (" #assertion ") failed: " message); \
|
||||
return retVal; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define NAPI_ASSERT(env, assertion, message) NAPI_ASSERT_BASE(env, assertion, message, nullptr)
|
||||
|
||||
#define NAPI_ASSERT_RETURN_VOID(env, assertion, message) NAPI_ASSERT_BASE(env, assertion, message, NAPI_RETVAL_NOTHING)
|
||||
|
||||
#define NAPI_CALL_BASE(env, theCall, retVal) \
|
||||
do { \
|
||||
if ((theCall) != napi_ok) { \
|
||||
GET_AND_THROW_LAST_ERROR((env)); \
|
||||
return retVal; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define NAPI_CALL(env, theCall) NAPI_CALL_BASE(env, theCall, nullptr)
|
||||
|
||||
#define NAPI_CALL_RETURN_VOID(env, theCall) NAPI_CALL_BASE(env, theCall, NAPI_RETVAL_NOTHING)
|
||||
|
||||
#define DECLARE_NAPI_PROPERTY(name, val) \
|
||||
{ \
|
||||
(name), nullptr, nullptr, nullptr, nullptr, val, napi_default, nullptr \
|
||||
}
|
||||
|
||||
#define DECLARE_NAPI_STATIC_PROPERTY(name, val) \
|
||||
{ \
|
||||
(name), nullptr, nullptr, nullptr, nullptr, val, napi_static, nullptr \
|
||||
}
|
||||
|
||||
#define DECLARE_NAPI_FUNCTION(name, func) \
|
||||
{ \
|
||||
(name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr \
|
||||
}
|
||||
|
||||
#define DECLARE_NAPI_FUNCTION_WITH_DATA(name, func, data) \
|
||||
{ \
|
||||
(name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, data \
|
||||
}
|
||||
|
||||
#define DECLARE_NAPI_STATIC_FUNCTION(name, func) \
|
||||
{ \
|
||||
(name), nullptr, (func), nullptr, nullptr, nullptr, napi_static, nullptr \
|
||||
}
|
||||
|
||||
#define DECLARE_NAPI_GETTER(name, getter) \
|
||||
{ \
|
||||
(name), nullptr, nullptr, (getter), nullptr, nullptr, napi_default, nullptr \
|
||||
}
|
||||
|
||||
#define DECLARE_NAPI_SETTER(name, setter) \
|
||||
{ \
|
||||
(name), nullptr, nullptr, nullptr, (setter), nullptr, napi_default, nullptr \
|
||||
}
|
||||
|
||||
#define DECLARE_NAPI_GETTER_SETTER(name, getter, setter) \
|
||||
{ \
|
||||
(name), nullptr, nullptr, (getter), (setter), nullptr, napi_default, nullptr \
|
||||
}
|
||||
|
||||
#endif /* FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_COMMON_H */
|
Reference in New Issue
Block a user