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 "ani_lattice.h"
17
18 namespace OHOS::Rosen {
19 namespace Drawing {
20 const char* ANI_CLASS_ANI_LATTICE_NAME = "L@ohos/graphics/drawing/drawing/Lattice;";
21
GetLatticeDividers(ani_env * env,ani_object dividersArray,uint32_t count,std::vector<int> & dividers)22 bool GetLatticeDividers(ani_env* env, ani_object dividersArray, uint32_t count, std::vector<int>& dividers)
23 {
24 ani_double aniLength;
25 if (ANI_OK != env->Object_GetPropertyByName_Double(dividersArray, "length", &aniLength)) {
26 ROSEN_LOGE("AniLattice::CreateImageLattice dividers are invalid");
27 return false;
28 }
29 uint32_t dividersSize = aniLength;
30
31 if (dividersSize != count || dividersSize > 5) { // 5 is max value, the api limit max size
32 ROSEN_LOGE("AniLattice::CreateImageLattice dividers are invalid");
33 return false;
34 }
35 if (dividersSize != 0) {
36 dividers.reserve(dividersSize);
37 for (uint32_t i = 0; i < dividersSize; i++) {
38 ani_double divider;
39 ani_ref dividerRef;
40 if (ANI_OK != env->Object_CallMethodByName_Ref(
41 dividersArray, "$_get", "I:Lstd/core/Object;", ÷rRef, (ani_int)i) ||
42 ANI_OK != env->Object_CallMethodByName_Double(
43 static_cast<ani_object>(dividerRef), "unboxed", ":D", ÷r)) {
44 ROSEN_LOGE("AniLattice::CreateImageLattice Incorrect parameter dividers type.");
45 return false;
46 }
47 dividers.push_back(divider);
48 }
49 }
50 return true;
51 }
52
GetLatticeRectTypes(ani_env * env,ani_object rectTypesArray,uint32_t count,std::vector<Lattice::RectType> & latticeRectTypes)53 bool GetLatticeRectTypes(ani_env* env, ani_object rectTypesArray, uint32_t count,
54 std::vector<Lattice::RectType>& latticeRectTypes)
55 {
56 ani_double aniLength;
57 if (ANI_OK != env->Object_GetPropertyByName_Double(rectTypesArray, "length", &aniLength)) {
58 ROSEN_LOGE("AniLattice::CreateImageLattice rectTypes are invalid");
59 return false;
60 }
61 uint32_t rectTypesSize = aniLength;
62
63 if ((rectTypesSize != 0 && rectTypesSize != count) || rectTypesSize > 36) { // 36: max value, limit max size
64 ROSEN_LOGE("AniLattice::CreateImageLattice rectTypes are invalid");
65 return false;
66 }
67 if (rectTypesSize != 0) {
68 latticeRectTypes.reserve(rectTypesSize);
69 for (uint32_t i = 0; i < rectTypesSize; i++) {
70 ani_int rectType;
71 ani_ref rectTypeRef;
72 if (ANI_OK != env->Object_CallMethodByName_Ref(
73 rectTypesArray, "$_get", "I:Lstd/core/Object;", &rectTypeRef, (ani_int)i) ||
74 ANI_OK != env->EnumItem_GetValue_Int((ani_enum_item)rectTypeRef, &rectType)) {
75 ROSEN_LOGE("AniLattice::CreateImageLattice Incorrect parameter dividers type.");
76 return false;
77 }
78 if (rectType < 0 || rectType > 2) { // 2: FIXEDCOLOR
79 ROSEN_LOGE("AniLattice::CreateImageLattice rectType is invalid");
80 return false;
81 }
82 latticeRectTypes.push_back(static_cast<Lattice::RectType>(rectType));
83 }
84 }
85 return true;
86 }
87
GetLatticeColors(ani_env * env,ani_object colorsArray,uint32_t count,std::vector<Color> & latticeColors)88 bool GetLatticeColors(ani_env* env, ani_object colorsArray, uint32_t count, std::vector<Color>& latticeColors)
89 {
90 ani_double aniLength;
91 if (ANI_OK != env->Object_GetPropertyByName_Double(colorsArray, "length", &aniLength)) {
92 ROSEN_LOGE("AniLattice::CreateImageLattice colors are invalid");
93 return false;
94 }
95 uint32_t colorsSize = aniLength;
96
97 if ((colorsSize != 0 && colorsSize != count) || colorsSize > 36) { // 36: max value
98 ROSEN_LOGE("AniLattice::CreateImageLattice colors are invalid");
99 return false;
100 }
101
102 ani_boolean isColorClass;
103 if (colorsSize != 0) {
104 latticeColors.reserve(colorsSize);
105 for (uint32_t i = 0; i < colorsSize; i++) {
106 ani_ref colorRef;
107 ani_double aniColor;
108 Drawing::ColorQuad colorQuad;
109 if (ANI_OK != env->Object_CallMethodByName_Ref(
110 colorsArray, "$_get", "I:Lstd/core/Object;", &colorRef, (ani_int)i)) {
111 ROSEN_LOGE("AniLattice::CreateImageLattice colors is invalid");
112 return false;
113 }
114 if (i == 0) {
115 ani_class colorClass;
116 env->FindClass("L@ohos/graphics/common2D/common2D/Color;", &colorClass);
117 env->Object_InstanceOf(static_cast<ani_object>(colorRef), colorClass, &isColorClass);
118 }
119
120 if ((isColorClass && !GetColorQuadFromColorObj(env, static_cast<ani_object>(colorRef), colorQuad)) ||
121 (!isColorClass && ANI_OK != env->Object_CallMethodByName_Double(
122 static_cast<ani_object>(colorRef), "unboxed", ":D", &aniColor))) {
123 ROSEN_LOGE("AniLattice::CreateImageLattice colors is invalid");
124 return false;
125 }
126 colorQuad = isColorClass ? colorQuad : static_cast<Drawing::ColorQuad>(aniColor);
127 Drawing::Color drawingColor;
128 drawingColor.SetColorQuad(colorQuad);
129 latticeColors.push_back(drawingColor);
130 }
131 }
132 return true;
133 }
134
AniInit(ani_env * env)135 ani_status AniLattice::AniInit(ani_env *env)
136 {
137 ani_class cls = nullptr;
138 ani_status ret = env->FindClass(ANI_CLASS_ANI_LATTICE_NAME, &cls);
139 if (ret != ANI_OK) {
140 ROSEN_LOGE("[ANI] can't find class: %{public}s", ANI_CLASS_ANI_LATTICE_NAME);
141 return ANI_NOT_FOUND;
142 }
143
144 std::array methods = {
145 ani_native_function { "createImageLattice", nullptr,
146 reinterpret_cast<void*>(CreateImageLattice) },
147 };
148
149 ret = env->Class_BindNativeMethods(cls, methods.data(), methods.size());
150 if (ret != ANI_OK) {
151 ROSEN_LOGE("[ANI] bind methods fail: %{public}s", ANI_CLASS_ANI_LATTICE_NAME);
152 return ANI_NOT_FOUND;
153 }
154
155 return ANI_OK;
156 }
157
~AniLattice()158 AniLattice::~AniLattice()
159 {
160 m_lattice = nullptr;
161 }
162
CreateImageLattice(ani_env * env,ani_object obj,ani_object xDivs,ani_object yDivs,ani_double fXCount,ani_double fYCount,ani_object fBounds,ani_object fRectTypes,ani_object fColors)163 ani_object AniLattice::CreateImageLattice(ani_env* env,
164 ani_object obj, ani_object xDivs, ani_object yDivs, ani_double fXCount,
165 ani_double fYCount, ani_object fBounds, ani_object fRectTypes, ani_object fColors)
166 {
167 uint32_t xCount = static_cast<uint32_t>(fXCount);
168 uint32_t yCount = static_cast<uint32_t>(fYCount);
169
170 Lattice lat;
171 if (!GetLatticeDividers(env, xDivs, xCount, lat.fXDivs)) {
172 ROSEN_LOGE("AniLattice::CreateImageLattice xDividers are invalid");
173 AniThrowError(env, "Incorrect parameter0 type.");
174 return CreateAniUndefined(env);
175 }
176 if (!GetLatticeDividers(env, yDivs, yCount, lat.fYDivs)) {
177 ROSEN_LOGE("AniLattice::CreateImageLattice yDividers are invalid");
178 AniThrowError(env, "Incorrect parameter1 type.");
179 return CreateAniUndefined(env);
180 }
181 lat.fXCount = static_cast<int>(xCount);
182 lat.fYCount = static_cast<int>(yCount);
183
184 Drawing::Rect drawingRect;
185 if (GetRectFromAniRectObj(env, fBounds, drawingRect)) {
186 lat.fBounds.push_back(Drawing::RectI(
187 drawingRect.left_, drawingRect.top_, drawingRect.right_, drawingRect.bottom_));
188 }
189
190 ani_boolean isUndefined = ANI_TRUE;
191 ani_boolean isNull = ANI_TRUE;
192 env->Reference_IsUndefined(fRectTypes, &isUndefined);
193 env->Reference_IsNull(fRectTypes, &isNull);
194 uint32_t count = (xCount + 1) * (yCount + 1); // 1: grid size need + 1
195 if (!isUndefined && !isNull) {
196 if (!GetLatticeRectTypes(env, fRectTypes, count, lat.fRectTypes)) {
197 AniThrowError(env, "Incorrect parameter6 type.");
198 return CreateAniUndefined(env);
199 }
200 }
201
202 env->Reference_IsUndefined(fColors, &isUndefined);
203 env->Reference_IsNull(fColors, &isNull);
204 if (!isUndefined && !isNull) {
205 if (!GetLatticeColors(env, fColors, count, lat.fColors)) {
206 AniThrowError(env, "Incorrect parameter7 type.");
207 return CreateAniUndefined(env);
208 }
209 }
210
211 AniLattice* aniLattice = new AniLattice(std::make_shared<Lattice>(lat));
212 ani_object aniObj = CreateAniObjectStatic(env, ANI_CLASS_ANI_LATTICE_NAME, aniLattice);
213 return aniObj;
214 }
215
GetLattice()216 std::shared_ptr<Lattice> AniLattice::GetLattice()
217 {
218 return m_lattice;
219 }
220 } // namespace Drawing
221 } // namespace OHOS::Rosen
222