1 /*
2 * Copyright (C) 2024 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 "sendable_image_napi.h"
17
18 #include "napi/native_node_api.h"
19 #include "image_log.h"
20 #include "media_errors.h"
21 #include "image_format.h"
22 #include "image_napi_utils.h"
23
24 #undef LOG_DOMAIN
25 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
26
27 #undef LOG_TAG
28 #define LOG_TAG "SendableImageNapi"
29
30 namespace {
31 constexpr int NUM0 = 0;
32 constexpr int NUM1 = 1;
33 constexpr int NUM2 = 2;
34 const std::string MY_NAME = "SendableImageNapi";
35 }
36
37 namespace OHOS {
38 namespace Media {
39 struct SendableImageAsyncContext {
40 napi_env env = nullptr;
41 napi_async_work work = nullptr;
42 napi_deferred deferred = nullptr;
43 napi_ref callbackRef = nullptr;
44 napi_ref thisRef = nullptr;
45 SendableImageNapi *napi = nullptr;
46 uint32_t status;
47 int32_t componentType;
48 NativeImage* image = nullptr;
49 NativeComponent* component = nullptr;
50 bool isTestContext = false;
51 };
52 ImageHolderManager<NativeImage> SendableImageNapi::sNativeImageHolder_;
53 thread_local napi_ref SendableImageNapi::sConstructor_ = nullptr;
54
SendableImageNapi()55 SendableImageNapi::SendableImageNapi()
56 {}
57
~SendableImageNapi()58 SendableImageNapi::~SendableImageNapi()
59 {
60 NativeRelease();
61 }
62
NativeRelease()63 void SendableImageNapi::NativeRelease()
64 {
65 if (native_ != nullptr) {
66 native_->release();
67 native_ = nullptr;
68 }
69 }
70
Init(napi_env env,napi_value exports)71 napi_value SendableImageNapi::Init(napi_env env, napi_value exports)
72 {
73 IMAGE_FUNCTION_IN();
74 napi_property_descriptor props[] = {
75 DECLARE_NAPI_GETTER("clipRect", JSGetClipRect),
76 DECLARE_NAPI_GETTER("size", JsGetSize),
77 DECLARE_NAPI_GETTER("format", JsGetFormat),
78 DECLARE_NAPI_GETTER("timestamp", JsGetTimestamp),
79 DECLARE_NAPI_FUNCTION("getComponent", JsGetComponent),
80 DECLARE_NAPI_FUNCTION("release", JsRelease),
81 };
82 size_t size = IMG_ARRAY_SIZE(props);
83 napi_value thisVar = nullptr;
84 auto name = MY_NAME.c_str();
85 if (napi_define_sendable_class(env, name, SIZE_MAX, Constructor, nullptr, size, props, nullptr, &thisVar) != napi_ok) {
86 IMAGE_ERR("Define class failed");
87 return exports;
88 }
89
90 sConstructor_ = nullptr;
91
92 if (napi_create_reference(env, thisVar, NUM1, &sConstructor_) != napi_ok) {
93 IMAGE_ERR("Create reference failed");
94 return exports;
95 }
96
97 if (napi_set_named_property(env, exports, name, thisVar) != napi_ok) {
98 IMAGE_ERR("Define class failed");
99 return exports;
100 }
101
102 IMAGE_DEBUG("Init success");
103 return exports;
104 }
105
106
GetNativeImage(napi_env env,napi_value image)107 std::shared_ptr<NativeImage> SendableImageNapi::GetNativeImage(napi_env env, napi_value image)
108 {
109 SendableImageNapi* napi = nullptr;
110
111 napi_status status = napi_unwrap_sendable(env, image, reinterpret_cast<void**>(&napi));
112 if (!IMG_IS_OK(status) || napi == nullptr) {
113 IMAGE_ERR("GetImage napi unwrap failed");
114 return nullptr;
115 }
116 return napi->native_;
117 }
118
Constructor(napi_env env,napi_callback_info info)119 napi_value SendableImageNapi::Constructor(napi_env env, napi_callback_info info)
120 {
121 napi_status status;
122 napi_value thisVar = nullptr;
123 napi_value undefineVar;
124 size_t argc = NUM1;
125 napi_value argv[NUM1];
126
127 IMAGE_FUNCTION_IN();
128 napi_get_undefined(env, &undefineVar);
129 status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
130 if (status != napi_ok || thisVar == nullptr || argc != NUM1) {
131 IMAGE_ERR("Constructor Failed to napi_get_cb_info");
132 return undefineVar;
133 }
134 std::string id;
135 if (!ImageNapiUtils::GetUtf8String(env, argv[NUM0], id) || (id.size() == NUM0)) {
136 IMAGE_ERR("Failed to parse native image id");
137 return undefineVar;
138 }
139 std::unique_ptr<SendableImageNapi> napi = std::make_unique<SendableImageNapi>();
140 napi->native_ = sNativeImageHolder_.get(id);
141 napi->isTestImage_ = false;
142 if (napi->native_ == nullptr) {
143 if (MY_NAME.compare(id.c_str()) == 0) {
144 napi->isTestImage_ = true;
145 } else {
146 IMAGE_ERR("Failed to get native image");
147 return undefineVar;
148 }
149 }
150 status = napi_wrap_sendable(env, thisVar,
151 reinterpret_cast<void *>(napi.get()), SendableImageNapi::Destructor, nullptr);
152 if (status != napi_ok) {
153 IMAGE_ERR("Failure wrapping js to native napi");
154 return undefineVar;
155 }
156
157 napi.release();
158 IMAGE_FUNCTION_OUT();
159 return thisVar;
160 }
161
Destructor(napi_env env,void * nativeObject,void * finalize)162 void SendableImageNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
163 {
164 if (nativeObject != nullptr) {
165 delete reinterpret_cast<SendableImageNapi *>(nativeObject);
166 }
167 }
168
Create(napi_env env)169 napi_value SendableImageNapi::Create(napi_env env)
170 {
171 napi_value constructor = nullptr;
172 napi_value result = nullptr;
173 napi_value argv[NUM1];
174
175 IMAGE_FUNCTION_IN();
176 if (env == nullptr) {
177 IMAGE_ERR("Input args is invalid");
178 return nullptr;
179 }
180 if (napi_get_reference_value(env, sConstructor_, &constructor) == napi_ok && constructor != nullptr) {
181 if (napi_create_string_utf8(env, MY_NAME.c_str(), NAPI_AUTO_LENGTH, &(argv[NUM0])) != napi_ok) {
182 IMAGE_ERR("Create native image id Failed");
183 }
184 if (napi_new_instance(env, constructor, NUM1, argv, &result) != napi_ok) {
185 IMAGE_ERR("New instance could not be obtained");
186 }
187 }
188 IMAGE_FUNCTION_OUT();
189 return result;
190 }
Create(napi_env env,std::shared_ptr<NativeImage> nativeImage)191 napi_value SendableImageNapi::Create(napi_env env, std::shared_ptr<NativeImage> nativeImage)
192 {
193 napi_value constructor = nullptr;
194 napi_value result = nullptr;
195 napi_value argv[NUM1];
196
197 IMAGE_FUNCTION_IN();
198 if (env == nullptr || nativeImage == nullptr) {
199 IMAGE_ERR("Input args is invalid");
200 return nullptr;
201 }
202 if (napi_get_reference_value(env, sConstructor_, &constructor) == napi_ok && constructor != nullptr) {
203 auto id = sNativeImageHolder_.save(nativeImage);
204 if (napi_create_string_utf8(env, id.c_str(), NAPI_AUTO_LENGTH, &(argv[NUM0])) != napi_ok) {
205 IMAGE_ERR("Create native image id Failed");
206 }
207 if (napi_new_instance(env, constructor, NUM1, argv, &result) != napi_ok) {
208 IMAGE_ERR("New instance could not be obtained");
209 }
210 }
211 IMAGE_FUNCTION_OUT();
212 return result;
213 }
JsCheckObjectType(napi_env env,napi_value value,napi_valuetype type)214 static inline bool JsCheckObjectType(napi_env env, napi_value value, napi_valuetype type)
215 {
216 return (ImageNapiUtils::getType(env, value) == type);
217 }
218
JsGetCallbackFunc(napi_env env,napi_value value,napi_ref * result)219 static inline bool JsGetCallbackFunc(napi_env env, napi_value value, napi_ref *result)
220 {
221 if (JsCheckObjectType(env, value, napi_function)) {
222 napi_create_reference(env, value, NUM1, result);
223 return true;
224 }
225 return false;
226 }
227
JsGetInt32Args(napi_env env,napi_value value,int * result)228 static inline bool JsGetInt32Args(napi_env env, napi_value value, int *result)
229 {
230 if (JsCheckObjectType(env, value, napi_number)) {
231 napi_get_value_int32(env, value, result);
232 return true;
233 }
234 return false;
235 }
236 using AsyncExecCallback = void (*)(napi_env env, SendableImageAsyncContext* ctx);
237 using AsyncCompleteCallback = void (*)(napi_env env, napi_status status, SendableImageAsyncContext* ctx);
JsCreateWork(napi_env env,const char * name,AsyncExecCallback exec,AsyncCompleteCallback complete,SendableImageAsyncContext * ctx)238 static bool JsCreateWork(napi_env env, const char* name, AsyncExecCallback exec,
239 AsyncCompleteCallback complete, SendableImageAsyncContext* ctx)
240 {
241 napi_value resource = nullptr;
242 napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &resource);
243 napi_status status = napi_create_async_work(
244 env, nullptr, resource, reinterpret_cast<napi_async_execute_callback>(exec),
245 reinterpret_cast<napi_async_complete_callback>(complete), static_cast<void *>(ctx), &(ctx->work));
246 if (status != napi_ok) {
247 IMAGE_ERR("fail to create async work %{public}d", status);
248 return false;
249 }
250
251 if (napi_queue_async_work(env, ctx->work) != napi_ok) {
252 IMAGE_ERR("fail to queue async work");
253 return false;
254 }
255 return true;
256 }
257
GetNative()258 NativeImage* SendableImageNapi::GetNative()
259 {
260 if (native_ != nullptr) {
261 return native_.get();
262 }
263 return nullptr;
264 }
265
UnwrapContext(napi_env env,napi_callback_info info,size_t * argc=nullptr,napi_value * argv=nullptr,bool needCreateRef=false)266 static std::unique_ptr<SendableImageAsyncContext> UnwrapContext(napi_env env, napi_callback_info info,
267 size_t* argc = nullptr, napi_value* argv = nullptr, bool needCreateRef = false)
268 {
269 napi_value thisVar = nullptr;
270 size_t tmp = NUM0;
271
272 IMAGE_FUNCTION_IN();
273
274 if (napi_get_cb_info(env, info, (argc == nullptr)?&tmp:argc, argv, &thisVar, nullptr) != napi_ok) {
275 IMAGE_ERR("Fail to napi_get_cb_info");
276 return nullptr;
277 }
278
279 std::unique_ptr<SendableImageAsyncContext> ctx = std::make_unique<SendableImageAsyncContext>();
280 if (napi_unwrap_sendable(env, thisVar, reinterpret_cast<void**>(&ctx->napi)) != napi_ok || ctx->napi == nullptr) {
281 IMAGE_ERR("fail to unwrap ets image object, image maybe released");
282 return nullptr;
283 }
284 ctx->image = ctx->napi->GetNative();
285 if (needCreateRef) {
286 napi_create_reference(env, thisVar, NUM1, &(ctx->thisRef));
287 }
288 return ctx;
289 }
290
ProcessPromise(napi_env env,napi_deferred deferred,napi_value * result,bool resolved)291 static inline void ProcessPromise(napi_env env, napi_deferred deferred, napi_value* result, bool resolved)
292 {
293 if (resolved) {
294 napi_resolve_deferred(env, deferred, result[NUM1]);
295 } else {
296 napi_reject_deferred(env, deferred, result[NUM0]);
297 }
298 }
ProcessCallback(napi_env env,napi_ref ref,napi_value * result)299 static inline void ProcessCallback(napi_env env, napi_ref ref, napi_value* result)
300 {
301 napi_value retVal;
302 napi_value callback;
303 napi_get_reference_value(env, ref, &callback);
304 napi_call_function(env, nullptr, callback, NUM2, result, &retVal);
305 napi_delete_reference(env, ref);
306 }
CommonCallbackRoutine(napi_env env,SendableImageAsyncContext * & context,const napi_value & valueParam)307 static void CommonCallbackRoutine(napi_env env, SendableImageAsyncContext* &context, const napi_value &valueParam)
308 {
309 IMAGE_FUNCTION_IN();
310 napi_value result[2] = {0};
311
312 if (context == nullptr) {
313 IMAGE_ERR("context is nullptr");
314 return;
315 }
316
317 if (context->status == SUCCESS) {
318 napi_create_uint32(env, context->status, &result[0]);
319 result[1] = valueParam;
320 } else {
321 ImageNapiUtils::CreateErrorObj(env, result[0], context->status,
322 "There is generic napi failure!");
323 napi_get_undefined(env, &result[1]);
324 }
325
326 if (context->deferred) {
327 ProcessPromise(env, context->deferred, result, context->status == SUCCESS);
328 } else {
329 ProcessCallback(env, context->callbackRef, result);
330 }
331
332 napi_delete_async_work(env, context->work);
333
334 delete context;
335 context = nullptr;
336 IMAGE_FUNCTION_OUT();
337 }
338
BuildIntProperty(napi_env env,const std::string & name,int32_t val,napi_value result)339 static void BuildIntProperty(napi_env env, const std::string &name,
340 int32_t val, napi_value result)
341 {
342 napi_value nVal;
343 napi_create_int32(env, val, &nVal);
344 napi_set_named_property(env, result, name.c_str(), nVal);
345 }
346
BuildJsSize(napi_env env,int32_t width,int32_t height)347 static napi_value BuildJsSize(napi_env env, int32_t width, int32_t height)
348 {
349 napi_value result = nullptr;
350
351 napi_create_object(env, &result);
352
353 BuildIntProperty(env, "width", width, result);
354 BuildIntProperty(env, "height", height, result);
355 return result;
356 }
357
BuildJsRegion(napi_env env,int32_t width,int32_t height,int32_t x,int32_t y)358 static napi_value BuildJsRegion(napi_env env, int32_t width,
359 int32_t height, int32_t x, int32_t y)
360 {
361 napi_value result = nullptr;
362
363 napi_create_object(env, &result);
364
365 napi_set_named_property(env, result, "size", BuildJsSize(env, width, height));
366
367 BuildIntProperty(env, "x", x, result);
368 BuildIntProperty(env, "y", y, result);
369 return result;
370 }
371
JSGetClipRect(napi_env env,napi_callback_info info)372 napi_value SendableImageNapi::JSGetClipRect(napi_env env, napi_callback_info info)
373 {
374 napi_value result = nullptr;
375
376 IMAGE_FUNCTION_IN();
377 napi_get_undefined(env, &result);
378 std::unique_ptr<SendableImageAsyncContext> context = UnwrapContext(env, info);
379 if (context != nullptr && context->napi != nullptr && context->napi->isTestImage_) {
380 const int32_t WIDTH = 8192;
381 const int32_t HEIGHT = 8;
382 return BuildJsRegion(env, WIDTH, HEIGHT, NUM0, NUM0);
383 }
384 if (context == nullptr || context->image == nullptr) {
385 IMAGE_ERR("Image surfacebuffer is nullptr");
386 return result;
387 }
388
389 int32_t width = NUM0;
390 int32_t height = NUM0;
391 if (context->image->GetSize(width, height) != SUCCESS) {
392 IMAGE_ERR("Image native get size failed");
393 return result;
394 }
395 return BuildJsRegion(env, width, height, NUM0, NUM0);
396 }
397
JsGetSize(napi_env env,napi_callback_info info)398 napi_value SendableImageNapi::JsGetSize(napi_env env, napi_callback_info info)
399 {
400 napi_value result = nullptr;
401
402 IMAGE_FUNCTION_IN();
403 napi_get_undefined(env, &result);
404 std::unique_ptr<SendableImageAsyncContext> context = UnwrapContext(env, info);
405 if (context != nullptr && context->napi != nullptr && context->napi->isTestImage_) {
406 const int32_t WIDTH = 8192;
407 const int32_t HEIGHT = 8;
408 return BuildJsSize(env, WIDTH, HEIGHT);
409 }
410 if (context == nullptr || context->image == nullptr) {
411 IMAGE_ERR("Image surfacebuffer is nullptr");
412 return result;
413 }
414
415 int32_t width = NUM0;
416 int32_t height = NUM0;
417 if (context->image->GetSize(width, height) != SUCCESS) {
418 IMAGE_ERR("Image native get size failed");
419 return result;
420 }
421 return BuildJsSize(env, width, height);
422 }
423
JsGetFormat(napi_env env,napi_callback_info info)424 napi_value SendableImageNapi::JsGetFormat(napi_env env, napi_callback_info info)
425 {
426 napi_value result = nullptr;
427
428 IMAGE_FUNCTION_IN();
429 napi_get_undefined(env, &result);
430 std::unique_ptr<SendableImageAsyncContext> context = UnwrapContext(env, info);
431 if (context != nullptr && context->napi != nullptr && context->napi->isTestImage_) {
432 const int32_t FORMAT = 12;
433 napi_create_int32(env, FORMAT, &result);
434 return result;
435 }
436 if (context == nullptr || context->image == nullptr) {
437 IMAGE_ERR("Image surfacebuffer is nullptr");
438 return result;
439 }
440
441 int32_t format = NUM0;
442 if (context->image->GetFormat(format) != SUCCESS) {
443 IMAGE_ERR("Image native get format failed");
444 return result;
445 }
446
447 napi_create_int32(env, format, &result);
448 return result;
449 }
450
JsGetTimestamp(napi_env env,napi_callback_info info)451 napi_value SendableImageNapi::JsGetTimestamp(napi_env env, napi_callback_info info)
452 {
453 napi_value result = nullptr;
454
455 IMAGE_FUNCTION_IN();
456 napi_get_undefined(env, &result);
457 std::unique_ptr<SendableImageAsyncContext> context = UnwrapContext(env, info);
458 if (context == nullptr || context->image == nullptr) {
459 IMAGE_ERR("context is nullptr or Image native is nullptr");
460 return result;
461 }
462
463 int64_t timestamp = 0;
464 if (context->image->GetTimestamp(timestamp) != SUCCESS) {
465 IMAGE_ERR("Image native get timestamp failed");
466 return result;
467 }
468
469 napi_create_int64(env, timestamp, &result);
470 return result;
471 }
472
JSReleaseCallBack(napi_env env,napi_status status,SendableImageAsyncContext * context)473 static void JSReleaseCallBack(napi_env env, napi_status status,
474 SendableImageAsyncContext* context)
475 {
476 IMAGE_FUNCTION_IN();
477 napi_value result = nullptr;
478 napi_get_undefined(env, &result);
479
480 if (context == nullptr) {
481 IMAGE_ERR("context is nullptr");
482 return;
483 }
484
485 if (context->thisRef != nullptr) {
486 napi_value thisVar;
487 napi_get_reference_value(env, context->thisRef, &thisVar);
488 napi_delete_reference(env, context->thisRef);
489 if (thisVar != nullptr) {
490 SendableImageNapi *tmp = nullptr;
491 auto status_ = napi_remove_wrap_sendable(env, thisVar, reinterpret_cast<void**>(&tmp));
492 if (status_ != napi_ok) {
493 IMAGE_ERR("NAPI remove wrap failed status %{public}d", status_);
494 }
495 }
496 }
497
498 context->status = SUCCESS;
499 IMAGE_FUNCTION_OUT();
500 CommonCallbackRoutine(env, context, result);
501 }
502
JsRelease(napi_env env,napi_callback_info info)503 napi_value SendableImageNapi::JsRelease(napi_env env, napi_callback_info info)
504 {
505 IMAGE_FUNCTION_IN();
506 napi_value result = nullptr;
507 size_t argc = NUM1;
508 napi_value argv[NUM1] = {0};
509
510 napi_get_undefined(env, &result);
511 auto context = UnwrapContext(env, info, &argc, argv, true);
512 if (context == nullptr) {
513 IMAGE_ERR("fail to unwrap ets image object, image maybe released");
514 return result;
515 }
516 if (argc == NUM1) {
517 if (!JsGetCallbackFunc(env, argv[NUM0], &(context->callbackRef))) {
518 IMAGE_ERR("Unsupport arg 0 type");
519 return result;
520 }
521 } else {
522 napi_create_promise(env, &(context->deferred), &result);
523 }
524
525 if (JsCreateWork(env, "JsRelease", [](napi_env env, SendableImageAsyncContext* data) {},
526 JSReleaseCallBack, context.get())) {
527 context.release();
528 }
529 IMAGE_FUNCTION_OUT();
530 return result;
531 }
532
CreateArrayBuffer(napi_env env,uint8_t * src,size_t srcLen,napi_value * res)533 static bool CreateArrayBuffer(napi_env env, uint8_t* src, size_t srcLen, napi_value *res)
534 {
535 if (src == nullptr || srcLen == 0) {
536 return false;
537 }
538 auto status = napi_create_external_arraybuffer(env, src, srcLen,
539 [](napi_env env, void* data, void* hint) { }, nullptr, res);
540 if (status != napi_ok) {
541 return false;
542 }
543 return true;
544 }
545
IsEqual(const int32_t & check,ImageFormat format)546 static inline bool IsEqual(const int32_t& check, ImageFormat format)
547 {
548 return (check == int32_t(format));
549 }
IsEqual(const int32_t & check,ComponentType type)550 static inline bool IsEqual(const int32_t& check, ComponentType type)
551 {
552 return (check == int32_t(type));
553 }
IsYUVComponent(const int32_t & type)554 static inline bool IsYUVComponent(const int32_t& type)
555 {
556 return (IsEqual(type, ComponentType::YUV_Y) ||
557 IsEqual(type, ComponentType::YUV_U) ||
558 IsEqual(type, ComponentType::YUV_V));
559 }
IsYUV422SPImage(int32_t format)560 static inline bool IsYUV422SPImage(int32_t format)
561 {
562 return (IsEqual(format, ImageFormat::YCBCR_422_SP) ||
563 (format == int32_t(GRAPHIC_PIXEL_FMT_YCBCR_422_SP)));
564 }
CheckComponentType(const int32_t & type,int32_t format)565 static inline bool CheckComponentType(const int32_t& type, int32_t format)
566 {
567 return ((IsYUV422SPImage(format) && IsYUVComponent(type)) ||
568 (!IsYUV422SPImage(format) && IsEqual(type, ComponentType::JPEG)));
569 }
570
BuildJsComponentObject(napi_env env,int32_t type,uint8_t * buffer,NativeComponent * component,napi_value * result)571 static bool BuildJsComponentObject(napi_env env, int32_t type, uint8_t* buffer,
572 NativeComponent* component, napi_value* result)
573 {
574 napi_value array;
575 if (!CreateArrayBuffer(env, buffer, component->size, &array)) {
576 return false;
577 }
578 napi_create_object(env, result);
579 napi_set_named_property(env, *result, "byteBuffer", array);
580 BuildIntProperty(env, "componentType", type, *result);
581 BuildIntProperty(env, "rowStride", component->rowStride, *result);
582 BuildIntProperty(env, "pixelStride", component->pixelStride, *result);
583 return true;
584 }
TestGetComponentCallBack(napi_env env,napi_status status,SendableImageAsyncContext * context)585 static void TestGetComponentCallBack(napi_env env, napi_status status, SendableImageAsyncContext* context)
586 {
587 if (context == nullptr) {
588 IMAGE_ERR("Invalid input context");
589 return;
590 }
591 napi_value result;
592 napi_value array;
593 void *nativePtr = nullptr;
594 if (napi_create_arraybuffer(env, NUM1, &nativePtr, &array) != napi_ok || nativePtr == nullptr) {
595 return;
596 }
597 napi_create_object(env, &result);
598 napi_set_named_property(env, result, "byteBuffer", array);
599 BuildIntProperty(env, "componentType", context->componentType, result);
600 BuildIntProperty(env, "rowStride", NUM0, result);
601 BuildIntProperty(env, "pixelStride", NUM0, result);
602 context->status = SUCCESS;
603 CommonCallbackRoutine(env, context, result);
604 }
605
JsGetComponentCallBack(napi_env env,napi_status status,SendableImageAsyncContext * context)606 static void JsGetComponentCallBack(napi_env env, napi_status status, SendableImageAsyncContext* context)
607 {
608 IMAGE_FUNCTION_IN();
609 napi_value result;
610 napi_get_undefined(env, &result);
611
612 if (context != nullptr && context->napi != nullptr && context->isTestContext) {
613 TestGetComponentCallBack(env, status, context);
614 return;
615 }
616
617 if (context == nullptr) {
618 IMAGE_ERR("Invalid input context");
619 return;
620 }
621 context->status = ERROR;
622 NativeComponent* component = context->component;
623 if (component == nullptr) {
624 IMAGE_ERR("Invalid component");
625 CommonCallbackRoutine(env, context, result);
626 return;
627 }
628
629 uint8_t *buffer = nullptr;
630 if (component->virAddr != nullptr) {
631 buffer = component->virAddr;
632 } else {
633 buffer = component->raw.data();
634 }
635
636 if (buffer == nullptr || component->size == NUM0) {
637 IMAGE_ERR("Invalid buffer");
638 CommonCallbackRoutine(env, context, result);
639 return;
640 }
641
642 if (BuildJsComponentObject(env, context->componentType, buffer, component, &result)) {
643 context->status = SUCCESS;
644 } else {
645 IMAGE_ERR("napi_create_arraybuffer failed!");
646 }
647
648 IMAGE_FUNCTION_OUT();
649 CommonCallbackRoutine(env, context, result);
650 }
JsGetComponentExec(napi_env env,SendableImageAsyncContext * context)651 static void JsGetComponentExec(napi_env env, SendableImageAsyncContext* context)
652 {
653 if (context == nullptr || context->napi == nullptr) {
654 IMAGE_ERR("Invalid input context");
655 return;
656 }
657
658 auto native = context->napi->GetNative();
659 if (native == nullptr) {
660 IMAGE_ERR("Empty native");
661 return;
662 }
663 context->component = native->GetComponent(context->componentType);
664 }
665
JsGetComponentArgs(napi_env env,size_t argc,napi_value * argv,SendableImageAsyncContext * context)666 static bool JsGetComponentArgs(napi_env env, size_t argc, napi_value* argv, SendableImageAsyncContext* context)
667 {
668 if (argv == nullptr || context == nullptr || argc < NUM1 || context->napi == nullptr) {
669 IMAGE_ERR("argv is nullptr");
670 return false;
671 }
672
673 if (!JsGetInt32Args(env, argv[NUM0], &(context->componentType))) {
674 IMAGE_ERR("Unsupport arg 0 type");
675 return false;
676 }
677
678 auto native = context->napi->GetNative();
679 int32_t format = NUM0;
680 if (context->isTestContext) {
681 const int32_t TEST_FORMAT = 12;
682 format = TEST_FORMAT;
683 } else if (native != nullptr) {
684 native->GetFormat(format);
685 } else {
686 IMAGE_ERR("GetFormat: native is nullptr");
687 return false;
688 }
689
690 if (!CheckComponentType(context->componentType, format)) {
691 IMAGE_ERR("Unsupport component type 0 value: %{public}d", context->componentType);
692 return false;
693 }
694
695 if (argc == NUM2 && !JsGetCallbackFunc(env, argv[NUM1], &(context->callbackRef))) {
696 IMAGE_ERR("Unsupport arg 1 type");
697 return false;
698 }
699 return true;
700 }
701
JsGetComponent(napi_env env,napi_callback_info info)702 napi_value SendableImageNapi::JsGetComponent(napi_env env, napi_callback_info info)
703 {
704 IMAGE_FUNCTION_IN();
705 napi_value result = nullptr;
706 size_t argc = NUM2;
707 napi_value argv[NUM2] = {0};
708
709 napi_get_undefined(env, &result);
710 auto context = UnwrapContext(env, info, &argc, argv);
711 if (context == nullptr) {
712 return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
713 "fail to unwrap ets image object, image maybe released");
714 }
715 context->isTestContext = context->napi->isTestImage_;
716 if (!JsGetComponentArgs(env, argc, argv, context.get())) {
717 return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
718 "Unsupport arg type!");
719 }
720
721 if (context->callbackRef == nullptr) {
722 napi_create_promise(env, &(context->deferred), &result);
723 }
724
725 if (JsCreateWork(env, "JsGetComponent", JsGetComponentExec, JsGetComponentCallBack, context.get())) {
726 context.release();
727 }
728
729 IMAGE_FUNCTION_OUT();
730 return result;
731 }
732 } // namespace Media
733 } // namespace OHOS
734