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 #include "sendable_image_source_napi.h"
16 #include <fcntl.h>
17 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
18 #include "color_space_object_convertor.h"
19 #endif
20 
21 #undef LOG_DOMAIN
22 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
23 
24 #undef LOG_TAG
25 #define LOG_TAG "SendableImageSourceNapi"
26 
27 namespace {
28     constexpr int INVALID_FD = -1;
29     constexpr uint32_t NUM_0 = 0;
30     constexpr uint32_t NUM_1 = 1;
31     constexpr uint32_t NUM_2 = 2;
32 }
33 
34 namespace OHOS {
35 namespace Media {
36 thread_local napi_ref SendableImageSourceNapi::sConstructor_ = nullptr;
37 thread_local std::shared_ptr<ImageSource> SendableImageSourceNapi::sImgSrc_ = nullptr;
38 std::shared_ptr<IncrementalPixelMap> SendableImageSourceNapi::sIncPixelMap_ = nullptr;
39 static const std::string CLASS_NAME = "ImageSourceSendable";
40 static const std::string FILE_URL_PREFIX = "file://";
41 thread_local std::string SendableImageSourceNapi::filePath_ = "";
42 thread_local int SendableImageSourceNapi::fileDescriptor_ = -1;
43 thread_local void* SendableImageSourceNapi::fileBuffer_ = nullptr;
44 thread_local size_t SendableImageSourceNapi::fileBufferSize_ = 0;
45 napi_ref SendableImageSourceNapi::pixelMapFormatRef_ = nullptr;
46 napi_ref SendableImageSourceNapi::propertyKeyRef_ = nullptr;
47 napi_ref SendableImageSourceNapi::imageFormatRef_ = nullptr;
48 napi_ref SendableImageSourceNapi::alphaTypeRef_ = nullptr;
49 napi_ref SendableImageSourceNapi::scaleModeRef_ = nullptr;
50 napi_ref SendableImageSourceNapi::componentTypeRef_ = nullptr;
51 napi_ref SendableImageSourceNapi::decodingDynamicRangeRef_ = nullptr;
52 
53 static std::mutex imageSourceCrossThreadMutex_;
54 
55 struct RawFileDescriptorInfo {
56     int32_t fd = INVALID_FD;
57     int32_t offset;
58     int32_t length;
59 };
60 
61 struct ImageSourceAsyncContext {
62     napi_env env;
63     napi_async_work work;
64     napi_deferred deferred;
65     napi_ref callbackRef = nullptr;
66     SendableImageSourceNapi *constructor_;
67     uint32_t status;
68     std::string pathName = "";
69     int fdIndex = INVALID_FD;
70     void* sourceBuffer = nullptr;
71     size_t sourceBufferSize = NUM_0;
72     std::string keyStr;
73     std::string valueStr;
74     std::vector<std::string> keyStrArray;
75     std::vector<std::pair<std::string, std::string>> kVStrArray;
76     std::string defaultValueStr;
77     int32_t valueInt;
78     int32_t deufltValueInt;
79     void *updataBuffer;
80     size_t updataBufferSize;
81     uint32_t updataBufferOffset = 0;
82     uint32_t updataLength = 0;
83     bool isCompleted = false;
84     bool isSuccess = false;
85     bool isBatch = false;
86     size_t pathNameLength;
87     SourceOptions opts;
88     uint32_t index = 0;
89     ImageInfo imageInfo;
90     DecodeOptions decodeOpts;
91     std::shared_ptr<ImageSource> rImageSource;
92     std::shared_ptr<PixelMap> rPixelMap;
93     std::string errMsg;
94     std::multimap<std::int32_t, std::string> errMsgArray;
95     std::unique_ptr<std::vector<std::unique_ptr<PixelMap>>> pixelMaps;
96     std::unique_ptr<std::vector<int32_t>> delayTimes;
97     std::unique_ptr<std::vector<int32_t>> disposalType;
98     uint32_t frameCount = 0;
99     struct RawFileDescriptorInfo rawFileInfo;
100 };
101 
102 struct ImageEnum {
103     std::string name;
104     int32_t numVal;
105     std::string strVal;
106 };
107 
108 static std::vector<struct ImageEnum> sPixelMapFormatMap = {
109     {"UNKNOWN", 0, ""},
110     {"ARGB_8888", 1, ""},
111     {"RGB_565", 2, ""},
112     {"RGBA_8888", 3, ""},
113     {"BGRA_8888", 4, ""},
114     {"RGB_888", 5, ""},
115     {"ALPHA_8", 6, ""},
116     {"RGBA_F16", 7, ""},
117     {"NV21", 8, ""},
118     {"NV12", 9, ""},
119 };
120 
121 static std::vector<struct ImageEnum> sPropertyKeyMap = {
122     {"BITS_PER_SAMPLE", 0, "BitsPerSample"},
123     {"ORIENTATION", 0, "Orientation"},
124     {"IMAGE_LENGTH", 0, "ImageLength"},
125     {"IMAGE_WIDTH", 0, "ImageWidth"},
126     {"GPS_LATITUDE", 0, "GPSLatitude"},
127     {"GPS_LONGITUDE", 0, "GPSLongitude"},
128     {"GPS_LATITUDE_REF", 0, "GPSLatitudeRef"},
129     {"GPS_LONGITUDE_REF", 0, "GPSLongitudeRef"},
130     {"DATE_TIME_ORIGINAL", 0, "DateTimeOriginal"},
131     {"EXPOSURE_TIME", 0, "ExposureTime"},
132     {"SCENE_TYPE", 0, "SceneType"},
133     {"ISO_SPEED_RATINGS", 0, "ISOSpeedRatings"},
134     {"F_NUMBER", 0, "FNumber"},
135     {"COMPRESSED_BITS_PER_PIXEL", 0, "CompressedBitsPerPixel"},
136     {"DATE_TIME", 0, "DateTime"},
137     {"GPS_TIME_STAMP", 0, "GPSTimeStamp"},
138     {"GPS_DATE_STAMP", 0, "GPSDateStamp"},
139     {"IMAGE_DESCRIPTION", 0, "ImageDescription"},
140     {"MAKE", 0, "Make"},
141     {"MODEL", 0, "Model"},
142     {"PHOTO_MODE", 0, "PhotoMode"},
143     {"SENSITIVITY_TYPE", 0, "SensitivityType"},
144     {"STANDARD_OUTPUT_SENSITIVITY", 0, "StandardOutputSensitivity"},
145     {"RECOMMENDED_EXPOSURE_INDEX", 0, "RecommendedExposureIndex"},
146     {"ISO_SPEED", 0, "ISOSpeedRatings"},
147     {"APERTURE_VALUE", 0, "ApertureValue"},
148     {"EXPOSURE_BIAS_VALUE", 0, "ExposureBiasValue"},
149     {"METERING_MODE", 0, "MeteringMode"},
150     {"LIGHT_SOURCE", 0, "LightSource"},
151     {"FLASH", 0, "Flash"},
152     {"FOCAL_LENGTH", 0, "FocalLength"},
153     {"USER_COMMENT", 0, "UserComment"},
154     {"PIXEL_X_DIMENSION", 0, "PixelXDimension"},
155     {"PIXEL_Y_DIMENSION", 0, "PixelYDimension"},
156     {"WHITE_BALANCE", 0, "WhiteBalance"},
157     {"FOCAL_LENGTH_IN_35_MM_FILM", 0, "FocalLengthIn35mmFilm"},
158     {"CAPTURE_MODE", 0, "HwMnoteCaptureMode"},
159     {"PHYSICAL_APERTURE", 0, "HwMnotePhysicalAperture"},
160     {"ROLL_ANGLE", 0, "HwMnoteRollAngle"},
161     {"PITCH_ANGLE", 0, "HwMnotePitchAngle"},
162     {"SCENE_FOOD_CONF", 0, "HwMnoteSceneFoodConf"},
163     {"SCENE_STAGE_CONF", 0, "HwMnoteSceneStageConf"},
164     {"SCENE_BLUE_SKY_CONF", 0, "HwMnoteSceneBlueSkyConf"},
165     {"SCENE_GREEN_PLANT_CONF", 0, "HwMnoteSceneGreenPlantConf"},
166     {"SCENE_BEACH_CONF", 0, "HwMnoteSceneBeachConf"},
167     {"SCENE_SNOW_CONF", 0, "HwMnoteSceneSnowConf"},
168     {"SCENE_SUNSET_CONF", 0, "HwMnoteSceneSunsetConf"},
169     {"SCENE_FLOWERS_CONF", 0, "HwMnoteSceneFlowersConf"},
170     {"SCENE_NIGHT_CONF", 0, "HwMnoteSceneNightConf"},
171     {"SCENE_TEXT_CONF", 0, "HwMnoteSceneTextConf"},
172     {"FACE_COUNT", 0, "HwMnoteFaceCount"},
173     {"FOCUS_MODE", 0, "HwMnoteFocusMode"},
174 };
175 static std::vector<struct ImageEnum> sImageFormatMap = {
176     {"YCBCR_422_SP", 1000, ""},
177     {"JPEG", 2000, ""},
178 };
179 static std::vector<struct ImageEnum> sAlphaTypeMap = {
180     {"UNKNOWN", 0, ""},
181     {"OPAQUE", 1, ""},
182     {"PREMUL", 2, ""},
183     {"UNPREMUL", 3, ""},
184 };
185 static std::vector<struct ImageEnum> sScaleModeMap = {
186     {"FIT_TARGET_SIZE", 0, ""},
187     {"CENTER_CROP", 1, ""},
188 };
189 static std::vector<struct ImageEnum> sComponentTypeMap = {
190     {"YUV_Y", 1, ""},
191     {"YUV_U", 2, ""},
192     {"YUV_V", 3, ""},
193     {"JPEG", 4, ""},
194 };
195 static std::vector<struct ImageEnum> sDecodingDynamicRangeMap = {
196     {"AUTO", 0, ""},
197     {"SDR", 1, ""},
198     {"HDR", 2, ""},
199 };
200 
ParseSize(napi_env env,napi_value root,Size * size)201 static bool ParseSize(napi_env env, napi_value root, Size* size)
202 {
203     if (size == nullptr) {
204         IMAGE_LOGE("size is nullptr");
205         return false;
206     }
207     if (!GET_INT32_BY_NAME(root, "height", size->height)) {
208         return false;
209     }
210 
211     if (!GET_INT32_BY_NAME(root, "width", size->width)) {
212         return false;
213     }
214 
215     return true;
216 }
217 
parseSourceOptions(napi_env env,napi_value root,SourceOptions * opts)218 static void parseSourceOptions(napi_env env, napi_value root, SourceOptions* opts)
219 {
220     if (!ImageNapiUtils::GetInt32ByName(env, root, "sourceDensity", &(opts->baseDensity))) {
221         IMAGE_LOGD("no sourceDensity");
222     }
223 
224     int32_t pixelFormat = 0;
225     if (!ImageNapiUtils::GetInt32ByName(env, root, "sourcePixelFormat", &pixelFormat)) {
226         IMAGE_LOGD("no sourcePixelFormat");
227     } else {
228         opts->pixelFormat = static_cast<PixelFormat>(pixelFormat);
229         IMAGE_LOGI("sourcePixelFormat:%{public}d", static_cast<int32_t>(opts->pixelFormat));
230     }
231 
232     napi_value tmpValue = nullptr;
233     if (!GET_NODE_BY_NAME(root, "sourceSize", tmpValue)) {
234         IMAGE_LOGD("no sourceSize");
235     } else {
236         if (!ParseSize(env, tmpValue, &(opts->size))) {
237             IMAGE_LOGD("ParseSize error");
238         }
239         IMAGE_LOGI("sourceSize:(%{public}d, %{public}d)", opts->size.width, opts->size.height);
240     }
241 }
242 
PrepareNapiEnv(napi_env env)243 static void PrepareNapiEnv(napi_env env)
244 {
245     napi_value globalValue;
246     napi_get_global(env, &globalValue);
247     napi_value func;
248     napi_get_named_property(env, globalValue, "requireNapi", &func);
249 
250     napi_value imageInfo;
251     napi_create_string_utf8(env, "multimedia.sendableimage", NAPI_AUTO_LENGTH, &imageInfo);
252     napi_value funcArgv[1] = { imageInfo };
253     napi_value returnValue;
254     napi_call_function(env, globalValue, func, 1, funcArgv, &returnValue);
255 }
256 
hasNamedProperty(napi_env env,napi_value object,const std::string & name)257 static bool hasNamedProperty(napi_env env, napi_value object, const std::string& name)
258 {
259     bool res = false;
260     return (napi_has_named_property(env, object, name.c_str(), &res) == napi_ok) && res;
261 }
262 
parseRawFileItem(napi_env env,napi_value argValue,const std::string & item,int32_t * value)263 static bool parseRawFileItem(napi_env env, napi_value argValue, const std::string& item, int32_t* value)
264 {
265     napi_value nItem;
266     if (napi_get_named_property(env, argValue, item.c_str(), &nItem) != napi_ok) {
267         IMAGE_LOGE("Failed to parse RawFileDescriptor item %{public}s", item.c_str());
268         return false;
269     }
270     if (napi_get_value_int32(env, nItem, value) != napi_ok) {
271         IMAGE_LOGE("Failed to get RawFileDescriptor item %{public}s value", item.c_str());
272         return false;
273     }
274     return true;
275 }
276 
isRawFileDescriptor(napi_env env,napi_value argValue,ImageSourceAsyncContext * context)277 static bool isRawFileDescriptor(napi_env env, napi_value argValue, ImageSourceAsyncContext* context)
278 {
279     if (env == nullptr || argValue == nullptr || context == nullptr) {
280         IMAGE_LOGE("isRawFileDescriptor invalid input");
281         return false;
282     }
283     if (!hasNamedProperty(env, argValue, "fd") ||
284         !hasNamedProperty(env, argValue, "offset") ||
285         !hasNamedProperty(env, argValue, "length")) {
286         IMAGE_LOGD("RawFileDescriptor mismatch");
287         return false;
288     }
289     if (parseRawFileItem(env, argValue, "fd", &(context->rawFileInfo.fd)) &&
290         parseRawFileItem(env, argValue, "offset", &(context->rawFileInfo.offset)) &&
291         parseRawFileItem(env, argValue, "length", &(context->rawFileInfo.length))) {
292         return true;
293     }
294 
295     IMAGE_LOGE("Failed to parse RawFileDescriptor item");
296     return false;
297 }
298 
FileUrlToRawPath(const std::string & path)299 static std::string FileUrlToRawPath(const std::string &path)
300 {
301     if (path.size() > FILE_URL_PREFIX.size() &&
302         (path.compare(0, FILE_URL_PREFIX.size(), FILE_URL_PREFIX) == 0)) {
303         return path.substr(FILE_URL_PREFIX.size());
304     }
305     return path;
306 }
307 
ParseRegion(napi_env env,napi_value root,Rect * region)308 static bool ParseRegion(napi_env env, napi_value root, Rect* region)
309 {
310     napi_value tmpValue = nullptr;
311 
312     if (region == nullptr) {
313         IMAGE_LOGE("region is nullptr");
314         return false;
315     }
316 
317     if (!GET_INT32_BY_NAME(root, "x", region->left)) {
318         return false;
319     }
320 
321     if (!GET_INT32_BY_NAME(root, "y", region->top)) {
322         return false;
323     }
324 
325     if (!GET_NODE_BY_NAME(root, "size", tmpValue)) {
326         return false;
327     }
328 
329     if (!GET_INT32_BY_NAME(tmpValue, "height", region->height)) {
330         return false;
331     }
332 
333     if (!GET_INT32_BY_NAME(tmpValue, "width", region->width)) {
334         return false;
335     }
336 
337     return true;
338 }
339 
IsSupportPixelFormat(int32_t val)340 static bool IsSupportPixelFormat(int32_t val)
341 {
342     if (val >= static_cast<int32_t>(PixelFormat::UNKNOWN) &&
343         val <= static_cast<int32_t>(PixelFormat::NV12)) {
344         return true;
345     }
346 
347     return false;
348 }
349 
ParsePixlForamt(int32_t val)350 static PixelFormat ParsePixlForamt(int32_t val)
351 {
352     if (val <= static_cast<int32_t>(PixelFormat::CMYK)) {
353         return PixelFormat(val);
354     }
355 
356     return PixelFormat::UNKNOWN;
357 }
358 
ParseDecodeOptions2(napi_env env,napi_value root,DecodeOptions * opts,std::string & error)359 static bool ParseDecodeOptions2(napi_env env, napi_value root, DecodeOptions* opts, std::string &error)
360 {
361     uint32_t tmpNumber = 0;
362     if (!GET_UINT32_BY_NAME(root, "desiredPixelFormat", tmpNumber)) {
363         IMAGE_LOGD("no desiredPixelFormat");
364     } else {
365         if (IsSupportPixelFormat(tmpNumber)) {
366             opts->desiredPixelFormat = ParsePixlForamt(tmpNumber);
367         } else {
368             IMAGE_LOGD("Invalid desiredPixelFormat %{public}d", tmpNumber);
369             error = "DecodeOptions mismatch";
370             return false;
371         }
372     }
373 
374     if (!GET_INT32_BY_NAME(root, "fitDensity", opts->fitDensity)) {
375         IMAGE_LOGD("no fitDensity");
376     }
377 
378     if (GET_UINT32_BY_NAME(root, "fillColor", opts->SVGOpts.fillColor.color)) {
379         opts->SVGOpts.fillColor.isValidColor = true;
380         IMAGE_LOGD("fillColor %{public}x", opts->SVGOpts.fillColor.color);
381     } else {
382         IMAGE_LOGD("no fillColor");
383     }
384 
385     if (GET_UINT32_BY_NAME(root, "SVGResize", opts->SVGOpts.SVGResize.resizePercentage)) {
386         opts->SVGOpts.SVGResize.isValidPercentage = true;
387         IMAGE_LOGD("SVGResize percentage %{public}x", opts->SVGOpts.SVGResize.resizePercentage);
388     } else {
389         IMAGE_LOGD("no SVGResize percentage");
390     }
391     napi_value nDesiredColorSpace = nullptr;
392     if (napi_get_named_property(env, root, "desiredColorSpace", &nDesiredColorSpace) == napi_ok) {
393         opts->desiredColorSpaceInfo = OHOS::ColorManager::GetColorSpaceByJSObject(env, nDesiredColorSpace);
394         IMAGE_LOGD("desiredColorSpace parse finished");
395     }
396     if (opts->desiredColorSpaceInfo == nullptr) {
397         IMAGE_LOGD("no desiredColorSpace");
398     }
399     return true;
400 }
401 
ParseDecodeOptions(napi_env env,napi_value root,DecodeOptions * opts,uint32_t * pIndex,std::string & error)402 static bool ParseDecodeOptions(napi_env env, napi_value root, DecodeOptions* opts,
403     uint32_t* pIndex, std::string &error)
404 {
405     napi_value tmpValue = nullptr;
406 
407     if (!ImageNapiUtils::GetUint32ByName(env, root, "index", pIndex)) {
408         IMAGE_LOGD("no index");
409     }
410 
411     if (opts == nullptr) {
412         IMAGE_LOGE("opts is nullptr");
413         return false;
414     }
415 
416     if (!GET_UINT32_BY_NAME(root, "sampleSize", opts->sampleSize)) {
417         IMAGE_LOGD("no sampleSize");
418     }
419 
420     if (!GET_UINT32_BY_NAME(root, "rotate", opts->rotateNewDegrees)) {
421         IMAGE_LOGD("no rotate");
422     } else {
423         if (opts->rotateNewDegrees >= 0 &&
424             opts->rotateNewDegrees <= 360) { // 360 is the maximum rotation angle.
425             opts->rotateDegrees = static_cast<float>(opts->rotateNewDegrees);
426         } else {
427             IMAGE_LOGD("Invalid rotate %{public}d", opts->rotateNewDegrees);
428             error = "DecodeOptions mismatch";
429             return false;
430         }
431     }
432 
433     if (!GET_BOOL_BY_NAME(root, "editable", opts->editable)) {
434         IMAGE_LOGD("no editable");
435     }
436 
437     if (!GET_NODE_BY_NAME(root, "desiredSize", tmpValue)) {
438         IMAGE_LOGD("no desiredSize");
439     } else {
440         if (!ParseSize(env, tmpValue, &(opts->desiredSize))) {
441             IMAGE_LOGD("ParseSize error");
442         }
443     }
444 
445     if (!GET_NODE_BY_NAME(root, "desiredRegion", tmpValue)) {
446         IMAGE_LOGD("no desiredRegion");
447     } else {
448         if (!ParseRegion(env, tmpValue, &(opts->CropRect))) {
449             IMAGE_LOGD("ParseRegion error");
450         }
451     }
452     return ParseDecodeOptions2(env, root, opts, error);
453 }
454 
ImageSourceCallbackRoutine(napi_env env,ImageSourceAsyncContext * & context,const napi_value & valueParam)455 static void ImageSourceCallbackRoutine(napi_env env, ImageSourceAsyncContext* &context, const napi_value &valueParam)
456 {
457     napi_value result[NUM_2] = {0};
458     napi_value retVal;
459     napi_value callback = nullptr;
460 
461     napi_get_undefined(env, &result[NUM_0]);
462     napi_get_undefined(env, &result[NUM_1]);
463 
464     if (context == nullptr) {
465         IMAGE_LOGE("context is nullptr");
466         return;
467     }
468 
469     if (context->status == SUCCESS) {
470         result[NUM_1] = valueParam;
471     } else if (context->errMsg.size() > 0) {
472         napi_create_string_utf8(env, context->errMsg.c_str(), NAPI_AUTO_LENGTH, &result[NUM_0]);
473     } else {
474         IMAGE_LOGD("error status, no message");
475         napi_create_string_utf8(env, "error status, no message", NAPI_AUTO_LENGTH, &result[NUM_0]);
476     }
477 
478     if (context->deferred) {
479         if (context->status == SUCCESS) {
480             napi_resolve_deferred(env, context->deferred, result[NUM_1]);
481         } else {
482             napi_reject_deferred(env, context->deferred, result[NUM_0]);
483         }
484     } else {
485         IMAGE_LOGD("call callback function");
486         napi_get_reference_value(env, context->callbackRef, &callback);
487         napi_call_function(env, nullptr, callback, NUM_2, result, &retVal);
488         napi_delete_reference(env, context->callbackRef);
489     }
490 
491     napi_delete_async_work(env, context->work);
492 
493     delete context;
494     context = nullptr;
495 }
496 
CreatePixelMapInner(SendableImageSourceNapi * thisPtr,std::shared_ptr<ImageSource> imageSource,uint32_t index,DecodeOptions decodeOpts,uint32_t & status)497 static std::shared_ptr<PixelMap> CreatePixelMapInner(SendableImageSourceNapi *thisPtr,
498     std::shared_ptr<ImageSource> imageSource, uint32_t index, DecodeOptions decodeOpts, uint32_t &status)
499 {
500     if (thisPtr == nullptr || imageSource == nullptr) {
501         IMAGE_LOGE("Invailed args");
502         status = ERROR;
503         return nullptr;
504     }
505 
506     std::shared_ptr<PixelMap> pixelMap;
507     auto incPixelMap = thisPtr->GetIncrementalPixelMap();
508     if (incPixelMap != nullptr) {
509         IMAGE_LOGD("Get Incremental PixelMap!!!");
510         pixelMap = incPixelMap;
511     } else {
512         pixelMap = imageSource->CreatePixelMapEx(index, decodeOpts, status);
513     }
514 
515     if (status != SUCCESS || !IMG_NOT_NULL(pixelMap)) {
516         IMAGE_LOGE("Create PixelMap error");
517     }
518 
519     return pixelMap;
520 }
521 
CreatePixelMapExecute(napi_env env,void * data)522 static void CreatePixelMapExecute(napi_env env, void *data)
523 {
524     IMAGE_LOGD("CreatePixelMapExecute IN");
525     if (data == nullptr) {
526         IMAGE_LOGE("data is nullptr");
527         return;
528     }
529     auto context = static_cast<ImageSourceAsyncContext*>(data);
530     if (context == nullptr) {
531         IMAGE_LOGE("empty context");
532         return;
533     }
534 
535     if (context->errMsg.size() > 0) {
536         IMAGE_LOGE("mismatch args");
537         context->status = ERROR;
538         return;
539     }
540 
541     context->rPixelMap = CreatePixelMapInner(context->constructor_, context->rImageSource,
542         context->index, context->decodeOpts, context->status);
543 
544     if (context->status != SUCCESS) {
545         context->errMsg = "Create PixelMap error";
546         IMAGE_LOGE("Create PixelMap error");
547     }
548     IMAGE_LOGD("CreatePixelMapExecute OUT");
549 }
550 
CreatePixelMapComplete(napi_env env,napi_status status,void * data)551 static void CreatePixelMapComplete(napi_env env, napi_status status, void *data)
552 {
553     IMAGE_LOGD("CreatePixelMapComplete IN");
554     napi_value result = nullptr;
555     auto context = static_cast<ImageSourceAsyncContext*>(data);
556 
557     if (context->status == SUCCESS) {
558         result = SendablePixelMapNapi::CreateSendablePixelMap(env, context->rPixelMap);
559     } else {
560         napi_get_undefined(env, &result);
561     }
562     IMAGE_LOGD("CreatePixelMapComplete OUT");
563     ImageSourceCallbackRoutine(env, context, result);
564 }
565 
CreateNativeImageSource(napi_env env,napi_value argValue,SourceOptions & opts,ImageSourceAsyncContext * context)566 static std::unique_ptr<ImageSource> CreateNativeImageSource(napi_env env, napi_value argValue,
567     SourceOptions &opts, ImageSourceAsyncContext* context)
568 {
569     std::unique_ptr<ImageSource> imageSource = nullptr;
570     uint32_t errorCode = ERR_MEDIA_INVALID_VALUE;
571     napi_status status;
572 
573     auto inputType = ImageNapiUtils::getType(env, argValue);
574     if (napi_string == inputType) { // File Path
575         if (!ImageNapiUtils::GetUtf8String(env, argValue, context->pathName)) {
576             IMAGE_LOGE("fail to get pathName");
577             return imageSource;
578         }
579         context->pathName = FileUrlToRawPath(context->pathName);
580         context->pathNameLength = context->pathName.size();
581         imageSource = ImageSource::CreateImageSource(context->pathName, opts, errorCode);
582     } else if (napi_number == inputType) { // Fd
583         napi_get_value_int32(env, argValue, &context->fdIndex);
584         IMAGE_LOGD("CreateImageSource fdIndex is [%{public}d]", context->fdIndex);
585         imageSource = ImageSource::CreateImageSource(context->fdIndex, opts, errorCode);
586     } else if (isRawFileDescriptor(env, argValue, context)) {
587         IMAGE_LOGE(
588             "CreateImageSource RawFileDescriptor fd: %{public}d, offset: %{public}d, length: %{public}d",
589             context->rawFileInfo.fd, context->rawFileInfo.offset, context->rawFileInfo.length);
590         int32_t fileSize = context->rawFileInfo.offset + context->rawFileInfo.length;
591         imageSource = ImageSource::CreateImageSource(context->rawFileInfo.fd,
592             context->rawFileInfo.offset, fileSize, opts, errorCode);
593     } else { // Input Buffer
594         uint32_t refCount = NUM_1;
595         napi_ref arrayRef = nullptr;
596         napi_create_reference(env, argValue, refCount, &arrayRef);
597         status = napi_get_arraybuffer_info(env, argValue, &(context->sourceBuffer), &(context->sourceBufferSize));
598         if (status != napi_ok) {
599             napi_delete_reference(env, arrayRef);
600             IMAGE_LOGE("fail to get arraybufferinfo");
601             return nullptr;
602         }
603         imageSource = ImageSource::CreateImageSource(static_cast<uint8_t *>(context->sourceBuffer),
604             context->sourceBufferSize, opts, errorCode);
605         napi_delete_reference(env, arrayRef);
606     }
607     return imageSource;
608 }
609 
CreatePixelMap(napi_env env,napi_callback_info info)610 napi_value SendableImageSourceNapi::CreatePixelMap(napi_env env, napi_callback_info info)
611 {
612     napi_value result = nullptr;
613     napi_get_undefined(env, &result);
614 
615     int32_t refCount = 1;
616     napi_status status;
617     napi_value thisVar = nullptr;
618     napi_value argValue[NUM_2] = {0};
619     size_t argCount = NUM_2;
620     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
621     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, thisVar), nullptr, IMAGE_LOGE("fail to get thisVar"));
622     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("fail to napi_get_cb_info"));
623 
624     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
625 
626     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
627     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_),
628         nullptr, IMAGE_LOGE("fail to unwrap context"));
629     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_->nativeImgSrc),
630         nullptr, IMAGE_LOGE("fail to unwrap nativeImgSrc"));
631     asyncContext->rImageSource = asyncContext->constructor_->nativeImgSrc;
632     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rImageSource),
633         nullptr, IMAGE_LOGE("empty native rImageSource"));
634 
635     if (argCount == NUM_0) {
636         IMAGE_LOGD("CreatePixelMap with no arg");
637     } else if (argCount == NUM_1 || argCount == NUM_2) {
638         if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_object) {
639             if (!ParseDecodeOptions(env, argValue[NUM_0], &(asyncContext->decodeOpts),
640                                     &(asyncContext->index), asyncContext->errMsg)) {
641                 IMAGE_LOGE("DecodeOptions mismatch");
642             }
643         }
644         if (ImageNapiUtils::getType(env, argValue[argCount - 1]) == napi_function) {
645             napi_create_reference(env, argValue[argCount - 1], refCount, &asyncContext->callbackRef);
646         }
647     } else {
648         IMAGE_LOGE("argCount mismatch");
649         return result;
650     }
651     if (asyncContext->callbackRef == nullptr) {
652         napi_create_promise(env, &(asyncContext->deferred), &result);
653     } else {
654         napi_get_undefined(env, &result);
655     }
656 
657     ImageNapiUtils::HicheckerReport();
658     IMG_CREATE_CREATE_ASYNC_WORK_WITH_QOS(env, status, "CreatePixelMap", CreatePixelMapExecute,
659         CreatePixelMapComplete, asyncContext, asyncContext->work, napi_qos_user_initiated);
660 
661     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
662         nullptr, IMAGE_LOGE("fail to create async work"));
663     return result;
664 }
665 
CreateImageSource(napi_env env,napi_callback_info info)666 napi_value SendableImageSourceNapi::CreateImageSource(napi_env env, napi_callback_info info)
667 {
668     PrepareNapiEnv(env);
669     napi_value result = nullptr;
670     napi_get_undefined(env, &result);
671 
672     napi_status status;
673     napi_value thisVar = nullptr;
674     napi_value argValue[NUM_2] = {0};
675     size_t argCount = 2;
676     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
677     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("fail to napi_get_cb_info"));
678     NAPI_ASSERT(env, argCount > 0, "No arg!");
679 
680     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
681     SourceOptions opts;
682     if (argCount > NUM_1) {
683         parseSourceOptions(env, argValue[NUM_1], &opts);
684     }
685     std::unique_ptr<ImageSource> imageSource = CreateNativeImageSource(env, argValue[NUM_0],
686         opts, asyncContext.get());
687     if (imageSource == nullptr) {
688         IMAGE_LOGE("CreateImageSourceExec error");
689         napi_get_undefined(env, &result);
690         return result;
691     }
692 
693     {
694         std::lock_guard<std::mutex> lock(imageSourceCrossThreadMutex_);
695         filePath_ = asyncContext->pathName;
696         fileDescriptor_ = asyncContext->fdIndex;
697         fileBuffer_ = asyncContext->sourceBuffer;
698         fileBufferSize_ = asyncContext->sourceBufferSize;
699     }
700 
701     napi_value constructor = nullptr;
702     status = napi_get_reference_value(env, sConstructor_, &constructor);
703     if (IMG_IS_OK(status)) {
704         sImgSrc_ = std::move(imageSource);
705         status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
706     }
707     if (!IMG_IS_OK(status)) {
708         IMAGE_LOGE("New instance could not be obtained");
709         napi_get_undefined(env, &result);
710     }
711     return result;
712 }
713 
714 struct ImageConstructorInfo {
715     std::string className;
716     napi_ref* classRef;
717     napi_callback constructor;
718     const napi_property_descriptor* property;
719     size_t propertyCount;
720     const napi_property_descriptor* staticProperty;
721     size_t staticPropertyCount;
722 };
723 
SendableImageSourceNapi()724 SendableImageSourceNapi::SendableImageSourceNapi():env_(nullptr)
725 {   }
726 
~SendableImageSourceNapi()727 SendableImageSourceNapi::~SendableImageSourceNapi()
728 {
729     release();
730 }
731 
DoInit(napi_env env,napi_value exports,struct ImageConstructorInfo info)732 static napi_value DoInit(napi_env env, napi_value exports, struct ImageConstructorInfo info)
733 {
734     napi_value constructor = nullptr;
735     napi_status status = napi_define_class(env, info.className.c_str(), NAPI_AUTO_LENGTH,
736         info.constructor, nullptr, info.propertyCount, info.property, &constructor);
737     if (status != napi_ok) {
738         IMAGE_LOGE("define class fail");
739         return nullptr;
740     }
741 
742     status = napi_create_reference(env, constructor, NUM_1, info.classRef);
743     if (status != napi_ok) {
744         IMAGE_LOGE("create reference fail");
745         return nullptr;
746     }
747 
748     napi_value global = nullptr;
749     status = napi_get_global(env, &global);
750     if (status != napi_ok) {
751         IMAGE_LOGE("Init:get global fail");
752         return nullptr;
753     }
754 
755     status = napi_set_named_property(env, global, info.className.c_str(), constructor);
756     if (status != napi_ok) {
757         IMAGE_LOGE("Init:set global named property fail");
758         return nullptr;
759     }
760 
761     status = napi_define_properties(env, exports, info.staticPropertyCount, info.staticProperty);
762     if (status != napi_ok) {
763         IMAGE_LOGE("define properties fail");
764         return nullptr;
765     }
766     return exports;
767 }
768 
Init(napi_env env,napi_value exports)769 napi_value SendableImageSourceNapi::Init(napi_env env, napi_value exports)
770 {
771     napi_property_descriptor properties[] = {
772         DECLARE_NAPI_FUNCTION("createPixelMap", CreatePixelMap),
773         DECLARE_NAPI_FUNCTION("release", Release),
774     };
775 
776     napi_property_descriptor static_prop[] = {
777         DECLARE_NAPI_STATIC_FUNCTION("createImageSource", CreateImageSource),
778     };
779 
780     struct ImageConstructorInfo info = {
781         .className = CLASS_NAME,
782         .classRef = &sConstructor_,
783         .constructor = Constructor,
784         .property = properties,
785         .propertyCount = sizeof(properties) / sizeof(properties[NUM_0]),
786         .staticProperty = static_prop,
787         .staticPropertyCount = sizeof(static_prop) / sizeof(static_prop[NUM_0]),
788     };
789 
790     if (DoInit(env, exports, info)) {
791         return nullptr;
792     }
793     return exports;
794 }
795 
Constructor(napi_env env,napi_callback_info info)796 napi_value SendableImageSourceNapi::Constructor(napi_env env, napi_callback_info info)
797 {
798     napi_value undefineValue = nullptr;
799     napi_get_undefined(env, &undefineValue);
800 
801     napi_status status;
802     napi_value thisVar = nullptr;
803     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
804     if (status == napi_ok && thisVar != nullptr) {
805         std::unique_ptr<SendableImageSourceNapi> pImgSrcNapi = std::make_unique<SendableImageSourceNapi>();
806         if (pImgSrcNapi != nullptr) {
807             pImgSrcNapi->env_ = env;
808             pImgSrcNapi->nativeImgSrc = sImgSrc_;
809             if (pImgSrcNapi->nativeImgSrc == nullptr) {
810                 IMAGE_LOGE("Failed to set nativeImageSource with null. Maybe a reentrancy error");
811             }
812             pImgSrcNapi->navIncPixelMap_ = sIncPixelMap_;
813             sIncPixelMap_ = nullptr;
814             sImgSrc_ = nullptr;
815             status = napi_wrap(env, thisVar, reinterpret_cast<void *>(pImgSrcNapi.get()),
816                                SendableImageSourceNapi::Destructor, nullptr, nullptr);
817             if (status == napi_ok) {
818                 pImgSrcNapi.release();
819                 return thisVar;
820             } else {
821                 IMAGE_LOGE("Failure wrapping js to native napi");
822             }
823         }
824     }
825 
826     return undefineValue;
827 }
828 
Destructor(napi_env env,void * nativeObject,void * finalize)829 void SendableImageSourceNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
830 {
831     reinterpret_cast<SendableImageSourceNapi *>(nativeObject)->nativeImgSrc = nullptr;
832     IMAGE_LOGD("ImageSourceNapi::Destructor");
833 }
834 
ReleaseComplete(napi_env env,napi_status status,void * data)835 static void ReleaseComplete(napi_env env, napi_status status, void *data)
836 {
837     napi_value result = nullptr;
838     napi_get_undefined(env, &result);
839 
840     auto context = static_cast<ImageSourceAsyncContext*>(data);
841     delete context->constructor_;
842     context->constructor_ = nullptr;
843     ImageSourceCallbackRoutine(env, context, result);
844 }
845 
Release(napi_env env,napi_callback_info info)846 napi_value SendableImageSourceNapi::Release(napi_env env, napi_callback_info info)
847 {
848     IMAGE_LOGD("Release enter");
849     napi_value result = nullptr;
850     napi_get_undefined(env, &result);
851 
852     int32_t refCount = 1;
853     napi_status status;
854     napi_value thisVar = nullptr;
855     napi_value argValue[NUM_1] = {0};
856     size_t argCount = 1;
857 
858     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
859     IMAGE_LOGD("Release argCount is [%{public}zu]", argCount);
860     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("fail to napi_get_cb_info"));
861 
862     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
863     status = napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
864 
865     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_), result,
866         IMAGE_LOGE("fail to unwrap context"));
867 
868     IMAGE_LOGD("Release argCount is [%{public}zu]", argCount);
869     if (argCount == 1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_function) {
870         napi_create_reference(env, argValue[NUM_0], refCount, &asyncContext->callbackRef);
871     }
872 
873     if (asyncContext->callbackRef == nullptr) {
874         napi_create_promise(env, &(asyncContext->deferred), &result);
875     }
876 
877     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "Release",
878         [](napi_env env, void *data) {}, ReleaseComplete, asyncContext, asyncContext->work);
879     IMAGE_LOGD("Release exit");
880     return result;
881 }
882 
release()883 void SendableImageSourceNapi::release()
884 {
885     if (!isRelease) {
886         nativeImgSrc = nullptr;
887         isRelease = true;
888     }
889 }
890 
891 }
892 }