1 /*
2  * Copyright (c) 2021 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_ANIMATION_KEYFRAME_ANIMATION_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_ANIMATION_KEYFRAME_ANIMATION_H
18 
19 #include <list>
20 
21 #include "base/utils/utils.h"
22 #include "core/animation/animation.h"
23 #include "core/animation/curve.h"
24 #include "core/animation/curves.h"
25 #include "core/animation/evaluator.h"
26 #include "core/animation/keyframe.h"
27 
28 namespace OHOS::Ace {
29 
30 template<typename T>
31 class KeyframeAnimation : public Animation<T> {
32     DECLARE_ACE_TYPE(KeyframeAnimation, Animation<T>);
33 public:
34     KeyframeAnimation() = default;
35 
36     ~KeyframeAnimation() override = default;
37 
AddKeyframe(const std::list<RefPtr<Keyframe<T>>> & keyframes)38     void AddKeyframe(const std::list<RefPtr<Keyframe<T>>>& keyframes)
39     {
40         for (const auto& keyframe : keyframes) {
41             AddKeyframe(keyframe);
42         }
43         // in order by time;
44         keyframes_.sort([](const RefPtr<Keyframe<T>>& a, const RefPtr<Keyframe<T>>& b) {
45             return a->GetKeyTime() < b->GetKeyTime();
46         });
47     }
48 
AddKeyframe(const RefPtr<Keyframe<T>> & keyframe)49     void AddKeyframe(const RefPtr<Keyframe<T>>& keyframe)
50     {
51         if (!keyframe) {
52             LOGE("add key frame failed. empty keyframe.");
53             return;
54         }
55         if (!keyframe->IsValid()) {
56             LOGE("add key frame failed. invalid keyframe.");
57             return;
58         }
59 
60         keyframes_.emplace_back(keyframe);
61         ++keyframeNum_;
62     }
63 
ReplaceKeyframe(const RefPtr<Keyframe<T>> & keyframeReplace)64     void ReplaceKeyframe(const RefPtr<Keyframe<T>>& keyframeReplace)
65     {
66         if (!keyframeReplace) {
67             LOGE("add key frame failed. empty keyframe.");
68             return;
69         }
70         if (!keyframeReplace->IsValid()) {
71             LOGE("add key frame failed. invalid keyframe.");
72             return;
73         }
74         for (auto& keyframe : keyframes_) {
75             if (NearEqual(keyframe->GetKeyTime(), keyframeReplace->GetKeyTime())) {
76                 keyframe = keyframeReplace;
77             }
78         }
79     }
80 
GetValue()81     const T& GetValue() const override
82     {
83         return currentValue_;
84     }
85 
GetKeyframes()86     const std::list<RefPtr<Keyframe<T>>>& GetKeyframes() const
87     {
88         return keyframes_;
89     }
90 
SetCurve(const RefPtr<Curve> & curve)91     void SetCurve(const RefPtr<Curve>& curve) override
92     {
93         if (!curve) {
94             LOGE("set curve failed. curve is null.");
95             return;
96         }
97         for (auto& keyframe : keyframes_) {
98             keyframe->SetCurve(curve);
99         }
100     }
101 
RunAsync(const WeakPtr<Scheduler> & weakScheduler,const AnimationOption & option,const std::function<void ()> prepareCallback,const std::function<void ()> finishCallback)102     bool RunAsync(const WeakPtr<Scheduler>& weakScheduler, const AnimationOption& option,
103         const std::function<void()> prepareCallback, const std::function<void()> finishCallback) override
104     {
105         auto scheduler = weakScheduler.Upgrade();
106         if (scheduler == nullptr) {
107             LOGE("run async failed, scheduler is null!");
108             return false;
109         }
110 
111         scheduler->OpenImplicitAnimation(option, Curves::EASE, finishCallback);
112 
113         for (const auto& keyframe : keyframes_) {
114             if (keyframe == nullptr) {
115                 continue;
116             }
117 
118             float fraction = keyframe->GetKeyTime();
119             auto curve = keyframe->GetCurve() ? keyframe->GetCurve() : AceType::DynamicCast<Curve>(Curves::EASE);
120             scheduler->AddKeyFrame(
121                 fraction, curve, [weak = AceType::WeakClaim(this), callback = prepareCallback, fraction]() {
122                     auto animation = weak.Upgrade();
123                     if (animation == nullptr) {
124                         LOGE("propetry change failed, animation is null!");
125                         return;
126                     }
127 
128                     if (callback != nullptr) {
129                         callback();
130                     }
131 
132                     animation->OnNormalizedTimestampChanged(fraction, false);
133                 });
134         }
135 
136         return scheduler->CloseImplicitAnimation();
137     }
138 
139 private:
Calculate(float keyTime)140     void Calculate(float keyTime)
141     {
142         if (keyframes_.empty()) {
143             return;
144         }
145         auto begin = keyframes_.front()->GetKeyValue();
146         auto end = keyframes_.back()->GetKeyValue();
147         // The initial state is maintained when keyTime < 0.
148         if (keyTime < 0.0f) {
149             currentValue_ = begin;
150             return;
151         } else if (keyTime > 1.0f || keyframeNum_ == 1) {
152             // The final state is maintained when keyTime > 1 or keyframeNum_ = 1.
153             currentValue_ = end;
154             return;
155         }
156         auto preKeyframe = keyframes_.front();
157         // Iteratively calculate the value between each keyframe.
158         for (const auto& keyframe : keyframes_) {
159             if (keyTime < keyframe->GetKeyTime()) {
160                 float preKeyTime = preKeyframe->GetKeyTime();
161                 if (NearEqual(keyframe->GetKeyTime(), preKeyTime)) {
162                     return;
163                 }
164                 float intervalKeyTime = (keyTime - preKeyTime) / (keyframe->GetKeyTime() - preKeyTime);
165                 auto& curve = keyframe->GetCurve();
166                 begin = preKeyframe->GetKeyValue();
167                 end = keyframe->GetKeyValue();
168                 if (curve) {
169                     currentValue_ = evaluator_->Evaluate(begin, end, curve->Move(intervalKeyTime));
170                     return;
171                 } else {
172                     currentValue_ = evaluator_->Evaluate(begin, end, Curves::EASE->Move(intervalKeyTime));
173                     return;
174                 }
175             }
176             preKeyframe = keyframe;
177         }
178         currentValue_ = end;
179     }
180 
OnNormalizedTimestampChanged(float normalized,bool reverse)181     void OnNormalizedTimestampChanged(float normalized, bool reverse) override
182     {
183         if (normalized < NORMALIZED_DURATION_MIN || normalized > NORMALIZED_DURATION_MAX) {
184             LOGE("normalized time check failed. normalized: %{public}f", normalized);
185             return;
186         }
187         Calculate(normalized);
188         ValueListenable<T>::NotifyListener(currentValue_);
189     }
190 
191     T currentValue_ {};
192     int32_t keyframeNum_ = 0;
193     std::list<RefPtr<Keyframe<T>>> keyframes_;
194     RefPtr<Evaluator<T>> evaluator_ = AceType::MakeRefPtr<LinearEvaluator<T>>();
195 };
196 
197 } // namespace OHOS::Ace
198 
199 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_ANIMATION_KEYFRAME_ANIMATION_H
200