• 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 }
JSCreateImageCreator(napi_env env,napi_callback_info info)215 napi_value ImageCreatorNapi::JSCreateImageCreator(napi_env env, napi_callback_info info)
216 {
217     napi_status status;
218     napi_value constructor = nullptr, result = nullptr, thisVar = nullptr;
219     size_t argc = ARGS4;
220     napi_value argv[ARGS4] = {0};
221     int32_t args[ARGS4] = {0};
222 
223     IMAGE_FUNCTION_IN();
224     napi_get_undefined(env, &result);
225     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
226     if (status != napi_ok || (argc != ARGS4)) {
227         std::string errMsg = "Invailed arg counts ";
228         return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
229             errMsg.append(std::to_string(argc)));
230     }
231     for (size_t i = PARAM0; i < argc; i++) {
232         napi_valuetype argvType = ImageNapiUtils::getType(env, argv[i]);
233         if (argvType != napi_number) {
234             std::string errMsg = "Invailed arg ";
235             return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
236                 errMsg.append(std::to_string(i)).append(" type ").append(std::to_string(argvType)));
237         }
238 
239         status = napi_get_value_int32(env, argv[i], &(args[i]));
240         if (status != napi_ok) {
241             std::string errMsg = "fail to get arg ";
242             return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
243                 errMsg.append(std::to_string(i)).append(" : ").append(std::to_string(status)));
244         }
245     }
246     int32_t len = sizeof(args) / sizeof(args[PARAM0]);
247     if (isTest(args, len)) {
248         g_creatorTest = true;
249     }
250     status = napi_get_reference_value(env, sConstructor_, &constructor);
251     if (IMG_IS_OK(status)) {
252         if (!g_creatorTest) {
253             staticInstance_ = ImageCreator::CreateImageCreator(args[PARAM0],
254                 args[PARAM1], args[PARAM2], args[PARAM3]);
255         }
256         status = napi_new_instance(env, constructor, 0, nullptr, &result);
257         if (status == napi_ok) {
258             IMAGE_FUNCTION_OUT();
259             return result;
260         } else {
261             IMAGE_ERR("New instance could not be obtained");
262         }
263     }
264     return result;
265 }
266 
CheckArgs(const ImageCreatorCommonArgs & args)267 static bool CheckArgs(const ImageCreatorCommonArgs &args)
268 {
269     if (args.async != CreatorCallType::GETTER) {
270         if (args.queryArgs == nullptr) {
271             IMAGE_ERR("No query args function");
272             return false;
273         }
274     }
275 
276     if (args.async != CreatorCallType::ASYNC || args.asyncLater) {
277         if (args.nonAsyncBack == nullptr) {
278             IMAGE_ERR("No non async back function");
279             return false;
280         }
281     }
282     return true;
283 }
284 
PrepareOneArg(ImageCreatorCommonArgs & args,struct ImageCreatorInnerContext & ic)285 static bool PrepareOneArg(ImageCreatorCommonArgs &args, struct ImageCreatorInnerContext &ic)
286 {
287     if (ic.argc == ARGS1) {
288         auto argType = ImageNapiUtils::getType(args.env, ic.argv[PARAM0]);
289         if (argType == napi_function) {
290             napi_create_reference(args.env, ic.argv[PARAM0], ic.refCount, &(ic.context->callbackRef));
291         } else {
292             IMAGE_ERR("Unsupport arg 0 type: %{public}d", argType);
293             return false;
294         }
295     }
296 
297     if (ic.context->callbackRef == nullptr) {
298         napi_create_promise(args.env, &(ic.context->deferred), &(ic.result));
299     } else {
300         napi_get_undefined(args.env, &ic.result);
301     }
302     return true;
303 }
304 
JSCommonProcess(ImageCreatorCommonArgs & args)305 napi_value ImageCreatorNapi::JSCommonProcess(ImageCreatorCommonArgs &args)
306 {
307     IMAGE_FUNCTION_IN();
308     struct ImageCreatorInnerContext ic;
309     ic.argc = args.argc;
310     ic.argv.resize(ic.argc);
311     napi_get_undefined(args.env, &ic.result);
312     IMG_NAPI_CHECK_RET(CheckArgs(args), ic.result);
313 
314     IMG_JS_ARGS(args.env, args.info, ic.status, ic.argc, &(ic.argv[0]), ic.thisVar);
315 
316     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(ic.status), ic.result, IMAGE_ERR("fail to napi_get_cb_info"));
317 
318     if (args.async != CreatorCallType::STATIC) {
319         ic.context = std::make_unique<ImageCreatorAsyncContext>();
320         if (ic.context == nullptr) {
321             return ic.result;
322         }
323         ic.status = napi_unwrap(args.env, ic.thisVar, reinterpret_cast<void**>(&(ic.context->constructor_)));
324 
325         IMG_NAPI_CHECK_RET_D(IMG_IS_READY(ic.status, ic.context->constructor_),
326             ic.result, IMAGE_ERR("fail to unwrap context"));
327         if (ic.context->constructor_ == nullptr) {
328             return ic.result;
329         }
330         if (!g_creatorTest) {
331             ic.context->creator_ = ic.context->constructor_->imageCreator_;
332 
333             IMG_NAPI_CHECK_RET_D(IMG_IS_READY(ic.status, ic.context->creator_),
334                 ic.result, IMAGE_ERR("empty native creator"));
335         }
336     }
337     if (args.async != CreatorCallType::GETTER) {
338         if (!args.queryArgs(args, ic)) {
339             return ic.result;
340         }
341     }
342     if (args.async == CreatorCallType::ASYNC) {
343         if (args.asyncLater) {
344             args.nonAsyncBack(args, ic);
345         } else {
346             napi_value _resource = nullptr;
347             napi_create_string_utf8((args.env), (args.name.c_str()), NAPI_AUTO_LENGTH, &_resource);
348             (ic.status) = napi_create_async_work(args.env, nullptr, _resource,
349                                                  ([](napi_env env, void *data) {}),
350                                                  (reinterpret_cast<napi_async_complete_callback>(args.callBack)),
351                                                  static_cast<void *>((ic.context).get()), &(ic.context->work));
352             napi_queue_async_work((args.env), (ic.context->work));
353             IMAGE_ERR("async success");
354             ic.context.release();
355         }
356     } else {
357         args.nonAsyncBack(args, ic);
358     }
359     IMAGE_FUNCTION_OUT();
360     return ic.result;
361 }
362 
BuildJsSize(napi_env env,int32_t width,int32_t height)363 static napi_value BuildJsSize(napi_env env, int32_t width, int32_t height)
364 {
365     napi_value result = nullptr, sizeWith = nullptr, sizeHeight = nullptr;
366 
367     napi_create_object(env, &result);
368 
369     napi_create_int32(env, width, &sizeWith);
370     napi_set_named_property(env, result, "width", sizeWith);
371 
372     napi_create_int32(env, height, &sizeHeight);
373     napi_set_named_property(env, result, "height", sizeHeight);
374     return result;
375 }
376 
JsGetSize(napi_env env,napi_callback_info info)377 napi_value ImageCreatorNapi::JsGetSize(napi_env env, napi_callback_info info)
378 {
379     IMAGE_FUNCTION_IN();
380     ImageCreatorCommonArgs args = {
381         .env = env, .info = info,
382         .async = CreatorCallType::GETTER,
383     };
384     args.argc = ARGS0;
385 
386     args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
387         napi_get_undefined(args.env, &(ic.result));
388         if (g_creatorTest) {
389             ic.result = BuildJsSize(args.env, TEST_WIDTH, TEST_HEIGHT);
390             return true;
391         }
392 
393         auto native = ic.context->constructor_->imageCreator_;
394         if (native == nullptr) {
395             IMAGE_ERR("Native instance is nullptr");
396             return false;
397         }
398 
399         if (native->iraContext_ == nullptr) {
400             IMAGE_ERR("Image creator context is nullptr");
401             return false;
402         }
403         ic.result = BuildJsSize(args.env,
404                                 native->iraContext_->GetWidth(),
405                                 native->iraContext_->GetHeight());
406         return true;
407     };
408 
409     return JSCommonProcess(args);
410 }
411 
JsGetCapacity(napi_env env,napi_callback_info info)412 napi_value ImageCreatorNapi::JsGetCapacity(napi_env env, napi_callback_info info)
413 {
414     IMAGE_FUNCTION_IN();
415     ImageCreatorCommonArgs args = {
416         .env = env, .info = info,
417         .async = CreatorCallType::GETTER,
418     };
419     args.argc = ARGS0;
420 
421     args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
422         napi_get_undefined(args.env, &(ic.result));
423         if (g_creatorTest) {
424             napi_create_int32(args.env, TEST_CAPACITY, &(ic.result));
425             return true;
426         }
427         auto native = ic.context->constructor_->imageCreator_;
428         if (native == nullptr) {
429             IMAGE_ERR("Native instance is nullptr");
430             return false;
431         }
432 
433         if (native->iraContext_ == nullptr) {
434             IMAGE_ERR("Image creator context is nullptr");
435             return false;
436         }
437         napi_create_int32(args.env, native->iraContext_->GetCapicity(), &(ic.result));
438         return true;
439     };
440 
441     return JSCommonProcess(args);
442 }
443 
JsGetFormat(napi_env env,napi_callback_info info)444 napi_value ImageCreatorNapi::JsGetFormat(napi_env env, napi_callback_info info)
445 {
446     IMAGE_FUNCTION_IN();
447     ImageCreatorCommonArgs args = {
448         .env = env, .info = info,
449         .async = CreatorCallType::GETTER,
450     };
451     args.argc = ARGS0;
452 
453     args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
454         napi_get_undefined(args.env, &(ic.result));
455         if (g_creatorTest) {
456             napi_create_int32(args.env, TEST_FORMAT, &(ic.result));
457             return true;
458         }
459         auto native = ic.context->constructor_->imageCreator_;
460         if (native == nullptr) {
461             IMAGE_ERR("Native instance is nullptr");
462             return false;
463         }
464 
465         if (native->iraContext_ == nullptr) {
466             IMAGE_ERR("Image creator context is nullptr");
467             return false;
468         }
469         napi_create_int32(args.env, native->iraContext_->GetFormat(), &(ic.result));
470         return true;
471     };
472 
473     return JSCommonProcess(args);
474 }
475 
476 #ifdef IMAGE_DEBUG_FLAG
TestAcquireBuffer(OHOS::sptr<OHOS::IConsumerSurface> & creatorSurface,int32_t & fence,int64_t & timestamp,OHOS::Rect & damage,std::shared_ptr<ImageCreator> imageCreator)477 static void TestAcquireBuffer(OHOS::sptr<OHOS::IConsumerSurface> &creatorSurface, int32_t &fence,
478     int64_t &timestamp, OHOS::Rect &damage, std::shared_ptr<ImageCreator> imageCreator)
479 {
480     OHOS::sptr<OHOS::SurfaceBuffer> buffer;
481     if (creatorSurface == nullptr) {
482         IMAGE_ERR("Creator Surface is nullptr");
483         return;
484     }
485     creatorSurface->AcquireBuffer(buffer, fence, timestamp, damage);
486     if (buffer == nullptr) {
487         IMAGE_ERR("Creator Surface is nullptr");
488         return;
489     }
490     IMAGE_ERR("...AcquireBuffer...");
491     InitializationOptions opts;
492     opts.size.width = creatorSurface->GetDefaultWidth();
493     opts.size.height = creatorSurface->GetDefaultHeight();
494     opts.pixelFormat = OHOS::Media::PixelFormat::BGRA_8888;
495     opts.alphaType = OHOS::Media::AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
496     opts.scaleMode = OHOS::Media::ScaleMode::CENTER_CROP;
497     opts.editable = true;
498     imageCreator->SaveSenderBufferAsImage(buffer, opts);
499 }
500 
DoTest(std::shared_ptr<ImageCreator> imageCreator)501 static void DoTest(std::shared_ptr<ImageCreator> imageCreator)
502 {
503     if (imageCreator == nullptr || imageCreator->iraContext_ == nullptr) {
504         IMAGE_ERR("image creator is nullptr");
505         return;
506     }
507     std::string creatorKey = imageCreator->iraContext_->GetCreatorKey();
508     IMAGE_ERR("CreatorKey = %{public}s", creatorKey.c_str());
509     OHOS::sptr<OHOS::IConsumerSurface> creatorSurface = ImageCreator::getSurfaceById(creatorKey);
510     IMAGE_ERR("getDefaultWidth = %{public}d", creatorSurface->GetDefaultWidth());
511     IMAGE_ERR("getDefaultHeight = %{public}d", creatorSurface->GetDefaultHeight());
512     int32_t flushFence = 0;
513     int64_t timestamp = 0;
514     OHOS::Rect damage = {};
515     IMAGE_ERR("TestAcquireBuffer 1...");
516     TestAcquireBuffer(creatorSurface, flushFence, timestamp, damage, imageCreator);
517 }
518 static void DoCallBackAfterWork(uv_work_t *work, int status);
JsTest(napi_env env,napi_callback_info info)519 napi_value ImageCreatorNapi::JsTest(napi_env env, napi_callback_info info)
520 {
521     IMAGE_FUNCTION_IN();
522     ImageCreatorCommonArgs args = {
523         .env = env, .info = info,
524         .async = CreatorCallType::GETTER,
525     };
526     args.argc = ARGS0;
527 
528     args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
529         DoTest(ic.context->creator_);
530         if (g_creatorTest && g_listener != nullptr) {
531             unique_ptr<uv_work_t> work = make_unique<uv_work_t>();
532             work->data = reinterpret_cast<void *>(g_listener->context.get());
533             DoCallBackAfterWork(work.release(), ARGS0);
534             g_listener = nullptr;
535         }
536         return true;
537     };
538 
539     return JSCommonProcess(args);
540 }
541 #endif
542 
JsDequeueImage(napi_env env,napi_callback_info info)543 napi_value ImageCreatorNapi::JsDequeueImage(napi_env env, napi_callback_info info)
544 {
545     IMAGE_FUNCTION_IN();
546     ImageCreatorCommonArgs args = {
547         .env = env, .info = info,
548         .async = CreatorCallType::ASYNC,
549         .name = "JsDequeueImage",
550         .callBack = nullptr,
551         .argc = ARGS1,
552         .queryArgs = PrepareOneArg,
553     };
554 
555     args.callBack = [](napi_env env, napi_status status, Contextc context) {
556         IMAGE_LINE_IN();
557         napi_value result = nullptr;
558         napi_get_undefined(env, &result);
559         if (g_creatorTest) {
560             result = ImageNapi::Create(env);
561             context->status = SUCCESS;
562             CommonCallbackRoutine(env, context, result);
563             return;
564         }
565 
566         auto native = context->constructor_->imageCreator_;
567         if (native != nullptr) {
568         result = ImageNapi::Create(env, native->DequeueNativeImage());
569         if (result == nullptr) {
570             IMAGE_ERR("ImageNapi Create failed");
571         }
572         } else {
573             IMAGE_ERR("Native instance is nullptr");
574         }
575 
576         if (result == nullptr) {
577             napi_get_undefined(env, &result);
578             context->status = ERR_IMAGE_INIT_ABNORMAL;
579         } else {
580             context->status = SUCCESS;
581         }
582 
583         IMAGE_LINE_OUT();
584         CommonCallbackRoutine(env, context, result);
585     };
586 
587     return JSCommonProcess(args);
588 }
589 
IsTestImageArgs(napi_env env,napi_value value)590 static bool IsTestImageArgs(napi_env env, napi_value value)
591 {
592     if (g_creatorTest) {
593         ImageNapi* image = nullptr;
594         napi_status status = napi_unwrap(env, value, reinterpret_cast<void**>(&image));
595         return (status == napi_ok && image != nullptr);
596     }
597     return false;
598 }
599 
JsQueueArgs(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<NativeImage> & imageNapi_,napi_ref * callbackRef)600 static bool JsQueueArgs(napi_env env, size_t argc, napi_value* argv,
601                         std::shared_ptr<NativeImage> &imageNapi_, napi_ref* callbackRef)
602 {
603     if (argc == ARGS1 || argc == ARGS2) {
604         auto argType0 = ImageNapiUtils::getType(env, argv[PARAM0]);
605         if (argType0 == napi_object) {
606             imageNapi_ = ImageNapi::GetNativeImage(env, argv[PARAM0]);
607             if (imageNapi_ == nullptr && !IsTestImageArgs(env, argv[PARAM0])) {
608                 ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
609                     "Could not get queue type object");
610                 return false;
611             }
612         } else {
613             std::string errMsg = "Unsupport args0 type: ";
614             ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
615                 errMsg.append(std::to_string(argType0)));
616             return false;
617         }
618         if (argc == ARGS2) {
619         auto argType1 = ImageNapiUtils::getType(env, argv[PARAM1]);
620         if (argType1 == napi_function) {
621             int32_t refCount = 1;
622             napi_create_reference(env, argv[PARAM1], refCount, callbackRef);
623         } else {
624             std::string errMsg = "Unsupport args1 type: ";
625             ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
626                 errMsg.append(std::to_string(argType1)));
627             return false;
628         }
629     }
630     } else {
631         std::string errMsg = "Invailed argc: ";
632         ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
633             errMsg.append(std::to_string(argc)));
634         return false;
635     }
636     return true;
637 }
638 
JsQueueImageCallBack(napi_env env,napi_status status,ImageCreatorAsyncContext * context)639 void ImageCreatorNapi::JsQueueImageCallBack(napi_env env, napi_status status,
640                                             ImageCreatorAsyncContext* context)
641 {
642     IMAGE_FUNCTION_IN();
643     napi_value result = nullptr;
644     napi_get_undefined(env, &result);
645     if (g_creatorTest) {
646         context->status = SUCCESS;
647         CommonCallbackRoutine(env, context, result);
648         return;
649     }
650 
651     auto native = context->constructor_->imageCreator_;
652     if (native == nullptr || context->imageNapi_ == nullptr) {
653         IMAGE_ERR("Native instance is nullptr");
654         context->status = ERR_IMAGE_INIT_ABNORMAL;
655     } else {
656         if (SUCCESS != context->imageNapi_->CombineYUVComponents()) {
657             IMAGE_ERR("JsQueueImageCallBack: try to combine componests");
658         }
659         native->QueueNativeImage(context->imageNapi_);
660         context->status = SUCCESS;
661     }
662     IMAGE_LINE_OUT();
663     CommonCallbackRoutine(env, context, result);
664 }
665 
JsQueueImage(napi_env env,napi_callback_info info)666 napi_value ImageCreatorNapi::JsQueueImage(napi_env env, napi_callback_info info)
667 {
668     IMAGE_FUNCTION_IN();
669     napi_value result = nullptr, thisVar = nullptr;
670     size_t argc = ARGS2;
671     napi_value argv[ARGS2] = {0};
672 
673     napi_get_undefined(env, &result);
674 
675     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
676     if (status != napi_ok) {
677         IMAGE_ERR("fail to napi_get_cb_info %{public}d", status);
678         return result;
679     }
680 
681     unique_ptr<ImageCreatorAsyncContext> context = make_unique<ImageCreatorAsyncContext>();
682     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
683     if (status != napi_ok || context->constructor_ == nullptr) {
684         IMAGE_ERR("fail to unwrap constructor_ %{public}d", status);
685         return result;
686     }
687 
688     if (!JsQueueArgs(env, argc, argv, context->imageNapi_, &(context->callbackRef))) {
689         return result;
690     }
691     if (context->callbackRef == nullptr) {
692         napi_create_promise(env, &(context->deferred), &result);
693     }
694 
695     napi_value resource = nullptr;
696     napi_create_string_utf8(env, "JsQueueImage", NAPI_AUTO_LENGTH, &resource);
697     status = napi_create_async_work(
698         env, nullptr, resource, [](napi_env env, void* data) {},
699         reinterpret_cast<napi_async_complete_callback>(JsQueueImageCallBack),
700         static_cast<void *>(context.get()), &(context->work));
701     if (status != napi_ok) {
702         IMAGE_ERR("fail to create async work %{public}d", status);
703         return result;
704     }
705 
706     status = napi_queue_async_work(env, context->work);
707     if (status != napi_ok) {
708         IMAGE_ERR("fail to queue async work %{public}d", status);
709         return result;
710     }
711     context.release();
712 
713     IMAGE_FUNCTION_OUT();
714     return result;
715 }
716 
CheckOnParam0(napi_env env,napi_value value,const std::string & refStr)717 static bool CheckOnParam0(napi_env env, napi_value value, const std::string& refStr)
718 {
719     bool ret = true;
720     size_t bufLength = 0;
721     napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &bufLength);
722     if (status != napi_ok || bufLength > PATH_MAX) {
723         return false;
724     }
725 
726     char *buffer = static_cast<char *>(malloc((bufLength + 1) * sizeof(char)));
727     if (buffer == nullptr) {
728         return false;
729     }
730 
731     status = napi_get_value_string_utf8(env, value, buffer, bufLength + 1, &bufLength);
732     if (status != napi_ok) {
733         free(buffer);
734         return false;
735     }
736 
737     std::string strValue = buffer;
738     if (strValue.compare(refStr) != 0) {
739         IMAGE_ERR("strValue is %{public}s", strValue.c_str());
740         ret = false;
741     }
742 
743     strValue = "";
744     free(buffer);
745     buffer = nullptr;
746     return ret;
747 }
748 
JsOnQueryArgs(ImageCreatorCommonArgs & args,ImageCreatorInnerContext & ic)749 static bool JsOnQueryArgs(ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic)
750 {
751     if (ic.argc == ARGS2) {
752         auto argType0 = ImageNapiUtils::getType(args.env, ic.argv[PARAM0]);
753         auto argType1 = ImageNapiUtils::getType(args.env, ic.argv[PARAM1]);
754         if (argType0 == napi_string && argType1 == napi_function) {
755             if (!ImageNapiUtils::GetUtf8String(args.env, ic.argv[PARAM0], ic.onType)) {
756                 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
757                     "Could not get On type string");
758                 return false;
759             }
760 
761             if (!CheckOnParam0(args.env, ic.argv[PARAM0], "imageRelease")) {
762                 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
763                     "Unsupport PARAM0");
764                 return false;
765             }
766 
767             napi_create_reference(args.env, ic.argv[PARAM1], ic.refCount, &(ic.context->callbackRef));
768         } else {
769             std::string errMsg = "Unsupport args type: ";
770             ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
771                 errMsg.append(std::to_string(argType0)).append(std::to_string(argType1)));
772             return false;
773         }
774     } else {
775         std::string errMsg = "Invailed argc: ";
776         ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
777             errMsg.append(std::to_string(ic.argc)));
778         return false;
779     }
780 
781     napi_get_undefined(args.env, &ic.result);
782     return true;
783 }
DoCallBackAfterWork(uv_work_t * work,int status)784 static void DoCallBackAfterWork(uv_work_t *work, int status)
785 {
786     IMAGE_LINE_IN();
787     Contextc context = reinterpret_cast<Contextc>(work->data);
788     if (context == nullptr) {
789         IMAGE_ERR("context is empty");
790     } else {
791         napi_value result[PARAM2] = {0};
792         napi_value retVal, callback = nullptr;
793         if (context->env != nullptr && context->callbackRef != nullptr) {
794             napi_handle_scope scope = nullptr;
795             napi_open_handle_scope(context->env, &scope);
796             if (scope == nullptr) {
797                 return;
798             }
799             napi_create_uint32(context->env, SUCCESS, &result[0]);
800             napi_get_undefined(context->env, &result[1]);
801             napi_get_reference_value(context->env, context->callbackRef, &callback);
802             if (callback != nullptr) {
803                 napi_call_function(context->env, nullptr, callback, PARAM2, result, &retVal);
804             } else {
805                 IMAGE_ERR("napi_get_reference_value callback is empty");
806             }
807             napi_close_handle_scope(context->env, scope);
808         } else {
809             IMAGE_ERR("env or callbackRef is empty");
810         }
811     }
812     delete work;
813     IMAGE_LINE_OUT();
814 }
DoCallBack(shared_ptr<ImageCreatorAsyncContext> context,string name,CompleteCreatorCallback callBack)815 void ImageCreatorNapi::DoCallBack(shared_ptr<ImageCreatorAsyncContext> context,
816     string name, CompleteCreatorCallback callBack)
817 {
818     IMAGE_FUNCTION_IN();
819     if (context == nullptr || context->env == nullptr) {
820         IMAGE_ERR("gContext or env is empty");
821         return;
822     }
823 
824     uv_loop_s *loop = nullptr;
825     napi_get_uv_event_loop(context->env, &loop);
826     if (loop == nullptr) {
827         IMAGE_ERR("napi_get_uv_event_loop failed");
828         return;
829     }
830 
831     unique_ptr<uv_work_t> work = make_unique<uv_work_t>();
832     if (work == nullptr) {
833         IMAGE_ERR("DoCallBack: No memory");
834         return;
835     }
836 
837     work->data = reinterpret_cast<void *>(context.get());
838     int ret = uv_queue_work(loop, work.get(), [] (uv_work_t *work) {}, DoCallBackAfterWork);
839     if (ret != 0) {
840         IMAGE_ERR("Failed to execute DoCallBack work queue");
841     } else {
842         work.release();
843     }
844     IMAGE_FUNCTION_OUT();
845 }
846 
JsOn(napi_env env,napi_callback_info info)847 napi_value ImageCreatorNapi::JsOn(napi_env env, napi_callback_info info)
848 {
849     IMAGE_FUNCTION_IN();
850     ImageCreatorCommonArgs args = {
851         .env = env, .info = info,
852         .async = CreatorCallType::ASYNC,
853         .name = "JsOn",
854     };
855     args.argc = ARGS2;
856     args.asyncLater = true;
857     args.queryArgs = JsOnQueryArgs;
858     args.nonAsyncBack = [](ImageCreatorCommonArgs &args, ImageCreatorInnerContext &ic) -> bool {
859         IMAGE_LINE_IN();
860         if (g_creatorTest) {
861             g_listener = make_shared<ImageCreatorReleaseListener>();
862             g_listener->context = std::move(ic.context);
863             g_listener->context->env = args.env;
864             g_listener->name = args.name;
865             return true;
866         }
867         napi_get_undefined(args.env, &(ic.result));
868 
869         auto native = ic.context->constructor_->imageCreator_;
870         if (native == nullptr) {
871             IMAGE_ERR("Native instance is nullptr");
872             ic.context->status = ERR_IMAGE_INIT_ABNORMAL;
873             return false;
874         }
875         shared_ptr<ImageCreatorReleaseListener> listener = make_shared<ImageCreatorReleaseListener>();
876         listener->context = std::move(ic.context);
877         listener->context->env = args.env;
878         listener->name = args.name;
879 
880         native->RegisterBufferReleaseListener((std::shared_ptr<SurfaceBufferReleaseListener> &)listener);
881 
882         IMAGE_LINE_OUT();
883         return true;
884     };
885 
886     return JSCommonProcess(args);
887 }
888 
JsRelease(napi_env env,napi_callback_info info)889 napi_value ImageCreatorNapi::JsRelease(napi_env env, napi_callback_info info)
890 {
891     IMAGE_FUNCTION_IN();
892     ImageCreatorCommonArgs args = {
893         .env = env, .info = info,
894         .async = CreatorCallType::ASYNC,
895         .name = "JsRelease",
896         .callBack = nullptr,
897         .argc = ARGS1,
898         .queryArgs = PrepareOneArg,
899     };
900 
901     args.callBack = [](napi_env env, napi_status status, Contextc context) {
902         IMAGE_LINE_IN();
903         napi_value result = nullptr;
904         napi_get_undefined(env, &result);
905 
906         context->constructor_->NativeRelease();
907         context->status = SUCCESS;
908 
909         IMAGE_LINE_OUT();
910         CommonCallbackRoutine(env, context, result);
911     };
912 
913     return JSCommonProcess(args);
914 }
915 
release()916 void ImageCreatorNapi::release()
917 {
918     if (!isRelease) {
919         NativeRelease();
920         isRelease = true;
921     }
922 }
923 }  // namespace Media
924 }  // namespace OHOS
925