• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 <memory>
17 #include <string>
18 
19 #include "animator_option.h"
20 #include "interfaces/napi/kits/utils/napi_utils.h"
21 #include "napi/native_api.h"
22 #include "napi/native_engine/native_value.h"
23 #include "napi/native_node_api.h"
24 
25 #include "base/log/log.h"
26 #include "base/memory/ace_type.h"
27 #include "base/memory/referenced.h"
28 #include "bridge/common/utils/utils.h"
29 #include "core/animation/animator.h"
30 #include "core/animation/curve.h"
31 #include "core/animation/curve_animation.h"
32 
33 namespace OHOS::Ace::Napi {
34 
ParseString(napi_env env,napi_value propertyNapi,std::string & property)35 static void ParseString(napi_env env, napi_value propertyNapi, std::string& property)
36 {
37     if (propertyNapi != nullptr) {
38         napi_valuetype valueType = napi_undefined;
39         napi_typeof(env, propertyNapi, &valueType);
40         if (valueType == napi_undefined) {
41             NapiThrow(env, "Required input parameters are missing.", Framework::ERROR_CODE_PARAM_INVALID);
42             return;
43         } else if (valueType != napi_string) {
44             NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
45             return;
46         }
47         auto nativeProperty = reinterpret_cast<NativeValue*>(propertyNapi);
48         auto resultProperty = nativeProperty->ToString();
49         auto nativeStringProperty =
50             reinterpret_cast<NativeString*>(resultProperty->GetInterface(NativeString::INTERFACE_ID));
51         size_t propertyLen = nativeStringProperty->GetLength() + 1;
52         std::unique_ptr<char[]> propertyString = std::make_unique<char[]>(propertyLen);
53         size_t retLen = 0;
54         napi_get_value_string_utf8(env, propertyNapi, propertyString.get(), propertyLen, &retLen);
55         property = propertyString.get();
56     }
57 }
58 
ParseInt(napi_env env,napi_value propertyNapi,int32_t & property)59 static void ParseInt(napi_env env, napi_value propertyNapi, int32_t& property)
60 {
61     if (propertyNapi != nullptr) {
62         napi_valuetype valueType = napi_undefined;
63         napi_typeof(env, propertyNapi, &valueType);
64         if (valueType == napi_undefined) {
65             NapiThrow(env, "Required input parameters are missing.", Framework::ERROR_CODE_PARAM_INVALID);
66             return;
67         } else if (valueType != napi_number) {
68             NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
69             return;
70         }
71         napi_get_value_int32(env, propertyNapi, &property);
72     }
73 }
74 
ParseDouble(napi_env env,napi_value propertyNapi,double & property)75 static void ParseDouble(napi_env env, napi_value propertyNapi, double& property)
76 {
77     if (propertyNapi != nullptr) {
78         napi_valuetype valueType = napi_undefined;
79         napi_typeof(env, propertyNapi, &valueType);
80         if (valueType == napi_undefined) {
81             NapiThrow(env, "Required input parameters are missing.", Framework::ERROR_CODE_PARAM_INVALID);
82             return;
83         } else if (valueType != napi_number) {
84             NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
85             return;
86         }
87         napi_get_value_double(env, propertyNapi, &property);
88     }
89 }
90 
StringToFillMode(const std::string & fillMode)91 static FillMode StringToFillMode(const std::string& fillMode)
92 {
93     if (fillMode.compare("forwards") == 0) {
94         return FillMode::FORWARDS;
95     } else if (fillMode.compare("backwards") == 0) {
96         return FillMode::BACKWARDS;
97     } else if (fillMode.compare("both") == 0) {
98         return FillMode::BOTH;
99     } else {
100         return FillMode::NONE;
101     }
102 }
103 
StringToAnimationDirection(const std::string & direction)104 static AnimationDirection StringToAnimationDirection(const std::string& direction)
105 {
106     if (direction.compare("alternate") == 0) {
107         return AnimationDirection::ALTERNATE;
108     } else if (direction.compare("reverse") == 0) {
109         return AnimationDirection::REVERSE;
110     } else if (direction.compare("alternate-reverse") == 0) {
111         return AnimationDirection::ALTERNATE_REVERSE;
112     } else {
113         return AnimationDirection::NORMAL;
114     }
115 }
116 
ParseAnimatorOption(napi_env env,napi_callback_info info,std::shared_ptr<AnimatorOption> & option)117 static void ParseAnimatorOption(napi_env env, napi_callback_info info, std::shared_ptr<AnimatorOption>& option)
118 {
119     LOGI("JsAnimator: ParseAnimatorOption");
120     size_t argc = 1;
121     napi_value argv;
122     napi_get_cb_info(env, info, &argc, &argv, NULL, NULL);
123     if (argc != 1) {
124         NapiThrow(env, "The number of parameters must be equal to 1.", Framework::ERROR_CODE_PARAM_INVALID);
125         return;
126     }
127     napi_value durationNapi = nullptr;
128     napi_value easingNapi = nullptr;
129     napi_value delayNapi = nullptr;
130     napi_value fillNapi = nullptr;
131     napi_value directionNapi = nullptr;
132     napi_value iterationsNapi = nullptr;
133     napi_value beginNapi = nullptr;
134     napi_value endNapi = nullptr;
135     napi_valuetype valueType = napi_undefined;
136     napi_typeof(env, argv, &valueType);
137     if (valueType == napi_object) {
138         napi_get_named_property(env, argv, "duration", &durationNapi);
139         napi_get_named_property(env, argv, "easing", &easingNapi);
140         napi_get_named_property(env, argv, "delay", &delayNapi);
141         napi_get_named_property(env, argv, "fill", &fillNapi);
142         napi_get_named_property(env, argv, "direction", &directionNapi);
143         napi_get_named_property(env, argv, "iterations", &iterationsNapi);
144         napi_get_named_property(env, argv, "begin", &beginNapi);
145         napi_get_named_property(env, argv, "end", &endNapi);
146     } else {
147         NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
148         return;
149     }
150 
151     int32_t duration = 0;
152     int32_t delay = 0;
153     int32_t iterations = 0;
154     double begin = 0.0;
155     double end = 0.0;
156     std::string easing = "ease";
157     std::string fill = "none";
158     std::string direction = "normal";
159     ParseString(env, easingNapi, easing);
160     ParseString(env, fillNapi, fill);
161     ParseString(env, directionNapi, direction);
162     ParseInt(env, durationNapi, duration);
163     ParseInt(env, delayNapi, delay);
164     ParseInt(env, iterationsNapi, iterations);
165     ParseDouble(env, beginNapi, begin);
166     ParseDouble(env, endNapi, end);
167     option->duration = duration;
168     option->delay = delay;
169     option->iterations = iterations;
170     option->begin = begin;
171     option->end = end;
172     option->easing = easing;
173     option->fill = fill;
174     option->direction = direction;
175 }
176 
GetAnimatorInResult(napi_env env,napi_callback_info info)177 static RefPtr<Animator> GetAnimatorInResult(napi_env env, napi_callback_info info)
178 {
179     AnimatorResult* animatorResult = nullptr;
180     napi_value thisVar;
181     napi_get_cb_info(env, info, NULL, NULL, &thisVar, NULL);
182     napi_unwrap(env, thisVar, (void**)&animatorResult);
183     if (!animatorResult) {
184         LOGE("unwrap animator result is failed");
185         return nullptr;
186     }
187     return animatorResult->GetAnimator();
188 }
189 
JSReset(napi_env env,napi_callback_info info)190 static napi_value JSReset(napi_env env, napi_callback_info info)
191 {
192     LOGI("JsAnimator: JSReset");
193     AnimatorResult* animatorResult = nullptr;
194     napi_value thisVar;
195     napi_get_cb_info(env, info, NULL, NULL, &thisVar, NULL);
196     napi_unwrap(env, thisVar, (void**)&animatorResult);
197     if (!animatorResult) {
198         LOGE("unwrap animator result is failed");
199         NapiThrow(env, "Internal error. Unwrap animator result is failed.", Framework::ERROR_CODE_INTERNAL_ERROR);
200         return nullptr;
201     }
202     auto option = animatorResult->GetAnimatorOption();
203     if (!option) {
204         LOGE("Option is null in AnimatorResult");
205         NapiThrow(env, "Internal error. Option is null in AnimatorResult.", Framework::ERROR_CODE_INTERNAL_ERROR);
206         return nullptr;
207     }
208     ParseAnimatorOption(env, info, option);
209     auto animator = animatorResult->GetAnimator();
210     if (!animator) {
211         LOGW("animator is null");
212         NapiThrow(env, "Internal error. Animator is null in AnimatorResult.", Framework::ERROR_CODE_INTERNAL_ERROR);
213         return nullptr;
214     }
215     animator->ClearInterpolators();
216     animator->ResetIsReverse();
217     animatorResult->ApplyOption();
218     napi_ref onframeRef = animatorResult->GetOnframeRef();
219     if (onframeRef) {
220         auto curve = Framework::CreateCurve(option->easing);
221         auto animation = AceType::MakeRefPtr<CurveAnimation<double>>(option->begin, option->end, curve);
222         animation->AddListener([env, onframeRef](double value) {
223             napi_handle_scope scope = nullptr;
224             napi_open_handle_scope(env, &scope);
225             if (scope == nullptr) {
226                 LOGW("JsAnimator: open handle scope failed");
227                 return;
228             }
229             napi_value ret = nullptr;
230             napi_value valueNapi = nullptr;
231             napi_value onframe = nullptr;
232             auto result = napi_get_reference_value(env, onframeRef, &onframe);
233             if (result != napi_ok || onframe == nullptr) {
234                 LOGW("JsAnimator: get onframe in callback failed");
235                 napi_close_handle_scope(env, scope);
236                 return;
237             }
238             napi_create_double(env, value, &valueNapi);
239             napi_call_function(env, nullptr, onframe, 1, &valueNapi, &ret);
240             napi_close_handle_scope(env, scope);
241         });
242         animator->AddInterpolator(animation);
243     }
244     napi_value result;
245     napi_get_null(env, &result);
246     return result;
247 }
248 
249 // since API 9 deprecated
JSUpdate(napi_env env,napi_callback_info info)250 static napi_value JSUpdate(napi_env env, napi_callback_info info)
251 {
252     LOGI("JsAnimator: JSUpdate");
253     return JSReset(env, info);
254 }
255 
JSPlay(napi_env env,napi_callback_info info)256 static napi_value JSPlay(napi_env env, napi_callback_info info)
257 {
258     auto animator = GetAnimatorInResult(env, info);
259     LOGI("JsAnimator: JSPlay, id:%{public}d", animator ? animator->GetId() : -1);
260     if (!animator) {
261         LOGE("animator is null");
262         return nullptr;
263     }
264     if (!animator->HasScheduler()) {
265         animator->AttachSchedulerOnContainer();
266     }
267     animator->Play();
268     napi_value result = nullptr;
269     napi_get_null(env, &result);
270     return result;
271 }
272 
JSFinish(napi_env env,napi_callback_info info)273 static napi_value JSFinish(napi_env env, napi_callback_info info)
274 {
275     auto animator = GetAnimatorInResult(env, info);
276     LOGI("JsAnimator: JSFinish, id:%{public}d", animator ? animator->GetId() : -1);
277     if (!animator) {
278         LOGE("animator is null");
279         return nullptr;
280     }
281     animator->Finish();
282     napi_value result = nullptr;
283     napi_get_null(env, &result);
284     return result;
285 }
286 
JSPause(napi_env env,napi_callback_info info)287 static napi_value JSPause(napi_env env, napi_callback_info info)
288 {
289     auto animator = GetAnimatorInResult(env, info);
290     LOGI("JsAnimator: JSPause, id:%{public}d", animator ? animator->GetId() : -1);
291     if (!animator) {
292         LOGE("animator is null");
293         return nullptr;
294     }
295     animator->Pause();
296     napi_value result;
297     napi_get_null(env, &result);
298     return result;
299 }
300 
JSCancel(napi_env env,napi_callback_info info)301 static napi_value JSCancel(napi_env env, napi_callback_info info)
302 {
303     auto animator = GetAnimatorInResult(env, info);
304     LOGI("JsAnimator: JSCancel, id:%{public}d", animator ? animator->GetId() : -1);
305     if (!animator) {
306         LOGE("animator is null");
307         return nullptr;
308     }
309     animator->Cancel();
310     napi_value result;
311     napi_get_null(env, &result);
312     return result;
313 }
314 
JSReverse(napi_env env,napi_callback_info info)315 static napi_value JSReverse(napi_env env, napi_callback_info info)
316 {
317     auto animator = GetAnimatorInResult(env, info);
318     LOGI("JsAnimator: JSReverse, id:%{public}d", animator ? animator->GetId() : -1);
319     if (!animator) {
320         LOGE("animator is null");
321         return nullptr;
322     }
323     if (!animator->HasScheduler()) {
324         animator->AttachSchedulerOnContainer();
325     }
326     animator->Reverse();
327     napi_value result;
328     napi_get_null(env, &result);
329     return result;
330 }
331 
SetOnframe(napi_env env,napi_callback_info info)332 static napi_value SetOnframe(napi_env env, napi_callback_info info)
333 {
334     LOGI("JsAnimator: SetOnframe");
335     AnimatorResult* animatorResult = nullptr;
336     size_t argc = 1;
337     napi_value thisVar = nullptr;
338     napi_value onframe = nullptr;
339     napi_get_cb_info(env, info, &argc, &onframe, &thisVar, NULL);
340     napi_unwrap(env, thisVar, (void**)&animatorResult);
341     if (!animatorResult) {
342         LOGE("unwrap animator result is failed");
343         return nullptr;
344     }
345     auto option = animatorResult->GetAnimatorOption();
346     if (!option) {
347         LOGE("option is null");
348         return nullptr;
349     }
350     auto animator = animatorResult->GetAnimator();
351     if (!animator) {
352         LOGE("animator is null");
353         return nullptr;
354     }
355     animator->ClearInterpolators();
356     auto curve = Framework::CreateCurve(option->easing);
357     auto animation = AceType::MakeRefPtr<CurveAnimation<double>>(option->begin, option->end, curve);
358     // convert onframe function to reference
359     napi_ref onframeRef = animatorResult->GetOnframeRef();
360     if (onframeRef) {
361         uint32_t count = 0;
362         napi_reference_unref(env, onframeRef, &count);
363     }
364     napi_create_reference(env, onframe, 1, &onframeRef);
365     animatorResult->SetOnframeRef(onframeRef);
366     animation->AddListener([env, onframeRef](double value) {
367         napi_handle_scope scope = nullptr;
368         napi_open_handle_scope(env, &scope);
369         if (scope == nullptr) {
370             LOGW("JsAnimator: open handle scope failed");
371             return;
372         }
373         napi_value ret = nullptr;
374         napi_value valueNapi = nullptr;
375         napi_value onframe = nullptr;
376         auto result = napi_get_reference_value(env, onframeRef, &onframe);
377         if (result != napi_ok || onframe == nullptr) {
378             LOGW("JsAnimator: get onframe in callback failed");
379             napi_close_handle_scope(env, scope);
380             return;
381         }
382         napi_create_double(env, value, &valueNapi);
383         napi_call_function(env, nullptr, onframe, 1, &valueNapi, &ret);
384         napi_close_handle_scope(env, scope);
385     });
386     animator->AddInterpolator(animation);
387     if (!animator->HasScheduler()) {
388         animator->AttachSchedulerOnContainer();
389     }
390     napi_value undefined;
391     napi_get_undefined(env, &undefined);
392     return undefined;
393 }
394 
SetOnfinish(napi_env env,napi_callback_info info)395 static napi_value SetOnfinish(napi_env env, napi_callback_info info)
396 {
397     LOGI("JsAnimator: SetOnfinish");
398     AnimatorResult* animatorResult = nullptr;
399     size_t argc = 1;
400     napi_value thisVar = nullptr;
401     napi_value onfinish = nullptr;
402     napi_get_cb_info(env, info, &argc, &onfinish, &thisVar, NULL);
403     napi_unwrap(env, thisVar, (void**)&animatorResult);
404     if (!animatorResult) {
405         LOGE("unwrap animator result is failed");
406         return nullptr;
407     }
408     auto option = animatorResult->GetAnimatorOption();
409     if (!option) {
410         LOGE("option is null");
411         return nullptr;
412     }
413     auto animator = animatorResult->GetAnimator();
414     if (!animator) {
415         LOGE("animator is null");
416         return nullptr;
417     }
418     // convert onfinish function to reference
419     napi_ref onfinishRef = animatorResult->GetOnfinishRef();
420     if (onfinishRef) {
421         uint32_t count = 0;
422         napi_reference_unref(env, onfinishRef, &count);
423     }
424     napi_create_reference(env, onfinish, 1, &onfinishRef);
425     animatorResult->SetOnfinishRef(onfinishRef);
426     animator->ClearStopListeners();
427     animator->AddStopListener([env, onfinishRef] {
428         LOGI("JsAnimator: onfinish");
429         napi_handle_scope scope = nullptr;
430         napi_open_handle_scope(env, &scope);
431         if (scope == nullptr) {
432             LOGW("JsAnimator: open handle scope failed");
433             return;
434         }
435         napi_value ret = nullptr;
436         napi_value onfinish = nullptr;
437         auto result = napi_get_reference_value(env, onfinishRef, &onfinish);
438         if (result != napi_ok || onfinish == nullptr) {
439             LOGW("JsAnimator: get onfinish in callback failed");
440             napi_close_handle_scope(env, scope);
441             return;
442         }
443         napi_call_function(env, NULL, onfinish, 0, NULL, &ret);
444         napi_close_handle_scope(env, scope);
445     });
446     napi_value undefined;
447     napi_get_undefined(env, &undefined);
448     return undefined;
449 }
450 
SetOncancel(napi_env env,napi_callback_info info)451 static napi_value SetOncancel(napi_env env, napi_callback_info info)
452 {
453     LOGI("JsAnimator: SetOncancel");
454     AnimatorResult* animatorResult = nullptr;
455     size_t argc = 1;
456     napi_value thisVar = nullptr;
457     napi_value oncancel = nullptr;
458     napi_get_cb_info(env, info, &argc, &oncancel, &thisVar, NULL);
459     napi_unwrap(env, thisVar, (void**)&animatorResult);
460     if (!animatorResult) {
461         LOGE("unwrap animator result is failed");
462         return nullptr;
463     }
464     auto option = animatorResult->GetAnimatorOption();
465     if (!option) {
466         LOGE("option is null");
467         return nullptr;
468     }
469     auto animator = animatorResult->GetAnimator();
470     if (!animator) {
471         LOGE("animator is null");
472         return nullptr;
473     }
474     // convert oncancel function to reference
475     napi_ref oncancelRef = animatorResult->GetOncancelRef();
476     if (oncancelRef) {
477         uint32_t count = 0;
478         napi_reference_unref(env, oncancelRef, &count);
479     }
480     napi_create_reference(env, oncancel, 1, &oncancelRef);
481     animatorResult->SetOncancelRef(oncancelRef);
482     animator->ClearIdleListeners();
483     animator->AddIdleListener([env, oncancelRef] {
484         LOGI("JsAnimator: oncancel");
485         napi_handle_scope scope = nullptr;
486         napi_open_handle_scope(env, &scope);
487         if (scope == nullptr) {
488             LOGW("JsAnimator: open handle scope failed");
489             return;
490         }
491         napi_value ret = nullptr;
492         napi_value oncancel = nullptr;
493         auto result = napi_get_reference_value(env, oncancelRef, &oncancel);
494         if (result != napi_ok || oncancel == nullptr) {
495             LOGW("JsAnimator: get oncancel in callback failed");
496             napi_close_handle_scope(env, scope);
497             return;
498         }
499         napi_call_function(env, NULL, oncancel, 0, NULL, &ret);
500         napi_close_handle_scope(env, scope);
501     });
502     napi_value undefined;
503     napi_get_undefined(env, &undefined);
504     return undefined;
505 }
506 
SetOnrepeat(napi_env env,napi_callback_info info)507 static napi_value SetOnrepeat(napi_env env, napi_callback_info info)
508 {
509     LOGI("JsAnimator: SetOnrepeat");
510     AnimatorResult* animatorResult = nullptr;
511     size_t argc = 1;
512     napi_value thisVar = nullptr;
513     napi_value onrepeat = nullptr;
514     napi_get_cb_info(env, info, &argc, &onrepeat, &thisVar, NULL);
515     napi_unwrap(env, thisVar, (void**)&animatorResult);
516     if (!animatorResult) {
517         LOGE("unwrap animator result is failed");
518         return nullptr;
519     }
520     auto option = animatorResult->GetAnimatorOption();
521     if (!option) {
522         LOGE("option is null");
523         return nullptr;
524     }
525     auto animator = animatorResult->GetAnimator();
526     if (!animator) {
527         LOGE("animator is null");
528         return nullptr;
529     }
530     // convert onrepeat function to reference
531     napi_ref onrepeatRef = animatorResult->GetOnrepeatRef();
532     if (onrepeatRef) {
533         uint32_t count = 0;
534         napi_reference_unref(env, onrepeatRef, &count);
535     }
536     napi_create_reference(env, onrepeat, 1, &onrepeatRef);
537     animatorResult->SetOnrepeatRef(onrepeatRef);
538     animator->ClearRepeatListeners();
539     animator->AddRepeatListener([env, onrepeatRef] {
540         LOGI("JsAnimator: onrepeat");
541         napi_handle_scope scope = nullptr;
542         napi_open_handle_scope(env, &scope);
543         if (scope == nullptr) {
544             LOGW("JsAnimator: open handle scope failed");
545             return;
546         }
547         napi_value ret = nullptr;
548         napi_value onrepeat = nullptr;
549         auto result = napi_get_reference_value(env, onrepeatRef, &onrepeat);
550         if (result != napi_ok || onrepeat == nullptr) {
551             LOGW("JsAnimator: get onrepeat in callback failed");
552             napi_close_handle_scope(env, scope);
553             return;
554         }
555         napi_call_function(env, NULL, onrepeat, 0, NULL, &ret);
556         napi_close_handle_scope(env, scope);
557     });
558     napi_value undefined;
559     napi_get_undefined(env, &undefined);
560     return undefined;
561 }
562 
JSCreate(napi_env env,napi_callback_info info)563 static napi_value JSCreate(napi_env env, napi_callback_info info)
564 {
565     LOGI("JsAnimator: JSCreate");
566     auto option = std::make_shared<AnimatorOption>();
567     ParseAnimatorOption(env, info, option);
568     auto animator = CREATE_ANIMATOR();
569     animator->AttachSchedulerOnContainer();
570     AnimatorResult* animatorResult = new AnimatorResult(animator, option);
571     napi_value jsAnimator = nullptr;
572     napi_create_object(env, &jsAnimator);
573     napi_wrap(
574         env, jsAnimator, animatorResult,
575         [](napi_env env, void* data, void* hint) {
576             AnimatorResult* animatorResult = (AnimatorResult*)data;
577             // release four references(onFunc) before releasing animatorResult
578             animatorResult->Destroy(env);
579             delete animatorResult;
580         },
581         nullptr, nullptr);
582     napi_property_descriptor resultFuncs[] = {
583         DECLARE_NAPI_FUNCTION("update", JSUpdate),
584         DECLARE_NAPI_FUNCTION("reset", JSReset),
585         DECLARE_NAPI_FUNCTION("play", JSPlay),
586         DECLARE_NAPI_FUNCTION("finish", JSFinish),
587         DECLARE_NAPI_FUNCTION("pause", JSPause),
588         DECLARE_NAPI_FUNCTION("cancel", JSCancel),
589         DECLARE_NAPI_FUNCTION("reverse", JSReverse),
590         DECLARE_NAPI_SETTER("onframe", SetOnframe),
591         DECLARE_NAPI_SETTER("onfinish", SetOnfinish),
592         DECLARE_NAPI_SETTER("oncancel", SetOncancel),
593         DECLARE_NAPI_SETTER("onrepeat", SetOnrepeat),
594     };
595 
596     NAPI_CALL(env, napi_define_properties(env, jsAnimator, sizeof(resultFuncs) / sizeof(resultFuncs[0]), resultFuncs));
597     return jsAnimator;
598 }
599 
600 // since API 9 deprecated
JSCreateAnimator(napi_env env,napi_callback_info info)601 static napi_value JSCreateAnimator(napi_env env, napi_callback_info info)
602 {
603     LOGI("JsAnimator: JSCreateAnimator");
604     return JSCreate(env, info);
605 }
606 
AnimatorExport(napi_env env,napi_value exports)607 static napi_value AnimatorExport(napi_env env, napi_value exports)
608 {
609     LOGI("JsAnimator: AnimatorExport");
610     napi_property_descriptor animatorDesc[] = {
611         DECLARE_NAPI_FUNCTION("create", JSCreate),
612         DECLARE_NAPI_FUNCTION("createAnimator", JSCreateAnimator),
613     };
614     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(animatorDesc) / sizeof(animatorDesc[0]), animatorDesc));
615     return exports;
616 }
617 
618 static napi_module animatorModule = {
619     .nm_version = 1,
620     .nm_flags = 0,
621     .nm_filename = nullptr,
622     .nm_register_func = AnimatorExport,
623     .nm_modname = "animator",
624     .nm_priv = ((void*)0),
625     .reserved = { 0 },
626 };
627 
AnimatorRegister()628 extern "C" __attribute__((constructor)) void AnimatorRegister()
629 {
630     napi_module_register(&animatorModule);
631 }
632 
ApplyOption()633 void AnimatorResult::ApplyOption()
634 {
635     CHECK_NULL_VOID_NOLOG(animator_);
636     CHECK_NULL_VOID_NOLOG(option_);
637     animator_->SetDuration(option_->duration);
638     animator_->SetIteration(option_->iterations);
639     animator_->SetStartDelay(option_->delay);
640     animator_->SetFillMode(StringToFillMode(option_->fill));
641     animator_->SetAnimationDirection(StringToAnimationDirection(option_->direction));
642 }
643 
Destroy(napi_env env)644 void AnimatorResult::Destroy(napi_env env)
645 {
646     if (animator_) {
647         LOGI("JsAnimator: animator object start destroying, isStopped:%{public}d, id:%{public}d",
648             animator_->IsStopped(), animator_->GetId());
649         if (!animator_->IsStopped()) {
650             animator_->Stop();
651             LOGW("JsAnimator: animator force stopping done, id:%{public}d", animator_->GetId());
652         }
653     }
654     if (onframe_ != nullptr) {
655         napi_delete_reference(env, onframe_);
656     }
657     if (onfinish_ != nullptr) {
658         napi_delete_reference(env, onfinish_);
659     }
660     if (oncancel_ != nullptr) {
661         napi_delete_reference(env, oncancel_);
662     }
663     if (onrepeat_ != nullptr) {
664         napi_delete_reference(env, onrepeat_);
665     }
666 }
667 
668 } // namespace OHOS::Ace::Napi
669