1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "frameworks/base/geometry/matrix4.h"
17
18 #include <algorithm>
19 #include <ani.h>
20 #include <array>
21 #include <chrono>
22 #include <future>
23 #include <iostream>
24 #include <map>
25 #include <string>
26 #include <thread>
27
28 namespace OHOS::Ace::MatrixAni {
29 constexpr int32_t MATRIX_LENGTH = 16;
30 class Matrix4_Obj {
31 public:
Matrix4_Obj(Matrix4 matrix)32 explicit Matrix4_Obj(Matrix4 matrix) : matrix4x4(matrix) {}
33 OHOS::Ace::Matrix4 matrix4x4;
34 };
35
GetMatrixObj(ani_env * env,ani_object obj)36 static Matrix4_Obj* GetMatrixObj(ani_env* env, ani_object obj)
37 {
38 ani_long matrix4x4;
39 if (ANI_OK != env->Object_GetFieldByName_Long(obj, "matrix4Object", &matrix4x4)) {
40 return nullptr;
41 }
42 return reinterpret_cast<Matrix4_Obj*>(matrix4x4);
43 }
44
Matrix4_Identity(ani_env * env,ani_object object)45 static ani_object Matrix4_Identity([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object)
46 {
47 static const char* className = "L@ohos/matrix4/matrix4/Matrix4TransitInner;";
48 ani_class cls;
49 if (ANI_OK != env->FindClass(className, &cls)) {
50 ani_object nullobj = nullptr;
51 return nullobj;
52 }
53 ani_method ctor;
54 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
55 ani_object nullobj = nullptr;
56 return nullobj;
57 }
58
59 auto matrix4Object = new Matrix4_Obj(OHOS::Ace::Matrix4::CreateIdentity());
60 ani_object matrix4_object = {};
61 if (ANI_OK != env->Object_New(cls, ctor, &matrix4_object, reinterpret_cast<ani_long>(matrix4Object))) {
62 ani_object nullobj = nullptr;
63 return nullobj;
64 }
65 return matrix4_object;
66 }
67
ConvertToMatrix(ani_env * env,ani_object option)68 Matrix4 ConvertToMatrix([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object option)
69 {
70 Matrix4 result = Matrix4::CreateIdentity();
71 ani_class arrayClass;
72 if (ANI_OK != env->FindClass("Lescompat/Array;", &arrayClass)) {
73 return result;
74 }
75 ani_boolean isArray;
76 if (ANI_OK != env->Object_InstanceOf(static_cast<ani_object>(option), arrayClass, &isArray)) {
77 return result;
78 }
79 ani_array inputArray = static_cast<ani_array>(option);
80 ani_size length = 0;
81 if (ANI_OK != env->Array_GetLength(inputArray, &length)) {
82 return result;
83 }
84 int32_t inputSize = static_cast<int32_t>(length);
85 if (inputSize != MATRIX_LENGTH) {
86 return result;
87 }
88 // in column order
89 ani_array_double doubleArray = static_cast<ani_array_double>(inputArray);
90 for (int32_t i = 0; i < Matrix4::DIMENSION; i++) {
91 for (int32_t j = 0; j < Matrix4::DIMENSION; j++) {
92 ani_double value;
93 auto index = static_cast<ani_size>(i * Matrix4::DIMENSION + j);
94 if (ANI_OK != env->Array_GetRegion_Double(doubleArray, index, 1, &value)) {
95 return result;
96 }
97 auto ret = static_cast<double>(value);
98 result.Set(j, i, ret);
99 }
100 }
101 return result;
102 }
103
Matrix4_Init(ani_env * env,ani_object object,ani_object option)104 static ani_object Matrix4_Init([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
105 [[maybe_unused]] ani_object option)
106 {
107 static const char* className = "L@ohos/matrix4/matrix4/Matrix4TransitInner;";
108 ani_class cls;
109 if (ANI_OK != env->FindClass(className, &cls)) {
110 ani_object nullobj = nullptr;
111 return nullobj;
112 }
113 ani_method ctor;
114 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
115 ani_object nullobj = nullptr;
116 return nullobj;
117 }
118
119 auto matrix = ConvertToMatrix(env, option);
120 auto matrix4Object = new Matrix4_Obj(matrix);
121
122 ani_object matrix4_object;
123 if (ANI_OK != env->Object_New(cls, ctor, &matrix4_object, reinterpret_cast<ani_long>(matrix4Object))) {
124 ani_object nullobj = nullptr;
125 return nullobj;
126 }
127 return matrix4_object;
128 }
129
Matrix4_Copy(ani_env * env,ani_object object)130 static ani_object Matrix4_Copy([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object)
131 {
132 static const char* className = "L@ohos/matrix4/matrix4/Matrix4TransitInner;";
133 ani_class cls;
134 if (ANI_OK != env->FindClass(className, &cls)) {
135 ani_object nullobj = nullptr;
136 return nullobj;
137 }
138 ani_method ctor;
139 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
140 ani_object nullobj = nullptr;
141 return nullobj;
142 }
143 Matrix4_Obj* matrixObj = GetMatrixObj(env, object);
144 if (matrixObj == nullptr) {
145 return nullptr;
146 }
147 auto matrix4Object = new Matrix4_Obj(matrixObj->matrix4x4);
148 ani_object matrix4_object;
149 if (ANI_OK != env->Object_New(cls, ctor, &matrix4_object, reinterpret_cast<ani_long>(matrix4Object))) {
150 ani_object nullobj = nullptr;
151 return nullobj;
152 }
153 return matrix4_object;
154 }
155
ParseOption(ani_env * env,ani_object options,double & input,const char * property,const char * className)156 bool ParseOption(ani_env* env, ani_object options, double& input, const char* property, const char* className)
157 {
158 ani_class cls;
159 if (ANI_OK != env->FindClass(className, &cls)) {
160 return false;
161 }
162 ani_ref property_ref;
163 if (ANI_OK != env->Object_GetPropertyByName_Ref(options, property, &property_ref)) {
164 return false;
165 }
166 ani_boolean isUndefined;
167 if (ANI_OK != env->Reference_IsUndefined(property_ref, &isUndefined)) {
168 return false;
169 }
170 if (isUndefined) {
171 return false;
172 }
173 ani_double propertyValue;
174 if (ANI_OK != env->Object_CallMethodByName_Double(static_cast<ani_object>(property_ref),
175 "doubleValue", nullptr, &propertyValue)) {
176 return false;
177 }
178 input = static_cast<int32_t>(propertyValue);
179 return true;
180 }
181
Matrix4_Scale(ani_env * env,ani_object object,ani_object options)182 static ani_object Matrix4_Scale([[maybe_unused]] ani_env* env, ani_object object, ani_object options)
183 {
184 double xValue = 1.0;
185 ParseOption(env, options, xValue, "x", "L@ohos/matrix4/matrix4/ScaleOption;");
186 double yValue = 1.0;
187 ParseOption(env, options, yValue, "y", "L@ohos/matrix4/matrix4/ScaleOption;");
188 double zValue = 1.0;
189 ParseOption(env, options, zValue, "z", "L@ohos/matrix4/matrix4/ScaleOption;");
190 double centerXValue = 0.0;
191 ParseOption(env, options, centerXValue, "centerX", "L@ohos/matrix4/matrix4/ScaleOption;");
192 double centerYValue = 0.0;
193 ParseOption(env, options, centerYValue, "centerY", "L@ohos/matrix4/matrix4/ScaleOption;");
194
195 auto scaleMatrix = Matrix4::CreateScale(xValue, yValue, zValue);
196 if (!NearZero(centerXValue) || !NearZero(centerYValue)) {
197 auto translate1 = Matrix4::CreateTranslate(centerXValue, centerYValue, 0.0);
198 auto translate2 = Matrix4::CreateTranslate(-centerXValue, -centerYValue, 0.0);
199 scaleMatrix = scaleMatrix * translate2;
200 scaleMatrix = translate1 * scaleMatrix;
201 }
202
203 Matrix4_Obj* matrixObj = GetMatrixObj(env, object);
204 if (matrixObj == nullptr) {
205 return nullptr;
206 }
207 matrixObj->matrix4x4 = scaleMatrix * matrixObj->matrix4x4;
208 return object;
209 }
210
Matrix4_Rotate(ani_env * env,ani_object object,ani_object options)211 static ani_object Matrix4_Rotate([[maybe_unused]] ani_env* env, ani_object object, ani_object options)
212 {
213 double dx = 0.0;
214 ParseOption(env, options, dx, "x", "L@ohos/matrix4/matrix4/RotateOption;");
215 double dy = 0.0;
216 ParseOption(env, options, dy, "y", "L@ohos/matrix4/matrix4/RotateOption;");
217 double dz = 0.0;
218 ParseOption(env, options, dz, "z", "L@ohos/matrix4/matrix4/RotateOption;");
219 double angle = 0.0;
220 ParseOption(env, options, angle, "angle", "L@ohos/matrix4/matrix4/RotateOption;");
221 double centerX = 0.0;
222 ParseOption(env, options, centerX, "centerX", "L@ohos/matrix4/matrix4/RotateOption;");
223 double centerY = 0.0;
224 ParseOption(env, options, centerY, "centerY", "L@ohos/matrix4/matrix4/RotateOption;");
225
226 auto rotateMatrix = Matrix4::CreateRotate(angle, dx, dy, dz);
227 if (!NearZero(centerX) || !NearZero(centerY)) {
228 auto translate1 = Matrix4::CreateTranslate(centerX, centerY, 0.0);
229 auto translate2 = Matrix4::CreateTranslate(-centerX, -centerY, 0.0);
230 rotateMatrix = rotateMatrix * translate2;
231 rotateMatrix = translate1 * rotateMatrix;
232 }
233
234 Matrix4_Obj* matrixObj = GetMatrixObj(env, object);
235 if (matrixObj == nullptr) {
236 return nullptr;
237 }
238 matrixObj->matrix4x4 = rotateMatrix * matrixObj->matrix4x4;
239 return object;
240 }
241
Matrix4_Translate(ani_env * env,ani_object object,ani_object options)242 static ani_object Matrix4_Translate([[maybe_unused]] ani_env* env, ani_object object, ani_object options)
243 {
244 double dx = 0.0;
245 ParseOption(env, options, dx, "x", "L@ohos/matrix4/matrix4/TranslateOption;");
246 double dy = 0.0;
247 ParseOption(env, options, dy, "y", "L@ohos/matrix4/matrix4/TranslateOption;");
248 double dz = 0.0;
249 ParseOption(env, options, dz, "z", "L@ohos/matrix4/matrix4/TranslateOption;");
250
251 Matrix4_Obj* matrixObj = GetMatrixObj(env, object);
252 if (matrixObj == nullptr) {
253 return nullptr;
254 }
255 matrixObj->matrix4x4 =
256 Matrix4::CreateTranslate(static_cast<float>(dx), static_cast<float>(dy), static_cast<float>(dz)) *
257 matrixObj->matrix4x4;
258 return object;
259 }
260
Matrix4_Invert(ani_env * env,ani_object object)261 static ani_object Matrix4_Invert([[maybe_unused]] ani_env* env, ani_object object)
262 {
263 Matrix4_Obj* matrixObj = GetMatrixObj(env, object);
264 if (matrixObj == nullptr) {
265 return nullptr;
266 }
267 matrixObj->matrix4x4 = Matrix4::Invert(matrixObj->matrix4x4);
268 return object;
269 }
270
Matrix4_Combine(ani_env * env,ani_object object,ani_object option)271 static ani_object Matrix4_Combine([[maybe_unused]] ani_env* env, ani_object object, ani_object option)
272 {
273 Matrix4_Obj* matrixOption = GetMatrixObj(env, option);
274 if (matrixOption == nullptr) {
275 return nullptr;
276 }
277
278 Matrix4_Obj* matrixObj = GetMatrixObj(env, object);
279 if (matrixObj == nullptr) {
280 return nullptr;
281 }
282 matrixObj->matrix4x4 = matrixOption->matrix4x4 * matrixObj->matrix4x4;
283 return object;
284 }
285
BindMatrix(ani_env * env)286 ani_status BindMatrix(ani_env* env)
287 {
288 static const char* className = "L@ohos/matrix4/matrix4;";
289 ani_class cls;
290 if (ANI_OK != env->FindClass(className, &cls)) {
291 return ANI_ERROR;
292 }
293
294 std::array methods = {
295 ani_native_function { "identity", nullptr, reinterpret_cast<void*>(Matrix4_Identity) },
296 ani_native_function { "init", nullptr, reinterpret_cast<void*>(Matrix4_Init) },
297 };
298
299 if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) {
300 return ANI_ERROR;
301 };
302 return ANI_OK;
303 }
304
BindMatrixTransit(ani_env * env)305 ani_status BindMatrixTransit(ani_env* env)
306 {
307 static const char* className = "L@ohos/matrix4/matrix4/Matrix4TransitInner;";
308 ani_class cls;
309 if (ANI_OK != env->FindClass(className, &cls)) {
310 return ANI_ERROR;
311 }
312
313 std::array methods = {
314 ani_native_function { "copy", nullptr, reinterpret_cast<void*>(Matrix4_Copy) },
315 ani_native_function { "scale", nullptr, reinterpret_cast<void*>(Matrix4_Scale) },
316 ani_native_function { "rotate", nullptr, reinterpret_cast<void*>(Matrix4_Rotate) },
317 ani_native_function { "translate", nullptr, reinterpret_cast<void*>(Matrix4_Translate) },
318 ani_native_function { "invert", nullptr, reinterpret_cast<void*>(Matrix4_Invert) },
319 ani_native_function { "combine", nullptr, reinterpret_cast<void*>(Matrix4_Combine) },
320 };
321 if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) {
322 return ANI_ERROR;
323 };
324 return ANI_OK;
325 }
326 } // namespace OHOS::Ace::MatrixAni
327
ANI_Constructor(ani_vm * vm,uint32_t * result)328 ANI_EXPORT ani_status ANI_Constructor(ani_vm* vm, uint32_t* result)
329 {
330 ani_env* env;
331 if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
332 return ANI_ERROR;
333 }
334
335 ani_status ret = OHOS::Ace::MatrixAni::BindMatrix(env);
336 if (ret != ANI_OK) {
337 return ret;
338 }
339
340 ani_status ret1 = OHOS::Ace::MatrixAni::BindMatrixTransit(env);
341 if (ret1 != ANI_OK) {
342 return ret1;
343 }
344 *result = ANI_VERSION_1;
345 return ANI_OK;
346 }