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