1 /*
2  * Copyright (c) 2021-2023 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 "camera_napi_utils.h"
17 
18 #include "camera_error_code.h"
19 #include "camera_log.h"
20 #include "napi/native_api.h"
21 
22 namespace OHOS {
23 namespace CameraStandard {
24 bool CameraNapiUtils::mEnableSecure = false;
CreateNapiErrorObject(napi_env env,int32_t errorCode,const char * errString,std::unique_ptr<JSAsyncContextOutput> & jsContext)25 void CameraNapiUtils::CreateNapiErrorObject(napi_env env, int32_t errorCode, const char* errString,
26     std::unique_ptr<JSAsyncContextOutput> &jsContext)
27 {
28     napi_get_undefined(env, &jsContext->data);
29     napi_value napiErrorCode = nullptr;
30     napi_value napiErrorMsg = nullptr;
31 
32     std::string errorCodeStr = std::to_string(errorCode);
33     napi_create_string_utf8(env, errorCodeStr.c_str(), NAPI_AUTO_LENGTH, &napiErrorCode);
34     napi_create_string_utf8(env, errString, NAPI_AUTO_LENGTH, &napiErrorMsg);
35 
36     napi_create_object(env, &jsContext->error);
37     napi_set_named_property(env, jsContext->error, "code", napiErrorCode);
38     napi_set_named_property(env, jsContext->error, "message", napiErrorMsg);
39 
40     jsContext->status = false;
41 }
42 
InvokeJSAsyncMethod(napi_env env,napi_deferred deferred,napi_ref callbackRef,napi_async_work work,const JSAsyncContextOutput & asyncContext)43 void CameraNapiUtils::InvokeJSAsyncMethod(napi_env env, napi_deferred deferred,
44     napi_ref callbackRef, napi_async_work work, const JSAsyncContextOutput &asyncContext)
45 {
46     napi_value retVal;
47     napi_value callback = nullptr;
48     std::string funcName = asyncContext.funcName;
49     MEDIA_INFO_LOG("%{public}s, context->InvokeJSAsyncMethod start", funcName.c_str());
50     /* Deferred is used when JS Callback method expects a promise value */
51     if (deferred) {
52         if (asyncContext.status) {
53             napi_resolve_deferred(env, deferred, asyncContext.data);
54             MEDIA_INFO_LOG("%{public}s, InvokeJSAsyncMethod napi_resolve_deferred", funcName.c_str());
55         } else {
56             napi_reject_deferred(env, deferred, asyncContext.error);
57             MEDIA_ERR_LOG("%{public}s, InvokeJSAsyncMethod napi_reject_deferred", funcName.c_str());
58         }
59         MEDIA_INFO_LOG("%{public}s, InvokeJSAsyncMethod end deferred", funcName.c_str());
60     } else {
61         MEDIA_INFO_LOG("%{public}s, InvokeJSAsyncMethod callback", funcName.c_str());
62         napi_value result[ARGS_TWO];
63         result[PARAM0] = asyncContext.error;
64         result[PARAM1] = asyncContext.data;
65         napi_get_reference_value(env, callbackRef, &callback);
66         MEDIA_INFO_LOG("%{public}s, InvokeJSAsyncMethod napi_call_function start", funcName.c_str());
67         napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal);
68         MEDIA_INFO_LOG("%{public}s, InvokeJSAsyncMethod napi_call_function end", funcName.c_str());
69         napi_delete_reference(env, callbackRef);
70     }
71     napi_delete_async_work(env, work);
72     MEDIA_INFO_LOG("%{public}s, InvokeJSAsyncMethod inner end", funcName.c_str());
73 }
74 
IncrementAndGet(uint32_t & num)75 int32_t CameraNapiUtils::IncrementAndGet(uint32_t& num)
76 {
77     int32_t temp = num & 0x00ffffff;
78     if (temp >= 0xffff) {
79         num = num & 0xff000000;
80     }
81     num++;
82     return num;
83 }
84 
GetEnableSecureCamera()85 bool CameraNapiUtils::GetEnableSecureCamera()
86 {
87     return mEnableSecure;
88 }
89 
IsEnableSecureCamera(bool isEnable)90 void CameraNapiUtils::IsEnableSecureCamera(bool isEnable)
91 {
92     mEnableSecure = isEnable;
93 }
94 
CheckInvalidArgument(napi_env env,size_t argc,int32_t length,napi_value * argv,CameraSteps step)95 bool CameraNapiUtils::CheckInvalidArgument(napi_env env, size_t argc, int32_t length,
96     napi_value *argv, CameraSteps step)
97 {
98     bool isPass = true;
99     napi_valuetype valueTypeArray[length];
100     for (int32_t i = 0; i < length; i++) {
101         napi_typeof(env, argv[i], &valueTypeArray[i]);
102     }
103     switch (step) {
104         case CREATE_CAMERA_INPUT_INSTANCE:
105             if (argc == ARGS_ONE) {
106                 isPass = valueTypeArray[0] == napi_object;
107             } else if (argc == ARGS_TWO) {
108                 isPass = (valueTypeArray[0] == napi_number) && (valueTypeArray[1] == napi_number);
109             } else {
110                 isPass = false;
111             }
112             break;
113 
114         case CREATE_PREVIEW_OUTPUT_INSTANCE:
115             isPass = (argc == ARGS_TWO) &&
116                         (valueTypeArray[0] == napi_object) && (valueTypeArray[1] == napi_string);
117             break;
118 
119         case CREATE_PHOTO_OUTPUT_INSTANCE:
120             isPass = (argc >= ARGS_ONE) && (valueTypeArray[0] == napi_object);
121             break;
122 
123         case CREATE_VIDEO_OUTPUT_INSTANCE:
124             isPass = (argc == ARGS_TWO) &&
125                         (valueTypeArray[0] == napi_object) && (valueTypeArray[1] == napi_string);
126             break;
127 
128         case CREATE_METADATA_OUTPUT_INSTANCE:
129             isPass = argc == ARGS_ONE;
130             if (argc == ARGS_ONE) {
131                 napi_is_array(env, argv[0], &isPass);
132             } else {
133                 isPass = false;
134             }
135             break;
136 
137         case ADD_INPUT:
138             isPass = (argc == ARGS_ONE) && (valueTypeArray[0] == napi_object);
139             break;
140 
141         case REMOVE_INPUT:
142             isPass = (argc == ARGS_ONE) && (valueTypeArray[0] == napi_object);
143             break;
144 
145         case ADD_OUTPUT:
146             isPass = (argc == ARGS_ONE) && (valueTypeArray[0] == napi_object);
147             break;
148 
149         case REMOVE_OUTPUT:
150             isPass = (argc == ARGS_ONE) && (valueTypeArray[0] == napi_object);
151             break;
152 
153         case PHOTO_OUT_CAPTURE:
154             if (argc == ARGS_ZERO) {
155                 isPass = true;
156             } else if (argc == ARGS_ONE) {
157                 isPass = (valueTypeArray[0] == napi_object) || (valueTypeArray[0] == napi_function) ||
158                     (valueTypeArray[0] == napi_undefined);
159             } else if (argc == ARGS_TWO) {
160                 isPass = (valueTypeArray[0] == napi_object) && (valueTypeArray[1] == napi_function);
161             } else {
162                 isPass = false;
163             }
164             break;
165 
166         case PHOTO_OUT_BURST_CAPTURE:
167             if (argc == ARGS_ONE) {
168                 isPass = valueTypeArray[0] == napi_object;
169             }  else {
170                 isPass = false;
171             }
172             break;
173 
174         case ADD_DEFERRED_SURFACE:
175             if (argc == ARGS_ONE) {
176                 isPass = valueTypeArray[0] == napi_string;
177             } else if (argc == ARGS_TWO) {
178                 isPass = (valueTypeArray[0] == napi_string) && (valueTypeArray[1] == napi_function);
179             } else {
180                 isPass = false;
181             }
182             break;
183 
184         case CREATE_DEFERRED_PREVIEW_OUTPUT:
185             if (argc == ARGS_ONE) {
186                 isPass = valueTypeArray[0] == napi_object;
187             }  else {
188                 isPass = false;
189             }
190             break;
191 
192         default:
193             break;
194     }
195     if (!isPass) {
196         std::string errorCode = std::to_string(CameraErrorCode::INVALID_ARGUMENT);
197         napi_throw_type_error(env, errorCode.c_str(), "");
198     }
199     return isPass;
200 }
201 
CheckError(napi_env env,int32_t retCode)202 bool CameraNapiUtils::CheckError(napi_env env, int32_t retCode)
203 {
204     if ((retCode != 0)) {
205         std::string errorCode = std::to_string(retCode);
206         napi_throw_error(env, errorCode.c_str(), "");
207         return false;
208     }
209     return true;
210 }
211 
FloatToDouble(float val)212 double CameraNapiUtils::FloatToDouble(float val)
213 {
214     const double precision = 1000000.0;
215     return std::round(val * precision) / precision;
216 }
217 
GetStringArgument(napi_env env,napi_value value)218 std::string CameraNapiUtils::GetStringArgument(napi_env env, napi_value value)
219 {
220     napi_valuetype valueNapiType = napi_undefined;
221     napi_typeof(env, value, &valueNapiType);
222     if (valueNapiType != napi_string) {
223         return "";
224     }
225     size_t stringSize = 0;
226     napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &stringSize);
227     if (status != napi_ok || stringSize == 0) {
228         return "";
229     }
230     std::string strValue = std::string(stringSize, '\0');
231     status = napi_get_value_string_utf8(env, value, strValue.data(), stringSize + 1, &stringSize);
232     if (status != napi_ok || stringSize == 0) {
233         return "";
234     }
235     return strValue;
236 }
237 
IsSameNapiValue(napi_env env,napi_value valueSrc,napi_value valueDst)238 bool CameraNapiUtils::IsSameNapiValue(napi_env env, napi_value valueSrc, napi_value valueDst)
239 {
240     if (valueSrc == nullptr && valueDst == nullptr) {
241         return true;
242     }
243     if (valueSrc == nullptr || valueDst == nullptr) {
244         return false;
245     }
246     bool isEquals = false;
247     if (napi_strict_equals(env, valueSrc, valueDst, &isEquals) != napi_ok) {
248         MEDIA_ERR_LOG("get napi_strict_equals failed");
249         return false;
250     }
251     return isEquals;
252 }
253 
CallPromiseFun(napi_env env,napi_value promiseValue,void * data,napi_callback thenCallback,napi_callback catchCallback)254 napi_status CameraNapiUtils::CallPromiseFun(
255     napi_env env, napi_value promiseValue, void* data, napi_callback thenCallback, napi_callback catchCallback)
256 {
257     MEDIA_DEBUG_LOG("CallPromiseFun Start");
258     bool isPromise = false;
259     napi_is_promise(env, promiseValue, &isPromise);
260     if (!isPromise) {
261         MEDIA_ERR_LOG("CallPromiseFun promiseValue is not promise");
262         return napi_invalid_arg;
263     }
264     // Create promiseThen
265     napi_value promiseThen = nullptr;
266     napi_get_named_property(env, promiseValue, "then", &promiseThen);
267     if (promiseThen == nullptr) {
268         MEDIA_ERR_LOG("CallPromiseFun get promiseThen failed");
269         return napi_invalid_arg;
270     }
271     napi_value thenValue;
272     napi_status ret = napi_create_function(env, "thenCallback", NAPI_AUTO_LENGTH, thenCallback, data, &thenValue);
273     if (ret != napi_ok) {
274         MEDIA_ERR_LOG("CallPromiseFun thenCallback got exception");
275         return ret;
276     }
277     napi_value catchValue;
278     ret = napi_create_function(env, "catchCallback", NAPI_AUTO_LENGTH, catchCallback, data, &catchValue);
279     if (ret != napi_ok) {
280         MEDIA_ERR_LOG("CallPromiseFun  catchCallback got exception");
281         return ret;
282     }
283     napi_value thenReturnValue;
284     constexpr uint32_t THEN_ARGC = 2;
285     napi_value thenArgv[THEN_ARGC] = { thenValue, catchValue };
286     ret = napi_call_function(env, promiseValue, promiseThen, THEN_ARGC, thenArgv, &thenReturnValue);
287     if (ret != napi_ok) {
288         MEDIA_ERR_LOG("CallPromiseFun PromiseThen got exception");
289         return ret;
290     }
291     MEDIA_DEBUG_LOG("CallPromiseFun End");
292     return napi_ok;
293 }
294 
GetPropertyDescriptor(std::vector<std::vector<napi_property_descriptor>> descriptors)295 std::vector<napi_property_descriptor> CameraNapiUtils::GetPropertyDescriptor(
296     std::vector<std::vector<napi_property_descriptor>> descriptors)
297 {
298     MEDIA_DEBUG_LOG("GetPropertyDescriptor Start %zu", descriptors.size());
299     std::vector<napi_property_descriptor> properties = {};
300     std::for_each(descriptors.begin(), descriptors.end(),
301                   [&properties](const std::vector<napi_property_descriptor> descriptor) {
302                       properties.insert(properties.end(), descriptor.begin(), descriptor.end());
303                   });
304     return properties;
305 };
306 
CreateObjectWithPropName(napi_env env,napi_value * result,size_t property_count,const char ** keys)307 napi_status CameraNapiUtils::CreateObjectWithPropName(
308     napi_env env, napi_value* result, size_t property_count, const char** keys)
309 {
310     napi_value values[property_count];
311     for (size_t i = 0; i < property_count; i++) {
312         napi_get_undefined(env, &values[i]);
313     }
314     return napi_create_object_with_named_properties(env, result, property_count, keys, values);
315 }
316 
CreateObjectWithPropNameAndValues(napi_env env,napi_value * result,size_t property_count,const char ** keys,const std::vector<std::string> values)317 napi_status CameraNapiUtils::CreateObjectWithPropNameAndValues(
318     napi_env env, napi_value* result, size_t property_count, const char** keys, const std::vector<std::string> values)
319 {
320     napi_value napiValues[property_count];
321     for (size_t i = 0; i < property_count; i++) {
322         napi_create_string_utf8(env, values[i].data(), values[i].size(), &napiValues[i]);
323     }
324     return napi_create_object_with_named_properties(env, result, property_count, keys, napiValues);
325 }
326 
GetNapiArgs(napi_env env,napi_callback_info callbackInfo)327 size_t CameraNapiUtils::GetNapiArgs(napi_env env, napi_callback_info callbackInfo)
328 {
329     size_t argsSize = 0;
330     napi_get_cb_info(env, callbackInfo, &argsSize, nullptr, nullptr, nullptr);
331     return argsSize;
332 }
333 
CreateFrameRateJSArray(napi_env env,std::vector<int32_t> frameRateRange,napi_value & result)334 void CameraNapiUtils::CreateFrameRateJSArray(napi_env env, std::vector<int32_t> frameRateRange, napi_value &result)
335 {
336     MEDIA_DEBUG_LOG("CreateFrameRateJSArray called");
337     if (frameRateRange.empty()) {
338         MEDIA_ERR_LOG("frameRateRange is empty");
339     }
340 
341     napi_status status = napi_create_object(env, &result);
342     if (status == napi_ok) {
343         napi_value minRate;
344         status = napi_create_int32(env, frameRateRange[0], &minRate);
345         napi_value maxRate;
346         status = napi_create_int32(env, frameRateRange[1], &maxRate);
347         if (status != napi_ok || napi_set_named_property(env, result, "min", minRate) != napi_ok ||
348             napi_set_named_property(env, result, "max", maxRate) != napi_ok) {
349             MEDIA_ERR_LOG("Failed to create frameRateArray with napi wrapper object.");
350         }
351     }
352 }
353 
CreateSupportFrameRatesJSArray(napi_env env,std::vector<std::vector<int32_t>> supportedFrameRatesRange)354 napi_value CameraNapiUtils::CreateSupportFrameRatesJSArray(
355     napi_env env, std::vector<std::vector<int32_t>> supportedFrameRatesRange)
356 {
357     MEDIA_DEBUG_LOG("CreateFrameRateJSArray called");
358     napi_value supportedFrameRateArray = nullptr;
359     if (supportedFrameRatesRange.empty()) {
360         MEDIA_ERR_LOG("frameRateRange is empty");
361     }
362 
363     napi_status status = napi_create_array(env, &supportedFrameRateArray);
364     if (status == napi_ok) {
365         for (size_t i = 0; i < supportedFrameRatesRange.size(); i++) {
366             napi_value supportedFrameRateItem;
367             CreateFrameRateJSArray(env, supportedFrameRatesRange[i], supportedFrameRateItem);
368             if (napi_set_element(env, supportedFrameRateArray, i, supportedFrameRateItem) != napi_ok) {
369                 MEDIA_ERR_LOG("Failed to create supportedFrameRateArray with napi wrapper object.");
370                 return nullptr;
371             }
372         }
373     }
374     return supportedFrameRateArray;
375 }
376 
ProcessingPhysicalApertures(napi_env env,std::vector<std::vector<float>> physicalApertures)377 napi_value CameraNapiUtils::ProcessingPhysicalApertures(napi_env env, std::vector<std::vector<float>> physicalApertures)
378 {
379     napi_value result = nullptr;
380     napi_create_array(env, &result);
381     size_t zoomRangeSize = 2;
382     size_t zoomMinIndex = 0;
383     size_t zoomMaxIndex = 1;
384     for (size_t i = 0; i < physicalApertures.size(); i++) {
385         if (physicalApertures[i].size() <= zoomRangeSize) {
386             continue;
387         }
388         napi_value zoomRange;
389         napi_create_array(env, &zoomRange);
390         napi_value physicalApertureRange;
391         napi_create_array(env, &physicalApertureRange);
392         for (size_t y = 0; y < physicalApertures[i].size(); y++) {
393             napi_value value;
394             napi_create_double(env, CameraNapiUtils::FloatToDouble(physicalApertures[i][y]), &value);
395             if (y == zoomMinIndex) {
396                 napi_set_element(env, zoomRange, y, value);
397                 napi_set_named_property(env, zoomRange, "min", value);
398                 continue;
399             }
400             if (y == zoomMaxIndex) {
401                 napi_set_element(env, zoomRange, y, value);
402                 napi_set_named_property(env, zoomRange, "max", value);
403                 continue;
404             }
405             napi_set_element(env, physicalApertureRange, y - zoomRangeSize, value);
406         }
407         napi_value obj;
408         napi_create_object(env, &obj);
409         napi_set_named_property(env, obj, "zoomRange", zoomRange);
410         napi_set_named_property(env, obj, "apertures", physicalApertureRange);
411         napi_set_element(env, result, i, obj);
412     }
413     return result;
414 }
415 
CreateJSArray(napi_env env,napi_status status,std::vector<int32_t> nativeArray)416 napi_value CameraNapiUtils::CreateJSArray(napi_env env, napi_status status,
417     std::vector<int32_t> nativeArray)
418 {
419     MEDIA_DEBUG_LOG("CreateJSArray is called");
420     napi_value jsArray = nullptr;
421     napi_value item = nullptr;
422 
423     if (nativeArray.empty()) {
424         MEDIA_ERR_LOG("nativeArray is empty");
425     }
426 
427     status = napi_create_array(env, &jsArray);
428     if (status == napi_ok) {
429         for (size_t i = 0; i < nativeArray.size(); i++) {
430             napi_create_int32(env, nativeArray[i], &item);
431             if (napi_set_element(env, jsArray, i, item) != napi_ok) {
432                 MEDIA_ERR_LOG("Failed to create profile napi wrapper object");
433                 return nullptr;
434             }
435         }
436     }
437     return jsArray;
438 }
439 
ParseMetadataObjectTypes(napi_env env,napi_value arrayParam,std::vector<MetadataObjectType> & metadataObjectTypes)440 napi_value CameraNapiUtils::ParseMetadataObjectTypes(napi_env env, napi_value arrayParam,
441     std::vector<MetadataObjectType> &metadataObjectTypes)
442 {
443     MEDIA_DEBUG_LOG("ParseMetadataObjectTypes is called");
444     napi_value result;
445     uint32_t length = 0;
446     napi_value value;
447     int32_t metadataType = 0;
448     napi_get_array_length(env, arrayParam, &length);
449     napi_valuetype type = napi_undefined;
450     const int32_t invalidType = -1;
451     for (uint32_t i = 0; i < length; i++) {
452         napi_get_element(env, arrayParam, i, &value);
453         napi_typeof(env, value, &type);
454         if (type != napi_number) {
455             return nullptr;
456         }
457         if (metadataType < static_cast<int32_t>(MetadataObjectType::INVALID) ||
458             metadataType > static_cast<int32_t>(MetadataObjectType::BAR_CODE_DETECTION)) {
459             metadataType = invalidType;
460         }
461         napi_get_value_int32(env, value, &metadataType);
462         metadataObjectTypes.push_back(static_cast<MetadataObjectType>(metadataType));
463     }
464     napi_get_boolean(env, true, &result);
465     return result;
466 }
467 } // namespace CameraStandard
468 } // namespace OHOS
469