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