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 int32_t argb[ARGC_FOUR] = {0};
162 if (!ConvertFromJsColor(env, tempColor, argb, ARGC_FOUR)) {
163 ROSEN_LOGE("JsLattice::CreateImageLattice colors is invalid");
164 return false;
165 }
166 drawingColor = Color::ColorQuadSetARGB(
167 argb[ARGC_ZERO], argb[ARGC_ONE], argb[ARGC_TWO], argb[ARGC_THREE]);
168 latticeColors.push_back(drawingColor);
169 }
170 }
171 return true;
172 }
173
CreateImageLattice(napi_env env,napi_callback_info info)174 napi_value JsLattice::CreateImageLattice(napi_env env, napi_callback_info info)
175 {
176 size_t argc = ARGC_SEVEN;
177 napi_value argv[ARGC_SEVEN] = {nullptr};
178 CHECK_PARAM_NUMBER_WITH_OPTIONAL_PARAMS(argv, argc, ARGC_FOUR, ARGC_SEVEN);
179
180 uint32_t xCount = 0;
181 GET_UINT32_PARAM(ARGC_TWO, xCount);
182 uint32_t yCount = 0;
183 GET_UINT32_PARAM(ARGC_THREE, yCount);
184
185 Lattice lat;
186 if (!GetLatticeDividers(env, argv[ARGC_ZERO], xCount, lat.fXDivs)) {
187 ROSEN_LOGE("JsLattice::CreateImageLattice xDividers are invalid");
188 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Incorrect parameter0 type.");
189 }
190 if (!GetLatticeDividers(env, argv[ARGC_ONE], yCount, lat.fYDivs)) {
191 ROSEN_LOGE("JsLattice::CreateImageLattice yDividers are invalid");
192 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Incorrect parameter1 type.");
193 }
194 lat.fXCount = xCount;
195 lat.fYCount = yCount;
196
197 if (argc >= ARGC_FIVE) {
198 napi_valuetype valueType = napi_undefined;
199 if (napi_typeof(env, argv[ARGC_FOUR], &valueType) != napi_ok ||
200 (valueType != napi_null && valueType != napi_object)) {
201 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM,
202 "Incorrect CreateImageLattice parameter5 type.");
203 }
204 if (valueType == napi_object) {
205 int32_t ltrb[ARGC_FOUR] = {0};
206 if (!ConvertFromJsIRect(env, argv[ARGC_FOUR], ltrb, ARGC_FOUR)) {
207 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM,
208 "Incorrect parameter5 type. The type of left, top, right and bottom must be number.");
209 }
210 lat.fBounds.push_back(Drawing::RectI(ltrb[ARGC_ZERO], ltrb[ARGC_ONE], ltrb[ARGC_TWO], ltrb[ARGC_THREE]));
211 }
212 }
213
214 if (argc >= ARGC_SIX) {
215 int count = (xCount + 1) * (yCount + 1); // 1: grid size need + 1
216 if (!GetLatticeRectTypes(env, argv[ARGC_FIVE], count, lat.fRectTypes)) {
217 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Incorrect parameter6 type.");
218 }
219
220 if (argc == ARGC_SEVEN) {
221 if (!GetLatticeColors(env, argv[ARGC_SIX], count, lat.fColors)) {
222 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Incorrect parameter7 type.");
223 }
224 }
225 }
226 return JsLattice::Create(env, std::make_shared<Lattice>(lat));
227 }
228
Create(napi_env env,std::shared_ptr<Lattice> lattice)229 napi_value JsLattice::Create(napi_env env, std::shared_ptr<Lattice> lattice)
230 {
231 napi_value objValue = nullptr;
232 napi_create_object(env, &objValue);
233 if (objValue == nullptr || lattice == nullptr) {
234 ROSEN_LOGE("JsLattice::Create object is null!");
235 return nullptr;
236 }
237
238 std::unique_ptr<JsLattice> jsLattice = std::make_unique<JsLattice>(lattice);
239 napi_wrap(env, objValue, jsLattice.release(), JsLattice::Finalizer, nullptr, nullptr);
240
241 if (objValue == nullptr) {
242 ROSEN_LOGE("JsLattice::Create object value is null!");
243 return nullptr;
244 }
245 return objValue;
246 }
247
GetLattice()248 std::shared_ptr<Lattice> JsLattice::GetLattice()
249 {
250 return m_lattice;
251 }
252 } // namespace Drawing
253 } // namespace OHOS::Rosen
254