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