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