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/svg_animate.h"
17 
18 #include "frameworks/core/components/svg/svg_transform.h"
19 
20 namespace OHOS::Ace {
21 
GetValuesRange(std::vector<float> & from,std::vector<float> & to,std::string & type)22 bool SvgAnimate::GetValuesRange(std::vector<float>& from, std::vector<float>& to, std::string& type)
23 {
24     if (to_.empty() || from_ == to_) {
25         return false;
26     }
27 
28     char tag = (from_.find(',') != std::string::npos) ? ',' : ' ';
29     StringUtils::StringSplitter(from_, tag, from);
30     tag = (to_.find(',') != std::string::npos) ? ',' : ' ';
31     StringUtils::StringSplitter(to_, tag, to);
32     if (to.empty()) {
33         return false;
34     }
35 
36     if (!SvgTransform::AlignmentValues(transformType_, from, to)) {
37         return false;
38     }
39 
40     type = transformType_;
41     return true;
42 }
43 
GetFrames(std::vector<std::vector<float>> & frames,std::string & type)44 bool SvgAnimate::GetFrames(std::vector<std::vector<float>>& frames, std::string& type)
45 {
46     type = transformType_;
47     std::vector<float> frame;
48     for (const auto& value : values_) {
49         char tag = (value.find(',') != std::string::npos) ? ',' : ' ';
50         StringUtils::StringSplitter(value, tag, frame);
51         if (!SvgTransform::AlignmentFrame(type, frame)) {
52             return false;
53         }
54         frames.push_back(frame);
55     }
56 
57     return true;
58 }
59 
60 template<typename T>
CreateKeyframe(const RefPtr<KeyframeAnimation<T>> & animation,const T & value,float time,const RefPtr<Curve> & curve)61 void SvgAnimate::CreateKeyframe(
62     const RefPtr<KeyframeAnimation<T>>& animation, const T& value, float time, const RefPtr<Curve>& curve)
63 {
64     if (!animation) {
65         LOGE("create discrete calcMode animate failed, animation is null");
66         return;
67     }
68     if (!curve) {
69         LOGE("Create keyframe failed, curve is null");
70         return;
71     }
72     auto keyframe = AceType::MakeRefPtr<Keyframe<T>>(time, value);
73     keyframe->SetCurve(curve);
74     animation->AddKeyframe(keyframe);
75 }
76 
77 template<typename T>
CreateFirstKeyframe(const RefPtr<KeyframeAnimation<T>> & animation,const T & value)78 void SvgAnimate::CreateFirstKeyframe(const RefPtr<KeyframeAnimation<T>>& animation, const T& value)
79 {
80     if (!animation) {
81         LOGE("create discrete calcMode animate failed, animation is null");
82         return;
83     }
84     auto keyframe = AceType::MakeRefPtr<Keyframe<T>>(0.0f, value);
85     animation->AddKeyframe(keyframe);
86 }
87 
88 template<typename T>
CreatePropertyAnimate(std::function<void (T)> && callback,const T & originalValue,const RefPtr<Animator> & animator)89 bool SvgAnimate::CreatePropertyAnimate(
90     std::function<void(T)>&& callback, const T& originalValue, const RefPtr<Animator>& animator)
91 {
92     bool ret = false;
93     switch (calcMode_) {
94         case CalcMode::DISCRETE:
95             ret = CreateDiscreteAnimate(std::move(callback), originalValue, animator);
96             break;
97         case CalcMode::LINEAR:
98             ret = CreateLinearAnimate(std::move(callback), originalValue, animator);
99             break;
100         case CalcMode::PACED:
101             ret = CreatePacedAnimate(std::move(callback), originalValue, animator);
102             break;
103         case CalcMode::SPLINE:
104             ret = CreateSplineAnimate(std::move(callback), originalValue, animator);
105             break;
106         default:
107             LOGE("invalid calcMode");
108             break;
109     }
110     return ret;
111 }
112 
CreateMotionAnimate(std::function<void (double)> && callback,const RefPtr<Animator> & animator)113 bool SvgAnimate::CreateMotionAnimate(std::function<void(double)>&& callback, const RefPtr<Animator>& animator)
114 {
115     if (keyPoints_.empty() || calcMode_ == CalcMode::PACED) {
116         auto animation = AceType::MakeRefPtr<CurveAnimation<double>>(0.0, 1.0, GetCurve());
117         animation->AddListener(callback);
118         animator->AddInterpolator(animation);
119         animator->SetDuration(GetDur());
120         animator->SetFillMode(GetFillMode());
121         animator->SetIteration(repeatCount_);
122         animator->SetStartDelay(GetBegin());
123         animator->Play();
124         return true;
125     }
126     bool ret = false;
127     double originalValue = 0.0;
128     switch (calcMode_) {
129         case CalcMode::DISCRETE:
130             ret = CreateDiscreteAnimate(std::move(callback), originalValue, animator);
131             break;
132         case CalcMode::LINEAR:
133             ret = CreateLinearAnimate(std::move(callback), originalValue, animator);
134             break;
135         case CalcMode::SPLINE:
136             ret = CreateSplineAnimate(std::move(callback), originalValue, animator);
137             break;
138         default:
139             LOGE("invalid calcMode");
140             break;
141     }
142     return ret;
143 }
144 
145 template<typename T>
CreateDiscreteAnimate(std::function<void (T)> && callback,const T & originalValue,const RefPtr<Animator> & animator)146 bool SvgAnimate::CreateDiscreteAnimate(
147     std::function<void(T)>&& callback, const T& originalValue, const RefPtr<Animator>& animator)
148 {
149     if (calcMode_ != CalcMode::DISCRETE) {
150         LOGW("invalid calcMode");
151         return false;
152     }
153     RefPtr<KeyframeAnimation<T>> animation = AceType::MakeRefPtr<KeyframeAnimation<T>>();
154     const auto& values = GetKeyValues();
155     if (values.empty()) {
156         T startValue = GetStartValue(originalValue);
157         T endValue = GetEndValue(startValue);
158         if (!DiscreteAnimate(animation, originalValue, startValue, endValue)) {
159             LOGW("discreteAnimate, create discrete animate failed");
160             return false;
161         }
162     } else {
163         if (!DiscreteAnimate(animation, originalValue)) {
164             LOGW("discreteAnimate with value, create discrete animate failed");
165             return false;
166         }
167     }
168     animation->SetInitValue(originalValue);
169     animation->AddListener(std::move(callback));
170     animator->AddInterpolator(animation);
171     animator->SetDuration(GetDur());
172     animator->SetFillMode(GetFillMode());
173     animator->SetIteration(repeatCount_);
174     animator->SetStartDelay(GetBegin());
175     animator->Play();
176     return true;
177 }
178 
179 template<typename T>
DiscreteAnimate(const RefPtr<KeyframeAnimation<T>> & animation,const T & originalValue,const T & startValue,const T & endValue)180 bool SvgAnimate::DiscreteAnimate(
181     const RefPtr<KeyframeAnimation<T>>& animation, const T& originalValue, const T& startValue, const T& endValue)
182 {
183     if (startValue == endValue && startValue == originalValue) {
184         LOGW("the start value and end value are the same as the original value");
185         return false;
186     }
187     CreateFirstKeyframe(animation, originalValue);
188     CreateKeyframe(animation, startValue, 0.5f, GetCurve());
189     CreateKeyframe(animation, endValue, 1.0f, GetCurve());
190     return true;
191 }
192 
193 template<typename T>
DiscreteAnimate(const RefPtr<KeyframeAnimation<T>> & animation,const T & originalValue)194 bool SvgAnimate::DiscreteAnimate(const RefPtr<KeyframeAnimation<T>>& animation, const T& originalValue)
195 {
196     const auto& values = GetKeyValues();
197     if (values.empty()) {
198         LOGW("create discrete calcMode animate failed, values is null");
199         return false;
200     }
201     if (values.size() == 1) {
202         CreateFirstKeyframe(animation, originalValue);
203         CreateKeyframe(animation, GetValue<T>(values.front()), 1.0f, GetCurve());
204         return true;
205     } else if (values.size() == 2) {
206         return DiscreteAnimate(animation, originalValue, GetValue<T>(values.front()), GetValue<T>(values.back()));
207     } else {
208         if (!keyTimes_.empty()) {
209             return DiscreteWithValues(animation, originalValue);
210         } else {
211             return DiscreteWithKeyTimes(animation, originalValue);
212         }
213     }
214 }
215 
216 template<typename T>
DiscreteWithValues(const RefPtr<KeyframeAnimation<T>> & animation,const T & originalValue)217 bool SvgAnimate::DiscreteWithValues(const RefPtr<KeyframeAnimation<T>>& animation, const T& originalValue)
218 {
219     if (!animation) {
220         LOGE("create discrete calcMode animate failed, animation is null");
221         return false;
222     }
223     const auto& values = GetKeyValues();
224     if (values.size() < 3) {
225         LOGW("create discrete calcMode animate failed, values is null");
226         return false;
227     }
228     // In discrete calcMode, if without keyTimes, the first value is the original value
229     // For example: values = {2, 3, 4} and originalValue=1, the keyframe values will be {1, 2, 3, 4}
230     float keyTime = ((int)(100.0f / (values.size()))) / 100.0f;
231     CreateFirstKeyframe(animation, originalValue);
232     auto valueIter = values.begin();
233     while (valueIter != (values.end() - 1)) {
234         CreateKeyframe(animation, GetValue<T>(*valueIter), keyTime, GetCurve());
235         keyTime += keyTime;
236         ++valueIter;
237     }
238     CreateKeyframe(animation, GetValue<T>(values.back()), 1.0f, GetCurve());
239     return true;
240 }
241 
242 template<typename T>
DiscreteWithKeyTimes(const RefPtr<KeyframeAnimation<T>> & animation,const T & originalValue)243 bool SvgAnimate::DiscreteWithKeyTimes(const RefPtr<KeyframeAnimation<T>>& animation, const T& originalValue)
244 {
245     if (!animation) {
246         LOGE("create discrete calcMode animate failed, animation is null");
247         return false;
248     }
249     const auto& values = GetKeyValues();
250     if (values.size() < 3 || keyTimes_.size() != values.size()) {
251         LOGW("create discrete calcMode animate failed, values or keyTimes invalid");
252         return false;
253     }
254     // In discrete calcMode, if has keyTimes, the first value is the original value and the last value of
255     // values is invalid. For example: values = {2, 3, 4} and originalValue=1, the keyframe values will be {1, 2, 3}
256     CreateFirstKeyframe(animation, originalValue);
257     auto valueIter = values.begin();
258     auto keyTimeIter = keyTimes_.begin() + 1;
259     while (valueIter != (values.end() - 2)) {
260         CreateKeyframe(animation, GetValue<T>(*valueIter), *keyTimeIter, GetCurve());
261         ++valueIter;
262         ++keyTimeIter;
263     }
264     CreateKeyframe(animation, GetValue<T>(*(values.end() - 2)), 1.0f, GetCurve());
265     return true;
266 }
267 
268 template<typename T>
CreateLinearAnimate(std::function<void (T)> && callback,const T & originalValue,const RefPtr<Animator> & animator)269 bool SvgAnimate::CreateLinearAnimate(
270     std::function<void(T)>&& callback, const T& originalValue, const RefPtr<Animator>& animator)
271 {
272     if (calcMode_ != CalcMode::LINEAR) {
273         LOGW("invalid calcMode");
274         return false;
275     }
276     const auto& values = GetKeyValues();
277     if (!values.empty()) {
278         RefPtr<KeyframeAnimation<T>> animation = AceType::MakeRefPtr<KeyframeAnimation<T>>();
279         if (!LinearAnimate(animation)) {
280             LOGW("create linear animate failed");
281             return false;
282         }
283         animation->SetInitValue(originalValue);
284         animation->AddListener(std::move(callback));
285         animator->AddInterpolator(animation);
286     } else {
287         if (!LinearAnimateFromTo(std::move(callback), originalValue, animator)) {
288             LOGW("create linear animate failed");
289             return false;
290         }
291     }
292     animator->SetDuration(GetDur());
293     animator->SetFillMode(GetFillMode());
294     animator->SetIteration(repeatCount_);
295     animator->SetStartDelay(GetBegin());
296     animator->Play();
297     return true;
298 }
299 
300 template<typename T>
LinearAnimateFromTo(std::function<void (T)> && callback,const T & originalValue,const RefPtr<Animator> & animator)301 bool SvgAnimate::LinearAnimateFromTo(
302     std::function<void(T)>&& callback, const T& originalValue, const RefPtr<Animator>& animator)
303 {
304     if (!animator) {
305         LOGE("create linear calcMode animate failed, animation is null");
306         return false;
307     }
308     T startValue = GetStartValue(originalValue);
309     T endValue = GetEndValue(startValue);
310     if (startValue == endValue) {
311         if (startValue == originalValue) {
312             LOGW("the start value and end value are the same as the original value, startValue=%{public}s",
313                 from_.c_str());
314             return false;
315         }
316         startValue = originalValue;
317     }
318     auto animation = AceType::MakeRefPtr<CurveAnimation<T>>(startValue, endValue, GetCurve());
319     animation->SetInitValue(originalValue);
320     animation->AddListener(std::move(callback));
321     animator->AddInterpolator(animation);
322     return true;
323 }
324 
325 template<typename T>
LinearAnimate(const RefPtr<KeyframeAnimation<T>> & animation)326 bool SvgAnimate::LinearAnimate(const RefPtr<KeyframeAnimation<T>>& animation)
327 {
328     const auto& values = GetKeyValues();
329     if (values.empty()) {
330         LOGW("create linear calcMode animate failed, values is invalid");
331         return false;
332     }
333     if (values.size() <= 2) {
334         CreateFirstKeyframe(animation, GetValue<T>(values.front()));
335         CreateKeyframe(animation, GetValue<T>(values.back()), 1.0f, GetCurve());
336         return true;
337     }
338     if (!keyTimes_.empty()) {
339         return LinearWithKeyTimes(animation);
340     } else {
341         return LinearWithValues(animation);
342     }
343 }
344 
345 template<typename T>
LinearWithValues(const RefPtr<KeyframeAnimation<T>> & animation)346 bool SvgAnimate::LinearWithValues(const RefPtr<KeyframeAnimation<T>>& animation)
347 {
348     if (!animation) {
349         LOGE("create linear calcMode animate failed, animation is null");
350         return false;
351     }
352     const auto& values = GetKeyValues();
353     if (values.size() < 3) {
354         LOGW("create linear calcMode animate failed, values is invalid");
355         return false;
356     }
357     CreateFirstKeyframe(animation, GetValue<T>(values.front()));
358     float keyTime = ((int)(100.0f / (values.size() - 1))) / 100.0f;
359     auto valueIter = values.begin() + 1;
360     while (valueIter != (values.end() - 1)) {
361         CreateKeyframe(animation, GetValue<T>(*valueIter), keyTime, GetCurve());
362         keyTime += keyTime;
363         ++valueIter;
364     }
365     CreateKeyframe(animation, GetValue<T>(values.back()), 1.0f, GetCurve());
366     return true;
367 }
368 
369 template<typename T>
LinearWithKeyTimes(const RefPtr<KeyframeAnimation<T>> & animation)370 bool SvgAnimate::LinearWithKeyTimes(const RefPtr<KeyframeAnimation<T>>& animation)
371 {
372     if (!animation) {
373         LOGE("create linear calcMode animate failed, animation is null");
374         return false;
375     }
376     const auto& values = GetKeyValues();
377     if (values.size() < 3 || keyTimes_.size() != values.size()) {
378         LOGW("create linear calcMode animate failed, values is invalid");
379         return false;
380     }
381     CreateFirstKeyframe(animation, GetValue<T>(values.front()));
382     auto valueIter = values.begin() + 1;
383     auto keyTimeIter = keyTimes_.begin() + 1;
384     while (valueIter != (values.end() - 1)) {
385         CreateKeyframe(animation, GetValue<T>(*valueIter), *keyTimeIter, GetCurve());
386         ++valueIter;
387         ++keyTimeIter;
388     }
389     CreateKeyframe(animation, GetValue<T>(values.back()), 1.0f, GetCurve());
390     return true;
391 }
392 
393 template<typename T>
CreatePacedAnimate(std::function<void (T)> && callback,const T & originalValue,const RefPtr<Animator> & animator)394 bool SvgAnimate::CreatePacedAnimate(
395     std::function<void(T)>&& callback, const T& originalValue, const RefPtr<Animator>& animator)
396 {
397     if (calcMode_ != CalcMode::PACED) {
398         LOGW("invalid calcMode");
399         return false;
400     }
401     const auto& values = GetKeyValues();
402     if (!values.empty()) {
403         RefPtr<KeyframeAnimation<T>> animation = AceType::MakeRefPtr<KeyframeAnimation<T>>();
404         if (values.size() <= 2) {
405             CreateFirstKeyframe(animation, GetValue<T>(values.front()));
406             CreateKeyframe(animation, GetValue<T>(values.back()), 1.0f, GetCurve());
407         } else {
408             if (!LinearWithValues(animation)) {
409                 LOGW("linearWithValues, create paced animate failed");
410                 return false;
411             }
412         }
413         animation->SetInitValue(originalValue);
414         animation->AddListener(std::move(callback));
415         animator->AddInterpolator(animation);
416     } else {
417         if (!LinearAnimateFromTo(std::move(callback), originalValue, animator)) {
418             LOGW("create linear animate failed");
419             return false;
420         }
421     }
422     animator->SetDuration(GetDur());
423     animator->SetFillMode(GetFillMode());
424     animator->SetIteration(repeatCount_);
425     animator->SetStartDelay(GetBegin());
426     animator->Play();
427     return true;
428 }
429 
430 template<typename T>
CreateSplineAnimate(std::function<void (T)> && callback,const T & originalValue,const RefPtr<Animator> & animator)431 bool SvgAnimate::CreateSplineAnimate(
432     std::function<void(T)>&& callback, const T& originalValue, const RefPtr<Animator>& animator)
433 {
434     if (calcMode_ != CalcMode::SPLINE) {
435         LOGW("invalid calcMode");
436         return false;
437     }
438     const auto& values = GetKeyValues();
439     if (values.empty()) {
440         if (!SplineAnimate(std::move(callback), originalValue, animator)) {
441             LOGW("create spline animate failed");
442             return false;
443         }
444     } else {
445         RefPtr<KeyframeAnimation<T>> animation = AceType::MakeRefPtr<KeyframeAnimation<T>>();
446         if (!SplineAnimate(animation)) {
447             LOGW("create spline animate failed");
448             return false;
449         }
450         animation->SetInitValue(originalValue);
451         animation->AddListener(std::move(callback));
452         animator->AddInterpolator(animation);
453     }
454     animator->SetDuration(GetDur());
455     animator->SetFillMode(GetFillMode());
456     animator->SetIteration(repeatCount_);
457     animator->SetStartDelay(GetBegin());
458     animator->Play();
459     return true;
460 }
461 
462 template<typename T>
SplineAnimate(std::function<void (T)> && callback,const T & originalValue,const RefPtr<Animator> & animator)463 bool SvgAnimate::SplineAnimate(
464     std::function<void(T)>&& callback, const T& originalValue, const RefPtr<Animator>& animator)
465 {
466     if (!animator) {
467         LOGE("create linear calcMode animate failed, animation is null");
468         return false;
469     }
470     if (keySplines_.empty()) {
471         LOGW("create linear calcMode animate failed, keySplines is invalid");
472         return false;
473     }
474     T startValue = GetStartValue(originalValue);
475     T endValue = GetEndValue(startValue);
476     if (startValue == endValue) {
477         if (startValue == originalValue) {
478             return false;
479         }
480         startValue = originalValue;
481     }
482     auto animation = AceType::MakeRefPtr<CurveAnimation<T>>(startValue, endValue, GetCurve(keySplines_[0]));
483     animation->SetInitValue(originalValue);
484     animation->AddListener(std::move(callback));
485     animator->AddInterpolator(animation);
486     return true;
487 }
488 
489 template<typename T>
SplineAnimate(const RefPtr<KeyframeAnimation<T>> & animation)490 bool SvgAnimate::SplineAnimate(const RefPtr<KeyframeAnimation<T>>& animation)
491 {
492     const auto& values = GetKeyValues();
493     if (values.size() < 2) {
494         LOGW("animation invalid, values is invalid");
495         return false;
496     }
497     if (values.size() == 2) {
498         if (keySplines_.size() != 1) {
499             LOGW("animation invalid, the curve is not defined.");
500             return false;
501         }
502         CreateFirstKeyframe(animation, GetValue<T>(values.front()));
503         CreateKeyframe(animation, GetValue<T>(values.back()), 1.0f, CubicCurveCreator(keySplines_.front()));
504         return true;
505     }
506     if (keyTimes_.empty()) {
507         return SplineWithKeySplines(animation);
508     } else {
509         return SplineWithKeyTimes(animation);
510     }
511 }
512 
513 template<typename T>
SplineWithKeySplines(const RefPtr<KeyframeAnimation<T>> & animation)514 bool SvgAnimate::SplineWithKeySplines(const RefPtr<KeyframeAnimation<T>>& animation)
515 {
516     if (!animation) {
517         LOGE("create spline calcMode animate failed, animation is null");
518         return false;
519     }
520     const auto& values = GetKeyValues();
521     if (values.size() < 3 || keySplines_.size() != (values.size() - 1)) {
522         LOGW("create spline calcMode animate failed, keySplines_ is invalid");
523         return false;
524     }
525     float keyTime = ((int)(100.0f / values.size() - 1)) / 100.0f;
526     CreateFirstKeyframe(animation, GetValue<T>(values.front()));
527     auto valueIter = values.begin() + 1;
528     auto keySplineIter = keySplines_.begin();
529     while (valueIter != (values.end() - 1)) {
530         CreateKeyframe(animation, GetValue<T>(*valueIter), keyTime, CubicCurveCreator(*keySplineIter));
531         ++valueIter;
532         ++keySplineIter;
533         keyTime += keyTime;
534     }
535     CreateKeyframe(animation, GetValue<T>(values.back()), 1.0f, CubicCurveCreator(keySplines_.back()));
536     return true;
537 }
538 
539 template<typename T>
SplineWithKeyTimes(const RefPtr<KeyframeAnimation<T>> & animation)540 bool SvgAnimate::SplineWithKeyTimes(const RefPtr<KeyframeAnimation<T>>& animation)
541 {
542     if (!animation) {
543         LOGE("create spline calcMode animate failed, animation is null");
544         return false;
545     }
546     const auto& values = GetKeyValues();
547     if (values.size() < 3 || keySplines_.size() != (values.size() - 1) || values.size() != keyTimes_.size()) {
548         LOGW("create spline calcMode animate failed");
549         return false;
550     }
551     CreateFirstKeyframe(animation, GetValue<T>(values.front()));
552     auto valueIter = values.begin() + 1;
553     auto keySplineIter = keySplines_.begin() + 1;
554     auto keyTimeIter = keyTimes_.begin() + 1;
555     while (valueIter != (values.end() - 1)) {
556         CreateKeyframe(animation, GetValue<T>(*valueIter), *keyTimeIter, CubicCurveCreator(*keySplineIter));
557         ++valueIter;
558         ++keySplineIter;
559         ++keyTimeIter;
560     }
561     CreateKeyframe(animation, GetValue<T>(values.back()), 1.0f, CubicCurveCreator(keySplines_.back()));
562     return true;
563 }
564 
565 template bool SvgAnimate::CreatePropertyAnimate(
566     std::function<void(double)>&& callback, const double& originalValue, const RefPtr<Animator>& animator);
567 template bool SvgAnimate::CreatePropertyAnimate(
568     std::function<void(Dimension)>&& callback, const Dimension& originalValue, const RefPtr<Animator>& animator);
569 template bool SvgAnimate::CreatePropertyAnimate(
570     std::function<void(Color)>&& callback, const Color& originalValue, const RefPtr<Animator>& animator);
571 
572 } // namespace OHOS::Ace