• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 
17 #include "animator_option.h"
18 #include "interfaces/napi/kits/utils/napi_utils.h"
19 #include "base/thread/frame_trace_adapter.h"
20 
21 namespace OHOS::Ace::Napi {
22 
23 namespace {
24 constexpr size_t INTERPOLATING_SPRING_PARAMS_SIZE = 4;
25 constexpr char INTERPOLATING_SPRING[] = "interpolating-spring";
26 constexpr size_t SIMPLEANIMATOR_CONSTRUCTOR_PARAMS_SIZE = 2;
27 constexpr float ANIMATOR_DEFALUT_BEGIN = 0.0f;
28 constexpr float ANIMATOR_DEFALUT_END = 1.0f;
29 constexpr int32_t ANIMATOR_DEFALUT_DURATION = 1000;
30 const std::string ANIMATOR_DEFALUT_EASING = "ease";
31 constexpr int32_t ANIMATOR_DEFALUT_DELAY = 0;
32 constexpr int32_t ANIMATOR_DEFALUT_ITERATIONS = 1;
33 const std::string ANIMATOR_FILLMODE_FORWARDS = "forwards";
34 const std::string ANIMATOR_FILLMODE_NONE = "none";
35 const std::string ANIMATOR_FILLMODE_BACKWARDS = "backwards";
36 const std::string ANIMATOR_FILLMODE_BOTH = "both";
37 const std::string ANIMATOR_DIRECTION_NORMAL = "normal";
38 const std::string ANIMATOR_DIRECTION_ALTERNATE = "alternate";
39 const std::string ANIMATOR_DIRECTION_REVERSE = "reverse";
40 const std::string ANIMATOR_DIRECTION_ALTERNATE_REVERSE = "alternate-reverse";
41 const std::string ANIMATOR_SIMPLE_ANIMATOR_OPTIONS_NAME = "SimpleAnimatorOptions";
42 } // namespace
43 
ParseString(napi_env env,napi_value propertyNapi,std::string & property)44 static void ParseString(napi_env env, napi_value propertyNapi, std::string& property)
45 {
46     if (propertyNapi != nullptr) {
47         napi_valuetype valueType = napi_undefined;
48         napi_typeof(env, propertyNapi, &valueType);
49         if (valueType == napi_undefined) {
50             NapiThrow(env, "Required input parameters are missing.", ERROR_CODE_PARAM_INVALID);
51             return;
52         } else if (valueType != napi_string) {
53             NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
54             return;
55         }
56 
57         size_t buffSize = 0;
58         napi_status status = napi_get_value_string_utf8(env, propertyNapi, nullptr, 0, &buffSize);
59         if (status != napi_ok || buffSize == 0) {
60             return;
61         }
62         std::unique_ptr<char[]> propertyString = std::make_unique<char[]>(buffSize + 1);
63         size_t retLen = 0;
64         napi_get_value_string_utf8(env, propertyNapi, propertyString.get(), buffSize + 1, &retLen);
65         property = propertyString.get();
66     }
67 }
68 
ParseInt(napi_env env,napi_value propertyNapi,int32_t & property)69 static void ParseInt(napi_env env, napi_value propertyNapi, int32_t& property)
70 {
71     if (propertyNapi != nullptr) {
72         napi_valuetype valueType = napi_undefined;
73         napi_typeof(env, propertyNapi, &valueType);
74         if (valueType == napi_undefined) {
75             NapiThrow(env, "Required input parameters are missing.", ERROR_CODE_PARAM_INVALID);
76             return;
77         } else if (valueType != napi_number) {
78             NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
79             return;
80         }
81         napi_get_value_int32(env, propertyNapi, &property);
82     }
83 }
84 
ParseDouble(napi_env env,napi_value propertyNapi,double & property)85 static void ParseDouble(napi_env env, napi_value propertyNapi, double& property)
86 {
87     if (propertyNapi != nullptr) {
88         napi_valuetype valueType = napi_undefined;
89         napi_typeof(env, propertyNapi, &valueType);
90         if (valueType == napi_undefined) {
91             NapiThrow(env, "Required input parameters are missing.", ERROR_CODE_PARAM_INVALID);
92             return;
93         } else if (valueType != napi_number) {
94             NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
95             return;
96         }
97         napi_get_value_double(env, propertyNapi, &property);
98     }
99 }
100 
StringToFillMode(const std::string & fillMode)101 static FillMode StringToFillMode(const std::string& fillMode)
102 {
103     if (fillMode.compare("forwards") == 0) {
104         return FillMode::FORWARDS;
105     } else if (fillMode.compare("backwards") == 0) {
106         return FillMode::BACKWARDS;
107     } else if (fillMode.compare("both") == 0) {
108         return FillMode::BOTH;
109     } else {
110         return FillMode::NONE;
111     }
112 }
113 
StringToAnimationDirection(const std::string & direction)114 static AnimationDirection StringToAnimationDirection(const std::string& direction)
115 {
116     if (direction.compare("alternate") == 0) {
117         return AnimationDirection::ALTERNATE;
118     } else if (direction.compare("reverse") == 0) {
119         return AnimationDirection::REVERSE;
120     } else if (direction.compare("alternate-reverse") == 0) {
121         return AnimationDirection::ALTERNATE_REVERSE;
122     } else {
123         return AnimationDirection::NORMAL;
124     }
125 }
126 
ParseOptionToMotion(const std::shared_ptr<AnimatorOption> & option)127 static RefPtr<Motion> ParseOptionToMotion(const std::shared_ptr<AnimatorOption>& option)
128 {
129     const auto& curveStr = option->easing;
130     if (curveStr.back() != ')') {
131         return nullptr;
132     }
133     std::string::size_type leftEmbracePosition = curveStr.find_last_of('(');
134     if (leftEmbracePosition == std::string::npos) {
135         return nullptr;
136     }
137     auto aniTimFuncName = curveStr.substr(0, leftEmbracePosition);
138     if (aniTimFuncName.compare(INTERPOLATING_SPRING)) {
139         return nullptr;
140     }
141     auto params = curveStr.substr(leftEmbracePosition + 1, curveStr.length() - leftEmbracePosition - 2);
142     std::vector<std::string> paramsVector;
143     StringUtils::StringSplitter(params, ',', paramsVector);
144     if (paramsVector.size() != INTERPOLATING_SPRING_PARAMS_SIZE) {
145         return nullptr;
146     }
147     for (auto& param : paramsVector) {
148         Framework::RemoveHeadTailSpace(param);
149     }
150     float velocity = StringUtils::StringToFloat(paramsVector[0]);
151     float mass = StringUtils::StringToFloat(paramsVector[1]);
152     float stiffness = StringUtils::StringToFloat(paramsVector[2]);
153     float damping = StringUtils::StringToFloat(paramsVector[3]);
154     // input velocity is normalized velocity, while the velocity of arkui's springMotion is absolute velocity.
155     velocity = velocity * (option->end - option->begin);
156     if (LessOrEqual(mass, 0)) {
157         mass = 1.0f;
158     }
159     if (LessOrEqual(stiffness, 0)) {
160         stiffness = 1.0f;
161     }
162     if (LessOrEqual(damping, 0)) {
163         damping = 1.0f;
164     }
165     return AceType::MakeRefPtr<SpringMotion>(
166         option->begin, option->end, velocity, AceType::MakeRefPtr<SpringProperty>(mass, stiffness, damping));
167 }
168 
GetNapiCallbackInfoAndThis(napi_env env,napi_callback_info info)169 void* GetNapiCallbackInfoAndThis(napi_env env, napi_callback_info info)
170 {
171     napi_value value = nullptr;
172     napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &value, nullptr);
173     if (status != napi_ok) {
174         return nullptr;
175     }
176     void* result = nullptr;
177     status = napi_unwrap(env, value, &result);
178     if (status != napi_ok) {
179         return nullptr;
180     }
181     return result;
182 }
183 
FillModeToString(const FillMode & fillMode)184 std::string FillModeToString(const FillMode& fillMode)
185 {
186     if (fillMode == FillMode::NONE) {
187         return ANIMATOR_FILLMODE_NONE;
188     } else if (fillMode == FillMode::BACKWARDS) {
189         return ANIMATOR_FILLMODE_BACKWARDS;
190     } else if (fillMode == FillMode::BOTH) {
191         return ANIMATOR_FILLMODE_BOTH;
192     } else {
193         return ANIMATOR_FILLMODE_FORWARDS;
194     }
195 }
196 
AnimationDirectionToString(const AnimationDirection & direction)197 std::string AnimationDirectionToString(const AnimationDirection& direction)
198 {
199     if (direction == AnimationDirection::ALTERNATE) {
200         return ANIMATOR_DIRECTION_ALTERNATE;
201     } else if (direction == AnimationDirection::REVERSE) {
202         return ANIMATOR_DIRECTION_REVERSE;
203     } else if (direction == AnimationDirection::ALTERNATE_REVERSE) {
204         return ANIMATOR_DIRECTION_ALTERNATE_REVERSE;
205     } else {
206         return ANIMATOR_DIRECTION_NORMAL;
207     }
208 }
209 
IsSimpleAnimatorOptions(napi_env env,napi_value argv)210 bool IsSimpleAnimatorOptions(napi_env env, napi_value argv)
211 {
212     bool isSimpleOption = false;
213     napi_value constructorName = nullptr;
214     napi_get_named_property(env, argv, "constructor", &constructorName);
215     napi_value name = nullptr;
216     napi_get_named_property(env, constructorName, "name", &name);
217 
218     napi_valuetype valueType = napi_undefined;
219     napi_typeof(env, name, &valueType);
220     if (valueType == napi_string) {
221         std::string strName = "";
222         ParseString(env, name, strName);
223         if (strName == ANIMATOR_SIMPLE_ANIMATOR_OPTIONS_NAME) {
224             isSimpleOption = true;
225         }
226     }
227     return isSimpleOption;
228 }
229 
SetSimpleAnimatorOptions(napi_env env,napi_value argv,std::shared_ptr<AnimatorOption> & option)230 void SetSimpleAnimatorOptions(napi_env env, napi_value argv, std::shared_ptr<AnimatorOption>& option)
231 {
232     void* result = nullptr;
233     napi_unwrap(env, argv, &result);
234     JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(result);
235     if (me == nullptr) {
236         return;
237     }
238     option->begin = me->GetBegin();
239     option->end = me->GetEnd();
240     option->duration = me->GetDuration().has_value() ? me->GetDuration().value() : ANIMATOR_DEFALUT_DURATION;
241     option->easing = me->GetEasing().has_value() ? me->GetEasing().value() : ANIMATOR_DEFALUT_EASING;
242     option->delay = me->GetDelay().has_value() ? me->GetDelay().value() : ANIMATOR_DEFALUT_DELAY;
243     option->fill = me->GetFill().has_value() ? FillModeToString(me->GetFill().value()) : ANIMATOR_FILLMODE_FORWARDS;
244     option->direction = me->GetDirection().has_value() ? AnimationDirectionToString(me->GetDirection().value())
245                                                        : ANIMATOR_DIRECTION_NORMAL;
246     option->iterations = me->GetIterations().has_value() ? me->GetIterations().value() : ANIMATOR_DEFALUT_ITERATIONS;
247 }
248 
ParseAnimatorOption(napi_env env,napi_callback_info info,std::shared_ptr<AnimatorOption> & option)249 static void ParseAnimatorOption(napi_env env, napi_callback_info info, std::shared_ptr<AnimatorOption>& option)
250 {
251     size_t argc = 1;
252     napi_value argv;
253     napi_get_cb_info(env, info, &argc, &argv, NULL, NULL);
254     if (argc != 1) {
255         NapiThrow(env, "The number of parameters must be equal to 1.", ERROR_CODE_PARAM_INVALID);
256         return;
257     }
258     if (IsSimpleAnimatorOptions(env, argv)) {
259         SetSimpleAnimatorOptions(env, argv, option);
260         return;
261     }
262     napi_value durationNapi = nullptr;
263     napi_value easingNapi = nullptr;
264     napi_value delayNapi = nullptr;
265     napi_value fillNapi = nullptr;
266     napi_value directionNapi = nullptr;
267     napi_value iterationsNapi = nullptr;
268     napi_value beginNapi = nullptr;
269     napi_value endNapi = nullptr;
270     napi_valuetype valueType = napi_undefined;
271     napi_typeof(env, argv, &valueType);
272     if (valueType == napi_object) {
273         napi_get_named_property(env, argv, "duration", &durationNapi);
274         napi_get_named_property(env, argv, "easing", &easingNapi);
275         napi_get_named_property(env, argv, "delay", &delayNapi);
276         napi_get_named_property(env, argv, "fill", &fillNapi);
277         napi_get_named_property(env, argv, "direction", &directionNapi);
278         napi_get_named_property(env, argv, "iterations", &iterationsNapi);
279         napi_get_named_property(env, argv, "begin", &beginNapi);
280         napi_get_named_property(env, argv, "end", &endNapi);
281     } else {
282         NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
283         return;
284     }
285 
286     int32_t duration = 0;
287     int32_t delay = 0;
288     int32_t iterations = 0;
289     double begin = 0.0;
290     double end = 0.0;
291     std::string easing = "ease";
292     std::string fill = "none";
293     std::string direction = "normal";
294     ParseString(env, easingNapi, easing);
295     ParseString(env, fillNapi, fill);
296     ParseString(env, directionNapi, direction);
297     ParseInt(env, durationNapi, duration);
298     ParseInt(env, delayNapi, delay);
299     ParseInt(env, iterationsNapi, iterations);
300     ParseDouble(env, beginNapi, begin);
301     ParseDouble(env, endNapi, end);
302     option->duration = std::max(duration, 0);
303     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
304         option->delay = delay;
305     } else {
306         option->delay = std::max(delay, 0);
307     }
308     option->iterations = iterations >= -1 ? iterations : 1;
309     option->begin = begin;
310     option->end = end;
311     option->easing = easing;
312     option->fill = fill;
313     option->direction = direction;
314 }
315 
GetAnimatorResult(napi_env env,napi_callback_info info)316 static AnimatorResult* GetAnimatorResult(napi_env env, napi_callback_info info)
317 {
318     AnimatorResult* animatorResult = nullptr;
319     napi_value thisVar;
320     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
321     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&animatorResult));
322     return animatorResult;
323 }
324 
GetAnimatorInResult(napi_env env,napi_callback_info info)325 static RefPtr<Animator> GetAnimatorInResult(napi_env env, napi_callback_info info)
326 {
327     AnimatorResult* animatorResult = GetAnimatorResult(env, info);
328     if (!animatorResult) {
329         return nullptr;
330     }
331     return animatorResult->GetAnimator();
332 }
333 
JSReset(napi_env env,napi_callback_info info)334 static napi_value JSReset(napi_env env, napi_callback_info info)
335 {
336     AnimatorResult* animatorResult = nullptr;
337     napi_value thisVar;
338     napi_get_cb_info(env, info, NULL, NULL, &thisVar, NULL);
339     napi_unwrap(env, thisVar, (void**)&animatorResult);
340     if (!animatorResult) {
341         NapiThrow(env, "Internal error. Unwrap animator result is failed.", ERROR_CODE_INTERNAL_ERROR);
342         return nullptr;
343     }
344     auto option = animatorResult->GetAnimatorOption();
345     if (!option) {
346         NapiThrow(env, "Internal error. Option is null in AnimatorResult.", ERROR_CODE_INTERNAL_ERROR);
347         return nullptr;
348     }
349     ParseAnimatorOption(env, info, option);
350     auto animator = animatorResult->GetAnimator();
351     if (!animator) {
352         NapiThrow(env, "Internal error. Animator is null in AnimatorResult.", ERROR_CODE_INTERNAL_ERROR);
353         return nullptr;
354     }
355     TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator reset, id:%{public}d", animator->GetId());
356     animator->ClearInterpolators();
357     animator->ResetIsReverse();
358     animatorResult->ApplyOption();
359     napi_ref onframeRef = animatorResult->GetOnframeRef();
360     if (onframeRef) {
361         auto onFrameCallback = [env, onframeRef, id = animator->GetId(),
362                                    weakOption = std::weak_ptr<AnimatorOption>(animatorResult->GetAnimatorOption())](
363                                    double value) {
364             napi_handle_scope scope = nullptr;
365             napi_open_handle_scope(env, &scope);
366             if (scope == nullptr) {
367                 TAG_LOGW(
368                     AceLogTag::ACE_ANIMATION, "ohos.animator call onFrame failed, scope is null, id:%{public}d", id);
369                 return;
370             }
371             napi_value ret = nullptr;
372             napi_value valueNapi = nullptr;
373             napi_value onframe = nullptr;
374             auto result = napi_get_reference_value(env, onframeRef, &onframe);
375             auto option = weakOption.lock();
376             if (!(result == napi_ok && onframe && option)) {
377                 TAG_LOGW(AceLogTag::ACE_ANIMATION,
378                     "ohos.animator call onFrame failed, get reference result:%{public}d, id:%{public}d",
379                     result == napi_ok, id);
380                 napi_close_handle_scope(env, scope);
381                 return;
382             }
383             ACE_SCOPED_TRACE(
384                 "ohos.animator onframe. duration:%d, curve:%s, id:%d", option->duration, option->easing.c_str(), id);
385             napi_create_double(env, value, &valueNapi);
386             napi_call_function(env, nullptr, onframe, 1, &valueNapi, &ret);
387             napi_close_handle_scope(env, scope);
388         };
389         RefPtr<Animation<double>> animation;
390         RefPtr<Motion> motion = ParseOptionToMotion(option);
391         if (motion) {
392             motion->AddListener(onFrameCallback);
393             animatorResult->SetMotion(motion);
394         } else {
395             auto curve = Framework::CreateCurve(option->easing);
396             animation = AceType::MakeRefPtr<CurveAnimation<double>>(option->begin, option->end, curve);
397             animation->AddListener(onFrameCallback);
398             animator->AddInterpolator(animation);
399             animatorResult->SetMotion(nullptr);
400         }
401     }
402     napi_value result;
403     napi_get_null(env, &result);
404     return result;
405 }
406 
407 // since API 9 deprecated
JSUpdate(napi_env env,napi_callback_info info)408 static napi_value JSUpdate(napi_env env, napi_callback_info info)
409 {
410     return JSReset(env, info);
411 }
412 
JSPlay(napi_env env,napi_callback_info info)413 static napi_value JSPlay(napi_env env, napi_callback_info info)
414 {
415     FrameTraceAdapter* ft = FrameTraceAdapter::GetInstance();
416     if (ft != nullptr) {
417         ft->SetFrameTraceLimit();
418     }
419     auto animatorResult = GetAnimatorResult(env, info);
420     if (!animatorResult) {
421         TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: cannot find animator result when call play");
422         return nullptr;
423     }
424     auto animator = animatorResult->GetAnimator();
425     if (!animator) {
426         TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: no animator is created when call play");
427         return nullptr;
428     }
429     if (!animator->HasScheduler()) {
430         auto result = animator->AttachSchedulerOnContainer();
431         if (!result) {
432             TAG_LOGW(AceLogTag::ACE_ANIMATION,
433                 "ohos.animator: play failed, animator is not bound to specific context, use uiContext.createAnimator "
434                 "instead, id:%{public}d",
435                 animator->GetId());
436             return nullptr;
437         }
438     }
439     TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator play, id:%{public}d, %{public}s",
440         animator->GetId(), animatorResult->GetAnimatorOption()->ToString().c_str());
441     if (animatorResult->GetMotion()) {
442         animator->PlayMotion(animatorResult->GetMotion());
443     } else {
444         animator->Play();
445     }
446     animator->PrintVsyncInfoIfNeed();
447     napi_value result = nullptr;
448     napi_get_null(env, &result);
449     return result;
450 }
451 
JSFinish(napi_env env,napi_callback_info info)452 static napi_value JSFinish(napi_env env, napi_callback_info info)
453 {
454     auto animator = GetAnimatorInResult(env, info);
455     if (!animator) {
456         return nullptr;
457     }
458     TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator finish, id:%{public}d", animator->GetId());
459     animator->Finish();
460     napi_value result = nullptr;
461     napi_get_null(env, &result);
462     return result;
463 }
464 
JSPause(napi_env env,napi_callback_info info)465 static napi_value JSPause(napi_env env, napi_callback_info info)
466 {
467     auto animator = GetAnimatorInResult(env, info);
468     if (!animator) {
469         return nullptr;
470     }
471     TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator pause, id:%{public}d", animator->GetId());
472     animator->Pause();
473     napi_value result;
474     napi_get_null(env, &result);
475     return result;
476 }
477 
JSCancel(napi_env env,napi_callback_info info)478 static napi_value JSCancel(napi_env env, napi_callback_info info)
479 {
480     auto animator = GetAnimatorInResult(env, info);
481     if (!animator) {
482         return nullptr;
483     }
484     TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator cancel, id:%{public}d", animator->GetId());
485     animator->Cancel();
486     napi_value result;
487     napi_get_null(env, &result);
488     return result;
489 }
490 
JSReverse(napi_env env,napi_callback_info info)491 static napi_value JSReverse(napi_env env, napi_callback_info info)
492 {
493     auto animatorResult = GetAnimatorResult(env, info);
494     if (!animatorResult) {
495         TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: cannot find animator result when call reverse");
496         return nullptr;
497     }
498     if (animatorResult->GetMotion()) {
499         TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: interpolatingSpringCurve, cannot reverse");
500         return nullptr;
501     }
502     auto animator = animatorResult->GetAnimator();
503     if (!animator) {
504         TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: no animator is created when call reverse");
505         return nullptr;
506     }
507     if (!animator->HasScheduler()) {
508         auto result = animator->AttachSchedulerOnContainer();
509         if (!result) {
510             TAG_LOGW(AceLogTag::ACE_ANIMATION,
511                 "ohos.animator: reverse failed, animator is not bound to specific context, use "
512                 "uiContext.createAnimator instead, id:%{public}d",
513                 animator->GetId());
514             return nullptr;
515         }
516     }
517     TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator reverse, id:%{public}d", animator->GetId());
518     animator->Reverse();
519     napi_value result;
520     napi_get_null(env, &result);
521     return result;
522 }
523 
ParseJsValue(napi_env env,napi_value jsObject,const std::string & name,int32_t & data)524 static bool ParseJsValue(napi_env env, napi_value jsObject, const std::string& name, int32_t& data)
525 {
526     napi_value value = nullptr;
527     napi_get_named_property(env, jsObject, name.c_str(), &value);
528     napi_valuetype type = napi_undefined;
529     napi_typeof(env, value, &type);
530     if (type == napi_number) {
531         napi_get_value_int32(env, value, &data);
532         return true;
533     } else {
534         return false;
535     }
536     return true;
537 }
538 
ParseExpectedFrameRateRange(napi_env env,napi_callback_info info,FrameRateRange & frameRateRange)539 static napi_value ParseExpectedFrameRateRange(napi_env env, napi_callback_info info, FrameRateRange& frameRateRange)
540 {
541     size_t argc = 1;
542     napi_value argv[1];
543     napi_value thisVar = nullptr;
544     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
545     if (argc != 1) {
546         NapiThrow(env, "The number of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
547         return nullptr;
548     }
549 
550     napi_value& nativeObj = argv[0];
551     if (nativeObj == nullptr) {
552         NapiThrow(env, "The nativeObj is nullptr.", ERROR_CODE_PARAM_INVALID);
553         return nullptr;
554     }
555 
556     int32_t minFPS = 0;
557     int32_t maxFPS = 0;
558     int32_t expectedFPS = 0;
559     ParseJsValue(env, nativeObj, "min", minFPS);
560     ParseJsValue(env, nativeObj, "max", maxFPS);
561     ParseJsValue(env, nativeObj, "expected", expectedFPS);
562 
563     frameRateRange.Set(minFPS, maxFPS, expectedFPS);
564     if (!frameRateRange.IsValid()) {
565         NapiThrow(env, "ExpectedFrameRateRange Error", ERROR_CODE_PARAM_INVALID);
566         return nullptr;
567     }
568     return nullptr;
569 }
570 
JSSetExpectedFrameRateRange(napi_env env,napi_callback_info info)571 static napi_value JSSetExpectedFrameRateRange(napi_env env, napi_callback_info info)
572 {
573     auto animatorResult = GetAnimatorResult(env, info);
574     if (!animatorResult) {
575         TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: cannot find animator when call SetExpectedFrameRateRange");
576         return nullptr;
577     }
578     auto animator = animatorResult->GetAnimator();
579     if (!animator) {
580         TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: no animator is created when call SetExpectedFrameRateRange");
581         return nullptr;
582     }
583     if (!animator->HasScheduler()) {
584         auto result = animator->AttachSchedulerOnContainer();
585         if (!result) {
586             TAG_LOGW(AceLogTag::ACE_ANIMATION,
587                 "ohos.animator: SetExpectedFrameRateRange failed because animator is not bound to specific context, "
588                 "use uiContext.createAnimator instead, id:%{public}d",
589                 animator->GetId());
590             return nullptr;
591         }
592     }
593     FrameRateRange frameRateRange;
594     ParseExpectedFrameRateRange(env, info, frameRateRange);
595     animator->SetExpectedFrameRateRange(frameRateRange);
596     TAG_LOGD(AceLogTag::ACE_ANIMATION, "animator id:%{public}d SetExpectedFrameRateRange"
597         "{%{public}d, %{public}d, %{public}d}", animator->GetId(), frameRateRange.min_, frameRateRange.max_,
598         frameRateRange.preferred_);
599     return nullptr;
600 }
601 
SetOnframe(napi_env env,napi_callback_info info)602 static napi_value SetOnframe(napi_env env, napi_callback_info info)
603 {
604     AnimatorResult* animatorResult = nullptr;
605     size_t argc = 1;
606     napi_value thisVar = nullptr;
607     napi_value onframe = nullptr;
608     napi_get_cb_info(env, info, &argc, &onframe, &thisVar, NULL);
609     napi_unwrap(env, thisVar, (void**)&animatorResult);
610     if (!animatorResult) {
611         return nullptr;
612     }
613     auto option = animatorResult->GetAnimatorOption();
614     if (!option) {
615         return nullptr;
616     }
617     auto animator = animatorResult->GetAnimator();
618     if (!animator) {
619         return nullptr;
620     }
621     animator->ClearInterpolators();
622     // convert onframe function to reference
623     napi_ref onframeRef = animatorResult->GetOnframeRef();
624     if (onframeRef) {
625         uint32_t count = 0;
626         napi_reference_unref(env, onframeRef, &count);
627     }
628     napi_create_reference(env, onframe, 1, &onframeRef);
629     animatorResult->SetOnframeRef(onframeRef);
630     auto onFrameCallback = [env, onframeRef, id = animator->GetId(),
631                                weakOption = std::weak_ptr<AnimatorOption>(animatorResult->GetAnimatorOption())](
632                                double value) {
633         napi_handle_scope scope = nullptr;
634         napi_open_handle_scope(env, &scope);
635         if (scope == nullptr) {
636             TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator call onFrame failed, scope is null, id:%{public}d", id);
637             return;
638         }
639         napi_value ret = nullptr;
640         napi_value valueNapi = nullptr;
641         napi_value onframe = nullptr;
642         auto result = napi_get_reference_value(env, onframeRef, &onframe);
643         auto option = weakOption.lock();
644         if (!(result == napi_ok && onframe && option)) {
645             TAG_LOGW(AceLogTag::ACE_ANIMATION,
646                 "ohos.animator call onFrame failed, get reference result:%{public}d, id:%{public}d", result == napi_ok,
647                 id);
648             napi_close_handle_scope(env, scope);
649             return;
650         }
651         ACE_SCOPED_TRACE(
652             "ohos.animator onframe. duration:%d, curve:%s, id:%d", option->duration, option->easing.c_str(), id);
653         napi_create_double(env, value, &valueNapi);
654         napi_call_function(env, nullptr, onframe, 1, &valueNapi, &ret);
655         napi_close_handle_scope(env, scope);
656     };
657     RefPtr<Animation<double>> animation;
658     RefPtr<Motion> motion = ParseOptionToMotion(option);
659     if (motion) {
660         motion->AddListener(onFrameCallback);
661         animatorResult->SetMotion(motion);
662     } else {
663         auto curve = Framework::CreateCurve(option->easing);
664         animation = AceType::MakeRefPtr<CurveAnimation<double>>(option->begin, option->end, curve);
665         animation->AddListener(onFrameCallback);
666         animator->AddInterpolator(animation);
667         animatorResult->SetMotion(nullptr);
668     }
669     if (!animator->HasScheduler()) {
670         animator->AttachSchedulerOnContainer();
671     }
672     napi_value undefined;
673     napi_get_undefined(env, &undefined);
674     return undefined;
675 }
676 
SetOnFrame(napi_env env,napi_callback_info info)677 static napi_value SetOnFrame(napi_env env, napi_callback_info info)
678 {
679     return SetOnframe(env, info);
680 }
681 
SetOnfinish(napi_env env,napi_callback_info info)682 static napi_value SetOnfinish(napi_env env, napi_callback_info info)
683 {
684     AnimatorResult* animatorResult = nullptr;
685     size_t argc = 1;
686     napi_value thisVar = nullptr;
687     napi_value onfinish = nullptr;
688     napi_get_cb_info(env, info, &argc, &onfinish, &thisVar, NULL);
689     napi_unwrap(env, thisVar, (void**)&animatorResult);
690     if (!animatorResult) {
691         return nullptr;
692     }
693     auto option = animatorResult->GetAnimatorOption();
694     if (!option) {
695         return nullptr;
696     }
697     auto animator = animatorResult->GetAnimator();
698     if (!animator) {
699         return nullptr;
700     }
701     // convert onfinish function to reference
702     napi_ref onfinishRef = animatorResult->GetOnfinishRef();
703     if (onfinishRef) {
704         uint32_t count = 0;
705         napi_reference_unref(env, onfinishRef, &count);
706     }
707     napi_create_reference(env, onfinish, 1, &onfinishRef);
708     animatorResult->SetOnfinishRef(onfinishRef);
709     animator->ClearStopListeners();
710     TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator set finish callback, id:%{public}d", animator->GetId());
711     animator->AddStopListener([env, onfinishRef, id = animator->GetId()] {
712         napi_handle_scope scope = nullptr;
713         napi_open_handle_scope(env, &scope);
714         if (scope == nullptr) {
715             TAG_LOGW(AceLogTag::ACE_ANIMATION,
716                 "ohos.animator call finish callback failed, scope is null, id:%{public}d", id);
717             return;
718         }
719         napi_value ret = nullptr;
720         napi_value onfinish = nullptr;
721         auto result = napi_get_reference_value(env, onfinishRef, &onfinish);
722         if (result != napi_ok || onfinish == nullptr) {
723             napi_close_handle_scope(env, scope);
724             TAG_LOGW(AceLogTag::ACE_ANIMATION,
725                 "ohos.animator call finish callback failed, get onFinish failed, id:%{public}d", id);
726             return;
727         }
728         ACE_SCOPED_TRACE("ohos.animator finishCallback, id:%d", id);
729         TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator call finish callback, id:%{public}d", id);
730         result = napi_call_function(env, NULL, onfinish, 0, NULL, &ret);
731         if (result != napi_ok) {
732             TAG_LOGW(
733                 AceLogTag::ACE_ANIMATION, "ohos.animator call finish callback failed, napi error, id:%{public}d", id);
734         }
735         napi_close_handle_scope(env, scope);
736     });
737     napi_value undefined;
738     napi_get_undefined(env, &undefined);
739     return undefined;
740 }
741 
SetOnFinish(napi_env env,napi_callback_info info)742 static napi_value SetOnFinish(napi_env env, napi_callback_info info)
743 {
744     return SetOnfinish(env, info);
745 }
746 
SetOncancel(napi_env env,napi_callback_info info)747 static napi_value SetOncancel(napi_env env, napi_callback_info info)
748 {
749     AnimatorResult* animatorResult = nullptr;
750     size_t argc = 1;
751     napi_value thisVar = nullptr;
752     napi_value oncancel = nullptr;
753     napi_get_cb_info(env, info, &argc, &oncancel, &thisVar, NULL);
754     napi_unwrap(env, thisVar, (void**)&animatorResult);
755     if (!animatorResult) {
756         return nullptr;
757     }
758     auto option = animatorResult->GetAnimatorOption();
759     if (!option) {
760         return nullptr;
761     }
762     auto animator = animatorResult->GetAnimator();
763     if (!animator) {
764         return nullptr;
765     }
766     // convert oncancel function to reference
767     napi_ref oncancelRef = animatorResult->GetOncancelRef();
768     if (oncancelRef) {
769         uint32_t count = 0;
770         napi_reference_unref(env, oncancelRef, &count);
771     }
772     napi_create_reference(env, oncancel, 1, &oncancelRef);
773     animatorResult->SetOncancelRef(oncancelRef);
774     animator->ClearIdleListeners();
775     animator->AddIdleListener([env, oncancelRef] {
776         napi_handle_scope scope = nullptr;
777         napi_open_handle_scope(env, &scope);
778         if (scope == nullptr) {
779             return;
780         }
781         napi_value ret = nullptr;
782         napi_value oncancel = nullptr;
783         auto result = napi_get_reference_value(env, oncancelRef, &oncancel);
784         if (result != napi_ok || oncancel == nullptr) {
785             napi_close_handle_scope(env, scope);
786             return;
787         }
788         napi_call_function(env, NULL, oncancel, 0, NULL, &ret);
789         napi_close_handle_scope(env, scope);
790     });
791     napi_value undefined;
792     napi_get_undefined(env, &undefined);
793     return undefined;
794 }
795 
SetOnCancel(napi_env env,napi_callback_info info)796 static napi_value SetOnCancel(napi_env env, napi_callback_info info)
797 {
798     return SetOncancel(env, info);
799 }
800 
SetOnrepeat(napi_env env,napi_callback_info info)801 static napi_value SetOnrepeat(napi_env env, napi_callback_info info)
802 {
803     AnimatorResult* animatorResult = nullptr;
804     size_t argc = 1;
805     napi_value thisVar = nullptr;
806     napi_value onrepeat = nullptr;
807     napi_get_cb_info(env, info, &argc, &onrepeat, &thisVar, NULL);
808     napi_unwrap(env, thisVar, (void**)&animatorResult);
809     if (!animatorResult) {
810         return nullptr;
811     }
812     auto option = animatorResult->GetAnimatorOption();
813     if (!option) {
814         return nullptr;
815     }
816     auto animator = animatorResult->GetAnimator();
817     if (!animator) {
818         return nullptr;
819     }
820     // convert onrepeat function to reference
821     napi_ref onrepeatRef = animatorResult->GetOnrepeatRef();
822     if (onrepeatRef) {
823         uint32_t count = 0;
824         napi_reference_unref(env, onrepeatRef, &count);
825     }
826     napi_create_reference(env, onrepeat, 1, &onrepeatRef);
827     animatorResult->SetOnrepeatRef(onrepeatRef);
828     animator->ClearRepeatListeners();
829     animator->AddRepeatListener([env, onrepeatRef] {
830         napi_handle_scope scope = nullptr;
831         napi_open_handle_scope(env, &scope);
832         if (scope == nullptr) {
833             return;
834         }
835         napi_value ret = nullptr;
836         napi_value onrepeat = nullptr;
837         auto result = napi_get_reference_value(env, onrepeatRef, &onrepeat);
838         if (result != napi_ok || onrepeat == nullptr) {
839             napi_close_handle_scope(env, scope);
840             return;
841         }
842         napi_call_function(env, NULL, onrepeat, 0, NULL, &ret);
843         napi_close_handle_scope(env, scope);
844     });
845     napi_value undefined;
846     napi_get_undefined(env, &undefined);
847     return undefined;
848 }
849 
SetOnRepeat(napi_env env,napi_callback_info info)850 static napi_value SetOnRepeat(napi_env env, napi_callback_info info)
851 {
852     return SetOnrepeat(env, info);
853 }
854 
JSCreate(napi_env env,napi_callback_info info)855 static napi_value JSCreate(napi_env env, napi_callback_info info)
856 {
857     auto option = std::make_shared<AnimatorOption>();
858     ParseAnimatorOption(env, info, option);
859     auto animator = CREATE_ANIMATOR("ohos.animator");
860     animator->AttachSchedulerOnContainer();
861     AnimatorResult* animatorResult = new AnimatorResult(animator, option);
862     napi_value jsAnimator = nullptr;
863     napi_create_object(env, &jsAnimator);
864     napi_wrap(
865         env, jsAnimator, animatorResult,
866         [](napi_env env, void* data, void* hint) {
867             AnimatorResult* animatorResult = (AnimatorResult*)data;
868             // release four references(onFunc) before releasing animatorResult
869             animatorResult->Destroy(env);
870             delete animatorResult;
871         },
872         nullptr, nullptr);
873     napi_property_descriptor resultFuncs[] = {
874         DECLARE_NAPI_FUNCTION("update", JSUpdate),
875         DECLARE_NAPI_FUNCTION("reset", JSReset),
876         DECLARE_NAPI_FUNCTION("play", JSPlay),
877         DECLARE_NAPI_FUNCTION("finish", JSFinish),
878         DECLARE_NAPI_FUNCTION("pause", JSPause),
879         DECLARE_NAPI_FUNCTION("cancel", JSCancel),
880         DECLARE_NAPI_FUNCTION("reverse", JSReverse),
881         DECLARE_NAPI_FUNCTION("setExpectedFrameRateRange", JSSetExpectedFrameRateRange),
882         DECLARE_NAPI_SETTER("onframe", SetOnframe),
883         DECLARE_NAPI_SETTER("onfinish", SetOnfinish),
884         DECLARE_NAPI_SETTER("oncancel", SetOncancel),
885         DECLARE_NAPI_SETTER("onrepeat", SetOnrepeat),
886         DECLARE_NAPI_SETTER("onFrame", SetOnFrame),
887         DECLARE_NAPI_SETTER("onFinish", SetOnFinish),
888         DECLARE_NAPI_SETTER("onCancel", SetOnCancel),
889         DECLARE_NAPI_SETTER("onRepeat", SetOnRepeat),
890     };
891 
892     NAPI_CALL(env, napi_define_properties(env, jsAnimator, sizeof(resultFuncs) / sizeof(resultFuncs[0]), resultFuncs));
893     return jsAnimator;
894 }
895 
896 // since API 9 deprecated
JSCreateAnimator(napi_env env,napi_callback_info info)897 static napi_value JSCreateAnimator(napi_env env, napi_callback_info info)
898 {
899     return JSCreate(env, info);
900 }
901 
ParseIntSimpleOptions(napi_env env,napi_value propertyNapi,int32_t & property,int32_t defaultValue)902 static void ParseIntSimpleOptions(napi_env env, napi_value propertyNapi, int32_t& property, int32_t defaultValue)
903 {
904     if (propertyNapi == nullptr) {
905         return;
906     }
907     napi_valuetype valueType = napi_undefined;
908     napi_typeof(env, propertyNapi, &valueType);
909     if (valueType != napi_number) {
910         property = defaultValue;
911         return;
912     }
913     napi_get_value_int32(env, propertyNapi, &property);
914 }
915 
ParseStringSimpleOptions(napi_env env,napi_value propertyNapi,std::string & property,const std::string & defaultValue)916 static void ParseStringSimpleOptions(
917     napi_env env, napi_value propertyNapi, std::string& property, const std::string& defaultValue)
918 {
919     if (propertyNapi == nullptr) {
920         return;
921     }
922     napi_valuetype valueType = napi_undefined;
923     napi_typeof(env, propertyNapi, &valueType);
924     if (valueType != napi_string) {
925         property = defaultValue;
926         return;
927     }
928     size_t buffSize = 0;
929     napi_status status = napi_get_value_string_utf8(env, propertyNapi, nullptr, 0, &buffSize);
930     if (status != napi_ok || buffSize == 0) {
931         return;
932     }
933     std::unique_ptr<char[]> propertyString = std::make_unique<char[]>(buffSize + 1);
934     size_t retLen = 0;
935     napi_get_value_string_utf8(env, propertyNapi, propertyString.get(), buffSize + 1, &retLen);
936     property = propertyString.get();
937 }
938 
ParseDoubleSimpleOptions(napi_env env,napi_value propertyNapi,double & property,double defaultValue)939 static void ParseDoubleSimpleOptions(napi_env env, napi_value propertyNapi, double& property, double defaultValue)
940 {
941     if (propertyNapi == nullptr) {
942         return;
943     }
944     napi_valuetype valueType = napi_undefined;
945     napi_typeof(env, propertyNapi, &valueType);
946     if (valueType != napi_number) {
947         property = defaultValue;
948         return;
949     }
950     napi_get_value_double(env, propertyNapi, &property);
951 }
952 
OnSetDuration(napi_env env,napi_callback_info info)953 napi_value JsSimpleAnimatorOption::OnSetDuration(napi_env env, napi_callback_info info)
954 {
955     size_t argc = 1;
956     napi_value argv[1] = { nullptr };
957     napi_value thisArg;
958     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
959     if (argc != 1) {
960         return nullptr;
961     }
962     int32_t duration = ANIMATOR_DEFALUT_DURATION;
963     ParseIntSimpleOptions(env, argv[0], duration, ANIMATOR_DEFALUT_DURATION);
964     duration_ = std::max(duration, 0);
965     return thisArg;
966 }
967 
OnSetEasing(napi_env env,napi_callback_info info)968 napi_value JsSimpleAnimatorOption::OnSetEasing(napi_env env, napi_callback_info info)
969 {
970     size_t argc = 1;
971     napi_value argv[1] = { nullptr };
972     napi_value thisArg;
973     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
974     if (argc != 1) {
975         return nullptr;
976     }
977     std::string easing = ANIMATOR_DEFALUT_EASING;
978     ParseStringSimpleOptions(env, argv[0], easing, ANIMATOR_DEFALUT_EASING);
979     easing_ = easing;
980     return thisArg;
981 }
982 
OnSetDelay(napi_env env,napi_callback_info info)983 napi_value JsSimpleAnimatorOption::OnSetDelay(napi_env env, napi_callback_info info)
984 {
985     size_t argc = 1;
986     napi_value argv[1] = { nullptr };
987     napi_value thisArg;
988     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
989     if (argc != 1) {
990         return nullptr;
991     }
992     int32_t delay = ANIMATOR_DEFALUT_DELAY;
993     ParseIntSimpleOptions(env, argv[0], delay, ANIMATOR_DEFALUT_DELAY);
994     delay_ = delay;
995     return thisArg;
996 }
997 
OnSetFill(napi_env env,napi_callback_info info)998 napi_value JsSimpleAnimatorOption::OnSetFill(napi_env env, napi_callback_info info)
999 {
1000     size_t argc = 1;
1001     napi_value argv[1] = { nullptr };
1002     napi_value thisArg;
1003     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
1004     if (argc != 1) {
1005         return nullptr;
1006     }
1007     int32_t intValue = static_cast<int32_t>(FillMode::FORWARDS);
1008     ParseIntSimpleOptions(env, argv[0], intValue, static_cast<int32_t>(FillMode::FORWARDS));
1009     FillMode fillValue = FillMode::FORWARDS;
1010     if (intValue >= static_cast<int32_t>(FillMode::NONE) && intValue <= static_cast<int32_t>(FillMode::BOTH)) {
1011         fillValue = static_cast<FillMode>(intValue);
1012     }
1013     fill_ = fillValue;
1014     return thisArg;
1015 }
1016 
OnSetDirection(napi_env env,napi_callback_info info)1017 napi_value JsSimpleAnimatorOption::OnSetDirection(napi_env env, napi_callback_info info)
1018 {
1019     size_t argc = 1;
1020     napi_value argv[1] = { nullptr };
1021     napi_value thisArg;
1022     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
1023     if (argc != 1) {
1024         return nullptr;
1025     }
1026     std::string direction = ANIMATOR_DIRECTION_NORMAL;
1027     ParseStringSimpleOptions(env, argv[0], direction, ANIMATOR_DIRECTION_NORMAL);
1028     AnimationDirection directionValue = StringToAnimationDirection(direction);
1029     direction_ = directionValue;
1030     return thisArg;
1031 }
1032 
OnSetIterations(napi_env env,napi_callback_info info)1033 napi_value JsSimpleAnimatorOption::OnSetIterations(napi_env env, napi_callback_info info)
1034 {
1035     size_t argc = 1;
1036     napi_value argv[1] = { nullptr };
1037     napi_value thisArg;
1038     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
1039     if (argc != 1) {
1040         return nullptr;
1041     }
1042     int32_t iterations = ANIMATOR_DEFALUT_ITERATIONS;
1043     ParseIntSimpleOptions(env, argv[0], iterations, ANIMATOR_DEFALUT_ITERATIONS);
1044     iterations_ = iterations >= ANIMATION_REPEAT_INFINITE ? iterations : ANIMATOR_DEFALUT_ITERATIONS;
1045     return thisArg;
1046 }
1047 
JsSetDuration(napi_env env,napi_callback_info info)1048 static napi_value JsSetDuration(napi_env env, napi_callback_info info)
1049 {
1050     JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(GetNapiCallbackInfoAndThis(env, info));
1051     if (me == nullptr) {
1052         return nullptr;
1053     }
1054     napi_value thisArg = me->OnSetDuration(env, info);
1055     return thisArg;
1056 }
1057 
JsSetEasing(napi_env env,napi_callback_info info)1058 static napi_value JsSetEasing(napi_env env, napi_callback_info info)
1059 {
1060     JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(GetNapiCallbackInfoAndThis(env, info));
1061     if (me == nullptr) {
1062         return nullptr;
1063     }
1064     napi_value thisArg = me->OnSetEasing(env, info);
1065     return thisArg;
1066 }
1067 
JsSetDelay(napi_env env,napi_callback_info info)1068 static napi_value JsSetDelay(napi_env env, napi_callback_info info)
1069 {
1070     JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(GetNapiCallbackInfoAndThis(env, info));
1071     if (me == nullptr) {
1072         return nullptr;
1073     }
1074     napi_value thisArg = me->OnSetDelay(env, info);
1075     return thisArg;
1076 }
1077 
JsSetFill(napi_env env,napi_callback_info info)1078 static napi_value JsSetFill(napi_env env, napi_callback_info info)
1079 {
1080     JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(GetNapiCallbackInfoAndThis(env, info));
1081     if (me == nullptr) {
1082         return nullptr;
1083     }
1084     napi_value thisArg = me->OnSetFill(env, info);
1085     return thisArg;
1086 }
1087 
JsSetDirection(napi_env env,napi_callback_info info)1088 static napi_value JsSetDirection(napi_env env, napi_callback_info info)
1089 {
1090     JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(GetNapiCallbackInfoAndThis(env, info));
1091     if (me == nullptr) {
1092         return nullptr;
1093     }
1094     napi_value thisArg = me->OnSetDirection(env, info);
1095     return thisArg;
1096 }
1097 
JsSetIterations(napi_env env,napi_callback_info info)1098 static napi_value JsSetIterations(napi_env env, napi_callback_info info)
1099 {
1100     JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(GetNapiCallbackInfoAndThis(env, info));
1101     if (me == nullptr) {
1102         return nullptr;
1103     }
1104     napi_value thisArg = me->OnSetIterations(env, info);
1105     return thisArg;
1106 }
1107 
SimpleOptionsConstructor(napi_env env,napi_callback_info info)1108 static napi_value SimpleOptionsConstructor(napi_env env, napi_callback_info info)
1109 {
1110     size_t argc = SIMPLEANIMATOR_CONSTRUCTOR_PARAMS_SIZE;
1111     napi_value argv[SIMPLEANIMATOR_CONSTRUCTOR_PARAMS_SIZE];
1112     napi_value thisArg;
1113     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
1114     if (argc != SIMPLEANIMATOR_CONSTRUCTOR_PARAMS_SIZE) {
1115         return nullptr;
1116     }
1117     double begin = ANIMATOR_DEFALUT_BEGIN;
1118     double end = ANIMATOR_DEFALUT_END;
1119     ParseDoubleSimpleOptions(env, argv[0], begin, ANIMATOR_DEFALUT_BEGIN);
1120     ParseDoubleSimpleOptions(env, argv[1], end, ANIMATOR_DEFALUT_END);
1121     auto me = new JsSimpleAnimatorOption();
1122     me->SetBegin(begin);
1123     me->SetEnd(end);
1124     napi_wrap(
1125         env, thisArg, me,
1126         [](napi_env env, void* data, void* hint) {
1127             auto me = reinterpret_cast<JsSimpleAnimatorOption*>(data);
1128             delete me;
1129         },
1130         nullptr, nullptr);
1131     return thisArg;
1132 }
1133 
InitSimpleAnimatorOptions(napi_env env,napi_value exports)1134 napi_value InitSimpleAnimatorOptions(napi_env env, napi_value exports)
1135 {
1136     napi_value classSimpleOptions = nullptr;
1137     napi_property_descriptor simpleAnimatorOptionsDesc[] = {
1138         DECLARE_NAPI_FUNCTION("duration", JsSetDuration),
1139         DECLARE_NAPI_FUNCTION("easing", JsSetEasing),
1140         DECLARE_NAPI_FUNCTION("delay", JsSetDelay),
1141         DECLARE_NAPI_FUNCTION("fill", JsSetFill),
1142         DECLARE_NAPI_FUNCTION("direction", JsSetDirection),
1143         DECLARE_NAPI_FUNCTION("iterations", JsSetIterations),
1144     };
1145     napi_define_class(env, "SimpleAnimatorOptions", NAPI_AUTO_LENGTH, SimpleOptionsConstructor, nullptr,
1146         sizeof(simpleAnimatorOptionsDesc) / sizeof(*simpleAnimatorOptionsDesc), simpleAnimatorOptionsDesc,
1147         &classSimpleOptions);
1148     NAPI_CALL(env, napi_set_named_property(env, exports, "SimpleAnimatorOptions", classSimpleOptions));
1149     return exports;
1150 }
1151 
AnimatorExport(napi_env env,napi_value exports)1152 static napi_value AnimatorExport(napi_env env, napi_value exports)
1153 {
1154     napi_property_descriptor animatorDesc[] = {
1155         DECLARE_NAPI_FUNCTION("create", JSCreate),
1156         DECLARE_NAPI_FUNCTION("createAnimator", JSCreateAnimator),
1157     };
1158     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(animatorDesc) / sizeof(animatorDesc[0]), animatorDesc));
1159     InitSimpleAnimatorOptions(env, exports);
1160     return exports;
1161 }
1162 
1163 static napi_module animatorModule = {
1164     .nm_version = 1,
1165     .nm_flags = 0,
1166     .nm_filename = nullptr,
1167     .nm_register_func = AnimatorExport,
1168     .nm_modname = "animator",
1169     .nm_priv = ((void*)0),
1170     .reserved = { 0 },
1171 };
1172 
AnimatorRegister()1173 extern "C" __attribute__((constructor)) void AnimatorRegister()
1174 {
1175     napi_module_register(&animatorModule);
1176 }
1177 
ApplyOption()1178 void AnimatorResult::ApplyOption()
1179 {
1180     CHECK_NULL_VOID(animator_);
1181     CHECK_NULL_VOID(option_);
1182     if (motion_) {
1183         // duration not works. Iteration can only be 1. Direction can only be normal.
1184         animator_->SetIteration(1);
1185         animator_->SetAnimationDirection(AnimationDirection::NORMAL);
1186     } else {
1187         animator_->SetDuration(option_->duration);
1188         animator_->SetIteration(option_->iterations);
1189         animator_->SetAnimationDirection(StringToAnimationDirection(option_->direction));
1190     }
1191     animator_->SetStartDelay(option_->delay);
1192     // FillMode not works for motion in animator implementation.
1193     animator_->SetFillMode(StringToFillMode(option_->fill));
1194 }
1195 
Destroy(napi_env env)1196 void AnimatorResult::Destroy(napi_env env)
1197 {
1198     if (animator_) {
1199         if (!animator_->IsStopped()) {
1200             animator_->Stop();
1201             TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator force stopping done when destroying, id:%{public}d",
1202                 animator_->GetId());
1203         }
1204     }
1205     if (onframe_ != nullptr) {
1206         napi_delete_reference(env, onframe_);
1207     }
1208     if (onfinish_ != nullptr) {
1209         napi_delete_reference(env, onfinish_);
1210     }
1211     if (oncancel_ != nullptr) {
1212         napi_delete_reference(env, oncancel_);
1213     }
1214     if (onrepeat_ != nullptr) {
1215         napi_delete_reference(env, onrepeat_);
1216     }
1217 }
1218 
1219 } // namespace OHOS::Ace::Napi
1220