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 "output/photo_napi.h"
17 
18 #include "camera_log.h"
19 #include "hilog/log.h"
20 #include "image_napi.h"
21 #include "napi/native_common.h"
22 
23 namespace OHOS {
24 namespace CameraStandard {
25 thread_local napi_ref PhotoNapi::sConstructor_ = nullptr;
26 thread_local napi_value PhotoNapi::sMainImage_ = nullptr;
27 thread_local napi_value PhotoNapi::sRawImage_ = nullptr;
28 thread_local uint32_t PhotoNapi::photoTaskId = PHOTO_TASKID;
29 
PhotoNapi()30 PhotoNapi::PhotoNapi() : env_(nullptr), mainImage_(nullptr), rawImage_(nullptr) {}
31 
~PhotoNapi()32 PhotoNapi::~PhotoNapi()
33 {
34     MEDIA_DEBUG_LOG("~PhotoNapi is called");
35 }
36 
37 // Constructor callback
PhotoNapiConstructor(napi_env env,napi_callback_info info)38 napi_value PhotoNapi::PhotoNapiConstructor(napi_env env, napi_callback_info info)
39 {
40     MEDIA_DEBUG_LOG("PhotoNapiConstructor is called");
41     napi_status status;
42     napi_value result = nullptr;
43     napi_value thisVar = nullptr;
44 
45     napi_get_undefined(env, &result);
46     CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
47 
48     if (status == napi_ok && thisVar != nullptr) {
49         std::unique_ptr<PhotoNapi> obj = std::make_unique<PhotoNapi>();
50         obj->env_ = env;
51         obj->mainImage_ = sMainImage_;
52         obj->rawImage_ = sRawImage_;
53         status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
54                            PhotoNapi::PhotoNapiDestructor, nullptr, nullptr);
55         if (status == napi_ok) {
56             obj.release();
57             return thisVar;
58         } else {
59             MEDIA_ERR_LOG("Failure wrapping js to native napi");
60         }
61     }
62     MEDIA_ERR_LOG("PhotoNapiConstructor call Failed!");
63     return result;
64 }
65 
PhotoNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)66 void PhotoNapi::PhotoNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
67 {
68     MEDIA_DEBUG_LOG("PhotoNapiDestructor is called");
69     PhotoNapi* photo = reinterpret_cast<PhotoNapi*>(nativeObject);
70     if (photo != nullptr) {
71         delete photo;
72     }
73 }
74 
Init(napi_env env,napi_value exports)75 napi_value PhotoNapi::Init(napi_env env, napi_value exports)
76 {
77     MEDIA_DEBUG_LOG("Init is called");
78     napi_status status;
79     napi_value ctorObj;
80     int32_t refCount = 1;
81 
82     napi_property_descriptor photo_properties[] = {
83         // Photo
84         DECLARE_NAPI_GETTER("main", GetMain),
85         DECLARE_NAPI_GETTER("rawImage", GetRaw),
86         DECLARE_NAPI_FUNCTION("release", Release),
87     };
88 
89     status = napi_define_class(env, PHOTO_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
90                                PhotoNapiConstructor, nullptr,
91                                sizeof(photo_properties) / sizeof(photo_properties[PARAM0]),
92                                photo_properties, &ctorObj);
93     if (status == napi_ok) {
94         if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
95             status = napi_set_named_property(env, exports, PHOTO_NAPI_CLASS_NAME, ctorObj);
96             if (status == napi_ok) {
97                 return exports;
98             }
99         }
100     }
101     MEDIA_ERR_LOG("Init call Failed!");
102     return nullptr;
103 }
104 
CreatePhoto(napi_env env,napi_value mainImage)105 napi_value PhotoNapi::CreatePhoto(napi_env env, napi_value mainImage)
106 {
107     MEDIA_DEBUG_LOG("CreatePhoto is called");
108     CAMERA_SYNC_TRACE;
109     napi_status status;
110     napi_value result = nullptr;
111     napi_value constructor;
112     napi_get_undefined(env, &result);
113 
114     status = napi_get_reference_value(env, sConstructor_, &constructor);
115     if (status == napi_ok) {
116         sMainImage_ = mainImage;
117         status = napi_new_instance(env, constructor, 0, nullptr, &result);
118         sMainImage_ = nullptr;
119         if (status == napi_ok && result != nullptr) {
120             return result;
121         } else {
122             MEDIA_ERR_LOG("Failed to create photo obj instance");
123         }
124     }
125     napi_get_undefined(env, &result);
126     MEDIA_ERR_LOG("CreatePhoto call Failed");
127     return result;
128 }
129 
GetMain(napi_env env,napi_callback_info info)130 napi_value PhotoNapi::GetMain(napi_env env, napi_callback_info info)
131 {
132     MEDIA_INFO_LOG("GetMain is called");
133     napi_status status;
134     napi_value result = nullptr;
135     size_t argc = ARGS_ZERO;
136     napi_value argv[ARGS_ZERO];
137     napi_value thisVar = nullptr;
138 
139     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
140 
141     napi_get_undefined(env, &result);
142     PhotoNapi* photoNapi = nullptr;
143     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&photoNapi));
144     if (status == napi_ok && photoNapi != nullptr) {
145         result = photoNapi->mainImage_;
146         MEDIA_DEBUG_LOG("PhotoNapi::GetMain Success");
147         return result;
148     }
149     napi_get_undefined(env, &result);
150     MEDIA_ERR_LOG("PhotoNapi::GetMain call Failed");
151     return result;
152 }
153 
CreateRawPhoto(napi_env env,napi_value rawImage)154 napi_value PhotoNapi::CreateRawPhoto(napi_env env, napi_value rawImage)
155 {
156     MEDIA_DEBUG_LOG("CreateRawPhoto is called");
157     CAMERA_SYNC_TRACE;
158     napi_status status;
159     napi_value result = nullptr;
160     napi_value constructor;
161     napi_get_undefined(env, &result);
162 
163     status = napi_get_reference_value(env, sConstructor_, &constructor);
164     if (status == napi_ok) {
165         sRawImage_ = rawImage;
166         status = napi_new_instance(env, constructor, 0, nullptr, &result);
167         sRawImage_ = nullptr;
168         if (status == napi_ok && result != nullptr) {
169             return result;
170         } else {
171             MEDIA_ERR_LOG("Failed to create photo obj instance");
172         }
173     }
174     napi_get_undefined(env, &result);
175     MEDIA_ERR_LOG("CreateRawPhoto call Failed");
176     return result;
177 }
178 
GetRaw(napi_env env,napi_callback_info info)179 napi_value PhotoNapi::GetRaw(napi_env env, napi_callback_info info)
180 {
181     MEDIA_INFO_LOG("GetRaw is called");
182     napi_status status;
183     napi_value result = nullptr;
184     size_t argc = ARGS_ZERO;
185     napi_value argv[ARGS_ZERO];
186     napi_value thisVar = nullptr;
187 
188     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
189 
190     napi_get_undefined(env, &result);
191     PhotoNapi* photoNapi = nullptr;
192     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&photoNapi));
193     if (status == napi_ok && photoNapi != nullptr) {
194         result = photoNapi->rawImage_;
195         MEDIA_DEBUG_LOG("PhotoNapi::GetRaw Success");
196         return result;
197     }
198     napi_get_undefined(env, &result);
199     MEDIA_ERR_LOG("PhotoNapi::GetRaw call Failed");
200     return result;
201 }
202 
Release(napi_env env,napi_callback_info info)203 napi_value PhotoNapi::Release(napi_env env, napi_callback_info info)
204 {
205     MEDIA_INFO_LOG("Release is called");
206     napi_status status;
207     napi_value result = nullptr;
208     napi_value resource = nullptr;
209     size_t argc = ARGS_ZERO;
210     napi_value argv[ARGS_ZERO];
211     napi_value thisVar = nullptr;
212 
213     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
214 
215     napi_get_undefined(env, &result);
216     std::unique_ptr<PhotoAsyncContext> asyncContext = std::make_unique<PhotoAsyncContext>();
217     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
218     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
219         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
220         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Release");
221 
222         status = napi_create_async_work(
223             env, nullptr, resource,
224             [](napi_env env, void* data) {
225                 auto context = static_cast<PhotoAsyncContext*>(data);
226                 context->status = false;
227                 // Start async trace
228                 context->funcName = "PhotoNapi::Release";
229                 context->taskId = CameraNapiUtils::IncrementAndGet(photoTaskId);
230                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
231                 if (context->objectInfo != nullptr) {
232                     context->status = true;
233                     context->objectInfo->mainImage_ = nullptr;
234                     context->objectInfo->rawImage_ = nullptr;
235                 }
236             },
237             [](napi_env env, napi_status status, void* data) {
238                 auto context = static_cast<PhotoAsyncContext*>(data);
239                 napi_resolve_deferred(env, context->deferred, nullptr);
240                 napi_delete_async_work(env, context->work);
241                 delete context->objectInfo;
242                 delete context;
243             }, static_cast<void*>(asyncContext.get()), &asyncContext->work);
244         if (status != napi_ok) {
245             MEDIA_ERR_LOG("Failed to create napi_create_async_work for PhotoNapi::Release");
246             napi_get_undefined(env, &result);
247         } else {
248             napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
249             asyncContext.release();
250         }
251     } else {
252         MEDIA_ERR_LOG("Release call Failed!");
253     }
254     return result;
255 }
256 } // namespace CameraStandard
257 } // namespace OHOS