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/simple_spring_node.h"
17
18 namespace OHOS::Ace {
19 namespace {
20
21 constexpr int32_t FRAME_SCHEDULED = 16;
22 constexpr int64_t NANOS_TO_MILLS = 1000000;
23
24 } // namespace
25
SimpleSpringNode(const WeakPtr<PipelineContext> & context,int32_t index,double value)26 SimpleSpringNode::SimpleSpringNode(const WeakPtr<PipelineContext>& context, int32_t index, double value)
27 : SpringNode(index), context_(context), value_(value)
28 {
29 springProperty_ = AceType::MakeRefPtr<SpringProperty>();
30 spring_ = AceType::MakeRefPtr<SpringMotion>(0.0, 0.0, 0.0, springProperty_);
31 spring_->SetAccuracy(valueAccuracy_);
32 auto&& callback = [weak = AceType::WeakClaim(this)](uint64_t duration) {
33 auto node = weak.Upgrade();
34 if (!node || !node->adapter_) {
35 LOGE("Empty node or adapter, skip tick callback.");
36 return;
37 }
38 auto context = node->context_.Upgrade();
39 if (!context) {
40 return;
41 }
42 node->adapter_->TickAnimation(context->GetTimeFromExternalTimer());
43 };
44 scheduler_ = AceType::MakeRefPtr<Scheduler>(callback, context);
45 }
46
SetValue(double value)47 void SimpleSpringNode::SetValue(double value)
48 {
49 SpringNode::SetValue(value);
50 value_ = value;
51 OnUpdate(value_, velocity_);
52 NotifyUpdateListener(value_, velocity_);
53 NotifyNext(value_, velocity_);
54 }
55
NotifyNext(double endValue,double initVelocity)56 void SimpleSpringNode::NotifyNext(double endValue, double initVelocity)
57 {
58 if (!adapter_) {
59 LOGE("Notify next failed. Adapter is null. index: %{public}d", index_);
60 return;
61 }
62 if (this != AceType::RawPtr(adapter_->GetControlNode())) {
63 return;
64 }
65 auto currentNode = adapter_->GetNext(AceType::WeakClaim(this).Upgrade());
66 while (currentNode) {
67 currentNode->EndToValue(endValue, initVelocity);
68 currentNode = adapter_->GetNext(currentNode);
69 }
70 }
71
EndToValue(double endValue,double velocity)72 void SimpleSpringNode::EndToValue(double endValue, double velocity)
73 {
74 if (!adapter_) {
75 LOGE("End to value failed. adapter is null. index: %{public}d", index_);
76 return;
77 }
78 auto context = context_.Upgrade();
79 if (!context) {
80 LOGE("End to value failed, context is null. index: %{public}d", index_);
81 }
82 SpringNode::EndToValue(endValue, velocity);
83 if (isRunning_) {
84 LOGD("EndToValue when running. index: %{public}d, endValue: %{public}.3lf, velocity: %{public}.3lf", index_,
85 endValue, velocity);
86 auto controlNode = adapter_->GetControlNode();
87 if (!controlNode) {
88 LOGE("End to value failed. control node is null. index: %{public}d", index_);
89 return;
90 }
91 if (controlNode->IsAnimateToEnd()) {
92 startTime_ = context->GetTimeFromExternalTimer() - static_cast<uint64_t>(FRAME_SCHEDULED);
93 } else {
94 startTime_ = context->GetTimeFromExternalTimer() - static_cast<uint64_t>(GetFrameDelta() * FRAME_SCHEDULED);
95 }
96 spring_->SetAccuracy(valueAccuracy_);
97 spring_->Reset(value_, endValue, velocity_, springProperty_);
98 } else {
99 LOGD("EndToValue first time. index: %{public}d, endValue: %{public}.3lf, velocity: %{public}.3lf", index_,
100 endValue, velocity);
101 startTime_ = context->GetTimeFromExternalTimer();
102 isRunning_ = true;
103 spring_->SetAccuracy(valueAccuracy_);
104 spring_->Reset(value_, endValue, velocity_, springProperty_);
105 OnAnimation();
106 }
107 NotifyNext(endValue, velocity);
108 }
109
OnAnimation()110 void SimpleSpringNode::OnAnimation()
111 {
112 if (!isRunning_) {
113 return;
114 }
115 auto context = context_.Upgrade();
116 if (!context) {
117 LOGE("Animate failed, context is null. index: %{public}d", index_);
118 return;
119 }
120 if (!spring_) {
121 LOGE("Animate failed, spring is null. index: %{public}d", index_);
122 return;
123 }
124 int64_t delta = static_cast<int64_t>(context->GetTimeFromExternalTimer()) - static_cast<int64_t>(startTime_);
125 spring_->OnTimestampChanged(static_cast<double>(delta) / static_cast<double>(NANOS_TO_MILLS), 0.0f, false);
126 value_ = spring_->GetCurrentPosition();
127 velocity_ = spring_->GetCurrentVelocity();
128 if (spring_->IsCompleted()) {
129 isRunning_ = false;
130 value_ = spring_->GetEndValue();
131 velocity_ = 0.0;
132 // Node's animation update callback
133 OnUpdate(value_, velocity_);
134 NotifyUpdateListener(value_, velocity_);
135 OnEnd(value_);
136 scheduler_->Stop();
137 } else {
138 OnUpdate(value_, velocity_);
139 NotifyUpdateListener(value_, velocity_);
140 scheduler_->Start();
141 }
142 }
143
Cancel()144 void SimpleSpringNode::Cancel()
145 {
146 scheduler_->Stop();
147 isRunning_ = false;
148 velocity_ = 0.0;
149 OnEnd(value_);
150 }
151
ResetNode(double value,double velocity)152 void SimpleSpringNode::ResetNode(double value, double velocity)
153 {
154 LOGD("ResetNode. value: %{public}.3lf, velocity: %{public}.3lf", value, velocity);
155 value_ = value;
156 velocity_ = velocity;
157 OnUpdate(value_, velocity_);
158 NotifyUpdateListener(value_, velocity_);
159 }
160
TransferParams(double stiffness,double damping)161 void SimpleSpringNode::TransferParams(double stiffness, double damping)
162 {
163 if (springProperty_) {
164 springProperty_->SetStiffness(stiffness);
165 springProperty_->SetDamping(damping);
166 }
167 }
168
169 } // namespace OHOS::Ace