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 <malloc.h>
17 
18 #include "bridge/common/utils/utils.h"
19 #include "cj_animator.h"
20 #include "cj_animator_ffi.h"
21 #include "core/animation/curve.h"
22 #include "core/animation/curve_animation.h"
23 #include "bridge/cj_frontend/frontend/cj_frontend_abstract.h"
24 
25 using namespace OHOS::Ace;
26 using namespace OHOS::FFI;
27 
28 constexpr int32_t ANIMATOR_OK = 0;
29 constexpr int32_t INIT_ERROR = 100001;
30 
31 extern "C" {
FfiAnimatorCreate(CAnimatorOptions option)32     int64_t FfiAnimatorCreate(CAnimatorOptions option)
33     {
34         auto opt = std::make_shared<AnimatorOption>();
35         auto animator = CREATE_ANIMATOR("ohos.animator");
36         animator->AttachSchedulerOnContainer();
37         opt->duration = std::max(option.duration, 0);
38         opt->delay = std::max(option.delay, 0);
39         opt->iterations = option.iterations >= -1 ? option.iterations : 1;
40         opt->begin = option.begin;
41         opt->end = option.end;
42         opt->easing = std::string(option.easing);
43         opt->fill = std::string(option.fill);
44         opt->direction = std::string(option.direction);
45         auto nativeAnimatorResult = FFIData::Create<AnimatorResultImpl>(std::move(animator), std::move(opt));
46         if (nativeAnimatorResult == nullptr) {
47             return INIT_ERROR;
48         }
49         int64_t id = nativeAnimatorResult->GetID();
50         return id;
51     }
52 
FfiAnimatorReset(int64_t id,CAnimatorOptions cOption)53     int32_t FfiAnimatorReset(int64_t id, CAnimatorOptions cOption)
54     {
55         auto nativeAnimatorResult = FFIData::GetData<AnimatorResultImpl>(id);
56         if (!nativeAnimatorResult) {
57             return INIT_ERROR;
58         }
59         auto option = nativeAnimatorResult->GetAnimatorOption();
60         if (!option) {
61             return INIT_ERROR;
62         }
63         option->duration = std::max(cOption.duration, 0);
64         option->delay = std::max(cOption.delay, 0);
65         option->iterations = cOption.iterations >= -1 ? cOption.iterations : 1;
66         option->begin = cOption.begin;
67         option->end = cOption.end;
68         option->easing = cOption.easing;
69         option->fill = cOption.fill;
70         option->direction = cOption.direction;
71         auto animator = nativeAnimatorResult->GetAnimator();
72         if (!animator) {
73             return INIT_ERROR;
74         }
75         animator->ClearInterpolators();
76         animator->ResetIsReverse();
77         nativeAnimatorResult->ApplyOption();
78         std::function<void(double)> onframeRef = nativeAnimatorResult->GetOnframeRef();
79         if (onframeRef) {
80             auto onFrameCallback = [
81                 onframeRef, weakOption = std::weak_ptr<AnimatorOption>(nativeAnimatorResult->GetAnimatorOption())]
82                 (double value) {
83                     auto option = weakOption.lock();
84                     ACE_SCOPED_TRACE("ohos.animator onframe. duration:%d, curve:%s",
85                         option->duration, option->easing.c_str());
86                     onframeRef(value);
87                 };
88             RefPtr<Animation<double>> animation;
89             RefPtr<Motion> motion = ParseOptionToMotion(option);
90             if (motion) {
91                 motion->AddListener(onFrameCallback);
92                 nativeAnimatorResult->SetMotion(motion);
93             } else {
94                 auto curve = Framework::CreateCurve(option->easing);
95                 animation = AceType::MakeRefPtr<CurveAnimation<double>>(option->begin, option->end, curve);
96                 animation->AddListener(onFrameCallback);
97                 animator->AddInterpolator(animation);
98                 nativeAnimatorResult->SetMotion(nullptr);
99             }
100         }
101         return ANIMATOR_OK;
102     }
103 
FfiAnimatorPlay(int64_t id)104     int32_t FfiAnimatorPlay(int64_t id)
105     {
106         auto nativeAnimatorResult = FFIData::GetData<AnimatorResultImpl>(id);
107         if (!nativeAnimatorResult) {
108             return INIT_ERROR;
109         }
110         auto animator = nativeAnimatorResult->GetAnimator();
111         if (!animator) {
112             TAG_LOGW(AceLogTag::ACE_ANIMATION, "Animator: no animator is created when call play");
113             return INIT_ERROR;
114         }
115         if (!animator->HasScheduler()) {
116             auto result = animator->AttachSchedulerOnContainer();
117             if (!result) {
118                 TAG_LOGW(AceLogTag::ACE_ANIMATION,
119                     "Animator: play failed, animator is not bound to specific context, id:%{public}d",
120                     animator->GetId());
121                 return INIT_ERROR;
122             }
123         }
124         TAG_LOGI(AceLogTag::ACE_ANIMATION, "Animator: Play, id:%{public}d", animator->GetId());
125         if (nativeAnimatorResult->GetMotion()) {
126             animator->PlayMotion(nativeAnimatorResult->GetMotion());
127         } else {
128             animator->Play();
129         }
130         animator->PrintVsyncInfoIfNeed();
131         return ANIMATOR_OK;
132     }
133 
FfiAnimatorFinish(int64_t id)134     int32_t FfiAnimatorFinish(int64_t id)
135     {
136         auto nativeAnimatorResult = FFIData::GetData<AnimatorResultImpl>(id);
137         if (!nativeAnimatorResult) {
138             return INIT_ERROR;
139         }
140         auto animator = nativeAnimatorResult->GetAnimator();
141         if (!animator) {
142             TAG_LOGW(AceLogTag::ACE_ANIMATION, "Animator: no animator is created when call play");
143             return INIT_ERROR;
144         }
145         animator->Finish();
146         return ANIMATOR_OK;
147     }
148 
FfiAnimatorPause(int64_t id)149     int32_t FfiAnimatorPause(int64_t id)
150     {
151         auto nativeAnimatorResult = FFIData::GetData<AnimatorResultImpl>(id);
152         if (!nativeAnimatorResult) {
153             return INIT_ERROR;
154         }
155         auto animator = nativeAnimatorResult->GetAnimator();
156         if (!animator) {
157             TAG_LOGW(AceLogTag::ACE_ANIMATION, "Animator: no animator is created when call play");
158             return INIT_ERROR;
159         }
160         animator->Pause();
161         return ANIMATOR_OK;
162     }
163 
FfiAnimatorCancel(int64_t id)164     int32_t FfiAnimatorCancel(int64_t id)
165     {
166         auto nativeAnimatorResult = FFIData::GetData<AnimatorResultImpl>(id);
167         if (!nativeAnimatorResult) {
168             return INIT_ERROR;
169         }
170         auto animator = nativeAnimatorResult->GetAnimator();
171         if (!animator) {
172             TAG_LOGW(AceLogTag::ACE_ANIMATION, "Animator: no animator is created when call play");
173             return INIT_ERROR;
174         }
175         animator->Cancel();
176         return ANIMATOR_OK;
177     }
178 
FfiAnimatorReverse(int64_t id)179     int32_t FfiAnimatorReverse(int64_t id)
180     {
181         auto nativeAnimatorResult = FFIData::GetData<AnimatorResultImpl>(id);
182         if (!nativeAnimatorResult) {
183             return INIT_ERROR;
184         }
185         if (nativeAnimatorResult->GetMotion()) {
186             TAG_LOGW(AceLogTag::ACE_ANIMATION, "JsAnimator: interpolatingSpringCurve, cannot reverse");
187             return INIT_ERROR;
188         }
189         auto animator = nativeAnimatorResult->GetAnimator();
190         if (!animator) {
191             TAG_LOGW(AceLogTag::ACE_ANIMATION, "JsAnimator: no animator is created when call reverse");
192             return INIT_ERROR;
193         }
194         TAG_LOGI(AceLogTag::ACE_ANIMATION, "JsAnimator: JSReverse, id:%{public}d", animator->GetId());
195         if (!animator->HasScheduler()) {
196             auto result = animator->AttachSchedulerOnContainer();
197             if (!result) {
198                 TAG_LOGW(AceLogTag::ACE_ANIMATION,
199                     "JsAnimator: reverse failed, animator is not bound to specific context");
200                 return INIT_ERROR;
201             }
202         }
203         animator->Reverse();
204         return ANIMATOR_OK;
205     }
206 
FfiAnimatorOnframe(int64_t id,int64_t funcId)207     int32_t FfiAnimatorOnframe(int64_t id, int64_t funcId)
208     {
209         auto nativeAnimatorResult = FFIData::GetData<AnimatorResultImpl>(id);
210         if (!nativeAnimatorResult) {
211             return INIT_ERROR;
212         }
213         nativeAnimatorResult->SetOnframe(funcId);
214         return ANIMATOR_OK;
215     }
216 
FfiAnimatorOncancel(int64_t id,int64_t funcId)217     int32_t FfiAnimatorOncancel(int64_t id, int64_t funcId)
218     {
219         auto nativeAnimatorResult = FFIData::GetData<AnimatorResultImpl>(id);
220         if (!nativeAnimatorResult) {
221             return INIT_ERROR;
222         }
223         nativeAnimatorResult->SetOncancel(funcId);
224         return ANIMATOR_OK;
225     }
226 
FfiAnimatorOnfinish(int64_t id,int64_t funcId)227     int32_t FfiAnimatorOnfinish(int64_t id, int64_t funcId)
228     {
229         auto nativeAnimatorResult = FFIData::GetData<AnimatorResultImpl>(id);
230         if (!nativeAnimatorResult) {
231             return INIT_ERROR;
232         }
233         nativeAnimatorResult->SetOnfinish(funcId);
234         return ANIMATOR_OK;
235     }
236 
FfiAnimatorOnrepeat(int64_t id,int64_t funcId)237     int32_t FfiAnimatorOnrepeat(int64_t id, int64_t funcId)
238     {
239         auto nativeAnimatorResult = FFIData::GetData<AnimatorResultImpl>(id);
240         if (!nativeAnimatorResult) {
241             return INIT_ERROR;
242         }
243         nativeAnimatorResult->SetOnrepeat(funcId);
244         return ANIMATOR_OK;
245     }
246 }
247