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 #include "core/animation/property_animation.h"
17 
18 #include "core/animation/animatable_data.h"
19 
20 namespace OHOS::Ace {
21 
PropertyAnimation(AnimatableType type)22 PropertyAnimation::PropertyAnimation(AnimatableType type)
23 {
24     type_ = type;
25 }
26 
SetStart(const RefPtr<Animatable> & animatable)27 void PropertyAnimation::SetStart(const RefPtr<Animatable>& animatable)
28 {
29     if (animatable == nullptr) {
30         return;
31     }
32     animatable->SetTimePoint(0.0f);
33     animatables_.emplace_front(animatable);
34 }
35 
AddAnimatable(const RefPtr<Animatable> & animatable)36 void PropertyAnimation::AddAnimatable(const RefPtr<Animatable>& animatable)
37 {
38     if (animatable == nullptr) {
39         return;
40     }
41     animatables_.emplace_back(animatable);
42 }
43 
SetCurve(const RefPtr<Curve> & curve)44 void PropertyAnimation::SetCurve(const RefPtr<Curve>& curve)
45 {
46     if (!curve) {
47         LOGE("set curve failed. curve is null.");
48         return;
49     }
50     for (auto& animatable : animatables_) {
51         animatable->SetCurve(curve);
52     }
53 }
54 
OnNormalizedTimestampChanged(float normalized,bool reverse)55 void PropertyAnimation::OnNormalizedTimestampChanged(float normalized, bool reverse)
56 {
57     if (normalized < NORMALIZED_DURATION_MIN || normalized > NORMALIZED_DURATION_MAX) {
58         LOGE("normalized time check failed. normalized: %{public}f", normalized);
59         return;
60     }
61     Calculate(normalized);
62 }
63 
OnInitNotify(float normalizedTime,bool reverse)64 void PropertyAnimation::OnInitNotify(float normalizedTime, bool reverse)
65 {
66     if (init_ && animateTo_) {
67         animateTo_(init_);
68     } else {
69         OnNormalizedTimestampChanged(normalizedTime, reverse);
70     }
71 }
72 
GetCurve()73 RefPtr<Curve> PropertyAnimation::GetCurve()
74 {
75     if (!animatables_.empty() && animatables_.front()->GetCurve() != nullptr) {
76         return animatables_.front()->GetCurve();
77     }
78     return Curves::EASE_IN_OUT;
79 }
80 
Calculate(float keyTime)81 void PropertyAnimation::Calculate(float keyTime)
82 {
83     if (animatables_.empty()) {
84         return;
85     }
86     auto preAnimatable = animatables_.front();
87     for (const auto& animatable : animatables_) {
88         if (keyTime < animatable->GetTimePoint()) {
89             float preKeyTime = preAnimatable->GetTimePoint();
90             float innerKeyTime = (keyTime - preKeyTime) / (animatable->GetTimePoint() - preKeyTime);
91             TriggerFrame(preAnimatable, animatable, innerKeyTime);
92             return;
93         }
94         preAnimatable = animatable;
95     }
96     // in range [1.0, inf]
97     const auto& lastAnimatable = animatables_.back();
98     TriggerFrame(lastAnimatable, lastAnimatable, 1.0);
99 }
100 
TriggerFrame(const RefPtr<Animatable> & start,const RefPtr<Animatable> & end,float time)101 void PropertyAnimation::TriggerFrame(const RefPtr<Animatable>& start, const RefPtr<Animatable>& end, float time)
102 {
103     if (animateTo_ == nullptr) {
104         return;
105     }
106     switch (type_) {
107         case AnimatableType::PROPERTY_WIDTH:
108         case AnimatableType::PROPERTY_HEIGHT:
109         case AnimatableType::PROPERTY_MARGIN_LEFT:
110         case AnimatableType::PROPERTY_MARGIN_TOP:
111         case AnimatableType::PROPERTY_MARGIN_RIGHT:
112         case AnimatableType::PROPERTY_MARGIN_BOTTOM:
113         case AnimatableType::PROPERTY_PADDING_LEFT:
114         case AnimatableType::PROPERTY_PADDING_TOP:
115         case AnimatableType::PROPERTY_PADDING_RIGHT:
116         case AnimatableType::PROPERTY_PADDING_BOTTOM:
117         case AnimatableType::PROPERTY_POSITION_LEFT:
118         case AnimatableType::PROPERTY_POSITION_TOP:
119         case AnimatableType::PROPERTY_POSITION_RIGHT:
120         case AnimatableType::PROPERTY_POSITION_BOTTOM: {
121             Next<Dimension>(start, end, time);
122             break;
123         }
124         case AnimatableType::PROPERTY_BG_COLOR:
125         case AnimatableType::PROPERTY_BORDER_LEFT_COLOR:
126         case AnimatableType::PROPERTY_BORDER_TOP_COLOR:
127         case AnimatableType::PROPERTY_BORDER_RIGHT_COLOR:
128         case AnimatableType::PROPERTY_BORDER_BOTTOM_COLOR: {
129             Next<Color>(start, end, time);
130             break;
131         }
132         case AnimatableType::PROPERTY_OPACITY:
133         case AnimatableType::PROPERTY_BACKDROP_FILTER_BLUR:
134         case AnimatableType::PROPERTY_FILTER_BLUR:
135         case AnimatableType::PROPERTY_WINDOW_FILTER_BLUR:
136         case AnimatableType::PROPERTY_BORDER_LEFT_WIDTH:
137         case AnimatableType::PROPERTY_BORDER_TOP_WIDTH:
138         case AnimatableType::PROPERTY_BORDER_RIGHT_WIDTH:
139         case AnimatableType::PROPERTY_BORDER_BOTTOM_WIDTH:
140         case AnimatableType::PROPERTY_BORDER_TOP_LEFT_RADIUS:
141         case AnimatableType::PROPERTY_BORDER_TOP_RIGHT_RADIUS:
142         case AnimatableType::PROPERTY_BORDER_BOTTOM_LEFT_RADIUS:
143         case AnimatableType::PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS: {
144             Next<float>(start, end, time);
145             break;
146         }
147         case AnimatableType::PROPERTY_BACKGROUND_SIZE: {
148             Next<BackgroundImageSize>(start, end, time);
149             break;
150         }
151         case AnimatableType::PROPERTY_BACKGROUND_POSITION: {
152             Next<BackgroundImagePosition>(start, end, time);
153             break;
154         }
155         case AnimatableType::PROPERTY_BOX_SHADOW: {
156             Next<Shadow>(start, end, time);
157             break;
158         }
159         case AnimatableType::PROPERTY_BORDER_LEFT_STYLE:
160         case AnimatableType::PROPERTY_BORDER_TOP_STYLE:
161         case AnimatableType::PROPERTY_BORDER_RIGHT_STYLE:
162         case AnimatableType::PROPERTY_BORDER_BOTTOM_STYLE: {
163             Next<BorderStyle>(start, end, time);
164             break;
165         }
166         default:
167             break;
168     }
169 }
170 
171 template<class T>
Next(const RefPtr<Animatable> & start,const RefPtr<Animatable> & end,float time)172 void PropertyAnimation::Next(const RefPtr<Animatable>& start, const RefPtr<Animatable>& end, float time)
173 {
174     auto from = AceType::DynamicCast<AnimatableData<T>>(start);
175     auto to = AceType::DynamicCast<AnimatableData<T>>(end);
176     auto value = AceType::MakeRefPtr<AnimatableData<T>>(T {});
177     if (from != nullptr && to != nullptr && value != nullptr) {
178         float process = to->GetCurve()->Move(time);
179         value->SetValue(to->Animate(from->GetValue(), to->GetValue(), process));
180         animateTo_(value);
181     }
182 }
183 
184 } // namespace OHOS::Ace
185