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)266 static std::unique_ptr<SendableImageAsyncContext> UnwrapContext(napi_env env, napi_callback_info info,
267     size_t* argc = nullptr, napi_value* argv = nullptr)
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     napi_create_reference(env, thisVar, NUM1, &(ctx->thisRef));
286     return ctx;
287 }
288 
ProcessPromise(napi_env env,napi_deferred deferred,napi_value * result,bool resolved)289 static inline void ProcessPromise(napi_env env, napi_deferred deferred, napi_value* result, bool resolved)
290 {
291     if (resolved) {
292         napi_resolve_deferred(env, deferred, result[NUM1]);
293     } else {
294         napi_reject_deferred(env, deferred, result[NUM0]);
295     }
296 }
ProcessCallback(napi_env env,napi_ref ref,napi_value * result)297 static inline void ProcessCallback(napi_env env, napi_ref ref, napi_value* result)
298 {
299     napi_value retVal;
300     napi_value callback;
301     napi_get_reference_value(env, ref, &callback);
302     napi_call_function(env, nullptr, callback, NUM2, result, &retVal);
303     napi_delete_reference(env, ref);
304 }
CommonCallbackRoutine(napi_env env,SendableImageAsyncContext * & context,const napi_value & valueParam)305 static void CommonCallbackRoutine(napi_env env, SendableImageAsyncContext* &context, const napi_value &valueParam)
306 {
307     IMAGE_FUNCTION_IN();
308     napi_value result[2] = {0};
309 
310     if (context == nullptr) {
311         IMAGE_ERR("context is nullptr");
312         return;
313     }
314 
315     if (context->status == SUCCESS) {
316         napi_create_uint32(env, context->status, &result[0]);
317         result[1] = valueParam;
318     } else {
319         ImageNapiUtils::CreateErrorObj(env, result[0], context->status,
320             "There is generic napi failure!");
321         napi_get_undefined(env, &result[1]);
322     }
323 
324     if (context->deferred) {
325         ProcessPromise(env, context->deferred, result, context->status == SUCCESS);
326     } else {
327         ProcessCallback(env, context->callbackRef, result);
328     }
329 
330     napi_delete_async_work(env, context->work);
331 
332     delete context;
333     context = nullptr;
334     IMAGE_FUNCTION_OUT();
335 }
336 
BuildIntProperty(napi_env env,const std::string & name,int32_t val,napi_value result)337 static void BuildIntProperty(napi_env env, const std::string &name,
338                              int32_t val, napi_value result)
339 {
340     napi_value nVal;
341     napi_create_int32(env, val, &nVal);
342     napi_set_named_property(env, result, name.c_str(), nVal);
343 }
344 
BuildJsSize(napi_env env,int32_t width,int32_t height)345 static napi_value BuildJsSize(napi_env env, int32_t width, int32_t height)
346 {
347     napi_value result = nullptr;
348 
349     napi_create_object(env, &result);
350 
351     BuildIntProperty(env, "width", width, result);
352     BuildIntProperty(env, "height", height, result);
353     return result;
354 }
355 
BuildJsRegion(napi_env env,int32_t width,int32_t height,int32_t x,int32_t y)356 static napi_value BuildJsRegion(napi_env env, int32_t width,
357                                 int32_t height, int32_t x, int32_t y)
358 {
359     napi_value result = nullptr;
360 
361     napi_create_object(env, &result);
362 
363     napi_set_named_property(env, result, "size", BuildJsSize(env, width, height));
364 
365     BuildIntProperty(env, "x", x, result);
366     BuildIntProperty(env, "y", y, result);
367     return result;
368 }
369 
JSGetClipRect(napi_env env,napi_callback_info info)370 napi_value SendableImageNapi::JSGetClipRect(napi_env env, napi_callback_info info)
371 {
372     napi_value result = nullptr;
373 
374     IMAGE_FUNCTION_IN();
375     napi_get_undefined(env, &result);
376     std::unique_ptr<SendableImageAsyncContext> context = UnwrapContext(env, info);
377     if (context != nullptr && context->napi != nullptr && context->napi->isTestImage_) {
378         const int32_t WIDTH = 8192;
379         const int32_t HEIGHT = 8;
380         return BuildJsRegion(env, WIDTH, HEIGHT, NUM0, NUM0);
381     }
382     if (context == nullptr || context->image == nullptr) {
383         IMAGE_ERR("Image surfacebuffer is nullptr");
384         return result;
385     }
386 
387     int32_t width = NUM0;
388     int32_t height = NUM0;
389     if (context->image->GetSize(width, height) != SUCCESS) {
390         IMAGE_ERR("Image native get size failed");
391         return result;
392     }
393     return BuildJsRegion(env, width, height, NUM0, NUM0);
394 }
395 
JsGetSize(napi_env env,napi_callback_info info)396 napi_value SendableImageNapi::JsGetSize(napi_env env, napi_callback_info info)
397 {
398     napi_value result = nullptr;
399 
400     IMAGE_FUNCTION_IN();
401     napi_get_undefined(env, &result);
402     std::unique_ptr<SendableImageAsyncContext> context = UnwrapContext(env, info);
403     if (context != nullptr && context->napi != nullptr && context->napi->isTestImage_) {
404         const int32_t WIDTH = 8192;
405         const int32_t HEIGHT = 8;
406         return BuildJsSize(env, WIDTH, HEIGHT);
407     }
408     if (context == nullptr || context->image == nullptr) {
409         IMAGE_ERR("Image surfacebuffer is nullptr");
410         return result;
411     }
412 
413     int32_t width = NUM0;
414     int32_t height = NUM0;
415     if (context->image->GetSize(width, height) != SUCCESS) {
416         IMAGE_ERR("Image native get size failed");
417         return result;
418     }
419     return BuildJsSize(env, width, height);
420 }
421 
JsGetFormat(napi_env env,napi_callback_info info)422 napi_value SendableImageNapi::JsGetFormat(napi_env env, napi_callback_info info)
423 {
424     napi_value result = nullptr;
425 
426     IMAGE_FUNCTION_IN();
427     napi_get_undefined(env, &result);
428     std::unique_ptr<SendableImageAsyncContext> context = UnwrapContext(env, info);
429     if (context != nullptr && context->napi != nullptr && context->napi->isTestImage_) {
430         const int32_t FORMAT = 12;
431         napi_create_int32(env, FORMAT, &result);
432         return result;
433     }
434     if (context == nullptr || context->image == nullptr) {
435         IMAGE_ERR("Image surfacebuffer is nullptr");
436         return result;
437     }
438 
439     int32_t format = NUM0;
440     if (context->image->GetFormat(format) != SUCCESS) {
441         IMAGE_ERR("Image native get format failed");
442         return result;
443     }
444 
445     napi_create_int32(env, format, &result);
446     return result;
447 }
448 
JsGetTimestamp(napi_env env,napi_callback_info info)449 napi_value SendableImageNapi::JsGetTimestamp(napi_env env, napi_callback_info info)
450 {
451     napi_value result = nullptr;
452 
453     IMAGE_FUNCTION_IN();
454     napi_get_undefined(env, &result);
455     std::unique_ptr<SendableImageAsyncContext> context = UnwrapContext(env, info);
456     if (context == nullptr || context->image == nullptr) {
457         IMAGE_ERR("context is nullptr or Image native is nullptr");
458         return result;
459     }
460 
461     int64_t timestamp = 0;
462     if (context->image->GetTimestamp(timestamp) != SUCCESS) {
463         IMAGE_ERR("Image native get timestamp failed");
464         return result;
465     }
466 
467     napi_create_int64(env, timestamp, &result);
468     return result;
469 }
470 
JSReleaseCallBack(napi_env env,napi_status status,SendableImageAsyncContext * context)471 static void JSReleaseCallBack(napi_env env, napi_status status,
472                               SendableImageAsyncContext* context)
473 {
474     IMAGE_FUNCTION_IN();
475     napi_value result = nullptr;
476     napi_get_undefined(env, &result);
477 
478     if (context == nullptr) {
479         IMAGE_ERR("context is nullptr");
480         return;
481     }
482 
483     if (context->thisRef != nullptr) {
484         napi_value thisVar;
485         napi_get_reference_value(env, context->thisRef, &thisVar);
486         napi_delete_reference(env, context->thisRef);
487         if (thisVar != nullptr) {
488             SendableImageNapi *tmp = nullptr;
489             auto status_ = napi_remove_wrap_sendable(env, thisVar, reinterpret_cast<void**>(&tmp));
490             if (status_ != napi_ok) {
491                 IMAGE_ERR("NAPI remove wrap failed status %{public}d", status_);
492             }
493         }
494     }
495 
496     context->status = SUCCESS;
497     IMAGE_FUNCTION_OUT();
498     CommonCallbackRoutine(env, context, result);
499 }
500 
JsRelease(napi_env env,napi_callback_info info)501 napi_value SendableImageNapi::JsRelease(napi_env env, napi_callback_info info)
502 {
503     IMAGE_FUNCTION_IN();
504     napi_value result = nullptr;
505     size_t argc = NUM1;
506     napi_value argv[NUM1] = {0};
507 
508     napi_get_undefined(env, &result);
509     auto context = UnwrapContext(env, info, &argc, argv);
510     if (context == nullptr) {
511         IMAGE_ERR("fail to unwrap ets image object, image maybe released");
512         return result;
513     }
514     if (argc == NUM1) {
515         if (!JsGetCallbackFunc(env, argv[NUM0], &(context->callbackRef))) {
516             IMAGE_ERR("Unsupport arg 0 type");
517             return result;
518         }
519     } else {
520         napi_create_promise(env, &(context->deferred), &result);
521     }
522 
523     if (JsCreateWork(env, "JsRelease", [](napi_env env, SendableImageAsyncContext* data) {},
524         JSReleaseCallBack, context.get())) {
525         context.release();
526     }
527     IMAGE_FUNCTION_OUT();
528     return result;
529 }
530 
CreateArrayBuffer(napi_env env,uint8_t * src,size_t srcLen,napi_value * res)531 static bool CreateArrayBuffer(napi_env env, uint8_t* src, size_t srcLen, napi_value *res)
532 {
533     if (src == nullptr || srcLen == 0) {
534         return false;
535     }
536     auto status = napi_create_external_arraybuffer(env, src, srcLen,
537         [](napi_env env, void* data, void* hint) { }, nullptr, res);
538     if (status != napi_ok) {
539         return false;
540     }
541     return true;
542 }
543 
IsEqual(const int32_t & check,ImageFormat format)544 static inline bool IsEqual(const int32_t& check,  ImageFormat format)
545 {
546     return (check == int32_t(format));
547 }
IsEqual(const int32_t & check,ComponentType type)548 static inline bool IsEqual(const int32_t& check,  ComponentType type)
549 {
550     return (check == int32_t(type));
551 }
IsYUVComponent(const int32_t & type)552 static inline bool IsYUVComponent(const int32_t& type)
553 {
554     return (IsEqual(type, ComponentType::YUV_Y) ||
555         IsEqual(type, ComponentType::YUV_U) ||
556         IsEqual(type, ComponentType::YUV_V));
557 }
IsYUV422SPImage(int32_t format)558 static inline bool IsYUV422SPImage(int32_t format)
559 {
560     return (IsEqual(format, ImageFormat::YCBCR_422_SP) ||
561         (format == int32_t(GRAPHIC_PIXEL_FMT_YCBCR_422_SP)));
562 }
CheckComponentType(const int32_t & type,int32_t format)563 static inline bool CheckComponentType(const int32_t& type, int32_t format)
564 {
565     return ((IsYUV422SPImage(format) && IsYUVComponent(type)) ||
566         (!IsYUV422SPImage(format) && IsEqual(type, ComponentType::JPEG)));
567 }
568 
BuildJsComponentObject(napi_env env,int32_t type,uint8_t * buffer,NativeComponent * component,napi_value * result)569 static bool BuildJsComponentObject(napi_env env, int32_t type, uint8_t* buffer,
570     NativeComponent* component, napi_value* result)
571 {
572     napi_value array;
573     if (!CreateArrayBuffer(env, buffer, component->size, &array)) {
574         return false;
575     }
576     napi_create_object(env, result);
577     napi_set_named_property(env, *result, "byteBuffer", array);
578     BuildIntProperty(env, "componentType", type, *result);
579     BuildIntProperty(env, "rowStride", component->rowStride, *result);
580     BuildIntProperty(env, "pixelStride", component->pixelStride, *result);
581     return true;
582 }
TestGetComponentCallBack(napi_env env,napi_status status,SendableImageAsyncContext * context)583 static void TestGetComponentCallBack(napi_env env, napi_status status, SendableImageAsyncContext* context)
584 {
585     if (context == nullptr) {
586         IMAGE_ERR("Invalid input context");
587         return;
588     }
589     napi_value result;
590     napi_value array;
591     void *nativePtr = nullptr;
592     if (napi_create_arraybuffer(env, NUM1, &nativePtr, &array) != napi_ok || nativePtr == nullptr) {
593         return;
594     }
595     napi_create_object(env, &result);
596     napi_set_named_property(env, result, "byteBuffer", array);
597     BuildIntProperty(env, "componentType", context->componentType, result);
598     BuildIntProperty(env, "rowStride", NUM0, result);
599     BuildIntProperty(env, "pixelStride", NUM0, result);
600     context->status = SUCCESS;
601     CommonCallbackRoutine(env, context, result);
602 }
603 
JsGetComponentCallBack(napi_env env,napi_status status,SendableImageAsyncContext * context)604 static void JsGetComponentCallBack(napi_env env, napi_status status, SendableImageAsyncContext* context)
605 {
606     IMAGE_FUNCTION_IN();
607     napi_value result;
608     napi_get_undefined(env, &result);
609 
610     if (context != nullptr && context->napi != nullptr && context->isTestContext) {
611         TestGetComponentCallBack(env, status, context);
612         return;
613     }
614 
615     if (context == nullptr) {
616         IMAGE_ERR("Invalid input context");
617         return;
618     }
619     context->status = ERROR;
620     NativeComponent* component = context->component;
621     if (component == nullptr) {
622         IMAGE_ERR("Invalid component");
623         CommonCallbackRoutine(env, context, result);
624         return;
625     }
626 
627     uint8_t *buffer = nullptr;
628     if (component->virAddr != nullptr) {
629         buffer = component->virAddr;
630     } else {
631         buffer = component->raw.data();
632     }
633 
634     if (buffer == nullptr || component->size == NUM0) {
635         IMAGE_ERR("Invalid buffer");
636         CommonCallbackRoutine(env, context, result);
637         return;
638     }
639 
640     if (BuildJsComponentObject(env, context->componentType, buffer, component, &result)) {
641         context->status = SUCCESS;
642     } else {
643         IMAGE_ERR("napi_create_arraybuffer failed!");
644     }
645 
646     IMAGE_FUNCTION_OUT();
647     CommonCallbackRoutine(env, context, result);
648 }
JsGetComponentExec(napi_env env,SendableImageAsyncContext * context)649 static void JsGetComponentExec(napi_env env, SendableImageAsyncContext* context)
650 {
651     if (context == nullptr || context->napi == nullptr) {
652         IMAGE_ERR("Invalid input context");
653         return;
654     }
655 
656     auto native = context->napi->GetNative();
657     if (native == nullptr) {
658         IMAGE_ERR("Empty native");
659         return;
660     }
661     context->component = native->GetComponent(context->componentType);
662 }
663 
JsGetComponentArgs(napi_env env,size_t argc,napi_value * argv,SendableImageAsyncContext * context)664 static bool JsGetComponentArgs(napi_env env, size_t argc, napi_value* argv, SendableImageAsyncContext* context)
665 {
666     if (argv == nullptr || context == nullptr || argc < NUM1 || context->napi == nullptr) {
667         IMAGE_ERR("argv is nullptr");
668         return false;
669     }
670 
671     if (!JsGetInt32Args(env, argv[NUM0], &(context->componentType))) {
672         IMAGE_ERR("Unsupport arg 0 type");
673         return false;
674     }
675 
676     auto native = context->napi->GetNative();
677     int32_t format = NUM0;
678     if (context->isTestContext) {
679         const int32_t TEST_FORMAT = 12;
680         format = TEST_FORMAT;
681     } else if (native != nullptr) {
682         native->GetFormat(format);
683     } else {
684         IMAGE_ERR("GetFormat: native is nullptr");
685         return false;
686     }
687 
688     if (!CheckComponentType(context->componentType, format)) {
689         IMAGE_ERR("Unsupport component type 0 value: %{public}d", context->componentType);
690         return false;
691     }
692 
693     if (argc == NUM2 && !JsGetCallbackFunc(env, argv[NUM1], &(context->callbackRef))) {
694         IMAGE_ERR("Unsupport arg 1 type");
695         return false;
696     }
697     return true;
698 }
699 
JsGetComponent(napi_env env,napi_callback_info info)700 napi_value SendableImageNapi::JsGetComponent(napi_env env, napi_callback_info info)
701 {
702     IMAGE_FUNCTION_IN();
703     napi_value result = nullptr;
704     size_t argc = NUM2;
705     napi_value argv[NUM2] = {0};
706 
707     napi_get_undefined(env, &result);
708     auto context = UnwrapContext(env, info, &argc, argv);
709     if (context == nullptr) {
710         return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
711             "fail to unwrap ets image object, image maybe released");
712     }
713     context->isTestContext = context->napi->isTestImage_;
714     if (!JsGetComponentArgs(env, argc, argv, context.get())) {
715         return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
716             "Unsupport arg type!");
717     }
718 
719     if (context->callbackRef == nullptr) {
720         napi_create_promise(env, &(context->deferred), &result);
721     }
722 
723     if (JsCreateWork(env, "JsGetComponent", JsGetComponentExec, JsGetComponentCallBack, context.get())) {
724         context.release();
725     }
726 
727     IMAGE_FUNCTION_OUT();
728     return result;
729 }
730 }  // namespace Media
731 }  // namespace OHOS
732