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 "napi/native_api.h"
19 #include "napi/native_common.h"
20 #include "napi/native_node_api.h"
21 #ifndef PREVIEW
22 #include "pixel_map_napi.h"
23 #else
24 #include "image_source_preview.h"
25 #endif
26 #include "resource_manager.h"
27
28 #include "base/log.h"
29
30 namespace {
31 constexpr char DRAWABLE_BASE[] = "DrawableDescriptor";
32 constexpr char DRAWABLE_LAYERED[] = "LayeredDrawableDescriptor";
33 constexpr char DRAWABLE_ANIMATED[] = "AnimatedDrawableDescriptor";
34 constexpr char DRAWABLE_PIXELMAP[] = "PixelMapDrawableDescriptor";
35 constexpr int32_t PARAMS_NUM_ONE = 1;
36 constexpr int32_t PARAMS_NUM_THREE = 3;
37
38 constexpr int32_t FOREGROUND_INDEX = 0;
39 constexpr int32_t BACKGROUND_INDEX = 1;
40 constexpr int32_t MASK_INDEX = 2;
41
UpdateLayeredParam(OHOS::Ace::Napi::LayeredDrawableDescriptor * layeredDrawable,int32_t pos,std::shared_ptr<OHOS::Media::PixelMap> pixelMap)42 void UpdateLayeredParam(OHOS::Ace::Napi::LayeredDrawableDescriptor* layeredDrawable, int32_t pos,
43 std::shared_ptr<OHOS::Media::PixelMap> pixelMap)
44 {
45 if (!layeredDrawable || !pixelMap) {
46 return;
47 }
48 switch (pos) {
49 case FOREGROUND_INDEX:
50 layeredDrawable->SetForeground(pixelMap);
51 break;
52 case BACKGROUND_INDEX:
53 layeredDrawable->SetBackground(pixelMap);
54 break;
55 case MASK_INDEX:
56 layeredDrawable->SetMask(pixelMap);
57 break;
58 default:
59 HILOGW("Arg[%{public}d] index error", pos);
60 }
61 }
62 } // namespace
63
64 namespace OHOS::Ace::Napi {
65 thread_local napi_ref JsDrawableDescriptor::baseConstructor_;
66 thread_local napi_ref JsDrawableDescriptor::layeredConstructor_;
67 thread_local napi_ref JsDrawableDescriptor::animatedConstructor_;
68 thread_local napi_ref JsDrawableDescriptor::pixelMapConstructor_;
69
GetPixelMapArray(napi_env env,napi_value arg,std::vector<std::shared_ptr<Media::PixelMap>> & pixelMaps)70 static bool GetPixelMapArray(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)
225 foregroundPixelMap = std::move(pixelMap);
226 }
227 }
228 napi_wrap(env, thisVar, layeredDrawable, Destructor, nullptr, nullptr);
229 napi_escape_handle(env, scope, thisVar, &thisVar);
230 napi_close_escapable_handle_scope(env, scope);
231 return thisVar;
232 }
233
GetPixelMapFromNapi(napi_env env,napi_value napiValue)234 std::shared_ptr<Media::PixelMap> JsDrawableDescriptor::GetPixelMapFromNapi(napi_env env, napi_value napiValue)
235 {
236 Media::PixelMapNapi* pixelMapNapi = nullptr;
237 napi_unwrap(env, napiValue, reinterpret_cast<void**>(&pixelMapNapi));
238 if (pixelMapNapi == nullptr) {
239 HILOGI("JsDrawableDescriptor::GetPixelMapFromNapi Argv is invalid");
240 return nullptr;
241 }
242 auto pixelMap = *(pixelMapNapi->GetPixelMap());
243 if (pixelMap == nullptr) {
244 HILOGI("JsDrawableDescriptor::GetPixelMapFromNapi GetPixelNapiInner from media is nullptr");
245 return nullptr;
246 }
247 return pixelMap;
248 }
249
GetPixelMapFromDrawableNapi(napi_env env,napi_value napiValue)250 std::shared_ptr<Media::PixelMap> JsDrawableDescriptor::GetPixelMapFromDrawableNapi(napi_env env, napi_value napiValue)
251 {
252 DrawableDescriptor* drawableNapi = nullptr;
253 napi_unwrap(env, napiValue, reinterpret_cast<void**>(&drawableNapi));
254 if (drawableNapi == nullptr) {
255 HILOGW("JsDrawableDescriptor::GetPixelMapFromDrawableNapi Argv is invalid");
256 return nullptr;
257 }
258 auto pixelMap = drawableNapi->GetPixelMap();
259 if (pixelMap == nullptr) {
260 HILOGW("JsDrawableDescriptor::GetPixelMapFromDrawableNapi GetPixelNapiInner from media is nullptr");
261 return nullptr;
262 }
263 return pixelMap;
264 }
265
Destructor(napi_env,void * data,void *)266 void JsDrawableDescriptor::Destructor(napi_env /* env */, void* data, void* /* hint */)
267 {
268 auto* field = reinterpret_cast<DrawableDescriptor*>(data);
269 delete field;
270 }
271
InitDrawable(napi_env env)272 napi_value JsDrawableDescriptor::InitDrawable(napi_env env)
273 {
274 napi_value cons = nullptr;
275 napi_property_descriptor baseDes[] = {
276 DECLARE_NAPI_FUNCTION("getPixelMap", GetPixelMap),
277 };
278 NAPI_CALL(env, napi_define_class(env, DRAWABLE_BASE, NAPI_AUTO_LENGTH, Constructor, nullptr,
279 sizeof(baseDes) / sizeof(napi_property_descriptor), baseDes, &cons));
280 NAPI_CALL(env, napi_create_reference(env, cons, 1, &baseConstructor_));
281 return cons;
282 }
283
InitPixelMapDrawable(napi_env env)284 napi_value JsDrawableDescriptor::InitPixelMapDrawable(napi_env env)
285 {
286 napi_value cons = nullptr;
287 napi_property_descriptor pixelDes[] = {
288 DECLARE_NAPI_FUNCTION("getPixelMap", GetPixelMap),
289 };
290 NAPI_CALL(env, napi_define_class(env, DRAWABLE_PIXELMAP, NAPI_AUTO_LENGTH, PixelMapConstructor, nullptr,
291 sizeof(pixelDes) / sizeof(napi_property_descriptor), pixelDes, &cons));
292 NAPI_CALL(env, napi_create_reference(env, cons, 1, &pixelMapConstructor_));
293 return cons;
294 }
295
InitLayeredDrawable(napi_env env)296 napi_value JsDrawableDescriptor::InitLayeredDrawable(napi_env env)
297 {
298 napi_value cons = nullptr;
299 napi_property_descriptor layeredDes[] = {
300 DECLARE_NAPI_FUNCTION("getPixelMap", GetPixelMap),
301 DECLARE_NAPI_FUNCTION("getForeground", GetForeground),
302 DECLARE_NAPI_FUNCTION("getBackground", GetBackground),
303 DECLARE_NAPI_FUNCTION("getMask", GetMask),
304 DECLARE_NAPI_STATIC_FUNCTION("getMaskClipPath", GetMaskClipPath),
305 };
306 NAPI_CALL(env, napi_define_class(env, DRAWABLE_LAYERED, NAPI_AUTO_LENGTH, LayeredConstructor, nullptr,
307 sizeof(layeredDes) / sizeof(napi_property_descriptor), layeredDes, &cons));
308 NAPI_CALL(env, napi_create_reference(env, cons, 1, &layeredConstructor_));
309 return cons;
310 }
311
InitAnimatedDrawable(napi_env env)312 napi_value JsDrawableDescriptor::InitAnimatedDrawable(napi_env env)
313 {
314 napi_value cons = nullptr;
315 napi_property_descriptor animatedDes[] = {
316 DECLARE_NAPI_FUNCTION("getPixelMap", GetPixelMap),
317 };
318 NAPI_CALL(env, napi_define_class(env, DRAWABLE_ANIMATED, NAPI_AUTO_LENGTH, AnimatedConstructor, nullptr,
319 sizeof(animatedDes) / sizeof(napi_property_descriptor), animatedDes, &cons));
320 NAPI_CALL(env, napi_create_reference(env, cons, 1, &animatedConstructor_));
321 return cons;
322 }
323
ToNapi(napi_env env,DrawableDescriptor * drawable,DrawableDescriptor::DrawableType type)324 napi_value JsDrawableDescriptor::ToNapi(
325 napi_env env, DrawableDescriptor* drawable, DrawableDescriptor::DrawableType type)
326 {
327 if (!drawable) {
328 return nullptr;
329 }
330 if (!baseConstructor_ || !layeredConstructor_ || !animatedConstructor_ || !pixelMapConstructor_) {
331 // init js class constructor by importing module manually
332 napi_value globalValue;
333 napi_get_global(env, &globalValue);
334 napi_value func;
335 napi_get_named_property(env, globalValue, "requireNapi", &func);
336
337 napi_value module;
338 napi_create_string_utf8(env, MODULE_NAME, NAPI_AUTO_LENGTH, &module);
339 napi_value returnValue;
340 napi_call_function(env, globalValue, func, 1, &module, &returnValue);
341 }
342
343 napi_value constructor = nullptr;
344 napi_value result = nullptr;
345 napi_status status;
346 switch (type) {
347 case DrawableDescriptor::DrawableType::ANIMATED:
348 status = napi_get_reference_value(env, animatedConstructor_, &constructor);
349 break;
350 case DrawableDescriptor::DrawableType::LAYERED:
351 status = napi_get_reference_value(env, layeredConstructor_, &constructor);
352 break;
353 case DrawableDescriptor::DrawableType::BASE:
354 status = napi_get_reference_value(env, baseConstructor_, &constructor);
355 break;
356 case DrawableDescriptor::DrawableType::PIXELMAP:
357 status = napi_get_reference_value(env, pixelMapConstructor_, &constructor);
358 break;
359 default:
360 status = napi_status::napi_invalid_arg;
361 break;
362 }
363 if (status == napi_status::napi_ok) {
364 NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &result));
365 NAPI_CALL(env, napi_wrap(env, result, drawable, Destructor, nullptr, nullptr));
366 } else {
367 HILOGI("create reference failed, drawable constructor is null");
368 }
369
370 return result;
371 }
372
GetPixelMap(napi_env env,napi_callback_info info)373 napi_value JsDrawableDescriptor::GetPixelMap(napi_env env, napi_callback_info info)
374 {
375 napi_escapable_handle_scope scope = nullptr;
376 napi_open_escapable_handle_scope(env, &scope);
377 napi_value thisVar = nullptr;
378 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
379 void* native = nullptr;
380 napi_unwrap(env, thisVar, &native);
381 auto* drawable = reinterpret_cast<DrawableDescriptor*>(native);
382 auto pixmap = drawable->GetPixelMap();
383
384 napi_value result = Media::PixelMapNapi::CreatePixelMap(env, pixmap);
385 napi_escape_handle(env, scope, result, &result);
386 napi_close_escapable_handle_scope(env, scope);
387 return result;
388 }
389
GetForeground(napi_env env,napi_callback_info info)390 napi_value JsDrawableDescriptor::GetForeground(napi_env env, napi_callback_info info)
391 {
392 napi_escapable_handle_scope scope = nullptr;
393 napi_open_escapable_handle_scope(env, &scope);
394 napi_value thisVar = nullptr;
395 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
396 void* native = nullptr;
397 napi_unwrap(env, thisVar, &native);
398 auto* drawable = reinterpret_cast<LayeredDrawableDescriptor*>(native);
399 if (!drawable) {
400 return nullptr;
401 }
402
403 auto foreground = drawable->GetForeground();
404 napi_value result = ToNapi(env, foreground.release(), DrawableDescriptor::DrawableType::BASE);
405 napi_escape_handle(env, scope, result, &result);
406 napi_close_escapable_handle_scope(env, scope);
407 return result;
408 }
409
GetBackground(napi_env env,napi_callback_info info)410 napi_value JsDrawableDescriptor::GetBackground(napi_env env, napi_callback_info info)
411 {
412 napi_escapable_handle_scope scope = nullptr;
413 napi_open_escapable_handle_scope(env, &scope);
414 napi_value thisVar = nullptr;
415 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
416 void* native = nullptr;
417 napi_unwrap(env, thisVar, &native);
418 auto* drawable = reinterpret_cast<LayeredDrawableDescriptor*>(native);
419 if (!drawable) {
420 return nullptr;
421 }
422
423 auto background = drawable->GetBackground();
424 napi_value result = ToNapi(env, background.release(), DrawableDescriptor::DrawableType::BASE);
425 napi_escape_handle(env, scope, result, &result);
426 napi_close_escapable_handle_scope(env, scope);
427 return result;
428 }
429
GetMask(napi_env env,napi_callback_info info)430 napi_value JsDrawableDescriptor::GetMask(napi_env env, napi_callback_info info)
431 {
432 napi_escapable_handle_scope scope = nullptr;
433 napi_open_escapable_handle_scope(env, &scope);
434 napi_value thisVar = nullptr;
435 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
436 void* native = nullptr;
437 napi_unwrap(env, thisVar, &native);
438 auto* drawable = reinterpret_cast<LayeredDrawableDescriptor*>(native);
439 if (!drawable) {
440 return nullptr;
441 }
442
443 auto mask = drawable->GetMask();
444 napi_value result = ToNapi(env, mask.release(), DrawableDescriptor::DrawableType::BASE);
445 napi_escape_handle(env, scope, result, &result);
446 napi_close_escapable_handle_scope(env, scope);
447 return result;
448 }
449
GetMaskClipPath(napi_env env,napi_callback_info info)450 napi_value JsDrawableDescriptor::GetMaskClipPath(napi_env env, napi_callback_info info)
451 {
452 auto path = OHOS::Ace::Napi::LayeredDrawableDescriptor::GetStaticMaskClipPath();
453 napi_value result = nullptr;
454 if (napi_ok != napi_create_string_utf8(env, path.c_str(), NAPI_AUTO_LENGTH, &result)) {
455 HILOGI("JsDrawableDescriptor Failed");
456 }
457 return result;
458 }
459
Export(napi_env env,napi_value exports)460 napi_value JsDrawableDescriptor::Export(napi_env env, napi_value exports)
461 {
462 // export base class
463 napi_value cons = InitDrawable(env);
464 NAPI_CALL(env, napi_set_named_property(env, exports, DRAWABLE_BASE, cons));
465
466 cons = InitPixelMapDrawable(env);
467 NAPI_CALL(env, napi_set_named_property(env, exports, DRAWABLE_PIXELMAP, cons));
468
469 // export child class
470 cons = InitLayeredDrawable(env);
471 NAPI_CALL(env, napi_set_named_property(env, exports, DRAWABLE_LAYERED, cons));
472
473 // export child class
474 cons = InitAnimatedDrawable(env);
475 NAPI_CALL(env, napi_set_named_property(env, exports, DRAWABLE_ANIMATED, cons));
476
477 return exports;
478 }
479 } // namespace OHOS::Ace::Napi
480