You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
cocos_lib/cocos/bindings/manual/jsb_global.cpp

1624 lines
60 KiB

/****************************************************************************
Copyright (c) 2017-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 "jsb_global.h"
#include "application/ApplicationManager.h"
#include "base/Assertf.h"
#include "base/Data.h"
#include "base/DeferredReleasePool.h"
#include "base/Scheduler.h"
#include "base/ThreadPool.h"
#include "base/ZipUtils.h"
#include "base/base64.h"
#include "bindings/auto/jsb_cocos_auto.h"
#include "core/data/JSBNativeDataHolder.h"
#include "gfx-base/GFXDef.h"
#include "jsb_conversions.h"
#include "network/Downloader.h"
#include "network/HttpClient.h"
#include "platform/Image.h"
#include "platform/interfaces/modules/ISystem.h"
#include "platform/interfaces/modules/ISystemWindow.h"
#include "ui/edit-box/EditBox.h"
#include "v8/Object.h"
#include "xxtea/xxtea.h"
#include <chrono>
#include <regex>
#include <sstream>
#if CC_PLATFORM == CC_PLATFORM_ANDROID
#include "platform/java/jni/JniImp.h"
#endif
#if CC_PLATFORM == CC_PLATFORM_OPENHARMONY && SCRIPT_ENGINE_TYPE != SCRIPT_ENGINE_NAPI
#include "platform/openharmony/napi/NapiHelper.h"
#endif
extern void jsb_register_ADPF(se::Object *); // NOLINT
using namespace cc; // NOLINT
static LegacyThreadPool *gThreadPool = nullptr;
static std::shared_ptr<cc::network::Downloader> gLocalDownloader = nullptr;
static ccstd::unordered_map<ccstd::string, std::function<void(const ccstd::string &, unsigned char *, uint)>> gLocalDownloaderHandlers;
static uint64_t gLocalDownloaderTaskId = 1000000;
static cc::network::Downloader *localDownloader() {
if (!gLocalDownloader) {
gLocalDownloader = std::make_shared<cc::network::Downloader>();
gLocalDownloader->onDataTaskSuccess = [=](const cc::network::DownloadTask &task,
const ccstd::vector<unsigned char> &data) {
if (data.empty()) {
SE_REPORT_ERROR("Getting image from (%s) failed!", task.requestURL.c_str());
return;
}
auto callback = gLocalDownloaderHandlers.find(task.identifier);
if (callback == gLocalDownloaderHandlers.end()) {
SE_REPORT_ERROR("Getting image from (%s), callback not found!!", task.requestURL.c_str());
return;
}
size_t imageBytes = data.size();
auto *imageData = static_cast<unsigned char *>(malloc(imageBytes));
memcpy(imageData, data.data(), imageBytes);
(callback->second)("", imageData, static_cast<uint>(imageBytes));
// initImageFunc("", imageData, imageBytes);
gLocalDownloaderHandlers.erase(callback);
};
gLocalDownloader->onTaskError = [=](const cc::network::DownloadTask &task,
int errorCode, // NOLINT
int errorCodeInternal, // NOLINT
const ccstd::string &errorStr) { // NOLINT
SE_REPORT_ERROR("Getting image from (%s) failed!", task.requestURL.c_str());
gLocalDownloaderHandlers.erase(task.identifier);
};
}
return gLocalDownloader.get();
}
static void localDownloaderCreateTask(const ccstd::string &url, const std::function<void(const ccstd::string &, unsigned char *, int)> &callback) {
#if CC_PLATFORM != CC_PLATFORM_OPENHARMONY // TODO(qgh):May be removed later
std::stringstream ss;
ss << "jsb_loadimage_" << (gLocalDownloaderTaskId++);
ccstd::string key = ss.str();
auto task = localDownloader()->createDataTask(url, key);
gLocalDownloaderHandlers.emplace(task->identifier, callback);
#endif
}
bool jsb_set_extend_property(const char *ns, const char *clsName) { // NOLINT
se::Object *globalObj = se::ScriptEngine::getInstance()->getGlobalObject();
se::Value nsVal;
if (globalObj->getProperty(ns, &nsVal) && nsVal.isObject()) {
se::Value ccVal;
if (globalObj->getProperty("cc", &ccVal) && ccVal.isObject()) {
se::Value ccClassVal;
if (ccVal.toObject()->getProperty("Class", &ccClassVal) && ccClassVal.isObject()) {
se::Value extendVal;
if (ccClassVal.toObject()->getProperty("extend", &extendVal) && extendVal.isObject() && extendVal.toObject()->isFunction()) {
se::Value targetClsVal;
if (nsVal.toObject()->getProperty(clsName, &targetClsVal) && targetClsVal.isObject()) {
return targetClsVal.toObject()->setProperty("extend", extendVal);
}
}
}
}
}
return false;
}
namespace {
ccstd::unordered_map<ccstd::string, se::Value> gModuleCache;
static bool require(se::State &s) { // NOLINT
const auto &args = s.args();
int argc = static_cast<int>(args.size());
CC_ASSERT_GE(argc, 1);
CC_ASSERT(args[0].isString());
return jsb_run_script(args[0].toString(), &s.rval());
}
SE_BIND_FUNC(require)
static bool doModuleRequire(const ccstd::string &path, se::Value *ret, const ccstd::string &prevScriptFileDir) { // NOLINT
se::AutoHandleScope hs;
CC_ASSERT(!path.empty());
const auto &fileOperationDelegate = se::ScriptEngine::getInstance()->getFileOperationDelegate();
CC_ASSERT(fileOperationDelegate.isValid());
ccstd::string fullPath;
ccstd::string pathWithSuffix = path;
if (pathWithSuffix.rfind(".js") != (pathWithSuffix.length() - 3)) {
pathWithSuffix += ".js";
}
ccstd::string scriptBuffer = fileOperationDelegate.onGetStringFromFile(pathWithSuffix);
if (scriptBuffer.empty() && !prevScriptFileDir.empty()) {
ccstd::string secondPath = prevScriptFileDir;
if (secondPath[secondPath.length() - 1] != '/') {
secondPath += "/";
}
secondPath += path;
if (FileUtils::getInstance()->isDirectoryExist(secondPath)) {
if (secondPath[secondPath.length() - 1] != '/') {
secondPath += "/";
}
secondPath += "index.js";
} else {
if (path.rfind(".js") != (path.length() - 3)) {
secondPath += ".js";
}
}
fullPath = fileOperationDelegate.onGetFullPath(secondPath);
scriptBuffer = fileOperationDelegate.onGetStringFromFile(fullPath);
} else {
fullPath = fileOperationDelegate.onGetFullPath(pathWithSuffix);
}
if (!scriptBuffer.empty()) {
const auto &iter = gModuleCache.find(fullPath);
if (iter != gModuleCache.end()) {
*ret = iter->second;
// printf("Found cache: %s, value: %d\n", fullPath.c_str(), (int)ret->getType());
return true;
}
ccstd::string currentScriptFileDir = FileUtils::getInstance()->getFileDir(fullPath);
// Add closure for evalutate the script
char prefix[] = "(function(currentScriptDir){ window.module = window.module || {}; var exports = window.module.exports = {}; ";
char suffix[512] = {0};
snprintf(suffix, sizeof(suffix), "\nwindow.module.exports = window.module.exports || exports;\n})('%s'); ", currentScriptFileDir.c_str());
// Add current script path to require function invocation
scriptBuffer = prefix + std::regex_replace(scriptBuffer, std::regex("([^A-Za-z0-9]|^)requireModule\\((.*?)\\)"), "$1requireModule($2, currentScriptDir)") + suffix;
// FILE* fp = fopen("/Users/james/Downloads/test.txt", "wb");
// fwrite(scriptBuffer.c_str(), scriptBuffer.length(), 1, fp);
// fclose(fp);
#if CC_PLATFORM == CC_PLATFORM_MACOS || CC_PLATFORM == CC_PLATFORM_IOS
ccstd::string reletivePath = fullPath;
#if CC_PLATFORM == CC_PLATFORM_MACOS
const ccstd::string reletivePathKey = "/Contents/Resources";
#else
const ccstd::string reletivePathKey = ".app";
#endif
size_t pos = reletivePath.find(reletivePathKey);
if (pos != ccstd::string::npos) {
reletivePath = reletivePath.substr(pos + reletivePathKey.length() + 1);
}
#else
const ccstd::string &reletivePath = fullPath;
#endif
auto *se = se::ScriptEngine::getInstance();
bool succeed = se->evalString(scriptBuffer.c_str(), static_cast<uint32_t>(scriptBuffer.length()), nullptr, reletivePath.c_str());
se::Value moduleVal;
if (succeed && se->getGlobalObject()->getProperty("module", &moduleVal) && moduleVal.isObject()) {
se::Value exportsVal;
if (moduleVal.toObject()->getProperty("exports", &exportsVal)) {
if (ret != nullptr) {
*ret = exportsVal;
}
gModuleCache[fullPath] = std::move(exportsVal);
} else {
gModuleCache[fullPath] = se::Value::Undefined;
}
// clear module.exports
moduleVal.toObject()->setProperty("exports", se::Value::Undefined);
} else {
gModuleCache[fullPath] = se::Value::Undefined;
}
CC_ASSERT(succeed);
return succeed;
}
SE_LOGE("doModuleRequire %s, buffer is empty!\n", path.c_str());
CC_ABORT();
return false;
}
static bool moduleRequire(se::State &s) { // NOLINT
const auto &args = s.args();
int argc = static_cast<int>(args.size());
CC_ASSERT_GE(argc, 2);
CC_ASSERT(args[0].isString());
CC_ASSERT(args[1].isString());
return doModuleRequire(args[0].toString(), &s.rval(), args[1].toString());
}
SE_BIND_FUNC(moduleRequire)
} // namespace
bool jsb_run_script(const ccstd::string &filePath, se::Value *rval /* = nullptr */) { // NOLINT
se::AutoHandleScope hs;
return se::ScriptEngine::getInstance()->runScript(filePath, rval);
}
bool jsb_run_script_module(const ccstd::string &filePath, se::Value *rval /* = nullptr */) { // NOLINT
return doModuleRequire(filePath, rval, "");
}
static bool jsc_garbageCollect(se::State &s) { // NOLINT
se::ScriptEngine::getInstance()->garbageCollect();
return true;
}
SE_BIND_FUNC(jsc_garbageCollect)
static bool jsc_dumpNativePtrToSeObjectMap(se::State &s) { // NOLINT
CC_LOG_DEBUG(">>> total: %d, Dump (native -> jsobj) map begin", (int)se::NativePtrToObjectMap::size());
struct NamePtrStruct {
const char *name;
void *ptr;
};
ccstd::vector<NamePtrStruct> namePtrArray;
for (const auto &e : se::NativePtrToObjectMap::instance()) {
se::Object *jsobj = e.second;
CC_ASSERT(jsobj->_getClass() != nullptr);
NamePtrStruct tmp;
tmp.name = jsobj->_getClass()->getName();
tmp.ptr = e.first;
namePtrArray.push_back(tmp);
}
std::sort(namePtrArray.begin(), namePtrArray.end(), [](const NamePtrStruct &a, const NamePtrStruct &b) -> bool {
ccstd::string left = a.name;
ccstd::string right = b.name;
for (ccstd::string::const_iterator lit = left.begin(), rit = right.begin(); lit != left.end() && rit != right.end(); ++lit, ++rit) {
if (::tolower(*lit) < ::tolower(*rit)) {
return true;
}
if (::tolower(*lit) > ::tolower(*rit)) {
return false;
}
}
return left.size() < right.size();
});
for (const auto &e : namePtrArray) {
CC_LOG_DEBUG("%s: %p", e.name, e.ptr);
}
CC_LOG_DEBUG(">>> total: %d, Dump (native -> jsobj) map end", (int)se::NativePtrToObjectMap::size());
return true;
}
SE_BIND_FUNC(jsc_dumpNativePtrToSeObjectMap)
static bool jsc_dumpRoot(se::State &s) { // NOLINT
CC_ABORT();
return true;
}
SE_BIND_FUNC(jsc_dumpRoot)
static bool JSBCore_platform(se::State &s) { // NOLINT
// Application::Platform platform = CC_CURRENT_ENGINE()->getPlatform();
cc::BasePlatform::OSType type =
cc::BasePlatform::getPlatform()->getOSType();
s.rval().setInt32(static_cast<int32_t>(type));
return true;
}
SE_BIND_FUNC(JSBCore_platform)
static bool JSBCore_os(se::State &s) { // NOLINT
se::Value os;
// osx, ios, android, windows, linux, etc..
#if (CC_PLATFORM == CC_PLATFORM_IOS)
os.setString("iOS");
#elif (CC_PLATFORM == CC_PLATFORM_ANDROID)
os.setString("Android");
#elif (CC_PLATFORM == CC_PLATFORM_WINDOWS)
os.setString("Windows");
#elif (CC_PLATFORM == CC_PLATFORM_LINUX)
os.setString("Linux");
#elif (CC_PLATFORM == CC_PLATFORM_QNX)
os.setString("Qnx");
#elif (CC_PLATFORM == CC_PLATFORM_MACOS)
os.setString("OS X");
#elif (CC_PLATFORM == CC_PLATFORM_OHOS)
os.setString("OHOS");
#elif (CC_PLATFORM == CC_PLATFORM_OPENHARMONY)
os.setString("OpenHarmony");
#endif
s.rval() = os;
return true;
}
SE_BIND_FUNC(JSBCore_os)
static bool JSBCore_getCurrentLanguage(se::State &s) { // NOLINT
auto *systemIntf = CC_GET_PLATFORM_INTERFACE(ISystem);
CC_ASSERT_NOT_NULL(systemIntf);
ccstd::string languageStr = systemIntf->getCurrentLanguageToString();
s.rval().setString(languageStr);
return true;
}
SE_BIND_FUNC(JSBCore_getCurrentLanguage)
static bool JSBCore_getCurrentLanguageCode(se::State &s) { // NOLINT
auto *systemIntf = CC_GET_PLATFORM_INTERFACE(ISystem);
CC_ASSERT_NOT_NULL(systemIntf);
ccstd::string language = systemIntf->getCurrentLanguageCode();
s.rval().setString(language);
return true;
}
SE_BIND_FUNC(JSBCore_getCurrentLanguageCode)
static bool JSB_getOSVersion(se::State &s) { // NOLINT
auto *systemIntf = CC_GET_PLATFORM_INTERFACE(ISystem);
CC_ASSERT_NOT_NULL(systemIntf);
ccstd::string systemVersion = systemIntf->getSystemVersion();
s.rval().setString(systemVersion);
return true;
}
SE_BIND_FUNC(JSB_getOSVersion)
static bool JSB_supportHPE(se::State &s) { // NOLINT
#if CC_PLATFORM == CC_PLATFORM_ANDROID
s.rval().setBoolean(getSupportHPE());
#else
s.rval().setBoolean(false);
#endif
return true;
}
SE_BIND_FUNC(JSB_supportHPE)
static bool JSB_core_restartVM(se::State &s) { // NOLINT
// REFINE: release AudioEngine, waiting HttpClient & WebSocket threads to exit.
CC_CURRENT_APPLICATION()->restart();
return true;
}
SE_BIND_FUNC(JSB_core_restartVM)
static bool JSB_closeWindow(se::State &s) { // NOLINT
CC_CURRENT_APPLICATION()->close();
return true;
}
SE_BIND_FUNC(JSB_closeWindow)
static bool JSB_exit(se::State &s) { // NOLINT
BasePlatform::getPlatform()->exit();
return true;
}
SE_BIND_FUNC(JSB_exit);
static bool JSB_isObjectValid(se::State &s) { // NOLINT
const auto &args = s.args();
int argc = static_cast<int>(args.size());
if (argc == 1) {
void *nativePtr = nullptr;
seval_to_native_ptr(args[0], &nativePtr);
s.rval().setBoolean(nativePtr != nullptr);
return true;
}
SE_REPORT_ERROR("Invalid number of arguments: %d. Expecting: 1", argc);
return false;
}
SE_BIND_FUNC(JSB_isObjectValid)
static bool JSB_setCursorEnabled(se::State &s) { // NOLINT
const auto &args = s.args();
int argc = static_cast<int>(args.size());
SE_PRECONDITION2(argc == 1, false, "Invalid number of arguments");
bool ok = true;
bool value = true;
ok &= sevalue_to_native(args[0], &value);
SE_PRECONDITION2(ok, false, "Error processing arguments");
auto *systemWindowIntf = CC_GET_SYSTEM_WINDOW(ISystemWindow::mainWindowId);
CC_ASSERT_NOT_NULL(systemWindowIntf);
systemWindowIntf->setCursorEnabled(value);
return true;
}
SE_BIND_FUNC(JSB_setCursorEnabled)
static bool JSB_saveByteCode(se::State &s) { // NOLINT
const auto &args = s.args();
int argc = static_cast<int>(args.size());
SE_PRECONDITION2(argc == 2, false, "Invalid number of arguments");
bool ok = true;
ccstd::string srcfile;
ccstd::string dstfile;
ok &= sevalue_to_native(args[0], &srcfile);
ok &= sevalue_to_native(args[1], &dstfile);
SE_PRECONDITION2(ok, false, "Error processing arguments");
ok = se::ScriptEngine::getInstance()->saveByteCodeToFile(srcfile, dstfile);
s.rval().setBoolean(ok);
return true;
}
SE_BIND_FUNC(JSB_saveByteCode)
static bool getOrCreatePlainObject_r(const char *name, se::Object *parent, se::Object **outObj) { // NOLINT
CC_ASSERT_NOT_NULL(parent);
CC_ASSERT_NOT_NULL(outObj);
se::Value tmp;
if (parent->getProperty(name, &tmp) && tmp.isObject()) {
*outObj = tmp.toObject();
(*outObj)->incRef();
} else {
*outObj = se::Object::createPlainObject();
parent->setProperty(name, se::Value(*outObj));
}
return true;
}
static bool js_performance_now(se::State &s) { // NOLINT
auto now = std::chrono::steady_clock::now();
auto micro = std::chrono::duration_cast<std::chrono::microseconds>(now - se::ScriptEngine::getInstance()->getStartTime()).count();
s.rval().setDouble(static_cast<double>(micro) * 0.001);
return true;
}
SE_BIND_FUNC(js_performance_now)
namespace {
struct ImageInfo {
uint32_t length = 0;
uint32_t width = 0;
uint32_t height = 0;
uint8_t *data = nullptr;
cc::gfx::Format format = cc::gfx::Format::UNKNOWN;
bool hasAlpha = false;
bool compressed = false;
ccstd::vector<uint32_t> mipmapLevelDataSize;
};
uint8_t *convertRGB2RGBA(uint32_t length, uint8_t *src) {
auto *dst = reinterpret_cast<uint8_t *>(malloc(length));
for (uint32_t i = 0; i < length; i += 4) {
dst[i] = *src++;
dst[i + 1] = *src++;
dst[i + 2] = *src++;
dst[i + 3] = 255;
}
return dst;
}
uint8_t *convertIA2RGBA(uint32_t length, uint8_t *src) {
auto *dst = reinterpret_cast<uint8_t *>(malloc(length));
for (uint32_t i = 0; i < length; i += 4) {
dst[i] = *src;
dst[i + 1] = *src;
dst[i + 2] = *src++;
dst[i + 3] = *src++;
}
return dst;
}
uint8_t *convertI2RGBA(uint32_t length, uint8_t *src) {
auto *dst = reinterpret_cast<uint8_t *>(malloc(length));
for (uint32_t i = 0; i < length; i += 4) {
dst[i] = *src;
dst[i + 1] = *src;
dst[i + 2] = *src++;
dst[i + 3] = 255;
}
return dst;
}
struct ImageInfo *createImageInfo(Image *img) {
auto *imgInfo = ccnew struct ImageInfo();
imgInfo->length = static_cast<uint32_t>(img->getDataLen());
imgInfo->width = img->getWidth();
imgInfo->height = img->getHeight();
img->takeData(&imgInfo->data);
imgInfo->format = img->getRenderFormat();
imgInfo->compressed = img->isCompressed();
imgInfo->mipmapLevelDataSize = img->getMipmapLevelDataSize();
// Convert to RGBA888 because standard web api will return only RGBA888.
// If not, then it may have issue in glTexSubImage. For example, engine
// will create a big texture, and update its content with small pictures.
// The big texture is RGBA888, then the small picture should be the same
// format, or it will cause 0x502 error on OpenGL ES 2.
if (!imgInfo->compressed && imgInfo->format != cc::gfx::Format::RGBA8) {
imgInfo->length = img->getWidth() * img->getHeight() * 4;
uint8_t *dst = nullptr;
uint32_t length = imgInfo->length;
uint8_t *src = imgInfo->data;
switch (imgInfo->format) {
case cc::gfx::Format::A8:
case cc::gfx::Format::LA8:
dst = convertIA2RGBA(length, src);
break;
case cc::gfx::Format::L8:
case cc::gfx::Format::R8:
case cc::gfx::Format::R8I:
dst = convertI2RGBA(length, src);
break;
case cc::gfx::Format::RGB8:
dst = convertRGB2RGBA(length, src);
break;
default:
SE_LOGE("unknown image format");
break;
}
if (dst != imgInfo->data) free(imgInfo->data);
imgInfo->data = dst;
imgInfo->hasAlpha = true;
}
return imgInfo;
}
} // namespace
bool jsb_global_load_image(const ccstd::string &path, const se::Value &callbackVal) { // NOLINT(readability-identifier-naming)
if (path.empty()) {
se::ValueArray seArgs;
callbackVal.toObject()->call(seArgs, nullptr);
return true;
}
std::shared_ptr<se::Value> callbackPtr = std::make_shared<se::Value>(callbackVal);
auto initImageFunc = [path, callbackPtr](const ccstd::string &fullPath, unsigned char *imageData, int imageBytes) {
auto *img = ccnew Image();
gThreadPool->pushTask([=](int /*tid*/) {
// NOTE: FileUtils::getInstance()->fullPathForFilename isn't a threadsafe method,
// Image::initWithImageFile will call fullPathForFilename internally which may
// cause thread race issues. Therefore, we get the full path of file before
// going into task callback.
// Be careful of invoking any Cocos2d-x interface in a sub-thread.
bool loadSucceed = false;
if (fullPath.empty()) {
loadSucceed = img->initWithImageData(imageData, imageBytes);
free(imageData);
} else {
loadSucceed = img->initWithImageFile(fullPath);
}
ImageInfo *imgInfo = nullptr;
if (loadSucceed) {
imgInfo = createImageInfo(img);
}
auto app = CC_CURRENT_APPLICATION();
if (!app) {
delete imgInfo;
delete img;
return;
}
auto engine = app->getEngine();
CC_ASSERT_NOT_NULL(engine);
engine->getScheduler()->performFunctionInCocosThread([=]() {
se::AutoHandleScope hs;
se::ValueArray seArgs;
if (loadSucceed) {
se::HandleObject retObj(se::Object::createPlainObject());
auto *obj = se::Object::createObjectWithClass(__jsb_cc_JSBNativeDataHolder_class);
auto *nativeObj = JSB_MAKE_PRIVATE_OBJECT(cc::JSBNativeDataHolder, imgInfo->data);
obj->setPrivateObject(nativeObj);
retObj->setProperty("data", se::Value(obj));
retObj->setProperty("width", se::Value(imgInfo->width));
retObj->setProperty("height", se::Value(imgInfo->height));
se::Value mipmapLevelDataSizeArr;
nativevalue_to_se(imgInfo->mipmapLevelDataSize, mipmapLevelDataSizeArr, nullptr);
retObj->setProperty("mipmapLevelDataSize", mipmapLevelDataSizeArr);
seArgs.push_back(se::Value(retObj));
delete imgInfo;
} else {
SE_REPORT_ERROR("initWithImageFile: %s failed!", path.c_str());
}
callbackPtr->toObject()->call(seArgs, nullptr);
delete img;
});
});
};
size_t pos = ccstd::string::npos;
if (path.find("http://") == 0 || path.find("https://") == 0) {
localDownloaderCreateTask(path, initImageFunc);
} else if (path.find("data:") == 0 && (pos = path.find("base64,")) != ccstd::string::npos) {
int imageBytes = 0;
unsigned char *imageData = nullptr;
size_t dataStartPos = pos + strlen("base64,");
const char *base64Data = path.data() + dataStartPos;
size_t dataLen = path.length() - dataStartPos;
imageBytes = base64Decode(reinterpret_cast<const unsigned char *>(base64Data), static_cast<unsigned int>(dataLen), &imageData);
if (imageBytes <= 0 || imageData == nullptr) {
SE_REPORT_ERROR("Decode base64 image data failed!");
return false;
}
initImageFunc("", imageData, imageBytes);
} else {
ccstd::string fullPath(FileUtils::getInstance()->fullPathForFilename(path));
if (0 == path.find("file://")) {
fullPath = FileUtils::getInstance()->fullPathForFilename(path.substr(strlen("file://")));
}
if (fullPath.empty()) {
SE_REPORT_ERROR("File (%s) doesn't exist!", path.c_str());
return false;
}
initImageFunc(fullPath, nullptr, 0);
}
return true;
}
static bool js_loadImage(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (argc == 2) {
ccstd::string path;
ok &= sevalue_to_native(args[0], &path);
SE_PRECONDITION2(ok, false, "Error processing arguments");
const auto &callbackVal = args[1];
CC_ASSERT(callbackVal.isObject());
CC_ASSERT(callbackVal.toObject()->isFunction());
return jsb_global_load_image(path, callbackVal);
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 2);
return false;
}
SE_BIND_FUNC(js_loadImage)
// pixels(RGBA), width, height, fullFilePath(*.png/*.jpg)
static bool js_saveImageData(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
bool ok = true; // NOLINT(readability-identifier-length)
if (argc == 4 || argc == 5) {
auto *uint8ArrayObj = args[0].toObject();
uint8_t *uint8ArrayData{nullptr};
size_t length = 0;
uint8ArrayObj->root();
uint8ArrayObj->incRef();
uint8ArrayObj->getTypedArrayData(&uint8ArrayData, &length);
int32_t width;
int32_t height;
ok &= sevalue_to_native(args[1], &width);
ok &= sevalue_to_native(args[2], &height);
std::string filePath;
ok &= sevalue_to_native(args[3], &filePath);
SE_PRECONDITION2(ok, false, "js_saveImageData : Error processing arguments");
se::Value callbackVal = argc == 5 ? args[4] : se::Value::Null;
se::Object *callbackObj{nullptr};
if (!callbackVal.isNull()) {
CC_ASSERT(callbackVal.isObject());
CC_ASSERT(callbackVal.toObject()->isFunction());
callbackObj = callbackVal.toObject();
callbackObj->root();
callbackObj->incRef();
}
gThreadPool->pushTask([=](int /*tid*/) {
// isToRGB = false, to keep alpha channel
auto *img = ccnew Image();
// A conversion from size_t to uint32_t might lose integer precision
img->initWithRawData(uint8ArrayData, static_cast<uint32_t>(length), width, height, 32 /*Unused*/);
bool isSuccess = img->saveToFile(filePath, false /*isToRGB*/);
CC_CURRENT_ENGINE()->getScheduler()->performFunctionInCocosThread([=]() {
se::AutoHandleScope hs;
se::ValueArray seArgs;
se::Value isSuccessVal;
nativevalue_to_se(isSuccess, isSuccessVal);
seArgs.push_back(isSuccessVal);
if (callbackObj) {
callbackObj->call(seArgs, nullptr);
callbackObj->unroot();
callbackObj->decRef();
}
uint8ArrayObj->unroot();
uint8ArrayObj->decRef();
delete img;
});
});
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d or %d", (int)argc, 4, 5);
return false;
}
SE_BIND_FUNC(js_saveImageData)
static bool js_destroyImage(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (argc == 1) {
cc::JSBNativeDataHolder *dataHolder = nullptr;
ok &= sevalue_to_native(args[0], &dataHolder);
SE_PRECONDITION2(ok, false, "Error processing arguments");
dataHolder->destroy();
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(js_destroyImage)
static bool JSB_openURL(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (argc > 0) {
ccstd::string url;
ok = sevalue_to_native(args[0], &url);
SE_PRECONDITION2(ok, false, "url is invalid!");
auto *systemIntf = CC_GET_PLATFORM_INTERFACE(ISystem);
CC_ASSERT_NOT_NULL(systemIntf);
systemIntf->openURL(url);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(JSB_openURL)
static bool JSB_copyTextToClipboard(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (argc > 0) {
ccstd::string text;
ok = sevalue_to_native(args[0], &text);
SE_PRECONDITION2(ok, false, "text is invalid!");
auto *systemIntf = CC_GET_PLATFORM_INTERFACE(ISystem);
CC_ASSERT_NOT_NULL(systemIntf);
systemIntf->copyTextToClipboard(text);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(JSB_copyTextToClipboard)
static bool JSB_setPreferredFramesPerSecond(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (argc > 0) {
int32_t fps;
ok = sevalue_to_native(args[0], &fps);
SE_PRECONDITION2(ok, false, "fps is invalid!");
// cc::log("EMPTY IMPLEMENTATION OF jsb.setPreferredFramesPerSecond");
CC_CURRENT_ENGINE()->setPreferredFramesPerSecond(fps);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(JSB_setPreferredFramesPerSecond)
#if CC_USE_EDITBOX
static bool JSB_showInputBox(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
if (argc == 1) {
bool ok;
se::Value tmp;
const auto &obj = args[0].toObject();
cc::EditBox::ShowInfo showInfo;
ok = obj->getProperty("defaultValue", &tmp);
SE_PRECONDITION2(ok && tmp.isString(), false, "defaultValue is invalid!");
showInfo.defaultValue = tmp.toString();
ok = obj->getProperty("maxLength", &tmp);
SE_PRECONDITION2(ok && tmp.isNumber(), false, "maxLength is invalid!");
showInfo.maxLength = tmp.toInt32();
ok = obj->getProperty("multiple", &tmp);
SE_PRECONDITION2(ok && tmp.isBoolean(), false, "multiple is invalid!");
showInfo.isMultiline = tmp.toBoolean();
if (obj->getProperty("confirmHold", &tmp)) {
SE_PRECONDITION2(tmp.isBoolean(), false, "confirmHold is invalid!");
if (!tmp.isUndefined()) {
showInfo.confirmHold = tmp.toBoolean();
}
}
if (obj->getProperty("confirmType", &tmp)) {
SE_PRECONDITION2(tmp.isString(), false, "confirmType is invalid!");
if (!tmp.isUndefined()) {
showInfo.confirmType = tmp.toString();
}
}
if (obj->getProperty("inputType", &tmp)) {
SE_PRECONDITION2(tmp.isString(), false, "inputType is invalid!");
if (!tmp.isUndefined()) {
showInfo.inputType = tmp.toString();
}
}
if (obj->getProperty("originX", &tmp)) {
SE_PRECONDITION2(tmp.isNumber(), false, "originX is invalid!");
if (!tmp.isUndefined()) {
showInfo.x = tmp.toInt32();
}
}
if (obj->getProperty("originY", &tmp)) {
SE_PRECONDITION2(tmp.isNumber(), false, "originY is invalid!");
if (!tmp.isUndefined()) {
showInfo.y = tmp.toInt32();
}
}
if (obj->getProperty("width", &tmp)) {
SE_PRECONDITION2(tmp.isNumber(), false, "width is invalid!");
if (!tmp.isUndefined()) {
showInfo.width = tmp.toInt32();
}
}
if (obj->getProperty("height", &tmp)) {
SE_PRECONDITION2(tmp.isNumber(), false, "height is invalid!");
if (!tmp.isUndefined()) {
showInfo.height = tmp.toInt32();
}
}
if (obj->getProperty("fontSize", &tmp)) {
SE_PRECONDITION2(tmp.isNumber(), false, "fontSize is invalid!");
if (!tmp.isUndefined()) {
showInfo.fontSize = tmp.toUint32();
}
}
if (obj->getProperty("fontColor", &tmp)) {
SE_PRECONDITION2(tmp.isNumber(), false, "fontColor is invalid!");
if (!tmp.isUndefined()) {
showInfo.fontColor = tmp.toUint32();
}
}
if (obj->getProperty("isBold", &tmp)) {
SE_PRECONDITION2(tmp.isBoolean(), false, "isBold is invalid!");
if (!tmp.isUndefined()) {
showInfo.isBold = tmp.toBoolean();
}
}
if (obj->getProperty("isItalic", &tmp)) {
SE_PRECONDITION2(tmp.isBoolean(), false, "isItalic is invalid!");
if (!tmp.isUndefined()) {
showInfo.isItalic = tmp.toBoolean();
}
}
if (obj->getProperty("isUnderline", &tmp)) {
SE_PRECONDITION2(tmp.isBoolean(), false, "isUnderline is invalid!");
if (!tmp.isUndefined()) {
showInfo.isUnderline = tmp.toBoolean();
}
}
if (obj->getProperty("underlineColor", &tmp)) {
SE_PRECONDITION2(tmp.isNumber(), false, "underlinrColor is invalid!");
if (!tmp.isUndefined()) {
showInfo.underlineColor = tmp.toUint32();
}
}
if (obj->getProperty("backColor", &tmp)) {
SE_PRECONDITION2(tmp.isNumber(), false, "backColor is invalid!");
if (!tmp.isUndefined()) {
showInfo.backColor = tmp.toUint32();
}
}
if (obj->getProperty("backgroundColor", &tmp)) {
SE_PRECONDITION2(tmp.isNumber(), false, "backgroundColor is invalid!");
if (!tmp.isUndefined()) {
showInfo.backgroundColor = tmp.toUint32();
}
}
if (obj->getProperty("textAlignment", &tmp)) {
SE_PRECONDITION2(tmp.isNumber(), false, "textAlignment is invalid!");
if (!tmp.isUndefined()) {
showInfo.textAlignment = tmp.toUint32();
}
}
EditBox::show(showInfo);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(JSB_showInputBox);
static bool JSB_hideInputBox(se::State &s) { // NOLINT
EditBox::hide();
return true;
}
SE_BIND_FUNC(JSB_hideInputBox)
#endif
static bool jsb_createExternalArrayBuffer(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (argc == 1) {
uint32_t byteLength{0};
ok &= sevalue_to_native(args[0], &byteLength, s.thisObject());
SE_PRECONDITION2(ok, false, "Error processing arguments");
if (byteLength > 0) {
// NOTE: Currently V8 use shared_ptr which has different abi on win64-debug and win64-release
#if CC_PLATFORM == CC_PLATFORM_WINDOWS && SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8
se::HandleObject arrayBuffer{se::Object::createArrayBufferObject(nullptr, byteLength)};
#else
void *buffer = malloc(byteLength);
memset(buffer, 0x00, byteLength);
se::HandleObject arrayBuffer{se::Object::createExternalArrayBufferObject(buffer, byteLength, [](void *contents, size_t /*byteLength*/, void * /*userData*/) {
if (contents != nullptr) {
free(contents);
}
})};
#endif // CC_PLATFORM == CC_PLATFORM_WINDOWS
s.rval().setObject(arrayBuffer);
} else {
s.rval().setNull();
}
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(jsb_createExternalArrayBuffer)
static bool JSB_zipUtils_inflateMemory(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (argc > 0) {
unsigned char *arg0 = nullptr;
size_t arg1 = 0;
if (args[0].isString()) {
const ccstd::string &str = args[0].toString();
arg0 = const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(str.c_str()));
arg1 = str.size();
} else if (args[0].isObject()) {
se::Object *obj = args[0].toObject();
if (obj->isArrayBuffer()) {
ok &= obj->getArrayBufferData(&arg0, &arg1);
SE_PRECONDITION2(ok, false, "getArrayBufferData failed!");
} else if (obj->isTypedArray()) {
ok &= obj->getTypedArrayData(&arg0, &arg1);
SE_PRECONDITION2(ok, false, "getTypedArrayData failed!");
} else {
ok = false;
}
} else {
ok = false;
}
SE_PRECONDITION2(ok, false, "args[0] is not in type of string | ArrayBuffer | TypedArray");
unsigned char *arg2 = nullptr;
uint32_t len = 0;
if (argc == 1) {
len = ZipUtils::inflateMemory(arg0, static_cast<uint32_t>(arg1), &arg2);
} else if (argc == 2) {
SE_PRECONDITION2(args[1].isNumber(), false, "outLengthHint is invalid!");
uint32_t outLengthHint = 0;
if (!args[1].isUndefined()) {
outLengthHint = args[1].toUint32();
len = ZipUtils::inflateMemoryWithHint(arg0, static_cast<uint32_t>(arg1), &arg2, outLengthHint);
} else {
ok = false;
}
} else {
ok = false;
}
SE_PRECONDITION2(ok, false, "args number is not as expected!");
se::HandleObject seObj(se::Object::createArrayBufferObject(arg2, len));
if (!seObj.isEmpty() && len > 0) {
s.rval().setObject(seObj);
} else {
s.rval().setNull();
}
free(arg2);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(JSB_zipUtils_inflateMemory)
static bool JSB_zipUtils_inflateGZipFile(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
if (argc == 1) {
SE_PRECONDITION2(args[0].isString(), false, "path is invalid!");
ccstd::string arg0 = args[0].toString();
unsigned char *arg1 = nullptr;
int32_t len = ZipUtils::inflateGZipFile(arg0.c_str(), &arg1);
se::HandleObject seObj(se::Object::createArrayBufferObject(arg1, len));
if (!seObj.isEmpty() && len > 0) {
s.rval().setObject(seObj);
} else {
s.rval().setNull();
}
free(arg1);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(JSB_zipUtils_inflateGZipFile)
static bool JSB_zipUtils_isGZipFile(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
if (argc == 1) {
SE_PRECONDITION2(args[0].isString(), false, "path is invalid!");
ccstd::string arg0 = args[0].toString();
bool flag = ZipUtils::isGZipFile(arg0.c_str());
s.rval().setBoolean(flag);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(JSB_zipUtils_isGZipFile)
static bool JSB_zipUtils_isGZipBuffer(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (argc == 1) {
unsigned char *arg0 = nullptr;
size_t arg1 = 0;
if (args[0].isString()) {
const ccstd::string &str = args[0].toString();
arg0 = const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(str.c_str()));
arg1 = str.size();
} else if (args[0].isObject()) {
se::Object *obj = args[0].toObject();
if (obj->isArrayBuffer()) {
ok &= obj->getArrayBufferData(&arg0, &arg1);
SE_PRECONDITION2(ok, false, "getArrayBufferData failed!");
} else if (obj->isTypedArray()) {
ok &= obj->getTypedArrayData(&arg0, &arg1);
SE_PRECONDITION2(ok, false, "getTypedArrayData failed!");
} else {
ok = false;
}
} else {
ok = false;
}
SE_PRECONDITION2(ok, false, "args[0] is not in type of string | ArrayBuffer | TypedArray");
bool flag = ZipUtils::isGZipBuffer(arg0, static_cast<uint32_t>(arg1));
s.rval().setBoolean(flag);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(JSB_zipUtils_isGZipBuffer)
static bool JSB_zipUtils_inflateCCZFile(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
if (argc == 1) {
SE_PRECONDITION2(args[0].isString(), false, "path is invalid!");
ccstd::string arg0 = args[0].toString();
unsigned char *arg1 = nullptr;
int32_t len = ZipUtils::inflateCCZFile(arg0.c_str(), &arg1);
se::HandleObject seObj(se::Object::createArrayBufferObject(arg1, len));
if (!seObj.isEmpty() && len > 0) {
s.rval().setObject(seObj);
} else {
s.rval().setNull();
}
free(arg1);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(JSB_zipUtils_inflateCCZFile)
static bool JSB_zipUtils_inflateCCZBuffer(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (argc == 1) {
unsigned char *arg0 = nullptr;
size_t arg1 = 0;
if (args[0].isString()) {
const ccstd::string &str = args[0].toString();
arg0 = const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(str.c_str()));
arg1 = str.size();
} else if (args[0].isObject()) {
se::Object *obj = args[0].toObject();
if (obj->isArrayBuffer()) {
ok &= obj->getArrayBufferData(&arg0, &arg1);
SE_PRECONDITION2(ok, false, "getArrayBufferData failed!");
} else if (obj->isTypedArray()) {
ok &= obj->getTypedArrayData(&arg0, &arg1);
SE_PRECONDITION2(ok, false, "getTypedArrayData failed!");
} else {
ok = false;
}
} else {
ok = false;
}
SE_PRECONDITION2(ok, false, "args[0] is not in type of string | ArrayBuffer | TypedArray");
unsigned char *arg2 = nullptr;
int32_t len = ZipUtils::inflateCCZBuffer(arg0, static_cast<uint32_t>(arg1), &arg2);
se::HandleObject seObj(se::Object::createArrayBufferObject(arg2, len));
if (!seObj.isEmpty() && len > 0) {
s.rval().setObject(seObj);
} else {
s.rval().setNull();
}
free(arg2);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(JSB_zipUtils_inflateCCZBuffer)
static bool JSB_zipUtils_isCCZFile(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
if (argc == 1) {
ccstd::string arg0;
SE_PRECONDITION2(args[0].isString(), false, "path is invalid!");
arg0 = args[0].toString();
bool flag = ZipUtils::isCCZFile(arg0.c_str());
s.rval().setBoolean(flag);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(JSB_zipUtils_isCCZFile)
static bool JSB_zipUtils_isCCZBuffer(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (argc == 1) {
unsigned char *arg0 = nullptr;
size_t arg1 = 0;
if (args[0].isString()) {
const ccstd::string &str = args[0].toString();
arg0 = const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(str.c_str()));
arg1 = str.size();
} else if (args[0].isObject()) {
se::Object *obj = args[0].toObject();
if (obj->isArrayBuffer()) {
ok &= obj->getArrayBufferData(&arg0, &arg1);
SE_PRECONDITION2(ok, false, "getArrayBufferData failed!");
} else if (obj->isTypedArray()) {
ok &= obj->getTypedArrayData(&arg0, &arg1);
SE_PRECONDITION2(ok, false, "getTypedArrayData failed!");
} else {
ok = false;
}
} else {
ok = false;
}
SE_PRECONDITION2(ok, false, "args[0] is not in type of string | ArrayBuffer | TypedArray");
bool flag = ZipUtils::isCCZBuffer(arg0, static_cast<uint32_t>(arg1));
s.rval().setBoolean(flag);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(JSB_zipUtils_isCCZBuffer)
static bool JSB_zipUtils_setPvrEncryptionKeyPart(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
if (argc == 2) {
SE_PRECONDITION2(args[0].isNumber() && args[1].isNumber(), false, "args is not as expected");
int32_t arg0 = args[0].toInt32();
uint32_t arg1 = args[1].toUint32();
ZipUtils::setPvrEncryptionKeyPart(arg0, arg1);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 2);
return false;
}
SE_BIND_FUNC(JSB_zipUtils_setPvrEncryptionKeyPart)
static bool JSB_zipUtils_setPvrEncryptionKey(se::State &s) { // NOLINT
const auto &args = s.args();
size_t argc = args.size();
if (argc == 4) {
SE_PRECONDITION2(args[0].isNumber() && args[1].isNumber(), false, "args is not as expected");
uint32_t arg0 = args[0].toUint32();
uint32_t arg1 = args[1].toUint32();
uint32_t arg2 = args[2].toUint32();
uint32_t arg3 = args[3].toUint32();
ZipUtils::setPvrEncryptionKey(arg0, arg1, arg2, arg3);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 4);
return false;
}
SE_BIND_FUNC(JSB_zipUtils_setPvrEncryptionKey)
// TextEncoder
static se::Class *__jsb_TextEncoder_class = nullptr; // NOLINT
static bool js_TextEncoder_finalize(se::State &) // NOLINT
{
return true;
}
SE_BIND_FINALIZE_FUNC(js_TextEncoder_finalize)
static bool js_TextEncoder_constructor(se::State &s) // NOLINT(readability-identifier-naming)
{
const auto &args = s.args();
size_t argc = args.size();
if (argc > 0) {
if (args[0].isString() && args[0].toString() != "utf-8") {
CC_LOG_WARNING("TextEncoder only supports utf-8");
}
}
s.thisObject()->setProperty("encoding", se::Value{"utf-8"});
s.thisObject()->setPrivateObject(nullptr);
return true;
}
SE_BIND_CTOR(js_TextEncoder_constructor, __jsb_TextEncoder_class, js_TextEncoder_finalize)
static bool js_TextEncoder_encode(se::State &s) // NOLINT(readability-identifier-naming)
{
const auto &args = s.args();
size_t argc = args.size();
if (argc == 1) {
const auto &arg0 = args[0];
SE_PRECONDITION2(arg0.isString(), false, "js_TextEncoder_encode, arg0 is not a string");
const auto &str = arg0.toString();
se::HandleObject encodedUint8Array{
se::Object::createTypedArray(se::Object::TypedArrayType::UINT8, str.data(), str.length())};
s.rval().setObject(encodedUint8Array);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(js_TextEncoder_encode)
// TextDecoder
static se::Class *__jsb_TextDecoder_class = nullptr; // NOLINT
static bool js_TextDecoder_finalize(se::State &) // NOLINT
{
return true;
}
SE_BIND_FINALIZE_FUNC(js_TextDecoder_finalize)
static bool js_TextDecoder_constructor(se::State &s) // NOLINT(readability-identifier-naming)
{
const auto &args = s.args();
size_t argc = args.size();
if (argc > 0) {
if (args[0].isString() && args[0].toString() != "utf-8") {
CC_LOG_WARNING("TextDecoder only supports utf-8");
}
}
s.thisObject()->setProperty("encoding", se::Value{"utf-8"});
s.thisObject()->setProperty("fatal", se::Value{false});
s.thisObject()->setProperty("ignoreBOM", se::Value{false});
s.thisObject()->setPrivateObject(nullptr); // FIXME: Don't need this line if https://github.com/cocos/3d-tasks/issues/11365 is done.
return true;
}
SE_BIND_CTOR(js_TextDecoder_constructor, __jsb_TextDecoder_class, js_TextDecoder_finalize)
static bool js_TextDecoder_decode(se::State &s) // NOLINT(readability-identifier-naming)
{
const auto &args = s.args();
size_t argc = args.size();
if (argc == 1) {
const auto &arg0 = args[0];
SE_PRECONDITION2(arg0.isObject() && arg0.toObject()->isTypedArray(), false, "js_TextDecoder_decode, arg0 is not a Uint8Array");
auto *uint8ArrayObj = arg0.toObject();
uint8_t *uint8ArrayData = nullptr;
size_t length = 0;
bool ok = uint8ArrayObj->getTypedArrayData(&uint8ArrayData, &length);
SE_PRECONDITION2(ok, false, "js_TextDecoder_decode, get typedarray data failed!");
ccstd::string str{reinterpret_cast<const char *>(uint8ArrayData), length};
s.rval().setString(str);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(js_TextDecoder_decode)
static bool jsb_register_TextEncoder(se::Object *globalObj) { // NOLINT
auto *cls = se::Class::create("TextEncoder", globalObj, nullptr, _SE(js_TextEncoder_constructor));
cls->defineFunction("encode", _SE(js_TextEncoder_encode));
cls->defineFinalizeFunction(_SE(js_TextEncoder_finalize));
cls->install();
__jsb_TextEncoder_class = cls;
se::ScriptEngine::getInstance()->clearException();
return true;
}
static bool jsb_register_TextDecoder(se::Object *globalObj) { // NOLINT
auto *cls = se::Class::create("TextDecoder", globalObj, nullptr, _SE(js_TextDecoder_constructor));
cls->defineFunction("decode", _SE(js_TextDecoder_decode));
cls->defineFinalizeFunction(_SE(js_TextDecoder_finalize));
cls->install();
__jsb_TextDecoder_class = cls;
se::ScriptEngine::getInstance()->clearException();
return true;
}
static bool JSB_process_get_argv(se::State &s) // NOLINT(readability-identifier-naming)
{
const auto &args = CC_CURRENT_APPLICATION()->getArguments();
nativevalue_to_se(args, s.rval());
return true;
}
SE_BIND_PROP_GET(JSB_process_get_argv)
#if CC_PLATFORM == CC_PLATFORM_OPENHARMONY && SCRIPT_ENGINE_TYPE != SCRIPT_ENGINE_NAPI
static bool sevalue_to_napivalue(const se::Value &seVal, Napi::Value *napiVal, Napi::Env env);
static bool seobject_to_napivalue(se::Object *seObj, Napi::Value *napiVal, Napi::Env env) {
auto napiObj = Napi::Object::New(env);
ccstd::vector<ccstd::string> allKeys;
bool ok = seObj->getAllKeys(&allKeys);
if (ok && !allKeys.empty()) {
for (const auto &key : allKeys) {
Napi::Value napiProp;
se::Value prop;
ok = seObj->getProperty(key, &prop);
if (ok) {
ok = sevalue_to_napivalue(prop, &napiProp, env);
if (ok) {
napiObj.Set(key.c_str(), napiProp);
}
}
}
}
*napiVal = napiObj;
return true;
}
static bool sevalue_to_napivalue(const se::Value &seVal, Napi::Value *napiVal, Napi::Env env) {
// Only supports number or {tag: number, url: string} now
if (seVal.isNumber()) {
*napiVal = Napi::Number::New(env, seVal.toDouble());
} else if (seVal.isString()) {
*napiVal = Napi::String::New(env, seVal.toString().c_str());
} else if (seVal.isBoolean()) {
*napiVal = Napi::Boolean::New(env, seVal.toBoolean());
} else if (seVal.isObject()) {
seobject_to_napivalue(seVal.toObject(), napiVal, env);
} else {
CC_LOG_WARNING("sevalue_to_napivalue, Unsupported type: %d", static_cast<int32_t>(seVal.getType()));
return false;
}
return true;
}
static bool JSB_openharmony_postMessage(se::State &s) { // NOLINT(readability-identifier-naming)
const auto &args = s.args();
size_t argc = args.size();
if (argc == 2) {
bool ok = false;
ccstd::string msgType;
ok = sevalue_to_native(args[0], &msgType, s.thisObject());
SE_PRECONDITION2(ok, false, "Error processing arguments");
const auto &arg1 = args[1];
auto env = NapiHelper::getWorkerEnv();
Napi::Value napiArg1 = env.Undefined();
if (arg1.isNumber()) {
napiArg1 = Napi::Number::New(env, arg1.toDouble());
} else if (arg1.isObject()) {
seobject_to_napivalue(arg1.toObject(), &napiArg1, env);
} else {
SE_REPORT_ERROR("postMessage, Unsupported type");
return false;
}
NapiHelper::postMessageToUIThread(msgType.c_str(), napiArg1);
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 2);
return false;
}
SE_BIND_FUNC(JSB_openharmony_postMessage)
static bool JSB_empty_promise_then(se::State &s) {
return true;
}
SE_BIND_FUNC(JSB_empty_promise_then)
static bool JSB_openharmony_postSyncMessage(se::State &s) { // NOLINT(readability-identifier-naming)
const auto &args = s.args();
size_t argc = args.size();
if (argc == 2) {
bool ok = false;
ccstd::string msgType;
ok = sevalue_to_native(args[0], &msgType, s.thisObject());
SE_PRECONDITION2(ok, false, "Error processing arguments");
const auto &arg1 = args[1];
auto env = NapiHelper::getWorkerEnv();
Napi::Value napiArg1 = env.Undefined();
if (arg1.isNumber()) {
napiArg1 = Napi::Number::New(env, arg1.toDouble());
} else if (arg1.isObject()) {
seobject_to_napivalue(arg1.toObject(), &napiArg1, env);
} else {
SE_REPORT_ERROR("postMessage, Unsupported type");
return false;
}
Napi::Value napiPromise = NapiHelper::postSyncMessageToUIThread(msgType.c_str(), napiArg1);
// TODO(cjh): Implement Promise for se
se::HandleObject retObj(se::Object::createPlainObject());
retObj->defineFunction("then", _SE(JSB_empty_promise_then));
s.rval().setObject(retObj);
//
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 2);
return false;
}
SE_BIND_FUNC(JSB_openharmony_postSyncMessage)
#endif
bool jsb_register_global_variables(se::Object *global) { // NOLINT
gThreadPool = LegacyThreadPool::newFixedThreadPool(3);
#if CC_EDITOR
global->defineFunction("__require", _SE(require));
#else
global->defineFunction("require", _SE(require));
#endif
global->defineFunction("requireModule", _SE(moduleRequire));
getOrCreatePlainObject_r("jsb", global, &__jsbObj);
__jsbObj->defineFunction("garbageCollect", _SE(jsc_garbageCollect));
__jsbObj->defineFunction("dumpNativePtrToSeObjectMap", _SE(jsc_dumpNativePtrToSeObjectMap));
__jsbObj->defineFunction("loadImage", _SE(js_loadImage));
__jsbObj->defineFunction("saveImageData", _SE(js_saveImageData));
__jsbObj->defineFunction("openURL", _SE(JSB_openURL));
__jsbObj->defineFunction("copyTextToClipboard", _SE(JSB_copyTextToClipboard));
__jsbObj->defineFunction("setPreferredFramesPerSecond", _SE(JSB_setPreferredFramesPerSecond));
__jsbObj->defineFunction("destroyImage", _SE(js_destroyImage));
#if CC_USE_EDITBOX
__jsbObj->defineFunction("showInputBox", _SE(JSB_showInputBox));
__jsbObj->defineFunction("hideInputBox", _SE(JSB_hideInputBox));
#endif
__jsbObj->defineFunction("setCursorEnabled", _SE(JSB_setCursorEnabled));
__jsbObj->defineFunction("saveByteCode", _SE(JSB_saveByteCode));
__jsbObj->defineFunction("createExternalArrayBuffer", _SE(jsb_createExternalArrayBuffer));
// Create process object
se::HandleObject processObj{se::Object::createPlainObject()};
processObj->defineProperty("argv", _SE(JSB_process_get_argv), nullptr);
__jsbObj->setProperty("process", se::Value(processObj));
se::HandleObject zipUtils(se::Object::createPlainObject());
zipUtils->defineFunction("inflateMemory", _SE(JSB_zipUtils_inflateMemory));
zipUtils->defineFunction("inflateGZipFile", _SE(JSB_zipUtils_inflateGZipFile));
zipUtils->defineFunction("isGZipFile", _SE(JSB_zipUtils_isGZipFile));
zipUtils->defineFunction("isGZipBuffer", _SE(JSB_zipUtils_isGZipBuffer));
zipUtils->defineFunction("inflateCCZFile", _SE(JSB_zipUtils_inflateCCZFile));
zipUtils->defineFunction("inflateCCZBuffer", _SE(JSB_zipUtils_inflateCCZBuffer));
zipUtils->defineFunction("isCCZFile", _SE(JSB_zipUtils_isCCZFile));
zipUtils->defineFunction("isCCZBuffer", _SE(JSB_zipUtils_isCCZBuffer));
zipUtils->defineFunction("setPvrEncryptionKeyPart", _SE(JSB_zipUtils_setPvrEncryptionKeyPart));
zipUtils->defineFunction("setPvrEncryptionKey", _SE(JSB_zipUtils_setPvrEncryptionKey));
__jsbObj->setProperty("zipUtils", se::Value(zipUtils));
global->defineFunction("__getPlatform", _SE(JSBCore_platform));
global->defineFunction("__getOS", _SE(JSBCore_os));
global->defineFunction("__getOSVersion", _SE(JSB_getOSVersion));
global->defineFunction("__supportHPE", _SE(JSB_supportHPE));
global->defineFunction("__getCurrentLanguage", _SE(JSBCore_getCurrentLanguage));
global->defineFunction("__getCurrentLanguageCode", _SE(JSBCore_getCurrentLanguageCode));
global->defineFunction("__restartVM", _SE(JSB_core_restartVM));
global->defineFunction("__close", _SE(JSB_closeWindow));
global->defineFunction("__isObjectValid", _SE(JSB_isObjectValid));
global->defineFunction("__exit", _SE(JSB_exit));
se::HandleObject performanceObj(se::Object::createPlainObject());
performanceObj->defineFunction("now", _SE(js_performance_now));
global->setProperty("performance", se::Value(performanceObj));
#if CC_PLATFORM == CC_PLATFORM_OPENHARMONY
#if SCRIPT_ENGINE_TYPE != SCRIPT_ENGINE_NAPI
se::HandleObject ohObj(se::Object::createPlainObject());
global->setProperty("oh", se::Value(ohObj));
ohObj->defineFunction("postMessage", _SE(JSB_openharmony_postMessage));
ohObj->defineFunction("postSyncMessage", _SE(JSB_openharmony_postSyncMessage));
#endif
#endif
jsb_register_TextEncoder(global);
jsb_register_TextDecoder(global);
jsb_register_ADPF(__jsbObj);
se::ScriptEngine::getInstance()->clearException();
se::ScriptEngine::getInstance()->addBeforeCleanupHook([]() {
delete gThreadPool;
gThreadPool = nullptr;
DeferredReleasePool::clear();
});
se::ScriptEngine::getInstance()->addAfterCleanupHook([]() {
DeferredReleasePool::clear();
gModuleCache.clear();
SAFE_DEC_REF(__jsbObj);
SAFE_DEC_REF(__glObj);
});
return true;
}