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 "cj_animator.h"
17 #include "base/memory/ace_type.h"
18 #include "base/memory/referenced.h"
19 #include "bridge/common/utils/utils.h"
20 #include "cj_lambda.h"
21 
22 using namespace OHOS::Ace;
23 using namespace OHOS::FFI;
24 
25 const char INTERPOLATING_SPRING[] = "interpolatingSpring";
26 constexpr size_t INTERPOLATING_SPRING_PARAMS_SIZE = 4;
27 
28 namespace OHOS::Ace {
29 
StringToAnimationDirection(const std::string & direction)30 AnimationDirection StringToAnimationDirection(const std::string& direction)
31 {
32     if (direction.compare("alternate") == 0) {
33         return AnimationDirection::ALTERNATE;
34     } else if (direction.compare("reverse") == 0) {
35         return AnimationDirection::REVERSE;
36     } else if (direction.compare("alternate-reverse") == 0) {
37         return AnimationDirection::ALTERNATE_REVERSE;
38     } else {
39         return AnimationDirection::NORMAL;
40     }
41 }
42 
StringToFillMode(const std::string & fillMode)43 FillMode StringToFillMode(const std::string& fillMode)
44 {
45     if (fillMode.compare("forwards") == 0) {
46         return FillMode::FORWARDS;
47     } else if (fillMode.compare("backwards") == 0) {
48         return FillMode::BACKWARDS;
49     } else if (fillMode.compare("both") == 0) {
50         return FillMode::BOTH;
51     } else {
52         return FillMode::NONE;
53     }
54 }
55 
ParseOptionToMotion(const std::shared_ptr<AnimatorOption> & option)56 RefPtr<Motion> ParseOptionToMotion(const std::shared_ptr<AnimatorOption>& option)
57 {
58     const auto& curveStr = option->easing;
59     if (curveStr.back() != ')') {
60         return nullptr;
61     }
62     std::string::size_type leftEmbracePosition = curveStr.find_last_of('(');
63     if (leftEmbracePosition == std::string::npos) {
64         return nullptr;
65     }
66     auto aniTimFuncName = curveStr.substr(0, leftEmbracePosition);
67     if (aniTimFuncName.compare(INTERPOLATING_SPRING)) {
68         return nullptr;
69     }
70     auto params = curveStr.substr(leftEmbracePosition + 1, curveStr.length() - leftEmbracePosition - 2);
71     std::vector<std::string> paramsVector;
72     StringUtils::StringSplitter(params, ',', paramsVector);
73     if (paramsVector.size() != INTERPOLATING_SPRING_PARAMS_SIZE) {
74         return nullptr;
75     }
76     for (auto& param : paramsVector) {
77         Framework::RemoveHeadTailSpace(param);
78     }
79     float velocity = StringUtils::StringToFloat(paramsVector[0]);
80     float mass = StringUtils::StringToFloat(paramsVector[1]);
81     float stiffness = StringUtils::StringToFloat(paramsVector[2]);
82     float damping = StringUtils::StringToFloat(paramsVector[3]);
83     // input velocity is normalized velocity, while the velocity of arkui's springMotion is absolute velocity.
84     velocity = velocity * (option->end - option->begin);
85     if (LessOrEqual(mass, 0)) {
86         mass = 1.0f;
87     }
88     if (LessOrEqual(stiffness, 0)) {
89         stiffness = 1.0f;
90     }
91     if (LessOrEqual(damping, 0)) {
92         damping = 1.0f;
93     }
94     return AceType::MakeRefPtr<SpringMotion>(
95         option->begin, option->end, velocity, AceType::MakeRefPtr<SpringProperty>(mass, stiffness, damping));
96 }
97 
ApplyOption()98 void AnimatorResultImpl::ApplyOption()
99 {
100     CHECK_NULL_VOID(animator_);
101     CHECK_NULL_VOID(option_);
102     if (motion_) {
103         // duration not works. Iteration can only be 1. Direction can only be normal.
104         animator_->SetIteration(1);
105         animator_->SetAnimationDirection(AnimationDirection::NORMAL);
106     } else {
107         animator_->SetDuration(option_->duration);
108         animator_->SetIteration(option_->iterations);
109         animator_->SetAnimationDirection(StringToAnimationDirection(option_->direction));
110     }
111     animator_->SetStartDelay(option_->delay);
112     // FillMode not works for motion in animator implementation.
113     animator_->SetFillMode(StringToFillMode(option_->fill));
114 }
115 
SetOnframe(int64_t funcId)116 void AnimatorResultImpl::SetOnframe(int64_t funcId)
117 {
118     auto func = reinterpret_cast<void(*)(double)>(funcId);
119     onframe_ = CJLambda::Create(func);
120     animator_->ClearInterpolators();
121     auto onFrameCallback = [&callback = onframe_,
122                                 weakOption = std::weak_ptr<AnimatorOption>(option_)]
123                             (double value) {
124         auto option = weakOption.lock();
125         ACE_SCOPED_TRACE("ohos.animator onframe. duration:%d, curve:%s", option->duration, option->easing.c_str());
126         callback(value);
127     };
128     RefPtr<Animation<double>> animation;
129     RefPtr<Motion> motion = ParseOptionToMotion(option_);
130     if (motion) {
131         motion->AddListener(onFrameCallback);
132         motion_ = motion;
133     } else {
134         auto curve = Framework::CreateCurve(option_->easing);
135         animation = AceType::MakeRefPtr<CurveAnimation<double>>(option_->begin, option_->end, curve);
136         animation->AddListener(onFrameCallback);
137         animator_->AddInterpolator(animation);
138         motion_ = nullptr;
139     }
140     if (!animator_->HasScheduler()) {
141         animator_->AttachSchedulerOnContainer();
142     }
143     return;
144 }
145 
SetOnfinish(int64_t funcId)146 void AnimatorResultImpl::SetOnfinish(int64_t funcId)
147 {
148     auto func = reinterpret_cast<void(*)(void)>(funcId);
149     onfinish_ = CJLambda::Create(func);
150     animator_->ClearStopListeners();
151     animator_->AddStopListener([&callback = onfinish_] {
152         callback();
153     });
154     return;
155 }
156 
SetOncancel(int64_t funcId)157 void AnimatorResultImpl::SetOncancel(int64_t funcId)
158 {
159     auto func = reinterpret_cast<void(*)(void)>(funcId);
160     oncancel_ = CJLambda::Create(func);
161     animator_->ClearIdleListeners();
162     animator_->AddIdleListener([&callback = oncancel_] {
163         callback();
164     });
165     return;
166 }
167 
SetOnrepeat(int64_t funcId)168 void AnimatorResultImpl::SetOnrepeat(int64_t funcId)
169 {
170     auto func = reinterpret_cast<void(*)(void)>(funcId);
171     onrepeat_ = CJLambda::Create(func);
172     animator_->ClearRepeatListeners();
173     animator_->AddRepeatListener([&callback = onrepeat_] {
174         callback();
175     });
176     return;
177 }
178 
Destroy()179 void AnimatorResultImpl::Destroy()
180 {
181     if (animator_) {
182         if (!animator_->IsStopped()) {
183             animator_->Stop();
184             LOGI("Animator force stopping done, id:%{public}d", animator_->GetId());
185         }
186     }
187 }
188 }
189