• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 "image_creator_napi.h"
17 #include <uv.h>
18 #include "media_errors.h"
19 #include "hilog/log.h"
20 #include "image_napi_utils.h"
21 #include "image_creator_context.h"
22 #include "image_napi.h"
23 #include "image_creator_manager.h"
24 
25 using OHOS::HiviewDFX::HiLog;
26 using std::string;
27 using std::shared_ptr;
28 using std::unique_ptr;
29 using std::vector;
30 using std::make_shared;
31 using std::make_unique;
32 
33 namespace {
34     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "ImageCreatorNapi"};
35     constexpr int32_t TEST_WIDTH = 8192;
36     constexpr int32_t TEST_HEIGHT = 8;
37     constexpr int32_t TEST_FORMAT = 4;
38     constexpr int32_t TEST_CAPACITY = 8;
39 }
40 
41 namespace OHOS {
42 namespace Media {
43 static const std::string CLASS_NAME = "ImageCreator";
44 shared_ptr<ImageCreator> ImageCreatorNapi::staticInstance_ = nullptr;
45 thread_local napi_ref ImageCreatorNapi::sConstructor_ = nullptr;
46 static bool g_creatorTest = false;
47 static std::shared_ptr<ImageCreatorReleaseListener> g_listener = nullptr;
48 
49 const int ARGS0 = 0;
50 const int ARGS1 = 1;
51 const int ARGS2 = 2;
52 const int ARGS4 = 4;
53 const int PARAM0 = 0;
54 const int PARAM1 = 1;
55 const int PARAM2 = 2;
56 const int PARAM3 = 3;
57 
ImageCreatorNapi()58 ImageCreatorNapi::ImageCreatorNapi():env_(nullptr)
59 {}
60 
~ImageCreatorNapi()61 ImageCreatorNapi::~ImageCreatorNapi()
62 {
63     release();
64 }
65 
CommonCallbackRoutine(napi_env env,Contextc & context,const napi_value & valueParam,bool isRelease=true)66 static void CommonCallbackRoutine(napi_env env, Contextc &context, const napi_value &valueParam, bool isRelease = true)
67 {
68     IMAGE_FUNCTION_IN();
69     napi_value result[2] = {0};
70     napi_value retVal;
71     napi_value callback = nullptr;
72 
73     napi_get_undefined(env, &result[0]);
74     napi_get_undefined(env, &result[1]);
75 
76     if (context->status == SUCCESS) {
77         result[1] = valueParam;
78     }
79 
80     if (context->deferred) {
81         if (context->status == SUCCESS) {
82             napi_resolve_deferred(env, context->deferred, result[1]);
83         } else {
84             napi_reject_deferred(env, context->deferred, result[0]);
85         }
86     } else {
87         napi_create_uint32(env, context->status, &result[0]);
88         napi_get_reference_value(env, context->callbackRef, &callback);
89         napi_call_function(env, nullptr, callback, PARAM2, result, &retVal);
90     }
91 
92     if (isRelease) {
93         if (context->callbackRef != nullptr) {
94             napi_delete_reference(env, context->callbackRef);
95             context->callbackRef = nullptr;
96         }
97 
98         napi_delete_async_work(env, context->work);
99 
100         delete context;
101         context = nullptr;
102     }
103     IMAGE_FUNCTION_OUT();
104 }
105 
NativeRelease()106 void ImageCreatorNapi::NativeRelease()
107 {
108     if (imageCreator_ != nullptr) {
109         imageCreator_->~ImageCreator();
110         imageCreator_ = nullptr;
111     }
112 }
113 
Init(napi_env env,napi_value exports)114 napi_value ImageCreatorNapi::Init(napi_env env, napi_value exports)
115 {
116     IMAGE_FUNCTION_IN();
117     napi_property_descriptor props[] = {
118         DECLARE_NAPI_FUNCTION("dequeueImage", JsDequeueImage),
119         DECLARE_NAPI_FUNCTION("queueImage", JsQueueImage),
120         DECLARE_NAPI_FUNCTION("on", JsOn),
121         DECLARE_NAPI_FUNCTION("release", JsRelease),
122 
123 #ifdef IMAGE_DEBUG_FLAG
124         DECLARE_NAPI_GETTER("test", JsTest),
125 #endif
126         DECLARE_NAPI_GETTER("capacity", JsGetCapacity),
127         DECLARE_NAPI_GETTER("format", JsGetFormat),
128         DECLARE_NAPI_GETTER("size", JsGetSize),
129     };
130     napi_property_descriptor static_prop[] = {
131         DECLARE_NAPI_STATIC_FUNCTION("createImageCreator", JSCreateImageCreator),
132     };
133 
134     napi_value constructor = nullptr;
135     size_t props_count = IMG_ARRAY_SIZE(props);
136     size_t static_props_count = IMG_ARRAY_SIZE(static_prop);
137 
138     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
139         napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor,
140         nullptr, props_count, props, &constructor)),
141         nullptr,
142         IMAGE_ERR("define class fail")
143     );
144 
145     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
146         napi_create_reference(env, constructor, 1, &sConstructor_)),
147         nullptr,
148         IMAGE_ERR("create reference fail")
149     );
150 
151     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
152         napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor)),
153         nullptr,
154         IMAGE_ERR("set named property fail")
155     );
156     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
157         napi_define_properties(env, exports, static_props_count, static_prop)),
158         nullptr,
159         IMAGE_ERR("define properties fail")
160     );
161 
162     IMAGE_DEBUG("Init success");
163 
164     IMAGE_FUNCTION_OUT();
165     return exports;
166 }
167 
Constructor(napi_env env,napi_callback_info info)168 napi_value ImageCreatorNapi::Constructor(napi_env env, napi_callback_info info)
169 {
170     napi_value undefineVar = nullptr;
171     napi_get_undefined(env, &undefineVar);
172 
173     napi_status status;
174     napi_value thisVar = nullptr;
175 
176     IMAGE_FUNCTION_IN();
177     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
178     if (status == napi_ok && thisVar != nullptr) {
179         std::unique_ptr<ImageCreatorNapi> reference = std::make_unique<ImageCreatorNapi>();
180         if (reference != nullptr) {
181             reference->env_ = env;
182             if (!g_creatorTest) {
183                 reference->imageCreator_ = staticInstance_;
184             }
185             status = napi_wrap(env, thisVar, reinterpret_cast<void *>(reference.get()),
186                                ImageCreatorNapi::Destructor, nullptr, nullptr);
187             if (status == napi_ok) {
188                 IMAGE_FUNCTION_OUT();
189                 reference.release();
190                 return thisVar;
191             } else {
192                 IMAGE_ERR("Failure wrapping js to native napi");
193             }
194         }
195     }
196 
197     return undefineVar;
198 }
199 
Destructor(napi_env env,void * nativeObject,void * finalize)200 void ImageCreatorNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
201 {
202 }
203 
isTest(const int32_t * args,const int32_t len)204 static bool isTest(const int32_t* args, const int32_t len)
205 {
206     if ((args[PARAM0] ==  TEST_WIDTH) &&
207         (args[PARAM1] ==  TEST_HEIGHT) &&
208         (args[PARAM2] ==  TEST_FORMAT) &&
209         (args[PARAM3] ==  TEST_CAPACITY) &&
210         (len == ARGS4)) {
211         return true;
212     }
213     return false;
214 }
215 
JSCreateImageCreator(napi_env env,napi_callback_info info)216 napi_value ImageCreatorNapi::JSCreateImageCreator(napi_env env, napi_callback_info info)
217 {
218     napi_status status;
219     napi_value constructor = nullptr, result = nullptr, thisVar = nullptr;
220     size_t argc = ARGS4;
221     napi_value argv[ARGS4] = {0};
222     int32_t args[ARGS4] = {0};
223 
224     IMAGE_FUNCTION_IN();
225     napi_get_undefined(env, &result);
226 
227     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
228     if (status != napi_ok) {
229         std::string errMsg = "Invailed arg counts ";
230         return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
231             errMsg.append(std::to_string(argc)));
232     }
233 
234     if (argc != ARGS4) {
235         IMAGE_ERR("Invailed arg counts %{public}zu", argc);
236         return result;
237     }
238 
239     for (size_t i = PARAM0; i < argc; i++) {
240         napi_valuetype argvType = ImageNapiUtils::getType(env, argv[i]);
241         if (argvType != napi_number) {
242             std::string errMsg = "Invailed arg ";
243             return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
244                 errMsg.append(std::to_string(i)).append(" type ").append(std::to_string(argvType)));
245         }
246 
247         status = napi_get_value_int32(env, argv[i], &(args[i]));
248         if (status != napi_ok) {
249             std::string errMsg = "fail to get arg ";
250             return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
251                 errMsg.append(std::to_string(i)).append(" : ").append(std::to_string(status)));
252         }
253     }
254 
255     int32_t len = sizeof(args) / sizeof(args[PARAM0]);
256     if (isTest(args, len)) {
257         g_creatorTest = true;
258     }
259     status = napi_get_reference_value(env, sConstructor_, &constructor);
260     if (IMG_IS_OK(status)) {
261         if (!g_creatorTest) {
262             staticInstance_ = ImageCreator::CreateImageCreator(args[PARAM0],
263                 args[PARAM1], args[PARAM2], args[PARAM3]);
264         }
265         status = napi_new_instance(env, constructor, 0, nullptr, &result);
266         if (status == napi_ok) {
267             IMAGE_FUNCTION_OUT();
268             return result;
269         } else {
270             IMAGE_ERR("New instance could not be obtained");
271         }
272     }
273 
274     IMAGE_ERR("Failed to get reference of constructor");
275     return result;
276 }
277 
CheckArgs(const ImageCreatorCommonArgs & args)278 static bool CheckArgs(const ImageCreatorCommonArgs &args)
279 {
280     if (args.async != CreatorCallType::GETTER) {
281         if (args.queryArgs == nullptr) {
282             IMAGE_ERR("No query args function");
283             return false;
284         }
285     }
286 
287     if (args.async != CreatorCallType::ASYNC || args.asyncLater) {
288         if (args.nonAsyncBack == nullptr) {
289             IMAGE_ERR("No non async back function");
290             return false;
291         }
292     }
293     return true;
294 }
295 
PrepareOneArg(ImageCreatorCommonArgs & args,struct ImageCreatorInnerContext & ic)296 static bool PrepareOneArg(ImageCreatorCommonArgs &args, struct ImageCreatorInnerContext &ic)
297 {
298     if (ic.argc == ARGS1) {
299         auto argType = ImageNapiUtils::getType(args.env, ic.argv[PARAM0]);
300         if (argType == napi_function) {
301             napi_create_reference(args.env, ic.argv[PARAM0], ic.refCount, &(ic.context->callbackRef));
302         } else {
303             IMAGE_ERR("Unsupport arg 0 type: %{public}d", argType);
304             return false;
305         }
306     }
307 
308     if (ic.context->callbackRef == nullptr) {
309         napi_create_promise(args.env, &(ic.context->deferred), &(ic.result));
310     } else {
311         napi_get_undefined(args.env, &ic.result);
312     }
313     return true;
314 }
315 
JSCommonProcess(ImageCreatorCommonArgs & args)316 napi_value ImageCreatorNapi::JSCommonProcess(ImageCreatorCommonArgs &args)
317 {
318     IMAGE_FUNCTION_IN();
319     struct ImageCreatorInnerContext ic;
320     ic.argc = args.argc;
321     ic.argv.resize(ic.argc);
322     napi_get_undefined(args.env, &ic.result);
323 
324     IMG_NAPI_CHECK_RET(CheckArgs(args), ic.result);
325 
326     IMG_JS_ARGS(args.env, args.info, ic.status, ic.argc, &(ic.argv[0]), ic.thisVar);
327 
328     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(ic.status), ic.result, IMAGE_ERR("fail to napi_get_cb_info"));
329 
330     if (args.async != CreatorCallType::STATIC) {
331         ic.context = std::make_unique<ImageCreatorAsyncContext>();
332         if (ic.context == nullptr) {
333             return ic.result;
334         }
335         ic.status = napi_unwrap(args.env, ic.thisVar, reinterpret_cast<void**>(&(ic.context->constructor_)));
336 
337         IMG_NAPI_CHECK_RET_D(IMG_IS_READY(ic.status, ic.context->constructor_),
338             ic.result, IMAGE_ERR("fail to unwrap context"));
339 
340         if (ic.context->constructor_ == nullptr) {
341             return ic.result;
342         }
343         if (!g_creatorTest) {
344             ic.context->creator_ = ic.context->constructor_->imageCreator_;
345 
346             IMG_NAPI_CHECK_RET_D(IMG_IS_READY(ic.status, ic.context->creator_),
347                 ic.result, IMAGE_ERR("empty native creator"));
348         }
349     }
350     if (args.async != CreatorCallType::GETTER) {
351         if (!args.queryArgs(args, ic)) {
352             return ic.result;
353         }
354     }
355 
356     if (args.async == CreatorCallType::ASYNC) {
357         if (args.asyncLater) {
358             args.nonAsyncBack(args, ic);
359         } else {
360             napi_value _resource = nullptr;
361             napi_create_string_utf8((args.env), (args.name.c_str()), NAPI_AUTO_LENGTH, &_resource);
362             (ic.status) = napi_create_async_work(args.env, nullptr, _resource,
363                                                  ([](napi_env env, void *data) {}),
364                                                  (reinterpret_cast<napi_async_complete_callback>(args.callBack)),
365                                                  static_cast<void *>((ic.context).get()), &(ic.context->work));
366             napi_queue_async_work((args.env), (ic.context->work));
367             IMAGE_ERR("async success");
368             ic.context.release();
369         }
370     } else {
371         args.nonAsyncBack(args, ic);
372     }
373 
374     IMAGE_FUNCTION_OUT();
375     return ic.result;
376 }
377 
BuildJsSize(napi_env env,int32_t width,int32_t height)378 static napi_value BuildJsSize(napi_env env, int32_t width, int32_t height)
379 {
380     napi_value result = nullptr, sizeWith = nullptr, sizeHeight = nullptr;
381 
382     napi_create_object(env, &result);
383 
384     napi_create_int32(env, width, &sizeWith);
385     napi_set_named_property(env, result, "width", sizeWith);
386 
387     napi_create_int32(env, height, &sizeHeight);
388     napi_set_named_property(env, result, "height", sizeHeight);
389     return result;
390 }
391 
JsGetSize(napi_env env,napi_callback_info info)392 napi_value ImageCreatorNapi::JsGetSize(napi_env env, napi_callback_info info)
393 {
394     IMAGE_FUNCTION_IN();
395     ImageCreatorCommonArgs args = {
396         .env = env, .info = info,
397         .async = CreatorCallType::GETTER,
398     };
399     args.argc = ARGS0;
400 
401     args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
402         napi_get_undefined(args.env, &(ic.result));
403         if (g_creatorTest) {
404             ic.result = BuildJsSize(args.env, TEST_WIDTH, TEST_HEIGHT);
405             return true;
406         }
407         auto native = ic.context->constructor_->imageCreator_;
408         if (native == nullptr) {
409             IMAGE_ERR("Native instance is nullptr");
410             return false;
411         }
412 
413         if (native->iraContext_ == nullptr) {
414             IMAGE_ERR("Image creator context is nullptr");
415             return false;
416         }
417         ic.result = BuildJsSize(args.env,
418                                 native->iraContext_->GetWidth(),
419                                 native->iraContext_->GetHeight());
420         return true;
421     };
422 
423     return JSCommonProcess(args);
424 }
425 
JsGetCapacity(napi_env env,napi_callback_info info)426 napi_value ImageCreatorNapi::JsGetCapacity(napi_env env, napi_callback_info info)
427 {
428     IMAGE_FUNCTION_IN();
429     ImageCreatorCommonArgs args = {
430         .env = env, .info = info,
431         .async = CreatorCallType::GETTER,
432     };
433     args.argc = ARGS0;
434 
435     args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
436         napi_get_undefined(args.env, &(ic.result));
437         if (g_creatorTest) {
438             napi_create_int32(args.env, TEST_CAPACITY, &(ic.result));
439             return true;
440         }
441         auto native = ic.context->constructor_->imageCreator_;
442         if (native == nullptr) {
443             IMAGE_ERR("Native instance is nullptr");
444             return false;
445         }
446 
447         if (native->iraContext_ == nullptr) {
448             IMAGE_ERR("Image creator context is nullptr");
449             return false;
450         }
451         napi_create_int32(args.env, native->iraContext_->GetCapicity(), &(ic.result));
452         return true;
453     };
454 
455     return JSCommonProcess(args);
456 }
457 
JsGetFormat(napi_env env,napi_callback_info info)458 napi_value ImageCreatorNapi::JsGetFormat(napi_env env, napi_callback_info info)
459 {
460     IMAGE_FUNCTION_IN();
461     ImageCreatorCommonArgs args = {
462         .env = env, .info = info,
463         .async = CreatorCallType::GETTER,
464     };
465     args.argc = ARGS0;
466 
467     args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
468         napi_get_undefined(args.env, &(ic.result));
469         if (g_creatorTest) {
470             napi_create_int32(args.env, TEST_FORMAT, &(ic.result));
471             return true;
472         }
473         auto native = ic.context->constructor_->imageCreator_;
474         if (native == nullptr) {
475             IMAGE_ERR("Native instance is nullptr");
476             return false;
477         }
478 
479         if (native->iraContext_ == nullptr) {
480             IMAGE_ERR("Image creator context is nullptr");
481             return false;
482         }
483         napi_create_int32(args.env, native->iraContext_->GetFormat(), &(ic.result));
484         return true;
485     };
486 
487     return JSCommonProcess(args);
488 }
489 
490 #ifdef IMAGE_DEBUG_FLAG
TestAcquireBuffer(OHOS::sptr<OHOS::Surface> & creatorSurface,int32_t & fence,int64_t & timestamp,OHOS::Rect & damage,std::shared_ptr<ImageCreator> imageCreator)491 static void TestAcquireBuffer(OHOS::sptr<OHOS::Surface> &creatorSurface, int32_t &fence,
492     int64_t &timestamp, OHOS::Rect &damage, std::shared_ptr<ImageCreator> imageCreator)
493 {
494     OHOS::sptr<OHOS::SurfaceBuffer> buffer;
495     if (creatorSurface == nullptr) {
496         IMAGE_ERR("Creator Surface is nullptr");
497         return;
498     }
499     creatorSurface->AcquireBuffer(buffer, fence, timestamp, damage);
500     if (buffer == nullptr) {
501         IMAGE_ERR("Creator Surface is nullptr");
502         return;
503     }
504     IMAGE_ERR("...AcquireBuffer...");
505     int32_t *p = static_cast<int32_t *>(buffer->GetVirAddr());
506     IMAGE_ERR("AcquireBuffer %{public}p", p);
507     InitializationOptions opts;
508     opts.size.width = creatorSurface->GetDefaultWidth();
509     opts.size.height = creatorSurface->GetDefaultHeight();
510     opts.pixelFormat = OHOS::Media::PixelFormat::BGRA_8888;
511     opts.alphaType = OHOS::Media::AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
512     opts.scaleMode = OHOS::Media::ScaleMode::CENTER_CROP;
513     opts.editable = true;
514     imageCreator->SaveSenderBufferAsImage(buffer, opts);
515 }
516 
DoTest(std::shared_ptr<ImageCreator> imageCreator)517 static void DoTest(std::shared_ptr<ImageCreator> imageCreator)
518 {
519     if (imageCreator == nullptr || imageCreator->iraContext_ == nullptr) {
520         IMAGE_ERR("image creator is nullptr");
521         return;
522     }
523     std::string creatorKey = imageCreator->iraContext_->GetCreatorKey();
524     IMAGE_ERR("CreatorKey = %{public}s", creatorKey.c_str());
525     OHOS::sptr<OHOS::Surface> creatorSurface = ImageCreator::getSurfaceById(creatorKey);
526     IMAGE_ERR("getDefaultWidth = %{public}d", creatorSurface->GetDefaultWidth());
527     IMAGE_ERR("getDefaultHeight = %{public}d", creatorSurface->GetDefaultHeight());
528     int32_t flushFence = 0;
529     int64_t timestamp = 0;
530     OHOS::Rect damage = {};
531     IMAGE_ERR("TestAcquireBuffer 1...");
532     TestAcquireBuffer(creatorSurface, flushFence, timestamp, damage, imageCreator);
533 }
534 static void DoCallBackAfterWork(uv_work_t *work, int status);
JsTest(napi_env env,napi_callback_info info)535 napi_value ImageCreatorNapi::JsTest(napi_env env, napi_callback_info info)
536 {
537     IMAGE_FUNCTION_IN();
538     ImageCreatorCommonArgs args = {
539         .env = env, .info = info,
540         .async = CreatorCallType::GETTER,
541     };
542     args.argc = ARGS0;
543 
544     args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
545         DoTest(ic.context->creator_);
546         if (g_creatorTest && g_listener != nullptr) {
547             unique_ptr<uv_work_t> work = make_unique<uv_work_t>();
548             work->data = reinterpret_cast<void *>(g_listener->context.get());
549             DoCallBackAfterWork(work.release(), ARGS0);
550             g_listener = nullptr;
551         }
552         return true;
553     };
554 
555     return JSCommonProcess(args);
556 }
557 #endif
558 
JsDequeueImage(napi_env env,napi_callback_info info)559 napi_value ImageCreatorNapi::JsDequeueImage(napi_env env, napi_callback_info info)
560 {
561     IMAGE_FUNCTION_IN();
562     ImageCreatorCommonArgs args = {
563         .env = env, .info = info,
564         .async = CreatorCallType::ASYNC,
565         .name = "JsDequeueImage",
566         .callBack = nullptr,
567         .argc = ARGS1,
568         .queryArgs = PrepareOneArg,
569     };
570 
571     args.callBack = [](napi_env env, napi_status status, Contextc context) {
572         IMAGE_LINE_IN();
573         napi_value result = nullptr;
574         napi_get_undefined(env, &result);
575         if (g_creatorTest) {
576             result = ImageNapi::Create(env, nullptr);
577             context->status = SUCCESS;
578             CommonCallbackRoutine(env, context, result);
579             return;
580         }
581 
582         auto native = context->constructor_->imageCreator_;
583         if (native == nullptr) {
584             IMAGE_ERR("Native instance is nullptr");
585             context->status = ERR_IMAGE_INIT_ABNORMAL;
586         } else {
587             auto surfacebuffer = native->DequeueImage();
588             result = ImageNapi::CreateBufferToImage(env, surfacebuffer, native);
589             if (result == nullptr) {
590                 IMAGE_ERR("ImageNapi Create failed");
591                 context->status = ERR_IMAGE_INIT_ABNORMAL;
592                 napi_get_undefined(env, &result);
593             } else {
594                 context->status = SUCCESS;
595             }
596         }
597 
598         IMAGE_LINE_OUT();
599         CommonCallbackRoutine(env, context, result);
600     };
601 
602     return JSCommonProcess(args);
603 }
604 
JsQueueArgs(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<ImageNapi> & imageNapi_,napi_ref * callbackRef)605 static bool JsQueueArgs(napi_env env, size_t argc, napi_value* argv,
606                         std::shared_ptr<ImageNapi> &imageNapi_, napi_ref* callbackRef)
607 {
608     if (argc == ARGS1 || argc == ARGS2) {
609         auto argType0 = ImageNapiUtils::getType(env, argv[PARAM0]);
610         if (argType0 == napi_object) {
611             imageNapi_ = ImageNapi::GetImageSource(env, argv[PARAM0]);
612             if (imageNapi_ == nullptr) {
613                 ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
614                     "Could not get queue type object");
615                 return false;
616             }
617         } else {
618             std::string errMsg = "Unsupport args0 type: ";
619             ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
620                 errMsg.append(std::to_string(argType0)));
621             return false;
622         }
623         if (argc == ARGS2) {
624         auto argType1 = ImageNapiUtils::getType(env, argv[PARAM1]);
625         if (argType1 == napi_function) {
626             int32_t refCount = 1;
627             napi_create_reference(env, argv[PARAM1], refCount, callbackRef);
628         } else {
629             std::string errMsg = "Unsupport args1 type: ";
630             ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
631                 errMsg.append(std::to_string(argType1)));
632             return false;
633         }
634     }
635     } else {
636         std::string errMsg = "Invailed argc: ";
637         ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
638             errMsg.append(std::to_string(argc)));
639         return false;
640     }
641     return true;
642 }
643 
JsQueueImageCallBack(napi_env env,napi_status status,ImageCreatorAsyncContext * context)644 void ImageCreatorNapi::JsQueueImageCallBack(napi_env env, napi_status status,
645                                             ImageCreatorAsyncContext* context)
646 {
647     IMAGE_FUNCTION_IN();
648     napi_value result = nullptr;
649     napi_get_undefined(env, &result);
650     if (g_creatorTest) {
651         context->status = SUCCESS;
652         CommonCallbackRoutine(env, context, result);
653         return;
654     }
655 
656     auto native = context->constructor_->imageCreator_;
657     if (native == nullptr) {
658         IMAGE_ERR("Native instance is nullptr");
659         context->status = ERR_IMAGE_INIT_ABNORMAL;
660     } else {
661         if (SUCCESS != context->imageNapi_->CombineComponentsIntoSurface()) {
662             IMAGE_ERR("JsQueueImageCallBack: try to combine componests");
663         }
664         auto surfacebuffer = context->imageNapi_->sSurfaceBuffer_;
665         native->QueueImage(surfacebuffer);
666         context->status = SUCCESS;
667     }
668     IMAGE_LINE_OUT();
669     CommonCallbackRoutine(env, context, result);
670 }
671 
JsQueueImage(napi_env env,napi_callback_info info)672 napi_value ImageCreatorNapi::JsQueueImage(napi_env env, napi_callback_info info)
673 {
674     IMAGE_FUNCTION_IN();
675     napi_value result = nullptr, thisVar = nullptr;
676     size_t argc = ARGS2;
677     napi_value argv[ARGS2] = {0};
678 
679     napi_get_undefined(env, &result);
680 
681     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
682     if (status != napi_ok) {
683         IMAGE_ERR("fail to napi_get_cb_info %{public}d", status);
684         return result;
685     }
686 
687     unique_ptr<ImageCreatorAsyncContext> context = make_unique<ImageCreatorAsyncContext>();
688     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
689     if (status != napi_ok || context->constructor_ == nullptr) {
690         IMAGE_ERR("fail to unwrap constructor_ %{public}d", status);
691         return result;
692     }
693 
694     if (!JsQueueArgs(env, argc, argv, context->imageNapi_, &(context->callbackRef))) {
695         return result;
696     }
697     if (context->callbackRef == nullptr) {
698         napi_create_promise(env, &(context->deferred), &result);
699     }
700 
701     napi_value resource = nullptr;
702     napi_create_string_utf8(env, "JsQueueImage", NAPI_AUTO_LENGTH, &resource);
703     status = napi_create_async_work(
704         env, nullptr, resource, [](napi_env env, void* data) {},
705         reinterpret_cast<napi_async_complete_callback>(JsQueueImageCallBack),
706         static_cast<void *>(context.get()), &(context->work));
707     if (status != napi_ok) {
708         IMAGE_ERR("fail to create async work %{public}d", status);
709         return result;
710     }
711 
712     status = napi_queue_async_work(env, context->work);
713     if (status != napi_ok) {
714         IMAGE_ERR("fail to queue async work %{public}d", status);
715         return result;
716     }
717     context.release();
718 
719     IMAGE_FUNCTION_OUT();
720     return result;
721 }
722 
CheckOnParam0(napi_env env,napi_value value,const std::string & refStr)723 static bool CheckOnParam0(napi_env env, napi_value value, const std::string& refStr)
724 {
725     bool ret = true;
726     size_t bufLength = 0;
727     napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &bufLength);
728     if (status != napi_ok || bufLength > PATH_MAX) {
729         return false;
730     }
731 
732     char *buffer = static_cast<char *>(malloc((bufLength + 1) * sizeof(char)));
733     if (buffer == nullptr) {
734         return false;
735     }
736 
737     status = napi_get_value_string_utf8(env, value, buffer, bufLength + 1, &bufLength);
738     if (status != napi_ok) {
739         free(buffer);
740         return false;
741     }
742 
743     std::string strValue = buffer;
744     if (strValue.compare(refStr) != 0) {
745         IMAGE_ERR("strValue is %{public}s", strValue.c_str());
746         ret = false;
747     }
748 
749     strValue = "";
750     free(buffer);
751     buffer = nullptr;
752     return ret;
753 }
754 
JsOnQueryArgs(ImageCreatorCommonArgs & args,ImageCreatorInnerContext & ic)755 static bool JsOnQueryArgs(ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic)
756 {
757     if (ic.argc == ARGS2) {
758         auto argType0 = ImageNapiUtils::getType(args.env, ic.argv[PARAM0]);
759         auto argType1 = ImageNapiUtils::getType(args.env, ic.argv[PARAM1]);
760         if (argType0 == napi_string && argType1 == napi_function) {
761             if (!ImageNapiUtils::GetUtf8String(args.env, ic.argv[PARAM0], ic.onType)) {
762                 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
763                     "Could not get On type string");
764                 return false;
765             }
766 
767             if (!CheckOnParam0(args.env, ic.argv[PARAM0], "imageRelease")) {
768                 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
769                     "Unsupport PARAM0");
770                 return false;
771             }
772 
773             napi_create_reference(args.env, ic.argv[PARAM1], ic.refCount, &(ic.context->callbackRef));
774         } else {
775             std::string errMsg = "Unsupport args type: ";
776             ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
777                 errMsg.append(std::to_string(argType0)).append(std::to_string(argType1)));
778             return false;
779         }
780     } else {
781         std::string errMsg = "Invailed argc: ";
782         ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
783             errMsg.append(std::to_string(ic.argc)));
784         return false;
785     }
786 
787     napi_get_undefined(args.env, &ic.result);
788     return true;
789 }
DoCallBackAfterWork(uv_work_t * work,int status)790 static void DoCallBackAfterWork(uv_work_t *work, int status)
791 {
792     IMAGE_LINE_IN();
793     Contextc context = reinterpret_cast<Contextc>(work->data);
794     if (context == nullptr) {
795         IMAGE_ERR("context is empty");
796     } else {
797         napi_value result[PARAM2] = {0};
798         napi_value retVal, callback = nullptr;
799         if (context->env != nullptr && context->callbackRef != nullptr) {
800             napi_handle_scope scope = nullptr;
801             napi_open_handle_scope(context->env, &scope);
802             if (scope == nullptr) {
803                 return;
804             }
805             napi_create_uint32(context->env, SUCCESS, &result[0]);
806             napi_get_undefined(context->env, &result[1]);
807             napi_get_reference_value(context->env, context->callbackRef, &callback);
808             if (callback != nullptr) {
809                 napi_call_function(context->env, nullptr, callback, PARAM2, result, &retVal);
810             } else {
811                 IMAGE_ERR("napi_get_reference_value callback is empty");
812             }
813             napi_close_handle_scope(context->env, scope);
814         } else {
815             IMAGE_ERR("env or callbackRef is empty");
816         }
817     }
818     delete work;
819     IMAGE_LINE_OUT();
820 }
DoCallBack(shared_ptr<ImageCreatorAsyncContext> context,string name,CompleteCreatorCallback callBack)821 void ImageCreatorNapi::DoCallBack(shared_ptr<ImageCreatorAsyncContext> context,
822     string name, CompleteCreatorCallback callBack)
823 {
824     IMAGE_FUNCTION_IN();
825     if (context == nullptr || context->env == nullptr) {
826         IMAGE_ERR("gContext or env is empty");
827         return;
828     }
829 
830     uv_loop_s *loop = nullptr;
831     napi_get_uv_event_loop(context->env, &loop);
832     if (loop == nullptr) {
833         IMAGE_ERR("napi_get_uv_event_loop failed");
834         return;
835     }
836 
837     unique_ptr<uv_work_t> work = make_unique<uv_work_t>();
838     if (work == nullptr) {
839         IMAGE_ERR("DoCallBack: No memory");
840         return;
841     }
842 
843     work->data = reinterpret_cast<void *>(context.get());
844     int ret = uv_queue_work(loop, work.get(), [] (uv_work_t *work) {}, DoCallBackAfterWork);
845     if (ret != 0) {
846         IMAGE_ERR("Failed to execute DoCallBack work queue");
847     } else {
848         work.release();
849     }
850     IMAGE_FUNCTION_OUT();
851 }
852 
JsOn(napi_env env,napi_callback_info info)853 napi_value ImageCreatorNapi::JsOn(napi_env env, napi_callback_info info)
854 {
855     IMAGE_FUNCTION_IN();
856     ImageCreatorCommonArgs args = {
857         .env = env, .info = info,
858         .async = CreatorCallType::ASYNC,
859         .name = "JsOn",
860     };
861     args.argc = ARGS2;
862     args.asyncLater = true;
863     args.queryArgs = JsOnQueryArgs;
864     args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
865         IMAGE_LINE_IN();
866         if (g_creatorTest) {
867             g_listener = make_shared<ImageCreatorReleaseListener>();
868             g_listener->context = std::move(ic.context);
869             g_listener->context->env = args.env;
870             g_listener->name = args.name;
871             return true;
872         }
873         napi_get_undefined(args.env, &(ic.result));
874 
875         auto native = ic.context->constructor_->imageCreator_;
876         if (native == nullptr) {
877             IMAGE_ERR("Native instance is nullptr");
878             ic.context->status = ERR_IMAGE_INIT_ABNORMAL;
879             return false;
880         }
881         shared_ptr<ImageCreatorReleaseListener> listener = make_shared<ImageCreatorReleaseListener>();
882         listener->context = std::move(ic.context);
883         listener->context->env = args.env;
884         listener->name = args.name;
885 
886         IMAGE_ERR("listener is %{public}p", listener.get());
887 
888         native->RegisterBufferReleaseListener((std::shared_ptr<SurfaceBufferReleaseListener> &)listener);
889 
890         IMAGE_LINE_OUT();
891         return true;
892     };
893 
894     return JSCommonProcess(args);
895 }
896 
JsRelease(napi_env env,napi_callback_info info)897 napi_value ImageCreatorNapi::JsRelease(napi_env env, napi_callback_info info)
898 {
899     IMAGE_FUNCTION_IN();
900     ImageCreatorCommonArgs args = {
901         .env = env, .info = info,
902         .async = CreatorCallType::ASYNC,
903         .name = "JsRelease",
904         .callBack = nullptr,
905         .argc = ARGS1,
906         .queryArgs = PrepareOneArg,
907     };
908 
909     args.callBack = [](napi_env env, napi_status status, Contextc context) {
910         IMAGE_LINE_IN();
911         napi_value result = nullptr;
912         napi_get_undefined(env, &result);
913 
914         context->constructor_->NativeRelease();
915         context->status = SUCCESS;
916 
917         IMAGE_LINE_OUT();
918         CommonCallbackRoutine(env, context, result);
919     };
920 
921     return JSCommonProcess(args);
922 }
923 
release()924 void ImageCreatorNapi::release()
925 {
926     if (!isRelease) {
927         NativeRelease();
928         isRelease = true;
929     }
930 }
931 }  // namespace Media
932 }  // namespace OHOS
933