1 /*
2 * Copyright (c) 2023-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_drawable_descriptor.h"
17
18 #include "drawable_descriptor.h"
19 #include "interfaces/inner_api/drawable_descriptor/drawable_descriptor.h"
20 #include "js_native_api.h"
21 #include "js_native_api_types.h"
22 #include "napi/native_api.h"
23 #include "napi/native_common.h"
24 #include "napi/native_node_api.h"
25 #ifndef PREVIEW
26 #include "pixel_map_napi.h"
27 #endif
28
29 namespace {
30 constexpr char DRAWABLE_BASE[] = "DrawableDescriptor";
31 constexpr char DRAWABLE_LAYERED[] = "LayeredDrawableDescriptor";
32 constexpr char DRAWABLE_ANIMATED[] = "AnimatedDrawableDescriptor";
33 constexpr char DRAWABLE_PIXELMAP[] = "PixelMapDrawableDescriptor";
34 constexpr int32_t PARAMS_NUM_ONE = 1;
35 constexpr int32_t PARAMS_NUM_THREE = 3;
36
37 constexpr int32_t FOREGROUND_INDEX = 0;
38 constexpr int32_t BACKGROUND_INDEX = 1;
39 constexpr int32_t MASK_INDEX = 2;
40
UpdateLayeredParam(OHOS::Ace::Napi::LayeredDrawableDescriptor * layeredDrawable,int32_t pos,std::shared_ptr<OHOS::Media::PixelMap> pixelMap)41 void UpdateLayeredParam(OHOS::Ace::Napi::LayeredDrawableDescriptor* layeredDrawable, int32_t pos,
42 std::shared_ptr<OHOS::Media::PixelMap> pixelMap)
43 {
44 if (!layeredDrawable || !pixelMap) {
45 return;
46 }
47 switch (pos) {
48 case FOREGROUND_INDEX:
49 layeredDrawable->SetForeground(pixelMap);
50 break;
51 case BACKGROUND_INDEX:
52 layeredDrawable->SetBackground(pixelMap);
53 break;
54 case MASK_INDEX:
55 layeredDrawable->SetMask(pixelMap);
56 break;
57 default:
58 HILOGW("Arg[%{public}d] index error", pos);
59 }
60 }
61 } // namespace
62
63 namespace OHOS::Ace::Napi {
64 thread_local napi_ref JsDrawableDescriptor::baseConstructor_;
65 thread_local napi_ref JsDrawableDescriptor::layeredConstructor_;
66 thread_local napi_ref JsDrawableDescriptor::animatedConstructor_;
67 thread_local napi_ref JsDrawableDescriptor::pixelMapConstructor_;
68
GetPixelMapArray(napi_env env,napi_value arg,std::vector<std::shared_ptr<Media::PixelMap>> & pixelMaps)69 static bool GetPixelMapArray(
70 napi_env env, napi_value arg, std::vector<std::shared_ptr<Media::PixelMap>>& pixelMaps)
71 {
72 bool isArray = false;
73 uint32_t length = 0;
74 napi_is_array(env, arg, &isArray);
75 if (!isArray) {
76 return false;
77 }
78 napi_get_array_length(env, arg, &length);
79 if (length < 1) {
80 return false;
81 }
82 for (uint32_t i = 0; i < length; i++) {
83 napi_value pixelMapValue = nullptr;
84 napi_get_element(env, arg, i, &pixelMapValue);
85 if (pixelMapValue == nullptr) {
86 continue;
87 }
88 Media::PixelMapNapi* pixmapNapi = nullptr;
89 napi_unwrap(env, pixelMapValue, reinterpret_cast<void**>(&pixmapNapi));
90 if (pixmapNapi == nullptr) {
91 continue;
92 }
93 pixelMaps.push_back(*(pixmapNapi->GetPixelMap()));
94 }
95 if (pixelMaps.size() <= 0) {
96 return false;
97 }
98 return true;
99 }
100
AnimatedConstructor(napi_env env,napi_callback_info info)101 napi_value JsDrawableDescriptor::AnimatedConstructor(napi_env env, napi_callback_info info)
102 {
103 napi_escapable_handle_scope scope = nullptr;
104 napi_open_escapable_handle_scope(env, &scope);
105
106 size_t argc = 2;
107 napi_value argv[2] = {nullptr};
108 napi_value thisVar = nullptr;
109 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
110 if (argc < 1) {
111 return nullptr;
112 }
113 std::vector<std::shared_ptr<Media::PixelMap>> pixelMaps;
114 if (!GetPixelMapArray(env, argv[0], pixelMaps)) {
115 return nullptr;
116 }
117
118 //napi_get_named_property
119 napi_value napiDuration;
120 napi_value napiIterations;
121 int32_t duration = -1;
122 int32_t iterations = 1;
123 if (argc > 1 && argv[1]) {
124 napi_get_named_property(env, argv[1], "duration", &napiDuration);
125 napi_get_named_property(env, argv[1], "iterations", &napiIterations);
126 napi_get_value_int32(env, napiDuration, &duration);
127 napi_get_value_int32(env, napiIterations, &iterations);
128 }
129 // create JsDrawable
130 auto* animatedDrawable = new AnimatedDrawableDescriptor(pixelMaps, duration, iterations);
131 // wrap to napi_value
132 napi_wrap(env, thisVar, animatedDrawable, Destructor, nullptr, nullptr);
133 napi_escape_handle(env, scope, thisVar, &thisVar);
134 napi_close_escapable_handle_scope(env, scope);
135 return thisVar;
136 }
137
Constructor(napi_env env,napi_callback_info info)138 napi_value JsDrawableDescriptor::Constructor(napi_env env, napi_callback_info info)
139 {
140 napi_escapable_handle_scope scope = nullptr;
141 napi_open_escapable_handle_scope(env, &scope);
142 napi_value thisVar = nullptr;
143 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
144 // create JsDrawable
145 auto* drawable = new DrawableDescriptor;
146 // wrap to napi_value
147 napi_wrap(env, thisVar, drawable, Destructor, nullptr, nullptr);
148 napi_escape_handle(env, scope, thisVar, &thisVar);
149 napi_close_escapable_handle_scope(env, scope);
150 return thisVar;
151 }
152
PixelMapConstructor(napi_env env,napi_callback_info info)153 napi_value JsDrawableDescriptor::PixelMapConstructor(napi_env env, napi_callback_info info)
154 {
155 napi_escapable_handle_scope scope = nullptr;
156 napi_open_escapable_handle_scope(env, &scope);
157 size_t argc = PARAMS_NUM_ONE;
158 napi_value argv[argc];
159 napi_value thisVar = nullptr;
160 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
161 auto* drawable = new DrawableDescriptor;
162 if (argc == 0) {
163 HILOGW("JsDrawableDescriptor::PixelMapConstructor get null pixelMap param");
164 napi_wrap(env, thisVar, drawable, Destructor, nullptr, nullptr);
165 napi_escape_handle(env, scope, thisVar, &thisVar);
166 napi_close_escapable_handle_scope(env, scope);
167 return thisVar;
168 }
169 napi_value argPixelMap = argv[0];
170 napi_valuetype type;
171 napi_typeof(env, argPixelMap, &type);
172 if (type == napi_object) {
173 auto pixelMap = GetPixelMapFromNapi(env, argPixelMap);
174 if (pixelMap) {
175 drawable->SetPixelMap(pixelMap);
176 }
177 }
178
179 // wrap to napi_value
180 napi_wrap(env, thisVar, drawable, Destructor, nullptr, nullptr);
181 napi_escape_handle(env, scope, thisVar, &thisVar);
182 napi_close_escapable_handle_scope(env, scope);
183 return thisVar;
184 }
185
LayeredConstructor(napi_env env,napi_callback_info info)186 napi_value JsDrawableDescriptor::LayeredConstructor(napi_env env, napi_callback_info info)
187 {
188 napi_escapable_handle_scope scope = nullptr;
189 napi_open_escapable_handle_scope(env, &scope);
190 size_t argc = PARAMS_NUM_THREE;
191 napi_value argv[argc];
192 napi_value thisVar = nullptr;
193 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
194 auto pos = -1;
195 auto* layeredDrawable = new LayeredDrawableDescriptor;
196 if (argc == 0) {
197 napi_wrap(env, thisVar, layeredDrawable, Destructor, nullptr, nullptr);
198 napi_escape_handle(env, scope, thisVar, &thisVar);
199 napi_close_escapable_handle_scope(env, scope);
200 return thisVar;
201 }
202 std::shared_ptr<Media::PixelMap> foregroundPixelMap = nullptr;
203 auto updateUndefinedPixelMap = [&pos, &layeredDrawable, &foregroundPixelMap]() -> void {
204 if (pos == MASK_INDEX) {
205 std::shared_ptr<Global::Resource::ResourceManager> resMgr(Global::Resource::CreateResourceManager());
206 layeredDrawable->InitialMask(resMgr);
207 } else if (pos == BACKGROUND_INDEX && foregroundPixelMap) {
208 UpdateLayeredParam(layeredDrawable, pos, foregroundPixelMap);
209 }
210 };
211 napi_valuetype type;
212 for (const auto& arg : argv) {
213 pos++;
214 napi_typeof(env, arg, &type);
215 if (type == napi_undefined) {
216 updateUndefinedPixelMap();
217 continue;
218 }
219 auto pixelMap = GetPixelMapFromDrawableNapi(env, arg);
220 if (!pixelMap) {
221 updateUndefinedPixelMap();
222 } else {
223 UpdateLayeredParam(layeredDrawable, pos, pixelMap);
224 if (pos == FOREGROUND_INDEX) foregroundPixelMap = std::move(pixelMap);
225 }
226 }
227 napi_wrap(env, thisVar, layeredDrawable, Destructor, nullptr, nullptr);
228 napi_escape_handle(env, scope, thisVar, &thisVar);
229 napi_close_escapable_handle_scope(env, scope);
230 return thisVar;
231 }
232
GetPixelMapFromNapi(napi_env env,napi_value napiValue)233 std::shared_ptr<Media::PixelMap> JsDrawableDescriptor::GetPixelMapFromNapi(napi_env env, napi_value napiValue)
234 {
235 Media::PixelMapNapi* pixelMapNapi = nullptr;
236 napi_unwrap(env, napiValue, reinterpret_cast<void**>(&pixelMapNapi));
237 if (pixelMapNapi == nullptr) {
238 HILOGI("JsDrawableDescriptor::GetPixelMapFromNapi Argv is invalid");
239 return nullptr;
240 }
241 auto pixelMap = *(pixelMapNapi->GetPixelMap());
242 if (pixelMap == nullptr) {
243 HILOGI("JsDrawableDescriptor::GetPixelMapFromNapi GetPixelNapiInner from media is nullptr");
244 return nullptr;
245 }
246 return pixelMap;
247 }
248
GetPixelMapFromDrawableNapi(napi_env env,napi_value napiValue)249 std::shared_ptr<Media::PixelMap> JsDrawableDescriptor::GetPixelMapFromDrawableNapi(napi_env env, napi_value napiValue)
250 {
251 DrawableDescriptor* drawableNapi = nullptr;
252 napi_unwrap(env, napiValue, reinterpret_cast<void**>(&drawableNapi));
253 if (drawableNapi == nullptr) {
254 HILOGW("JsDrawableDescriptor::GetPixelMapFromDrawableNapi Argv is invalid");
255 return nullptr;
256 }
257 auto pixelMap = drawableNapi->GetPixelMap();
258 if (pixelMap == nullptr) {
259 HILOGW("JsDrawableDescriptor::GetPixelMapFromDrawableNapi GetPixelNapiInner from media is nullptr");
260 return nullptr;
261 }
262 return pixelMap;
263 }
264
Destructor(napi_env,void * data,void *)265 void JsDrawableDescriptor::Destructor(napi_env /* env */, void* data, void* /* hint */)
266 {
267 auto* field = reinterpret_cast<DrawableDescriptor*>(data);
268 delete field;
269 }
270
InitDrawable(napi_env env)271 napi_value JsDrawableDescriptor::InitDrawable(napi_env env)
272 {
273 napi_value cons = nullptr;
274 napi_property_descriptor baseDes[] = {
275 DECLARE_NAPI_FUNCTION("getPixelMap", GetPixelMap),
276 };
277 NAPI_CALL(env, napi_define_class(env, DRAWABLE_BASE, NAPI_AUTO_LENGTH, Constructor, nullptr,
278 sizeof(baseDes) / sizeof(napi_property_descriptor), baseDes, &cons));
279 NAPI_CALL(env, napi_create_reference(env, cons, 1, &baseConstructor_));
280 return cons;
281 }
282
InitPixelMapDrawable(napi_env env)283 napi_value JsDrawableDescriptor::InitPixelMapDrawable(napi_env env)
284 {
285 napi_value cons = nullptr;
286 napi_property_descriptor pixelDes[] = {
287 DECLARE_NAPI_FUNCTION("getPixelMap", GetPixelMap),
288 };
289 NAPI_CALL(env, napi_define_class(env, DRAWABLE_PIXELMAP, NAPI_AUTO_LENGTH, PixelMapConstructor, nullptr,
290 sizeof(pixelDes) / sizeof(napi_property_descriptor), pixelDes, &cons));
291 NAPI_CALL(env, napi_create_reference(env, cons, 1, &pixelMapConstructor_));
292 return cons;
293 }
294
InitLayeredDrawable(napi_env env)295 napi_value JsDrawableDescriptor::InitLayeredDrawable(napi_env env)
296 {
297 napi_value cons = nullptr;
298 napi_property_descriptor layeredDes[] = {
299 DECLARE_NAPI_FUNCTION("getPixelMap", GetPixelMap),
300 DECLARE_NAPI_FUNCTION("getForeground", GetForeground),
301 DECLARE_NAPI_FUNCTION("getBackground", GetBackground),
302 DECLARE_NAPI_FUNCTION("getMask", GetMask),
303 DECLARE_NAPI_STATIC_FUNCTION("getMaskClipPath", GetMaskClipPath),
304 };
305 NAPI_CALL(env, napi_define_class(env, DRAWABLE_LAYERED, NAPI_AUTO_LENGTH, LayeredConstructor, nullptr,
306 sizeof(layeredDes) / sizeof(napi_property_descriptor), layeredDes, &cons));
307 NAPI_CALL(env, napi_create_reference(env, cons, 1, &layeredConstructor_));
308 return cons;
309 }
310
InitAnimatedDrawable(napi_env env)311 napi_value JsDrawableDescriptor::InitAnimatedDrawable(napi_env env)
312 {
313 napi_value cons = nullptr;
314 napi_property_descriptor animatedDes[] = {
315 DECLARE_NAPI_FUNCTION("getPixelMap", GetPixelMap),
316 };
317 NAPI_CALL(env, napi_define_class(env, DRAWABLE_ANIMATED, NAPI_AUTO_LENGTH, AnimatedConstructor, nullptr,
318 sizeof(animatedDes) / sizeof(napi_property_descriptor), animatedDes, &cons));
319 NAPI_CALL(env, napi_create_reference(env, cons, 1, &animatedConstructor_));
320 return cons;
321 }
322
ToNapi(napi_env env,DrawableDescriptor * drawable,DrawableDescriptor::DrawableType type)323 napi_value JsDrawableDescriptor::ToNapi(
324 napi_env env, DrawableDescriptor* drawable, DrawableDescriptor::DrawableType type)
325 {
326 if (!drawable) {
327 return nullptr;
328 }
329 if (!baseConstructor_ || !layeredConstructor_ || !animatedConstructor_ || !pixelMapConstructor_) {
330 // init js class constructor by importing module manually
331 napi_value globalValue;
332 napi_get_global(env, &globalValue);
333 napi_value func;
334 napi_get_named_property(env, globalValue, "requireNapi", &func);
335
336 napi_value module;
337 napi_create_string_utf8(env, MODULE_NAME, NAPI_AUTO_LENGTH, &module);
338 napi_value returnValue;
339 napi_call_function(env, globalValue, func, 1, &module, &returnValue);
340 }
341
342 napi_value constructor = nullptr;
343 napi_value result = nullptr;
344 napi_status status;
345 switch (type) {
346 case DrawableDescriptor::DrawableType::ANIMATED:
347 status = napi_get_reference_value(env, animatedConstructor_, &constructor);
348 break;
349 case DrawableDescriptor::DrawableType::LAYERED:
350 status = napi_get_reference_value(env, layeredConstructor_, &constructor);
351 break;
352 case DrawableDescriptor::DrawableType::BASE:
353 status = napi_get_reference_value(env, baseConstructor_, &constructor);
354 break;
355 case DrawableDescriptor::DrawableType::PIXELMAP:
356 status = napi_get_reference_value(env, pixelMapConstructor_, &constructor);
357 break;
358 default:
359 status = napi_status::napi_invalid_arg;
360 break;
361 }
362 if (status == napi_status::napi_ok) {
363 NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &result));
364 NAPI_CALL(env, napi_wrap(env, result, drawable, Destructor, nullptr, nullptr));
365 } else {
366 HILOGI("create reference failed, drawable constructor is null");
367 }
368
369 return result;
370 }
371
GetPixelMap(napi_env env,napi_callback_info info)372 napi_value JsDrawableDescriptor::GetPixelMap(napi_env env, napi_callback_info info)
373 {
374 napi_escapable_handle_scope scope = nullptr;
375 napi_open_escapable_handle_scope(env, &scope);
376 napi_value thisVar = nullptr;
377 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
378 void* native = nullptr;
379 napi_unwrap(env, thisVar, &native);
380 auto* drawable = reinterpret_cast<DrawableDescriptor*>(native);
381 auto pixmap = drawable->GetPixelMap();
382
383 napi_value result = Media::PixelMapNapi::CreatePixelMap(env, pixmap);
384 napi_escape_handle(env, scope, result, &result);
385 napi_close_escapable_handle_scope(env, scope);
386 return result;
387 }
388
GetForeground(napi_env env,napi_callback_info info)389 napi_value JsDrawableDescriptor::GetForeground(napi_env env, napi_callback_info info)
390 {
391 napi_escapable_handle_scope scope = nullptr;
392 napi_open_escapable_handle_scope(env, &scope);
393 napi_value thisVar = nullptr;
394 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
395 void* native = nullptr;
396 napi_unwrap(env, thisVar, &native);
397 auto* drawable = reinterpret_cast<LayeredDrawableDescriptor*>(native);
398 if (!drawable) {
399 return nullptr;
400 }
401
402 auto foreground = drawable->GetForeground();
403 napi_value result = ToNapi(env, foreground.release(), DrawableDescriptor::DrawableType::BASE);
404 napi_escape_handle(env, scope, result, &result);
405 napi_close_escapable_handle_scope(env, scope);
406 return result;
407 }
408
GetBackground(napi_env env,napi_callback_info info)409 napi_value JsDrawableDescriptor::GetBackground(napi_env env, napi_callback_info info)
410 {
411 napi_escapable_handle_scope scope = nullptr;
412 napi_open_escapable_handle_scope(env, &scope);
413 napi_value thisVar = nullptr;
414 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
415 void* native = nullptr;
416 napi_unwrap(env, thisVar, &native);
417 auto* drawable = reinterpret_cast<LayeredDrawableDescriptor*>(native);
418 if (!drawable) {
419 return nullptr;
420 }
421
422 auto background = drawable->GetBackground();
423 napi_value result = ToNapi(env, background.release(), DrawableDescriptor::DrawableType::BASE);
424 napi_escape_handle(env, scope, result, &result);
425 napi_close_escapable_handle_scope(env, scope);
426 return result;
427 }
428
GetMask(napi_env env,napi_callback_info info)429 napi_value JsDrawableDescriptor::GetMask(napi_env env, napi_callback_info info)
430 {
431 napi_escapable_handle_scope scope = nullptr;
432 napi_open_escapable_handle_scope(env, &scope);
433 napi_value thisVar = nullptr;
434 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
435 void* native = nullptr;
436 napi_unwrap(env, thisVar, &native);
437 auto* drawable = reinterpret_cast<LayeredDrawableDescriptor*>(native);
438 if (!drawable) {
439 return nullptr;
440 }
441
442 auto mask = drawable->GetMask();
443 napi_value result = ToNapi(env, mask.release(), DrawableDescriptor::DrawableType::BASE);
444 napi_escape_handle(env, scope, result, &result);
445 napi_close_escapable_handle_scope(env, scope);
446 return result;
447 }
448
GetMaskClipPath(napi_env env,napi_callback_info info)449 napi_value JsDrawableDescriptor::GetMaskClipPath(napi_env env, napi_callback_info info)
450 {
451 auto path = OHOS::Ace::Napi::LayeredDrawableDescriptor::GetStaticMaskClipPath();
452 napi_value result = nullptr;
453 if (napi_ok != napi_create_string_utf8(env, path.c_str(), NAPI_AUTO_LENGTH, &result)) {
454 HILOGI("JsDrawableDescriptor Failed");
455 }
456 return result;
457 }
458
Export(napi_env env,napi_value exports)459 napi_value JsDrawableDescriptor::Export(napi_env env, napi_value exports)
460 {
461 // export base class
462 napi_value cons = InitDrawable(env);
463 NAPI_CALL(env, napi_set_named_property(env, exports, DRAWABLE_BASE, cons));
464
465 cons = InitPixelMapDrawable(env);
466 NAPI_CALL(env, napi_set_named_property(env, exports, DRAWABLE_PIXELMAP, cons));
467
468 // export child class
469 cons = InitLayeredDrawable(env);
470 NAPI_CALL(env, napi_set_named_property(env, exports, DRAWABLE_LAYERED, cons));
471
472 //export child class
473 cons = InitAnimatedDrawable(env);
474 NAPI_CALL(env, napi_set_named_property(env, exports, DRAWABLE_ANIMATED, cons));
475
476 return exports;
477 }
478 } // namespace OHOS::Ace::Napi
479