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 "core/interfaces/native/node/node_animate.h"
17 
18 #include "base/error/error_code.h"
19 #include "base/memory/ace_type.h"
20 #include "base/utils/utils.h"
21 #include "core/animation/animation_pub.h"
22 #include "core/animation/curve_animation.h"
23 #include "core/animation/spring_curve.h"
24 #include "core/common/ace_engine.h"
25 #include "core/common/container.h"
26 #include "core/common/container_scope.h"
27 #include "core/components_ng/base/view_stack_model.h"
28 #include "core/components_ng/base/view_stack_processor.h"
29 
30 namespace OHOS::Ace::NG::ViewAnimate {
31 namespace {
32 constexpr int32_t MAX_FLUSH_COUNT = 2;
33 int32_t g_animationCount = 0;
34 
35 const std::vector<OHOS::Ace::RefPtr<OHOS::Ace::Curve>> CURVES_LIST = {
36     OHOS::Ace::Curves::LINEAR,
37     OHOS::Ace::Curves::EASE,
38     OHOS::Ace::Curves::EASE_IN,
39     OHOS::Ace::Curves::EASE_OUT,
40     OHOS::Ace::Curves::EASE_IN_OUT,
41     OHOS::Ace::Curves::FAST_OUT_SLOW_IN,
42     OHOS::Ace::Curves::LINEAR_OUT_SLOW_IN,
43     OHOS::Ace::Curves::FAST_OUT_LINEAR_IN,
44     OHOS::Ace::Curves::EXTREME_DECELERATION,
45     OHOS::Ace::Curves::SHARP,
46     OHOS::Ace::Curves::RHYTHM,
47     OHOS::Ace::Curves::SMOOTH,
48     OHOS::Ace::Curves::FRICTION,
49 };
50 
51 const std::vector<AnimationDirection> DIRECTION_LIST = {
52     AnimationDirection::NORMAL,
53     AnimationDirection::REVERSE,
54     AnimationDirection::ALTERNATE,
55     AnimationDirection::ALTERNATE_REVERSE,
56 };
57 
58 enum class ArkUICurveType {
59     CURVE_TYPE_CURVE = 0,
60     CURVE_TYPE_STEPS,
61     CURVE_TYPE_CUBIC_BEZIER,
62     CURVE_TYPE_SPRING,
63     CURVE_TYPE_SPRING_MOTION,
64     CURVE_TYPE_RESPONSIVE_SPRING_MOTION,
65     CURVE_TYPE_INTERPOLATING_SPRING,
66     CURVE_TYPE_CUSTOM,
67 };
68 
PrintNodeAnimationInfo(const AnimationOption & option,AnimationInterface interface,const std::optional<int32_t> & cnt)69 void PrintNodeAnimationInfo(const AnimationOption& option,
70     AnimationInterface interface, const std::optional<int32_t>& cnt)
71 {
72     auto animationInterfaceName = GetAnimationInterfaceName(interface);
73     CHECK_NULL_VOID(animationInterfaceName);
74     if (option.GetIteration() == ANIMATION_REPEAT_INFINITE) {
75         if (interface == AnimationInterface::KEYFRAME_ANIMATE_TO) {
76             TAG_LOGI(AceLogTag::ACE_ANIMATION,
77                 "nodeAnimate:keyframeAnimateTo iteration is infinite, remember to stop it. total duration:%{public}d",
78                 option.GetDuration());
79         } else {
80             TAG_LOGI(AceLogTag::ACE_ANIMATION,
81                 "nodeAnimate:%{public}s iteration is infinite, remember to stop it."
82                 "duration:%{public}d, curve:%{public}s",
83                 animationInterfaceName,
84                 option.GetDuration(), option.GetCurve()->ToString().c_str());
85         }
86         return;
87     }
88     if (cnt) {
89         TAG_LOGI(AceLogTag::ACE_ANIMATION, "nodeAnimate:%{public}s starts, [%{public}s], finish cnt:%{public}d",
90             animationInterfaceName, option.ToString().c_str(), cnt.value());
91     }
92 }
93 
FlushDirtyNodesWhenExist(const RefPtr<PipelineBase> & pipelineContext,const AnimationOption & option,AnimationInterface interface)94 void FlushDirtyNodesWhenExist(const RefPtr<PipelineBase>& pipelineContext,
95     const AnimationOption& option, AnimationInterface interface)
96 {
97     auto animationInterfaceName = GetAnimationInterfaceName(interface);
98     CHECK_NULL_VOID(animationInterfaceName);
99     int32_t flushCount = 0;
100     bool isDirtyNodesEmpty = pipelineContext->IsDirtyNodesEmpty();
101     bool isDirtyLayoutNodesEmpty = pipelineContext->IsDirtyLayoutNodesEmpty();
102     while (!isDirtyNodesEmpty || (!isDirtyLayoutNodesEmpty && !pipelineContext->IsLayouting())) {
103         if (flushCount >= MAX_FLUSH_COUNT || option.GetIteration() != ANIMATION_REPEAT_INFINITE) {
104             TAG_LOGW(AceLogTag::ACE_ANIMATION, "node_animate:%{public}s, dirtyNodes is empty:%{public}d,"
105                 "dirtyLayoutNodes is empty:%{public}d, isLayouting:%{public}d",
106                 animationInterfaceName, isDirtyNodesEmpty,
107                 isDirtyLayoutNodesEmpty, pipelineContext->IsLayouting());
108             break;
109         }
110         if (!isDirtyNodesEmpty) {
111             pipelineContext->FlushBuild();
112             isDirtyLayoutNodesEmpty = pipelineContext->IsDirtyLayoutNodesEmpty();
113         }
114         if (!isDirtyLayoutNodesEmpty && !pipelineContext->IsLayouting()) {
115             pipelineContext->FlushUITasks(true);
116         }
117         isDirtyNodesEmpty = pipelineContext->IsDirtyNodesEmpty();
118         isDirtyLayoutNodesEmpty = pipelineContext->IsDirtyLayoutNodesEmpty();
119         flushCount++;
120     }
121 }
122 } // namespace
123 
AnimateToInner(ArkUIContext * context,AnimationOption & option,const std::function<void ()> & animateToFunc,const std::function<void ()> & onFinishFunc,const std::optional<int32_t> & count,bool immediately)124 void AnimateToInner(ArkUIContext* context, AnimationOption& option, const std::function<void()>& animateToFunc,
125     const std::function<void()>& onFinishFunc, const std::optional<int32_t>& count, bool immediately)
126 {
127     CHECK_NULL_VOID(context);
128     ContainerScope scope(context->id);
129     auto containerSafely = Container::GetContainer(context->id);
130     CHECK_NULL_VOID(containerSafely);
131     auto pipelineContext = containerSafely->GetPipelineContext();
132     CHECK_NULL_VOID(pipelineContext);
133 
134     ACE_SCOPED_TRACE("duration:%d, curve:%s, iteration:%d", option.GetDuration(), option.GetCurve()->ToString().c_str(),
135         option.GetIteration());
136     PrintNodeAnimationInfo(
137         option, immediately ? AnimationInterface::ANIMATE_TO_IMMEDIATELY : AnimationInterface::ANIMATE_TO, count);
138     if (!ViewStackModel::GetInstance()->IsEmptyStack()) {
139         TAG_LOGW(AceLogTag::ACE_ANIMATION,
140             "node_animate:when call animateTo, node stack is not empty, not suitable for animateTo."
141             "param is [option:%{public}s]", option.ToString().c_str());
142     }
143     NG::ScopedViewStackProcessor scopedProcessor;
144     auto triggerId = context->id;
145     AceEngine::Get().NotifyContainersOrderly([triggerId, option](const RefPtr<Container>& container) {
146         auto context = container->GetPipelineContext();
147         if (!context) {
148             // pa container do not have pipeline context.
149             return;
150         }
151         if (!container->GetSettings().usingSharedRuntime) {
152             return;
153         }
154         if (!container->IsFRSCardContainer() && !container->WindowIsShow()) {
155             return;
156         }
157         ContainerScope scope(container->GetInstanceId());
158         context->FlushBuild();
159         if (context->GetInstanceId() == triggerId) {
160             return;
161         }
162         context->PrepareOpenImplicitAnimation();
163     });
164     pipelineContext->PrepareOpenImplicitAnimation();
165     FlushDirtyNodesWhenExist(pipelineContext, option,
166         immediately ? AnimationInterface::ANIMATE_TO_IMMEDIATELY : AnimationInterface::ANIMATE_TO);
167     pipelineContext->StartImplicitAnimation(option, option.GetCurve(), onFinishFunc);
168     auto previousOption = pipelineContext->GetSyncAnimationOption();
169     pipelineContext->SetSyncAnimationOption(option);
170     // Execute the function.
171     animateToFunc();
172     pipelineContext->FlushOnceVsyncTask();
173     AceEngine::Get().NotifyContainersOrderly([triggerId](const RefPtr<Container>& container) {
174         auto context = container->GetPipelineContext();
175         if (!context) {
176             // pa container do not have pipeline context.
177             return;
178         }
179         if (!container->GetSettings().usingSharedRuntime) {
180             return;
181         }
182         if (!container->IsFRSCardContainer() && !container->WindowIsShow()) {
183             return;
184         }
185         ContainerScope scope(container->GetInstanceId());
186         context->FlushBuild();
187         if (context->GetInstanceId() == triggerId) {
188             return;
189         }
190         context->PrepareCloseImplicitAnimation();
191     });
192     pipelineContext->CloseImplicitAnimation();
193     pipelineContext->SetSyncAnimationOption(previousOption);
194     pipelineContext->FlushAfterLayoutCallbackInImplicitAnimationTask();
195     if (immediately) {
196         pipelineContext->FlushMessages();
197     } else {
198         pipelineContext->RequestFrame();
199     }
200 }
201 
AnimateTo(ArkUIContext * context,ArkUIAnimateOption option,void (* event)(void * userData),void * user)202 void AnimateTo(ArkUIContext* context, ArkUIAnimateOption option, void (*event)(void* userData), void* user)
203 {
204     AnimationOption animationOption;
205     animationOption.SetDuration(NearZero(static_cast<double>(option.tempo)) ? 0 : option.duration);
206     animationOption.SetTempo(option.tempo);
207     if (option.iCurve) {
208         auto curve = reinterpret_cast<Curve*>(option.iCurve);
209         animationOption.SetCurve(AceType::Claim(curve));
210     } else {
211         animationOption.SetCurve(
212             CURVES_LIST[option.curve > static_cast<ArkUI_Int32>(CURVES_LIST.size()) ? 0 : option.curve]);
213     }
214     animationOption.SetDelay(option.delay);
215     animationOption.SetIteration(option.iterations);
216     animationOption.SetAnimationDirection(
217         DIRECTION_LIST[option.playMode > static_cast<ArkUI_Int32>(DIRECTION_LIST.size()) ? 0 : option.playMode]);
218     animationOption.SetFinishCallbackType(static_cast<FinishCallbackType>(option.finishCallbackType));
219 
220     if (option.expectedFrameRateRange) {
221         RefPtr<FrameRateRange> frameRateRange = AceType::MakeRefPtr<FrameRateRange>(option.expectedFrameRateRange->min,
222             option.expectedFrameRateRange->max, option.expectedFrameRateRange->expected);
223         animationOption.SetFrameRateRange(frameRateRange);
224     }
225 
226     auto onEvent = [event, user]() {
227         if (event) {
228             event(user);
229         }
230     };
231     std::optional<int32_t> count;
232     std::function<void()> onFinishEvent;
233     if (option.onFinishCallback) {
234         count = g_animationCount++;
235         onFinishEvent = [option, count]() {
236             ACE_SCOPED_TRACE("nodeAnimate:onFinish[cnt:%d]", count.value());
237             TAG_LOGI(AceLogTag::ACE_ANIMATION, "nodeAnimate:animateTo finish, cnt:%{public}d", count.value());
238             auto* onFinishFunc = reinterpret_cast<void (*)(void*)>(option.onFinishCallback);
239             onFinishFunc(option.user);
240         };
241     }
242 
243     AnimateToInner(context, animationOption, onEvent, onFinishEvent, count, false);
244 }
245 
StartKeyframeAnimation(const RefPtr<PipelineBase> & pipelineContext,AnimationOption & option,ArkUIKeyframeAnimateOption * animateOption)246 void StartKeyframeAnimation(const RefPtr<PipelineBase>& pipelineContext,
247     AnimationOption& option, ArkUIKeyframeAnimateOption* animateOption)
248 {
249     // flush build and flush ui tasks before open animation closure.
250     pipelineContext->FlushBuild();
251     if (!pipelineContext->IsLayouting()) {
252         pipelineContext->FlushUITasks(true);
253     }
254 
255     // flush build when exist dirty nodes, flush ui tasks when exist dirty layout nodes.
256     FlushDirtyNodesWhenExist(pipelineContext, option, AnimationInterface::KEYFRAME_ANIMATE_TO);
257 
258     // start KeyframeAnimation.
259     pipelineContext->StartImplicitAnimation(option, option.GetCurve(), option.GetOnFinishEvent());
260     for (int32_t i = 0; i < animateOption->keyframeSize; i++) {
261         auto keyframe = animateOption->keyframes[i];
262         if (!keyframe.event) {
263             continue;
264         }
265         auto event = [&keyframe, &pipelineContext]() {
266             keyframe.event(keyframe.userData);
267             pipelineContext->FlushBuild();
268             if (!pipelineContext->IsLayouting()) {
269                 pipelineContext->FlushUITasks(true);
270             }
271         };
272         if (keyframe.curve) {
273             auto curve = reinterpret_cast<Curve*>(keyframe.curve);
274             AnimationUtils::AddDurationKeyFrame(keyframe.duration, AceType::Claim(curve), event);
275         } else {
276             AnimationUtils::AddDurationKeyFrame(keyframe.duration, Curves::EASE_IN_OUT, event);
277         }
278     }
279 
280     // close KeyframeAnimation.
281     AnimationUtils::CloseImplicitAnimation();
282 }
283 
KeyframeAnimateTo(ArkUIContext * context,ArkUIKeyframeAnimateOption * animateOption)284 void KeyframeAnimateTo(ArkUIContext* context, ArkUIKeyframeAnimateOption* animateOption)
285 {
286     CHECK_NULL_VOID(context);
287     ContainerScope scope(context->id);
288     auto containerSafely = Container::GetContainer(context->id);
289     CHECK_NULL_VOID(containerSafely);
290     auto pipelineContext = containerSafely->GetPipelineContext();
291     CHECK_NULL_VOID(pipelineContext);
292 
293     AnimationOption option;
294     if (animateOption->onFinish) {
295         auto onFinishEvent = [onFinish = animateOption->onFinish, userData = animateOption->userData,
296                                  id = context->id]() {
297             ContainerScope scope(id);
298             onFinish(userData);
299         };
300         option.SetOnFinishEvent(onFinishEvent);
301     }
302 
303     option.SetDelay(animateOption->delay);
304     option.SetIteration(animateOption->iterations);
305 
306     int duration = 0;
307     for (int32_t i = 0; i < animateOption->keyframeSize; i++) {
308         duration += animateOption->keyframes[i].duration;
309     }
310     option.SetDuration(duration);
311     // actual curve is in keyframe, this curve will not be effective
312     option.SetCurve(Curves::EASE_IN_OUT);
313     AceScopedTrace trace("nodeAnimate:KeyframeAnimateTo iteration:%d, delay:%d",
314                          option.GetIteration(), option.GetDelay());
315     PrintNodeAnimationInfo(option, AnimationInterface::KEYFRAME_ANIMATE_TO, std::nullopt);
316     if (!ViewStackModel::GetInstance()->IsEmptyStack()) {
317         TAG_LOGW(AceLogTag::ACE_ANIMATION,
318             "nodeAnimate:when call keyframeAnimateTo, node stack is not empty, not suitable for keyframeAnimateTo."
319             "param is [duration:%{public}d, delay:%{public}d, iteration:%{public}d]",
320             option.GetDuration(), option.GetDelay(), option.GetIteration());
321     }
322     NG::ScopedViewStackProcessor scopedProcessor;
323     StartKeyframeAnimation(pipelineContext, option, animateOption);
324     pipelineContext->FlushAfterLayoutCallbackInImplicitAnimationTask();
325 }
326 
ParseAnimatorAnimation(const ArkUIAnimatorOption * option)327 RefPtr<Animation<double>> ParseAnimatorAnimation(const ArkUIAnimatorOption* option)
328 {
329     if (option->keyframeSize > 0) {
330         auto keyframeAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
331         for (int32_t i = 0; i < option->keyframeSize; i++) {
332             auto keyframe = option->keyframes[i];
333             auto animatorKeyframe = AceType::MakeRefPtr<Keyframe<double>>(keyframe.keyTime, keyframe.keyValue);
334             if (keyframe.curve) {
335                 auto curve = reinterpret_cast<Curve*>(keyframe.curve);
336                 animatorKeyframe->SetCurve(AceType::Claim(curve));
337             } else {
338                 animatorKeyframe->SetCurve(Curves::EASE_IN_OUT);
339             }
340             keyframeAnimation->AddKeyframe(animatorKeyframe);
341         }
342         return keyframeAnimation;
343     } else {
344         RefPtr<Animation<double>> animation;
345         auto curve = reinterpret_cast<Curve*>(option->easing);
346         if (curve) {
347             animation = AceType::MakeRefPtr<CurveAnimation<double>>(option->begin, option->end, AceType::Claim(curve));
348         } else {
349             animation = AceType::MakeRefPtr<CurveAnimation<double>>(option->begin, option->end, Curves::EASE_IN_OUT);
350         }
351         return animation;
352     }
353 }
354 
ParseAnimatorOption(const RefPtr<Animator> & animator,ArkUIAnimatorOption * option)355 void ParseAnimatorOption(const RefPtr<Animator>& animator, ArkUIAnimatorOption* option)
356 {
357     animator->SetDuration(option->duration);
358     animator->SetIteration(option->iterations);
359     animator->SetAnimationDirection(
360         DIRECTION_LIST[option->direction > static_cast<ArkUI_Int32>(DIRECTION_LIST.size()) ? 0 : option->direction]);
361     animator->SetStartDelay(option->delay);
362     animator->SetFillMode(static_cast<FillMode>(option->fill));
363 
364     if (option->isHasExpectedFrameRateRange) {
365         FrameRateRange frameRateRange { option->expectedFrameRateRange.min, option->expectedFrameRateRange.max,
366             option->expectedFrameRateRange.expected };
367         animator->SetExpectedFrameRateRange(frameRateRange);
368     }
369 }
370 
RegisterAnimatorOnFrameEvent(const RefPtr<Animator> & animator,ArkUIAnimatorOption * option)371 void RegisterAnimatorOnFrameEvent(const RefPtr<Animator>& animator, ArkUIAnimatorOption* option)
372 {
373     animator->ClearInterpolators();
374     //onframe
375     auto onFrameCallback = [callback = option->onFrame, userData = option->frameUserData](double value) {
376         if (callback) {
377             ArkUI_AnimatorOnFrameEvent event;
378             event.progress = static_cast<ArkUI_Float32>(value);
379             event.userData = userData;
380             callback(&event);
381         }
382     };
383     RefPtr<Animation<double>> animation = ParseAnimatorAnimation(option);
384     if (animation) {
385         animation->AddListener(onFrameCallback);
386         animator->AddInterpolator(animation);
387     }
388 }
389 
RegisterAnimatorEvent(const RefPtr<Animator> & animator,ArkUIAnimatorOption * option)390 void RegisterAnimatorEvent(const RefPtr<Animator>& animator, ArkUIAnimatorOption* option)
391 {
392     animator->ClearStopListeners();
393     animator->ClearIdleListeners();
394     animator->ClearRepeatListeners();
395 
396     RegisterAnimatorOnFrameEvent(animator, option);
397 
398     //onfinish
399     animator->AddStopListener([callback = option->onFinish, userData = option->finishUserData] {
400         if (callback) {
401             ArkUI_AnimatorEvent event;
402             event.userData = userData;
403             callback(&event);
404         }
405     });
406 
407     //oncancel
408     animator->AddIdleListener([callback = option->onCancel, userData = option->cancelUserData] {
409         if (callback) {
410             ArkUI_AnimatorEvent event;
411             event.userData = userData;
412             callback(&event);
413         }
414     });
415 
416     //onRepeat
417     animator->AddRepeatListener([callback = option->onRepeat, userData = option->repeatUserData] {
418         if (callback) {
419             ArkUI_AnimatorEvent event;
420             event.userData = userData;
421             callback(&event);
422         }
423     });
424 }
425 
CreateAnimator(ArkUIContext * context,ArkUIAnimatorOption * option)426 ArkUIAnimatorHandle CreateAnimator(ArkUIContext* context, ArkUIAnimatorOption* option)
427 {
428     CHECK_NULL_RETURN(context, nullptr);
429     ContainerScope scope(context->id);
430     auto containerSafely = Container::GetContainer(context->id);
431     CHECK_NULL_RETURN(containerSafely, nullptr);
432     auto pipelineContext = containerSafely->GetPipelineContext();
433     CHECK_NULL_RETURN(pipelineContext, nullptr);
434 
435     ArkUIAnimator* result = new ArkUIAnimator;
436     auto animator = CREATE_ANIMATOR("ohos.animator");
437     animator->AttachScheduler(pipelineContext);
438     ParseAnimatorOption(animator, option);
439     RegisterAnimatorEvent(animator, option);
440     animator->IncRefCount();
441     result->animator = AceType::RawPtr(animator);
442     result->context = context;
443     result->animatorOption = option;
444     return result;
445 }
446 
DisposeAnimator(ArkUIAnimatorHandle animatorHandle)447 void DisposeAnimator(ArkUIAnimatorHandle animatorHandle)
448 {
449     if (animatorHandle->animator) {
450         auto* animator = reinterpret_cast<Animator*>(animatorHandle->animator);
451         if (animator) {
452             animator->DecRefCount();
453         }
454     }
455     delete animatorHandle;
456 }
457 
AnimatorReset(ArkUIAnimatorHandle animatorHandle,ArkUIAnimatorOption * option)458 int32_t AnimatorReset(ArkUIAnimatorHandle animatorHandle, ArkUIAnimatorOption* option)
459 {
460     CHECK_NULL_RETURN(animatorHandle, ERROR_CODE_PARAM_INVALID);
461     CHECK_NULL_RETURN(animatorHandle->animator, ERROR_CODE_PARAM_INVALID);
462     auto animator = reinterpret_cast<Animator*>(animatorHandle->animator);
463     animator->Cancel();
464     ParseAnimatorOption(AceType::Claim(animator), option);
465     RegisterAnimatorEvent(AceType::Claim(animator), option);
466     animatorHandle->animatorOption = option;
467     animator->ResetIsReverse();
468     return ERROR_CODE_NO_ERROR;
469 }
470 
AnimatorPlay(ArkUIAnimatorHandle animatorHandle)471 int32_t AnimatorPlay(ArkUIAnimatorHandle animatorHandle)
472 {
473     CHECK_NULL_RETURN(animatorHandle, ERROR_CODE_PARAM_INVALID);
474     CHECK_NULL_RETURN(animatorHandle->animator, ERROR_CODE_PARAM_INVALID);
475     auto animator = reinterpret_cast<Animator*>(animatorHandle->animator);
476     animator->Play();
477     return ERROR_CODE_NO_ERROR;
478 }
479 
AnimatorFinish(ArkUIAnimatorHandle animatorHandle)480 int32_t AnimatorFinish(ArkUIAnimatorHandle animatorHandle)
481 {
482     CHECK_NULL_RETURN(animatorHandle, ERROR_CODE_PARAM_INVALID);
483     CHECK_NULL_RETURN(animatorHandle->animator, ERROR_CODE_PARAM_INVALID);
484     auto animator = reinterpret_cast<Animator*>(animatorHandle->animator);
485     animator->Finish();
486     return ERROR_CODE_NO_ERROR;
487 }
488 
AnimatorPause(ArkUIAnimatorHandle animatorHandle)489 int32_t AnimatorPause(ArkUIAnimatorHandle animatorHandle)
490 {
491     CHECK_NULL_RETURN(animatorHandle, ERROR_CODE_PARAM_INVALID);
492     CHECK_NULL_RETURN(animatorHandle->animator, ERROR_CODE_PARAM_INVALID);
493     auto animator = reinterpret_cast<Animator*>(animatorHandle->animator);
494     animator->Pause();
495     return ERROR_CODE_NO_ERROR;
496 }
497 
AnimatorCancel(ArkUIAnimatorHandle animatorHandle)498 int32_t AnimatorCancel(ArkUIAnimatorHandle animatorHandle)
499 {
500     CHECK_NULL_RETURN(animatorHandle, ERROR_CODE_PARAM_INVALID);
501     CHECK_NULL_RETURN(animatorHandle->animator, ERROR_CODE_PARAM_INVALID);
502     auto animator = reinterpret_cast<Animator*>(animatorHandle->animator);
503     animator->Cancel();
504     return ERROR_CODE_NO_ERROR;
505 }
506 
AnimatorReverse(ArkUIAnimatorHandle animatorHandle)507 int32_t AnimatorReverse(ArkUIAnimatorHandle animatorHandle)
508 {
509     CHECK_NULL_RETURN(animatorHandle, ERROR_CODE_PARAM_INVALID);
510     CHECK_NULL_RETURN(animatorHandle->animator, ERROR_CODE_PARAM_INVALID);
511     auto animator = reinterpret_cast<Animator*>(animatorHandle->animator);
512     animator->Reverse();
513     return ERROR_CODE_NO_ERROR;
514 }
515 
CreateCurve(ArkUI_Int32 curve)516 ArkUICurveHandle CreateCurve(ArkUI_Int32 curve)
517 {
518     auto iCurve = AceType::RawPtr(CURVES_LIST[curve > static_cast<ArkUI_Int32>(CURVES_LIST.size()) ? 0 : curve]);
519     iCurve->IncRefCount();
520     return reinterpret_cast<ArkUICurveHandle>(iCurve);
521 }
522 
CreateStepsCurve(ArkUI_Int32 count,ArkUI_Bool end)523 ArkUICurveHandle CreateStepsCurve(ArkUI_Int32 count, ArkUI_Bool end)
524 {
525     auto curve = AceType::MakeRefPtr<StepsCurve>(count, static_cast<StepsCurvePosition>(end));
526     curve->IncRefCount();
527     return reinterpret_cast<ArkUICurveHandle>(AceType::RawPtr(curve));
528 }
529 
CreateCubicBezierCurve(ArkUI_Float32 x1,ArkUI_Float32 y1,ArkUI_Float32 x2,ArkUI_Float32 y2)530 ArkUICurveHandle CreateCubicBezierCurve(ArkUI_Float32 x1, ArkUI_Float32 y1, ArkUI_Float32 x2, ArkUI_Float32 y2)
531 {
532     auto curve = AceType::MakeRefPtr<CubicCurve>(x1, y1, x2, y2);
533     curve->IncRefCount();
534     return reinterpret_cast<ArkUICurveHandle>(AceType::RawPtr(curve));
535 }
536 
CreateSpringCurve(ArkUI_Float32 velocity,ArkUI_Float32 mass,ArkUI_Float32 stiffness,ArkUI_Float32 damping)537 ArkUICurveHandle CreateSpringCurve(
538     ArkUI_Float32 velocity, ArkUI_Float32 mass, ArkUI_Float32 stiffness, ArkUI_Float32 damping)
539 {
540     auto curve = AceType::MakeRefPtr<SpringCurve>(velocity, mass, stiffness, damping);
541     curve->IncRefCount();
542     return reinterpret_cast<ArkUICurveHandle>(AceType::RawPtr(curve));
543 }
544 
CreateSpringMotion(ArkUI_Float32 response,ArkUI_Float32 dampingFraction,ArkUI_Float32 overlapDuration)545 ArkUICurveHandle CreateSpringMotion(
546     ArkUI_Float32 response, ArkUI_Float32 dampingFraction, ArkUI_Float32 overlapDuration)
547 {
548     auto curve = AceType::MakeRefPtr<ResponsiveSpringMotion>(response, dampingFraction, overlapDuration);
549     curve->IncRefCount();
550     return reinterpret_cast<ArkUICurveHandle>(AceType::RawPtr(curve));
551 }
552 
CreateResponsiveSpringMotion(ArkUI_Float32 response,ArkUI_Float32 dampingFraction,ArkUI_Float32 overlapDuration)553 ArkUICurveHandle CreateResponsiveSpringMotion(
554     ArkUI_Float32 response, ArkUI_Float32 dampingFraction, ArkUI_Float32 overlapDuration)
555 {
556     auto curve = AceType::MakeRefPtr<ResponsiveSpringMotion>(response, dampingFraction, overlapDuration);
557     curve->IncRefCount();
558     return reinterpret_cast<ArkUICurveHandle>(AceType::RawPtr(curve));
559 }
560 
CreateInterpolatingSpring(ArkUI_Float32 velocity,ArkUI_Float32 mass,ArkUI_Float32 stiffness,ArkUI_Float32 damping)561 ArkUICurveHandle CreateInterpolatingSpring(
562     ArkUI_Float32 velocity, ArkUI_Float32 mass, ArkUI_Float32 stiffness, ArkUI_Float32 damping)
563 {
564     auto curve = AceType::MakeRefPtr<InterpolatingSpring>(velocity, mass, stiffness, damping);
565     curve->IncRefCount();
566     return reinterpret_cast<ArkUICurveHandle>(AceType::RawPtr(curve));
567 }
568 
CreateCustomCurve(ArkUI_Float32 (* interpolate)(ArkUI_Float32 fraction,void * userData),void * userData)569 ArkUICurveHandle CreateCustomCurve(ArkUI_Float32 (*interpolate)(ArkUI_Float32 fraction, void* userData), void* userData)
570 {
571     auto func = [interpolate, userData](float value) -> float {
572         if (interpolate) {
573             return interpolate(value, userData);
574         }
575         return 0.0f;
576     };
577     auto curve = AceType::MakeRefPtr<CustomCurve>(func);
578     curve->IncRefCount();
579     return reinterpret_cast<ArkUICurveHandle>(AceType::RawPtr(curve));
580 }
581 
DisposeCurve(ArkUICurveHandle curve)582 void DisposeCurve(ArkUICurveHandle curve)
583 {
584     CHECK_NULL_VOID(curve);
585     auto* curvePtr = reinterpret_cast<Curve*>(curve);
586     if (curvePtr) {
587         curvePtr->DecRefCount();
588     }
589 }
590 } // namespace OHOS::Ace::NG::ViewAnimate