• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }