1 /*
2 * Copyright (c) 2024 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 "js_lattice.h"
17 #include "js_drawing_utils.h"
18 #include "native_value.h"
19
20 namespace OHOS::Rosen {
21 namespace Drawing {
22 const std::string CLASS_NAME = "Lattice";
23 thread_local napi_ref JsLattice::constructor_ = nullptr;
Init(napi_env env,napi_value exportObj)24 napi_value JsLattice::Init(napi_env env, napi_value exportObj)
25 {
26 napi_property_descriptor properties[] = {
27 DECLARE_NAPI_STATIC_FUNCTION("createImageLattice", JsLattice::CreateImageLattice),
28 };
29
30 napi_value constructor = nullptr;
31 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
32 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
33 if (status != napi_ok) {
34 ROSEN_LOGE("JsLattice::Init failed to define lattice class");
35 return nullptr;
36 }
37
38 status = napi_create_reference(env, constructor, 1, &constructor_);
39 if (status != napi_ok) {
40 ROSEN_LOGE("JsLattice::Init failed to create reference of constructor");
41 return nullptr;
42 }
43
44 status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
45 if (status != napi_ok) {
46 ROSEN_LOGE("JsLattice::Init failed to set constructor");
47 return nullptr;
48 }
49
50 status = napi_define_properties(env, exportObj, sizeof(properties) / sizeof(properties[0]), properties);
51 if (status != napi_ok) {
52 ROSEN_LOGE("JsLattice::Init failed to define static function");
53 return nullptr;
54 }
55 return exportObj;
56 }
57
Finalizer(napi_env env,void * data,void * hint)58 void JsLattice::Finalizer(napi_env env, void* data, void* hint)
59 {
60 std::unique_ptr<JsLattice>(static_cast<JsLattice*>(data));
61 }
62
~JsLattice()63 JsLattice::~JsLattice()
64 {
65 m_lattice = nullptr;
66 }
67
Constructor(napi_env env,napi_callback_info info)68 napi_value JsLattice::Constructor(napi_env env, napi_callback_info info)
69 {
70 size_t argCount = 0;
71 napi_value jsThis = nullptr;
72 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
73 if (status != napi_ok) {
74 ROSEN_LOGE("JsLattice::Constructor failed to napi_get_cb_info");
75 return nullptr;
76 }
77
78 JsLattice *jsLattice = new JsLattice();
79 status = napi_wrap(env, jsThis, jsLattice, JsLattice::Destructor, nullptr, nullptr);
80 if (status != napi_ok) {
81 delete jsLattice;
82 ROSEN_LOGE("JsLattice::Constructor failed to wrap native instance");
83 return nullptr;
84 }
85 return jsThis;
86 }
87
Destructor(napi_env env,void * nativeObject,void * finalize)88 void JsLattice::Destructor(napi_env env, void *nativeObject, void *finalize)
89 {
90 (void)finalize;
91 if (nativeObject != nullptr) {
92 JsLattice *napi = reinterpret_cast<JsLattice *>(nativeObject);
93 delete napi;
94 }
95 }
96
GetLatticeDividers(napi_env env,napi_value dividersArray,uint32_t count,std::vector<int> & dividers)97 bool GetLatticeDividers(napi_env env, napi_value dividersArray, uint32_t count, std::vector<int>& dividers)
98 {
99 uint32_t dividersSize = 0;
100 napi_get_array_length(env, dividersArray, ÷rsSize);
101 if (dividersSize != count || dividersSize > 5) { // 5: max value
102 ROSEN_LOGE("JsLattice::CreateImageLattice dividers are invalid");
103 return false;
104 }
105 if (dividersSize != 0) {
106 dividers.reserve(dividersSize);
107 for (uint32_t i = 0; i < dividersSize; i++) {
108 napi_value tempDiv = nullptr;
109 napi_get_element(env, dividersArray, i, &tempDiv);
110 int div = 0;
111 if (napi_get_value_int32(env, tempDiv, &div) != napi_ok) {
112 ROSEN_LOGE("JsLattice::CreateImageLattice divider is invalid");
113 return false;
114 }
115 dividers.push_back(div);
116 }
117 }
118 return true;
119 }
120
GetLatticeRectTypes(napi_env env,napi_value rectTypesArray,uint32_t count,std::vector<Lattice::RectType> & latticeRectTypes)121 bool GetLatticeRectTypes(napi_env env, napi_value rectTypesArray, uint32_t count,
122 std::vector<Lattice::RectType>& latticeRectTypes)
123 {
124 uint32_t rectTypesSize = 0;
125 napi_get_array_length(env, rectTypesArray, &rectTypesSize);
126 if ((rectTypesSize != 0 && rectTypesSize != count) || rectTypesSize > 36) { // 36: max value
127 ROSEN_LOGE("JsLattice::CreateImageLattice rectTypes are invalid");
128 return false;
129 }
130 if (rectTypesSize != 0) {
131 latticeRectTypes.reserve(rectTypesSize);
132 for (uint32_t i = 0; i < rectTypesSize; i++) {
133 napi_value tempType = nullptr;
134 napi_get_element(env, rectTypesArray, i, &tempType);
135 int rectType = 0;
136 if (napi_get_value_int32(env, tempType, &rectType) != napi_ok ||
137 rectType < 0 || rectType > 2) { // 2: FIXEDCOLOR
138 ROSEN_LOGE("JsLattice::CreateImageLattice rectType is invalid");
139 return false;
140 }
141 latticeRectTypes.push_back(static_cast<Lattice::RectType>(rectType));
142 }
143 }
144 return true;
145 }
146
GetLatticeColors(napi_env env,napi_value colorsArray,uint32_t count,std::vector<Color> & latticeColors)147 bool GetLatticeColors(napi_env env, napi_value colorsArray, uint32_t count, std::vector<Color>& latticeColors)
148 {
149 uint32_t colorsSize = 0;
150 napi_get_array_length(env, colorsArray, &colorsSize);
151 if ((colorsSize != 0 && colorsSize != count) || colorsSize > 36) { // 36: max value
152 ROSEN_LOGE("JsLattice::CreateImageLattice colors are invalid");
153 return false;
154 }
155 if (colorsSize != 0) {
156 latticeColors.reserve(colorsSize);
157 for (uint32_t i = 0; i < colorsSize; i++) {
158 napi_value tempColor = nullptr;
159 napi_get_element(env, colorsArray, i, &tempColor);
160 Drawing::Color drawingColor;
161 ColorQuad color;
162 if (!ConvertFromAdaptHexJsColor(env, tempColor, color)) {
163 ROSEN_LOGE("JsLattice::CreateImageLattice colors is invalid");
164 return false;
165 }
166 drawingColor.SetColorQuad(color);
167 latticeColors.push_back(drawingColor);
168 }
169 }
170 return true;
171 }
172
CreateImageLattice(napi_env env,napi_callback_info info)173 napi_value JsLattice::CreateImageLattice(napi_env env, napi_callback_info info)
174 {
175 size_t argc = ARGC_SEVEN;
176 napi_value argv[ARGC_SEVEN] = {nullptr};
177 CHECK_PARAM_NUMBER_WITH_OPTIONAL_PARAMS(argv, argc, ARGC_FOUR, ARGC_SEVEN);
178
179 uint32_t xCount = 0;
180 GET_UINT32_PARAM(ARGC_TWO, xCount);
181 uint32_t yCount = 0;
182 GET_UINT32_PARAM(ARGC_THREE, yCount);
183
184 Lattice lat;
185 if (!GetLatticeDividers(env, argv[ARGC_ZERO], xCount, lat.fXDivs)) {
186 ROSEN_LOGE("JsLattice::CreateImageLattice xDividers are invalid");
187 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Incorrect parameter0 type.");
188 }
189 if (!GetLatticeDividers(env, argv[ARGC_ONE], yCount, lat.fYDivs)) {
190 ROSEN_LOGE("JsLattice::CreateImageLattice yDividers are invalid");
191 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Incorrect parameter1 type.");
192 }
193 lat.fXCount = xCount;
194 lat.fYCount = yCount;
195
196 if (argc >= ARGC_FIVE) {
197 napi_valuetype valueType = napi_undefined;
198 if (napi_typeof(env, argv[ARGC_FOUR], &valueType) != napi_ok ||
199 (valueType != napi_null && valueType != napi_object)) {
200 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM,
201 "Incorrect CreateImageLattice parameter5 type.");
202 }
203 if (valueType == napi_object) {
204 int32_t ltrb[ARGC_FOUR] = {0};
205 if (!ConvertFromJsIRect(env, argv[ARGC_FOUR], ltrb, ARGC_FOUR)) {
206 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM,
207 "Incorrect parameter5 type. The type of left, top, right and bottom must be number.");
208 }
209 lat.fBounds.push_back(Drawing::RectI(ltrb[ARGC_ZERO], ltrb[ARGC_ONE], ltrb[ARGC_TWO], ltrb[ARGC_THREE]));
210 }
211 }
212
213 if (argc >= ARGC_SIX) {
214 int count = (xCount + 1) * (yCount + 1); // 1: grid size need + 1
215 if (!GetLatticeRectTypes(env, argv[ARGC_FIVE], count, lat.fRectTypes)) {
216 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Incorrect parameter6 type.");
217 }
218
219 if (argc == ARGC_SEVEN) {
220 if (!GetLatticeColors(env, argv[ARGC_SIX], count, lat.fColors)) {
221 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Incorrect parameter7 type.");
222 }
223 }
224 }
225 return JsLattice::Create(env, std::make_shared<Lattice>(lat));
226 }
227
Create(napi_env env,std::shared_ptr<Lattice> lattice)228 napi_value JsLattice::Create(napi_env env, std::shared_ptr<Lattice> lattice)
229 {
230 napi_value objValue = nullptr;
231 napi_create_object(env, &objValue);
232 if (objValue == nullptr || lattice == nullptr) {
233 ROSEN_LOGE("JsLattice::Create object is null!");
234 return nullptr;
235 }
236
237 std::unique_ptr<JsLattice> jsLattice = std::make_unique<JsLattice>(lattice);
238 napi_wrap(env, objValue, jsLattice.release(), JsLattice::Finalizer, nullptr, nullptr);
239
240 if (objValue == nullptr) {
241 ROSEN_LOGE("JsLattice::Create object value is null!");
242 return nullptr;
243 }
244 return objValue;
245 }
246
GetLattice()247 std::shared_ptr<Lattice> JsLattice::GetLattice()
248 {
249 return m_lattice;
250 }
251 } // namespace Drawing
252 } // namespace OHOS::Rosen
253