mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-01-15 07:21:07 +00:00
739 lines
24 KiB
C++
739 lines
24 KiB
C++
|
/****************************************************************************
|
||
|
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
|