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