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