• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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