* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <ani.h>
#include <ani_signature_builder.h>
#include <array>
#include <iostream>
#include "base/memory/referenced.h"
#include "frameworks/bridge/common/utils/engine_helper.h"
#include "frameworks/core/common/container.h"
#include "frameworks/core/pipeline/pipeline_base.h"
#include "core/components_ng/base/inspector.h"
using namespace arkts::ani_signature;
namespace {
std::string ANIUtils_ANIStringToStdString(ani_env* env, ani_string ani_str)
{
ani_size strSize;
env->String_GetUTF8Size(ani_str, &strSize);
std::vector<char> buffer(strSize + 1);
char* utf8Buffer = buffer.data();
ani_size bytes_written = 0;
env->String_GetUTF8(ani_str, utf8Buffer, strSize + 1, &bytes_written);
utf8Buffer[bytes_written] = '\0';
std::string content = std::string(utf8Buffer);
return content;
}
static ani_ref gOffsetClass;
static ani_ref gSizeClass;
static ani_ref gTranslateResultClass;
static ani_ref gScaleResultClass;
static ani_ref gRotateResultClass;
static ani_ref gComponentInfoClass;
static ani_method gOffsetCtor;
static ani_method gSizeCtor;
static ani_method gTranslateResultCtor;
static ani_method gScaleResultCtor;
static ani_method gRotateResultCtor;
static ani_method gComponentInfoCtor;
static std::string gComponentInfoSignature;
static ani_object CreateOffset(ani_env* env, ani_double x, ani_double y)
{
CHECK_NULL_RETURN(env, nullptr);
CHECK_NULL_RETURN(gOffsetClass, nullptr);
CHECK_NULL_RETURN(gOffsetCtor, nullptr);
ani_object obj = {};
if (ANI_OK != env->Object_New(static_cast<ani_class>(gOffsetClass), gOffsetCtor, &obj, x, y)) {
return nullptr;
}
return obj;
}
static ani_object getSize([[maybe_unused]] ani_env* env, OHOS::Ace::NG::Rectangle rectangle)
{
CHECK_NULL_RETURN(gSizeClass, nullptr);
CHECK_NULL_RETURN(gSizeCtor, nullptr);
ani_object obj = {};
ani_double width = rectangle.size.Width();
ani_double height = rectangle.size.Height();
if (ANI_OK != env->Object_New(static_cast<ani_class>(gSizeClass), gSizeCtor, &obj, width, height)) {
return nullptr;
}
return obj;
}
static ani_object getLocalOffset([[maybe_unused]] ani_env* env, OHOS::Ace::NG::Rectangle rectangle)
{
return CreateOffset(env, rectangle.localOffset.GetX(), rectangle.localOffset.GetY());
}
static ani_object getWindowOffset([[maybe_unused]] ani_env* env, OHOS::Ace::NG::Rectangle rectangle)
{
return CreateOffset(env, rectangle.windowOffset.GetX(), rectangle.windowOffset.GetY());
}
static ani_object getScreenOffset([[maybe_unused]] ani_env* env, OHOS::Ace::NG::Rectangle rectangle)
{
ani_double x = rectangle.windowOffset.GetX() + rectangle.screenRect.GetOffset().GetX();
ani_double y = rectangle.windowOffset.GetY() + rectangle.screenRect.GetOffset().GetY();
return CreateOffset(env, x, y);
}
static ani_object getTranslateResult([[maybe_unused]] ani_env* env, OHOS::Ace::NG::Rectangle rectangle)
{
CHECK_NULL_RETURN(gTranslateResultClass, nullptr);
CHECK_NULL_RETURN(gTranslateResultCtor, nullptr);
ani_object obj = {};
ani_double x = rectangle.translate.x;
ani_double y = rectangle.translate.y;
ani_double z = rectangle.translate.z;
if (ANI_OK !=
env->Object_New(static_cast<ani_class>(gTranslateResultClass), gTranslateResultCtor, &obj, x, y, z)) {
return nullptr;
}
return obj;
}
static ani_object getScaleResult([[maybe_unused]] ani_env* env, OHOS::Ace::NG::Rectangle rectangle)
{
CHECK_NULL_RETURN(gScaleResultClass, nullptr);
CHECK_NULL_RETURN(gScaleResultCtor, nullptr);
ani_object obj = {};
ani_double x = rectangle.scale.x;
ani_double y = rectangle.scale.y;
ani_double z = rectangle.scale.z;
ani_double centerX = rectangle.scale.centerX;
ani_double centerY = rectangle.scale.centerY;
if (ANI_OK !=
env->Object_New(static_cast<ani_class>(gScaleResultClass), gScaleResultCtor,
&obj, x, y, z, centerX, centerY)) {
return nullptr;
}
return obj;
}
static ani_object getRotateResult([[maybe_unused]] ani_env* env, OHOS::Ace::NG::Rectangle rectangle)
{
CHECK_NULL_RETURN(gRotateResultClass, nullptr);
CHECK_NULL_RETURN(gRotateResultCtor, nullptr);
ani_object obj = {};
ani_double x = rectangle.rotate.x;
ani_double y = rectangle.rotate.y;
ani_double z = rectangle.rotate.z;
ani_double centerX = rectangle.rotate.centerX;
ani_double centerY = rectangle.rotate.centerY;
ani_double angle = rectangle.rotate.angle;
if (ANI_OK !=
env->Object_New(static_cast<ani_class>(gRotateResultClass), gRotateResultCtor,
&obj, x, y, z, centerX, centerY, angle)) {
return nullptr;
}
return obj;
}
static ani_object getTransform([[maybe_unused]] ani_env* env, OHOS::Ace::NG::Rectangle rectangle)
{
const int32_t size = 16;
std::vector<double> matrixArray(size);
for (int32_t i = 1; i < size; i++) {
matrixArray[i] = rectangle.matrix4[i];
}
ani_valuearray_double doubleArray;
if (ANI_OK != env->ValueArray_New_Double(matrixArray.size(), &doubleArray)) {
return nullptr;
}
const auto *data = reinterpret_cast<const ani_double*>(matrixArray.data());
if (ANI_OK != env->ValueArray_SetRegion_Double(doubleArray, 0, matrixArray.size(), data)) {
return nullptr;
}
ani_array array;
if (ANI_OK != env->Array_New(1, doubleArray, &array)) {
return nullptr;
}
return array;
}
static ani_object getRectangleById([[maybe_unused]] ani_env* env, ani_string id)
{
OHOS::Ace::NG::Rectangle rectangle;
auto key = ANIUtils_ANIStringToStdString(env, id);
OHOS::Ace::NG::Inspector::GetRectangleById(key, rectangle);
ani_object size_obj = getSize(env, rectangle);
CHECK_NULL_RETURN(size_obj, nullptr);
ani_object localOffset_obj = getLocalOffset(env, rectangle);
CHECK_NULL_RETURN(localOffset_obj, nullptr);
ani_object windowOffset_obj = getWindowOffset(env, rectangle);
CHECK_NULL_RETURN(windowOffset_obj, nullptr);
ani_object screenOffset_obj = getScreenOffset(env, rectangle);
CHECK_NULL_RETURN(screenOffset_obj, nullptr);
ani_object translate_obj = getTranslateResult(env, rectangle);
CHECK_NULL_RETURN(translate_obj, nullptr);
ani_object scale_obj = getScaleResult(env, rectangle);
CHECK_NULL_RETURN(scale_obj, nullptr);
ani_object rotate_obj = getRotateResult(env, rectangle);
CHECK_NULL_RETURN(rotate_obj, nullptr);
ani_object transform_obj = getTransform(env, rectangle);
CHECK_NULL_RETURN(transform_obj, nullptr);
ani_object rectangleObj = {};
CHECK_NULL_RETURN(gComponentInfoClass, nullptr);
CHECK_NULL_RETURN(gComponentInfoCtor, nullptr);
if (ANI_OK != env->Object_New(static_cast<ani_class>(gComponentInfoClass), gComponentInfoCtor, &rectangleObj,
size_obj, localOffset_obj, windowOffset_obj, screenOffset_obj, translate_obj, scale_obj, rotate_obj,
transform_obj)) {
return nullptr;
}
return rectangleObj;
}
bool InitCachedClass(
ani_env* env, const char* className, ani_ref* outGlobalRef, ani_method* outCtor, const char* signature)
{
ani_class cls;
if (ANI_OK != env->FindClass(className, &cls)) {
return false;
}
if (ANI_OK != env->GlobalReference_Create(static_cast<ani_ref>(cls), outGlobalRef)) {
return false;
}
if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", signature, outCtor)) {
return false;
}
return true;
}
}
ANI_EXPORT ani_status ANI_Constructor(ani_vm* vm, uint32_t* result)
{
ani_env* env;
if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
return ANI_ERROR;
}
if (!InitCachedClass(env,
"@ohos.arkui.componentUtils.componentUtils.OffsetInner", &gOffsetClass, &gOffsetCtor, "dd:")) {
return ANI_ERROR;
}
if (!InitCachedClass(env, "@ohos.arkui.componentUtils.componentUtils.SizeInner", &gSizeClass, &gSizeCtor, "dd:")) {
return ANI_ERROR;
}
if (!InitCachedClass(env, "@ohos.arkui.componentUtils.componentUtils.TranslateResultInner",
&gTranslateResultClass, &gTranslateResultCtor, "ddd:")) {
return ANI_ERROR;
}
if (!InitCachedClass(env, "@ohos.arkui.componentUtils.componentUtils.ScaleResultInner",
&gScaleResultClass, &gScaleResultCtor, "ddddd:")) {
return ANI_ERROR;
}
if (!InitCachedClass(env, "@ohos.arkui.componentUtils.componentUtils.RotateResultInner",
&gRotateResultClass, &gRotateResultCtor, "dddddd:")) {
return ANI_ERROR;
}
{
ani_class cls;
if (ANI_OK != env->FindClass("@ohos.arkui.componentUtils.componentUtils.ComponentInfoInner", &cls)) {
return ANI_ERROR;
}
if (ANI_OK != env->GlobalReference_Create(static_cast<ani_ref>(cls), &gComponentInfoClass)) {
return ANI_ERROR;
}
SignatureBuilder signatureBuilder {};
signatureBuilder
.AddClass("@ohos.arkui.componentUtils.componentUtils.Size")
.AddClass("@ohos.arkui.componentUtils.componentUtils.Offset")
.AddClass("@ohos.arkui.componentUtils.componentUtils.Offset")
.AddClass("@ohos.arkui.componentUtils.componentUtils.Offset")
.AddClass("@ohos.arkui.componentUtils.componentUtils.TranslateResult")
.AddClass("@ohos.arkui.componentUtils.componentUtils.ScaleResult")
.AddClass("@ohos.arkui.componentUtils.componentUtils.RotateResult")
.AddClass("std.core.Tuple16");
gComponentInfoSignature = signatureBuilder.BuildSignatureDescriptor();
if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", gComponentInfoSignature.c_str(), &gComponentInfoCtor)) {
return ANI_ERROR;
}
}
ani_namespace ns;
if (ANI_OK != env->FindNamespace("@ohos.arkui.componentUtils.componentUtils", &ns)) {
return ANI_ERROR;
}
std::array methods = {
ani_native_function { "getRectangleById", nullptr, reinterpret_cast<void*>(getRectangleById) },
};
if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size())) {
return ANI_ERROR;
}
*result = ANI_VERSION_1;
return ANI_OK;
}