1 /*
2  * Copyright (c) 2023-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/deferred_photo_proxy_napi.h"
17 
18 #include "camera_log.h"
19 #include "deferred_photo_proxy.h"
20 #include "hilog/log.h"
21 #include "image_napi.h"
22 #include "napi/native_common.h"
23 #include "photo_proxy.h"
24 #include "pixel_map_napi.h"
25 
26 namespace OHOS {
27 namespace CameraStandard {
28 thread_local napi_ref DeferredPhotoProxyNapi::sConstructor_ = nullptr;
29 thread_local uint32_t DeferredPhotoProxyNapi::deferredPhotoProxyTaskId = DEFERRED_PHOTO_PROXY_TASKID;
DeferredPhotoProxyNapi()30 DeferredPhotoProxyNapi::DeferredPhotoProxyNapi() : env_(nullptr)
31 {
32 }
33 
~DeferredPhotoProxyNapi()34 DeferredPhotoProxyNapi::~DeferredPhotoProxyNapi()
35 {
36     MEDIA_DEBUG_LOG("~DeferredPhotoProxyNapi is called");
37 }
38 
39 // Constructor callback
DeferredPhotoProxyNapiConstructor(napi_env env,napi_callback_info info)40 napi_value DeferredPhotoProxyNapi::DeferredPhotoProxyNapiConstructor(napi_env env, napi_callback_info info)
41 {
42     MEDIA_DEBUG_LOG("DeferredPhotoProxyNapiConstructor is called");
43     napi_status status;
44     napi_value result = nullptr;
45     napi_value thisVar = nullptr;
46     napi_get_undefined(env, &result);
47     CAMERA_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
48     if (status == napi_ok && thisVar != nullptr) {
49         std::unique_ptr<DeferredPhotoProxyNapi> obj = std::make_unique<DeferredPhotoProxyNapi>();
50         obj->env_ = env;
51 
52         obj->deferredPhotoProxy_ = static_cast<DeferredPhotoProxy*>(sPhotoProxy_.GetRefPtr());
53         obj->photoProxy_ = obj->deferredPhotoProxy_;
54         status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
55                            DeferredPhotoProxyNapi::DeferredPhotoProxyNapiDestructor, nullptr, nullptr);
56         if (status == napi_ok) {
57             obj.release();
58             return thisVar;
59         } else {
60             MEDIA_ERR_LOG("Failure wrapping js to native napi");
61         }
62     }
63     MEDIA_ERR_LOG("DeferredPhotoProxyNapiConstructor call Failed!");
64     return result;
65 }
66 
DeferredPhotoProxyNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)67 void DeferredPhotoProxyNapi::DeferredPhotoProxyNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
68 {
69     MEDIA_DEBUG_LOG("DeferredPhotoProxyNapiDestructor is called");
70     DeferredPhotoProxyNapi* deferredPhotoProxy = reinterpret_cast<DeferredPhotoProxyNapi*>(nativeObject);
71     if (deferredPhotoProxy != nullptr) {
72         delete deferredPhotoProxy;
73     }
74 }
75 
Init(napi_env env,napi_value exports)76 napi_value DeferredPhotoProxyNapi::Init(napi_env env, napi_value exports)
77 {
78     MEDIA_DEBUG_LOG("Init is called");
79     napi_status status;
80     napi_value ctorObj;
81     int32_t refCount = 1;
82 
83     napi_property_descriptor deferred_photo_proxy_properties[] = {
84         // DeferredPhotoProxy
85         DECLARE_NAPI_FUNCTION("getThumbnail", GetThumbnail),
86         DECLARE_NAPI_FUNCTION("release", Release),
87     };
88 
89     status = napi_define_class(env, DEFERRED_PHOTO_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH,
90         DeferredPhotoProxyNapiConstructor, nullptr,
91         sizeof(deferred_photo_proxy_properties) / sizeof(deferred_photo_proxy_properties[PARAM0]),
92         deferred_photo_proxy_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, DEFERRED_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 
CreateDeferredPhotoProxy(napi_env env,sptr<DeferredPhotoProxy> deferredPhotoProxy)105 napi_value DeferredPhotoProxyNapi::CreateDeferredPhotoProxy(napi_env env, sptr<DeferredPhotoProxy> deferredPhotoProxy)
106 {
107     MEDIA_DEBUG_LOG("CreateDeferredPhotoProxy 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     status = napi_get_reference_value(env, sConstructor_, &constructor);
114     if (status == napi_ok) {
115         sPhotoProxy_ = deferredPhotoProxy;
116         status = napi_new_instance(env, constructor, 0, nullptr, &result);
117         sPhotoProxy_ = nullptr;
118         if (status == napi_ok && result != nullptr) {
119             return result;
120         } else {
121             MEDIA_ERR_LOG("Failed to create deferredPhotoProxy obj instance");
122         }
123     }
124     napi_get_undefined(env, &result);
125     MEDIA_ERR_LOG("CreateDeferredPhotoProxy call Failed");
126     return result;
127 }
128 
GetThumbnail(napi_env env,napi_callback_info info)129 napi_value DeferredPhotoProxyNapi::GetThumbnail(napi_env env, napi_callback_info info)
130 {
131     MEDIA_INFO_LOG("GetThumbnail is called");
132     napi_status status;
133     napi_value result = nullptr;
134     napi_value resource = nullptr;
135     size_t argc = ARGS_ZERO;
136     napi_value argv[ARGS_ZERO];
137     napi_value thisVar = nullptr;
138     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
139     napi_get_undefined(env, &result);
140     std::unique_ptr<DeferredPhotoProxAsyncContext> asyncContext = std::make_unique<DeferredPhotoProxAsyncContext>();
141     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
142     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
143         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
144         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "GetThumbnail");
145         status = napi_create_async_work(
146             env, nullptr, resource,
147             [](napi_env env, void* data) {
148                 auto context = static_cast<DeferredPhotoProxAsyncContext*>(data);
149                 context->status = false;
150                 // Start async trace
151                 context->funcName = "DeferredPhotoProxyNapi::GetThumbnail";
152                 context->taskId = CameraNapiUtils::IncrementAndGet(deferredPhotoProxyTaskId);
153                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
154                 if (context->objectInfo != nullptr) {
155                     context->status = true;
156                 }
157             },
158             DeferredPhotoAsyncTaskComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
159         if (status != napi_ok) {
160             MEDIA_ERR_LOG("Failed to create napi_create_async_work for DeferredPhotoProxyNapi::GetThumbnail");
161             napi_get_undefined(env, &result);
162         } else {
163             napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
164             asyncContext.release();
165         }
166     } else {
167         MEDIA_ERR_LOG("GetThumbnail call Failed!");
168     }
169     return result;
170 }
171 
DeferredPhotoAsyncTaskComplete(napi_env env,napi_status status,void * data)172 void DeferredPhotoProxyNapi::DeferredPhotoAsyncTaskComplete(napi_env env, napi_status status, void* data)
173 {
174     auto context = static_cast<DeferredPhotoProxAsyncContext*>(data);
175     void* fdAddr = context->objectInfo->deferredPhotoProxy_->GetFileDataAddr();
176     int32_t thumbnailWidth = context->objectInfo->deferredPhotoProxy_->GetWidth();
177     int32_t thumbnailHeight = context->objectInfo->deferredPhotoProxy_->GetHeight();
178     Media::InitializationOptions opts;
179     opts.srcPixelFormat = Media::PixelFormat::RGBA_8888;
180     opts.pixelFormat = Media::PixelFormat::RGBA_8888;
181     opts.size = { .width = thumbnailWidth, .height = thumbnailHeight };
182     MEDIA_INFO_LOG("thumbnailWidth:%{public}d, thumbnailheight: %{public}d",
183         thumbnailWidth, thumbnailHeight);
184     auto pixelMap = Media::PixelMap::Create(static_cast<const uint32_t*>(fdAddr),
185         thumbnailWidth * thumbnailHeight * 4, 0, thumbnailWidth, opts, true);
186     napi_value thumbnail = Media::PixelMapNapi::CreatePixelMap(env, std::move(pixelMap));
187     napi_resolve_deferred(env, context->deferred, thumbnail);
188     napi_delete_async_work(env, context->work);
189 }
190 
Release(napi_env env,napi_callback_info info)191 napi_value DeferredPhotoProxyNapi::Release(napi_env env, napi_callback_info info)
192 {
193     MEDIA_INFO_LOG("Release is called");
194     napi_status status;
195     napi_value result = nullptr;
196     napi_value resource = nullptr;
197     size_t argc = ARGS_ZERO;
198     napi_value argv[ARGS_ZERO];
199     napi_value thisVar = nullptr;
200     CAMERA_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
201     napi_get_undefined(env, &result);
202     std::unique_ptr<DeferredPhotoProxAsyncContext> asyncContext = std::make_unique<DeferredPhotoProxAsyncContext>();
203     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
204     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
205         CAMERA_NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
206         CAMERA_NAPI_CREATE_RESOURCE_NAME(env, resource, "Release");
207         status = napi_create_async_work(
208             env, nullptr, resource,
209             [](napi_env env, void* data) {
210                 auto context = static_cast<DeferredPhotoProxAsyncContext*>(data);
211                 context->status = false;
212                 // Start async trace
213                 context->funcName = "DeferredPhotoProxyNapi::Release";
214                 context->taskId = CameraNapiUtils::IncrementAndGet(deferredPhotoProxyTaskId);
215                 CAMERA_START_ASYNC_TRACE(context->funcName, context->taskId);
216                 if (context->objectInfo != nullptr) {
217                     context->status = true;
218                 }
219             },
220             [](napi_env env, napi_status status, void* data) {
221                 auto context = static_cast<DeferredPhotoProxAsyncContext*>(data);
222                 napi_resolve_deferred(env, context->deferred, nullptr);
223                 napi_delete_async_work(env, context->work);
224                 delete context->objectInfo;
225                 delete context;
226             }, static_cast<void*>(asyncContext.get()), &asyncContext->work);
227         if (status != napi_ok) {
228             MEDIA_ERR_LOG("Failed to create napi_create_async_work for DeferredPhotoProxyNapi::Release");
229             napi_get_undefined(env, &result);
230         } else {
231             napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
232             asyncContext.release();
233         }
234     } else {
235         MEDIA_ERR_LOG("Release call Failed!");
236     }
237     return result;
238 }
239 } // namespace CameraStandard
240 } // namespace OHOS