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