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 "movingphoto_napi.h"
17 
18 #include "ext_napi_utils.h"
19 #include "movingphoto_model_ng.h"
20 
21 extern const char _binary_multimedia_movingphotoview_js_start[];
22 extern const char _binary_multimedia_movingphotoview_abc_start[];
23 #if !defined(IOS_PLATFORM)
24 extern const char _binary_multimedia_movingphotoview_js_end[];
25 extern const char _binary_multimedia_movingphotoview_abc_end[];
26 #else
27 extern const char* _binary_multimedia_movingphotoview_js_end;
28 extern const char* _binary_multimedia_movingphotoview_abc_end;
29 #endif
30 
31 namespace OHOS::Ace {
32 namespace {
33 static constexpr size_t MAX_ARG_NUM = 10;
34 static constexpr int32_t ARG_NUM_ONE = 1;
35 static constexpr int32_t ARG_NUM_TWO = 2;
36 static constexpr int32_t PARAM_INDEX_ZERO = 0;
37 static constexpr int32_t PARAM_INDEX_ONE = 1;
38 } // namespace
39 
40 std::unique_ptr<NG::MovingPhotoModelNG> NG::MovingPhotoModelNG::instance_ = nullptr;
41 std::mutex NG::MovingPhotoModelNG::mutex_;
42 
GetInstance()43 NG::MovingPhotoModelNG* NG::MovingPhotoModelNG::GetInstance()
44 {
45     if (!instance_) {
46         std::lock_guard<std::mutex> lock(mutex_);
47         if (!instance_) {
48             instance_.reset(new NG::MovingPhotoModelNG());
49         }
50     }
51     return instance_.get();
52 }
53 
JsCreate(napi_env env, napi_callback_info info)54 napi_value JsCreate(napi_env env, napi_callback_info info)
55 {
56     size_t argc = MAX_ARG_NUM;
57     napi_value argv[MAX_ARG_NUM] = { nullptr };
58     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
59     NAPI_ASSERT(env, argc >= ARG_NUM_ONE, "Wrong number of arguments");
60 
61     if (!ExtNapiUtils::CheckTypeForNapiValue(env, argv[0], napi_object)) {
62         return ExtNapiUtils::CreateNull(env);
63     }
64 
65     napi_value jsController = nullptr;
66     NG::MovingPhotoController* controller = nullptr;
67     napi_get_named_property(env, argv[0], "controller", &jsController);
68     if (ExtNapiUtils::CheckTypeForNapiValue(env, jsController, napi_object)) {
69         napi_unwrap(env, jsController, (void**)&controller);
70     }
71     NG::MovingPhotoModelNG::GetInstance()->Create(Referenced::Claim(controller));
72 
73     napi_value jsData = nullptr;
74     napi_get_named_property(env, argv[0], "movingPhoto", &jsData);
75     if (!ExtNapiUtils::CheckTypeForNapiValue(env, jsData, napi_object)) {
76         return ExtNapiUtils::CreateNull(env);
77     }
78 
79     napi_value jsImageAIOptions = nullptr;
80     napi_get_named_property(env, argv[0], "imageAIOptions", &jsImageAIOptions);
81     NG::MovingPhotoModelNG::GetInstance()->SetImageAIOptions(jsImageAIOptions);
82 
83     napi_value getUri = nullptr;
84     napi_get_named_property(env, jsData, "getUri", &getUri);
85     if (!ExtNapiUtils::CheckTypeForNapiValue(env, getUri, napi_function)) {
86         return ExtNapiUtils::CreateNull(env);
87     }
88     napi_value imageUri;
89     napi_call_function(env, jsData, getUri, 0, nullptr, &imageUri);
90     std::string imageUriStr = ExtNapiUtils::GetStringFromValueUtf8(env, imageUri);
91     NG::MovingPhotoModelNG::GetInstance()->SetImageSrc(imageUriStr);
92 
93     return ExtNapiUtils::CreateNull(env);
94 }
95 
JsMuted(napi_env env, napi_callback_info info)96 napi_value JsMuted(napi_env env, napi_callback_info info)
97 {
98     size_t argc = MAX_ARG_NUM;
99     napi_value argv[MAX_ARG_NUM] = { nullptr };
100     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
101     NAPI_ASSERT(env, argc >= ARG_NUM_ONE, "Wrong number of arguments");
102 
103     bool muted = false;
104     if (ExtNapiUtils::CheckTypeForNapiValue(env, argv[0], napi_boolean)) {
105         muted = ExtNapiUtils::GetBool(env, argv[0]);
106     }
107     NG::MovingPhotoModelNG::GetInstance()->SetMuted(muted);
108 
109     return ExtNapiUtils::CreateNull(env);
110 }
111 
JsObjectFit(napi_env env, napi_callback_info info)112 napi_value JsObjectFit(napi_env env, napi_callback_info info)
113 {
114     size_t argc = MAX_ARG_NUM;
115     napi_value argv[MAX_ARG_NUM] = { nullptr };
116     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
117     NAPI_ASSERT(env, argc >= ARG_NUM_ONE, "Wrong number of arguments");
118 
119     auto objectFit = ImageFit::COVER;
120     if (ExtNapiUtils::CheckTypeForNapiValue(env, argv[0], napi_number)) {
121         objectFit = static_cast<ImageFit>(ExtNapiUtils::GetCInt32(env, argv[0]));
122     }
123     NG::MovingPhotoModelNG::GetInstance()->SetObjectFit(objectFit);
124 
125     return ExtNapiUtils::CreateNull(env);
126 }
127 
JsOnComplete(napi_env env, napi_callback_info info)128 napi_value JsOnComplete(napi_env env, napi_callback_info info)
129 {
130     size_t argc = MAX_ARG_NUM;
131     napi_value thisVal = nullptr;
132     napi_value argv[MAX_ARG_NUM] = { nullptr };
133     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVal, nullptr));
134     NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments");
135     if (!ExtNapiUtils::CheckTypeForNapiValue(env, argv[0], napi_function)) {
136         return ExtNapiUtils::CreateNull(env);
137     }
138     auto asyncEvent = std::make_shared<NapiAsyncEvent>(env, argv[0]);
139     auto onComplete = [asyncEvent]() {
140         asyncEvent->Call(0, nullptr);
141     };
142     NG::MovingPhotoModelNG::GetInstance()->SetOnComplete(std::move(onComplete));
143     return ExtNapiUtils::CreateNull(env);
144 }
145 
JsOnStart(napi_env env, napi_callback_info info)146 napi_value JsOnStart(napi_env env, napi_callback_info info)
147 {
148     size_t argc = MAX_ARG_NUM;
149     napi_value thisVal = nullptr;
150     napi_value argv[MAX_ARG_NUM] = { nullptr };
151     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVal, nullptr));
152     NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments");
153     if (!ExtNapiUtils::CheckTypeForNapiValue(env, argv[0], napi_function)) {
154         return ExtNapiUtils::CreateNull(env);
155     }
156     auto asyncEvent = std::make_shared<NapiAsyncEvent>(env, argv[0]);
157     auto onStart = [asyncEvent]() {
158         asyncEvent->Call(0, nullptr);
159     };
160     NG::MovingPhotoModelNG::GetInstance()->SetOnStart(std::move(onStart));
161     return ExtNapiUtils::CreateNull(env);
162 }
163 
JsOnStop(napi_env env, napi_callback_info info)164 napi_value JsOnStop(napi_env env, napi_callback_info info)
165 {
166     size_t argc = MAX_ARG_NUM;
167     napi_value thisVal = nullptr;
168     napi_value argv[MAX_ARG_NUM] = { nullptr };
169     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVal, nullptr));
170     NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments");
171     if (!ExtNapiUtils::CheckTypeForNapiValue(env, argv[0], napi_function)) {
172         return ExtNapiUtils::CreateNull(env);
173     }
174     auto asyncEvent = std::make_shared<NapiAsyncEvent>(env, argv[0]);
175     auto onStop = [asyncEvent]() {
176         asyncEvent->Call(0, nullptr);
177     };
178     NG::MovingPhotoModelNG::GetInstance()->SetOnStop(std::move(onStop));
179     return ExtNapiUtils::CreateNull(env);
180 }
181 
JsOnPause(napi_env env, napi_callback_info info)182 napi_value JsOnPause(napi_env env, napi_callback_info info)
183 {
184     size_t argc = MAX_ARG_NUM;
185     napi_value thisVal = nullptr;
186     napi_value argv[MAX_ARG_NUM] = { nullptr };
187     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVal, nullptr));
188     NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments");
189     if (!ExtNapiUtils::CheckTypeForNapiValue(env, argv[0], napi_function)) {
190         return ExtNapiUtils::CreateNull(env);
191     }
192     auto asyncEvent = std::make_shared<NapiAsyncEvent>(env, argv[0]);
193     auto onPause = [asyncEvent]() {
194         asyncEvent->Call(0, nullptr);
195     };
196     NG::MovingPhotoModelNG::GetInstance()->SetOnPause(std::move(onPause));
197     return ExtNapiUtils::CreateNull(env);
198 }
199 
JsOnFinish(napi_env env, napi_callback_info info)200 napi_value JsOnFinish(napi_env env, napi_callback_info info)
201 {
202     size_t argc = MAX_ARG_NUM;
203     napi_value thisVal = nullptr;
204     napi_value argv[MAX_ARG_NUM] = { nullptr };
205     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVal, nullptr));
206     NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments");
207     if (!ExtNapiUtils::CheckTypeForNapiValue(env, argv[0], napi_function)) {
208         return ExtNapiUtils::CreateNull(env);
209     }
210     auto asyncEvent = std::make_shared<NapiAsyncEvent>(env, argv[0]);
211     auto onFinish = [asyncEvent]() {
212         asyncEvent->Call(0, nullptr);
213     };
214     NG::MovingPhotoModelNG::GetInstance()->SetOnFinish(std::move(onFinish));
215     return ExtNapiUtils::CreateNull(env);
216 }
217 
JsOnError(napi_env env, napi_callback_info info)218 napi_value JsOnError(napi_env env, napi_callback_info info)
219 {
220     size_t argc = MAX_ARG_NUM;
221     napi_value thisVal = nullptr;
222     napi_value argv[MAX_ARG_NUM] = { nullptr };
223     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVal, nullptr));
224     NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments");
225     if (!ExtNapiUtils::CheckTypeForNapiValue(env, argv[0], napi_function)) {
226         return ExtNapiUtils::CreateNull(env);
227     }
228     auto asyncEvent = std::make_shared<NapiAsyncEvent>(env, argv[0]);
229     auto onError = [asyncEvent]() {
230         asyncEvent->Call(0, nullptr);
231     };
232     NG::MovingPhotoModelNG::GetInstance()->SetOnError(std::move(onError));
233     return ExtNapiUtils::CreateNull(env);
234 }
235 
InitView(napi_env env, napi_value exports)236 napi_value InitView(napi_env env, napi_value exports)
237 {
238     static napi_property_descriptor desc[] = {
239         DECLARE_NAPI_FUNCTION("create", JsCreate),
240         DECLARE_NAPI_FUNCTION("muted", JsMuted),
241         DECLARE_NAPI_FUNCTION("objectFit", JsObjectFit),
242         DECLARE_NAPI_FUNCTION("onComplete", JsOnComplete),
243         DECLARE_NAPI_FUNCTION("onStart", JsOnStart),
244         DECLARE_NAPI_FUNCTION("onStop", JsOnStop),
245         DECLARE_NAPI_FUNCTION("onPause", JsOnPause),
246         DECLARE_NAPI_FUNCTION("onFinish", JsOnFinish),
247         DECLARE_NAPI_FUNCTION("onError", JsOnError),
248         DECLARE_NAPI_FUNCTION("autoPlayPeriod", JsAutoPlayPeriod),
249         DECLARE_NAPI_FUNCTION("autoPlay", JsAutoPlay),
250         DECLARE_NAPI_FUNCTION("repeatPlay", JsRepeatPlay),
251         DECLARE_NAPI_FUNCTION("enableAnalyzer", JsEnableAnalyzer),
252     };
253     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
254     return exports;
255 }
256 
StartPlayback(napi_env env, napi_callback_info info)257 napi_value StartPlayback(napi_env env, napi_callback_info info)
258 {
259     napi_value thisVar = nullptr;
260     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, NULL));
261     NG::MovingPhotoController* controller = nullptr;
262     napi_unwrap(env, thisVar, (void**)&controller);
263     if (controller == nullptr) {
264         return ExtNapiUtils::CreateNull(env);
265     }
266     controller->StartPlayback();
267     return ExtNapiUtils::CreateNull(env);
268 }
269 
StopPlayback(napi_env env, napi_callback_info info)270 napi_value StopPlayback(napi_env env, napi_callback_info info)
271 {
272     napi_value thisVar = nullptr;
273     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, NULL));
274     NG::MovingPhotoController* controller = nullptr;
275     napi_unwrap(env, thisVar, (void**)&controller);
276     if (controller == nullptr) {
277         return ExtNapiUtils::CreateNull(env);
278     }
279     controller->StopPlayback();
280     return ExtNapiUtils::CreateNull(env);
281 }
282 
MovingPhotoControllerConstructor(napi_env env, napi_callback_info info)283 napi_value MovingPhotoControllerConstructor(napi_env env, napi_callback_info info)
284 {
285     napi_value thisVar = nullptr;
286     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
287     auto controller = AceType::MakeRefPtr<NG::MovingPhotoController>();
288     if (controller == nullptr) {
289         return ExtNapiUtils::CreateNull(env);
290     }
291     controller->IncRefCount();
292     napi_wrap(
293         env, thisVar, AceType::RawPtr(controller),
294         [](napi_env env, void* data, void* hint) {
295             auto* controller = reinterpret_cast<NG::MovingPhotoController*>(data);
296             controller->DecRefCount();
297         },
298         nullptr, nullptr);
299     return thisVar;
300 }
301 
InitController(napi_env env, napi_value exports)302 napi_value InitController(napi_env env, napi_value exports)
303 {
304     napi_value movingphotoControllerClass = nullptr;
305     napi_property_descriptor properties[] = {
306         DECLARE_NAPI_FUNCTION("startPlayback", StartPlayback),
307         DECLARE_NAPI_FUNCTION("stopPlayback", StopPlayback),
308     };
309     NAPI_CALL(env, napi_define_class(env, "MovingPhotoViewController", NAPI_AUTO_LENGTH,
310         MovingPhotoControllerConstructor, nullptr, sizeof(properties) / sizeof(*properties), properties,
311         &movingphotoControllerClass));
312     NAPI_CALL(env, napi_set_named_property(env, exports, "MovingPhotoViewController", movingphotoControllerClass));
313     return exports;
314 }
315 
ExportMovingPhoto(napi_env env, napi_value exports)316 napi_value ExportMovingPhoto(napi_env env, napi_value exports)
317 {
318     InitView(env, exports);
319     InitController(env, exports);
320     return exports;
321 }
322 
JsAutoPlayPeriod(napi_env env, napi_callback_info info)323 napi_value JsAutoPlayPeriod(napi_env env, napi_callback_info info)
324 {
325     size_t argc = MAX_ARG_NUM;
326     napi_value argv[MAX_ARG_NUM] = { nullptr };
327     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
328     NAPI_ASSERT(env, argc >= ARG_NUM_TWO, "Wrong number of arguments");
329 
330     int64_t startTime = 0;
331     if (ExtNapiUtils::CheckTypeForNapiValue(env, argv[PARAM_INDEX_ZERO], napi_number)) {
332         startTime = ExtNapiUtils::GetCInt64(env, argv[PARAM_INDEX_ZERO]);
333     }
334     int64_t endTime = 0;
335     if (ExtNapiUtils::CheckTypeForNapiValue(env, argv[PARAM_INDEX_ONE], napi_number)) {
336         endTime = ExtNapiUtils::GetCInt64(env, argv[PARAM_INDEX_ONE]);
337     }
338     NG::MovingPhotoModelNG::GetInstance()->AutoPlayPeriod(startTime, endTime);
339 
340     return ExtNapiUtils::CreateNull(env);
341 }
342 
JsAutoPlay(napi_env env, napi_callback_info info)343 napi_value JsAutoPlay(napi_env env, napi_callback_info info)
344 {
345     size_t argc = MAX_ARG_NUM;
346     napi_value argv[MAX_ARG_NUM] = { nullptr };
347     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
348     NAPI_ASSERT(env, argc >= ARG_NUM_ONE, "Wrong number of arguments");
349 
350     bool isAutoPlay = false;
351     if (ExtNapiUtils::CheckTypeForNapiValue(env, argv[PARAM_INDEX_ZERO], napi_boolean)) {
352         isAutoPlay = ExtNapiUtils::GetBool(env, argv[PARAM_INDEX_ZERO]);
353     }
354     NG::MovingPhotoModelNG::GetInstance()->AutoPlay(isAutoPlay);
355 
356     return ExtNapiUtils::CreateNull(env);
357 }
358 
JsEnableAnalyzer(napi_env env, napi_callback_info info)359 napi_value JsEnableAnalyzer(napi_env env, napi_callback_info info)
360 {
361     size_t argc = MAX_ARG_NUM;
362     napi_value argv[MAX_ARG_NUM] = { nullptr };
363     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
364     NAPI_ASSERT(env, argc >= ARG_NUM_ONE, "Wrong number of arguments");
365 
366     bool enabled = false;
367     if (ExtNapiUtils::CheckTypeForNapiValue(env, argv[PARAM_INDEX_ZERO], napi_boolean)) {
368         enabled = ExtNapiUtils::GetBool(env, argv[PARAM_INDEX_ZERO]);
369     }
370     NG::MovingPhotoModelNG::GetInstance()->EnableAnalyzer(enabled);
371 
372     return ExtNapiUtils::CreateNull(env);
373 }
374 
JsRepeatPlay(napi_env env, napi_callback_info info)375 napi_value JsRepeatPlay(napi_env env, napi_callback_info info)
376 {
377     size_t argc = MAX_ARG_NUM;
378     napi_value argv[MAX_ARG_NUM] = { nullptr };
379     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
380     NAPI_ASSERT(env, argc >= ARG_NUM_ONE, "Wrong number of arguments");
381 
382     bool isRepeatPlay = false;
383     if (ExtNapiUtils::CheckTypeForNapiValue(env, argv[PARAM_INDEX_ZERO], napi_boolean)) {
384         isRepeatPlay = ExtNapiUtils::GetBool(env, argv[PARAM_INDEX_ZERO]);
385     }
386     NG::MovingPhotoModelNG::GetInstance()->RepeatPlay(isRepeatPlay);
387 
388     return ExtNapiUtils::CreateNull(env);
389 }
390 
391 } // namespace OHOS::Ace
392 
NAPI_multimedia_movingphotoview_GetJSCode( const char** buf, int* bufLen)393 extern "C" __attribute__((visibility("default"))) void NAPI_multimedia_movingphotoview_GetJSCode(
394     const char** buf, int* bufLen)
395 {
396     if (buf != nullptr) {
397         *buf = _binary_multimedia_movingphotoview_js_start;
398     }
399 
400     if (bufLen != nullptr) {
401         *bufLen = _binary_multimedia_movingphotoview_js_end - _binary_multimedia_movingphotoview_js_start;
402     }
403 }
404 
405 // multimedia_movingphotoview JS register
NAPI_multimedia_movingphotoview_GetABCCode( const char** buf, int* buflen)406 extern "C" __attribute__((visibility("default"))) void NAPI_multimedia_movingphotoview_GetABCCode(
407     const char** buf, int* buflen)
408 {
409     if (buf != nullptr) {
410         *buf = _binary_multimedia_movingphotoview_abc_start;
411     }
412     if (buflen != nullptr) {
413         *buflen = _binary_multimedia_movingphotoview_abc_end - _binary_multimedia_movingphotoview_abc_start;
414     }
415 }
416 
417 static napi_module movingphotoModule  = {
418     .nm_version = 1,
419     .nm_flags = 0,
420     .nm_filename = nullptr,
421     .nm_register_func = OHOS::Ace::ExportMovingPhoto,
422     .nm_modname = "multimedia.movingphotoview",
423     .nm_priv = ((void*)0),
424     .reserved = { 0 },
425 };
426 
RegisterModuleMovingPhoto()427 extern "C" __attribute__((constructor)) void RegisterModuleMovingPhoto()
428 {
429     napi_module_register(&movingphotoModule);
430 }
431