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 ×tamp, 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