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/components/common/properties/animatable_path.h"
17
18 #include "include/core/SkPath.h"
19 #include "include/core/SkString.h"
20 #include "include/utils/SkParsePath.h"
21
22 #include "core/event/ace_event_helper.h"
23
24 namespace OHOS::Ace {
25
operator =(const AnimatablePath & newValue)26 AnimatablePath& AnimatablePath::operator=(const AnimatablePath& newValue)
27 {
28 SetAnimationOption(newValue.GetAnimationOption());
29 auto context = context_.Upgrade();
30 if (!context || !animationCallback_) {
31 SetValue(newValue.GetValue());
32 return *this;
33 }
34 AnimationOption explicitAnim;
35 explicitAnim = context->GetExplicitAnimationOption();
36 if (explicitAnim.IsValid()) {
37 SetAnimationOption(explicitAnim);
38 AnimateTo(newValue.GetValue());
39 } else if (animationOption_.IsValid()) {
40 AnimateTo(newValue.GetValue());
41 } else {
42 SetValue(newValue.GetValue());
43 }
44 isFirstAssign_ = false;
45 return *this;
46 }
47
AnimateTo(std::string endValue)48 void AnimatablePath::AnimateTo(std::string endValue)
49 {
50 if (isFirstAssign_) {
51 isFirstAssign_ = false;
52 SetValue(endValue);
53 return;
54 }
55 if (path_ == endValue) {
56 return;
57 }
58 pathFrom_ = FormatPathString(path_);
59 pathTo_ = FormatPathString(endValue);
60 if (pathFrom_ == pathTo_) {
61 return;
62 }
63
64 ResetController();
65
66 SkPath skPathFrom;
67 SkPath skPathTo;
68 SkParsePath::FromSVGString(pathFrom_.c_str(), &skPathFrom);
69 SkParsePath::FromSVGString(pathTo_.c_str(), &skPathTo);
70 if (!skPathTo.isInterpolatable(skPathFrom)) {
71 isFirstAssign_ = false;
72 SetValue(endValue);
73 return;
74 }
75
76 if (!animationController_) {
77 animationController_ = AceType::MakeRefPtr<Animator>(context_);
78 }
79 RefPtr<CurveAnimation<double>> animation =
80 AceType::MakeRefPtr<CurveAnimation<double>>(0.0, 1.0, animationOption_.GetCurve());
81 animation->AddListener(std::bind(&AnimatablePath::OnAnimationCallback, this, std::placeholders::_1));
82
83 animationController_->AddInterpolator(animation);
84 auto onFinishEvent = animationOption_.GetOnFinishEvent();
85 if (onFinishEvent) {
86 animationController_->AddStopListener([onFinishEvent, weakContext = context_] {
87 auto context = weakContext.Upgrade();
88 if (context) {
89 context->PostAsyncEvent(onFinishEvent);
90 } else {
91 LOGE("the context is null");
92 }
93 });
94 }
95 animationController_->SetDuration(animationOption_.GetDuration());
96 animationController_->SetStartDelay(animationOption_.GetDelay());
97 animationController_->SetIteration(animationOption_.GetIteration());
98 animationController_->SetTempo(animationOption_.GetTempo());
99 animationController_->SetAnimationDirection(animationOption_.GetAnimationDirection());
100 animationController_->Play();
101 }
102
ResetController()103 void AnimatablePath::ResetController()
104 {
105 if (animationController_) {
106 if (!animationController_->IsStopped()) {
107 animationController_->Stop();
108 }
109 animationController_->ClearInterpolators();
110 animationController_->ClearAllListeners();
111 animationController_.Reset();
112 }
113 }
114
OnAnimationCallback(double value)115 void AnimatablePath::OnAnimationCallback(double value)
116 {
117 SkPath skPathFrom;
118 SkPath skPathTo;
119 SkParsePath::FromSVGString(pathFrom_.c_str(), &skPathFrom);
120 SkParsePath::FromSVGString(pathTo_.c_str(), &skPathTo);
121
122 SkPath out;
123 SkString outString;
124 if (skPathTo.interpolate(skPathFrom, value, &out)) {
125 SkParsePath::ToSVGString(out, &outString);
126 SetValue(outString.c_str());
127 } else {
128 SetValue(pathTo_);
129 }
130
131 if (animationCallback_) {
132 animationCallback_();
133 }
134 }
135
136 // Format path string before judging whether interpolation can be done
137 // e.g. 'M0 20 L50 50 L50 100 Z' --> 'M0 20L50 50L50 100L0 20Z'
FormatPathString(const std::string & path)138 std::string AnimatablePath::FormatPathString(const std::string& path)
139 {
140 SkPath skPath;
141 SkString outString;
142 SkParsePath::FromSVGString(path.c_str(), &skPath);
143 SkParsePath::ToSVGString(skPath, &outString);
144 return outString.c_str();
145 }
146
147 }