1 /*
2 * Copyright (c) 2021-2022 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<PipelineBase> & context,int32_t index,double value)26 SimpleSpringNode::SimpleSpringNode(const WeakPtr<PipelineBase>& 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 return;
82 }
83 SpringNode::EndToValue(endValue, velocity);
84 if (isRunning_) {
85 LOGD("EndToValue when running. index: %{public}d, endValue: %{public}.3lf, velocity: %{public}.3lf", index_,
86 endValue, velocity);
87 auto controlNode = adapter_->GetControlNode();
88 if (!controlNode) {
89 LOGE("End to value failed. control node is null. index: %{public}d", index_);
90 return;
91 }
92 if (controlNode->IsAnimateToEnd()) {
93 startTime_ = context->GetTimeFromExternalTimer() - static_cast<uint64_t>(FRAME_SCHEDULED);
94 } else {
95 startTime_ = context->GetTimeFromExternalTimer() - static_cast<uint64_t>(GetFrameDelta() * FRAME_SCHEDULED);
96 }
97 spring_->SetAccuracy(valueAccuracy_);
98 spring_->Reset(value_, endValue, velocity_, springProperty_);
99 } else {
100 LOGD("EndToValue first time. index: %{public}d, endValue: %{public}.3lf, velocity: %{public}.3lf", index_,
101 endValue, velocity);
102 startTime_ = context->GetTimeFromExternalTimer();
103 isRunning_ = true;
104 spring_->SetAccuracy(valueAccuracy_);
105 spring_->Reset(value_, endValue, velocity_, springProperty_);
106 OnAnimation();
107 }
108 NotifyNext(endValue, velocity);
109 }
110
OnAnimation()111 void SimpleSpringNode::OnAnimation()
112 {
113 if (!isRunning_) {
114 return;
115 }
116 auto context = context_.Upgrade();
117 if (!context) {
118 LOGE("Animate failed, context is null. index: %{public}d", index_);
119 return;
120 }
121 if (!spring_) {
122 LOGE("Animate failed, spring is null. index: %{public}d", index_);
123 return;
124 }
125 int64_t delta = static_cast<int64_t>(context->GetTimeFromExternalTimer()) - static_cast<int64_t>(startTime_);
126 spring_->OnTimestampChanged(static_cast<double>(delta) / static_cast<double>(NANOS_TO_MILLS), 0.0f, false);
127 value_ = spring_->GetCurrentPosition();
128 velocity_ = spring_->GetCurrentVelocity();
129 if (spring_->IsCompleted()) {
130 isRunning_ = false;
131 value_ = spring_->GetEndValue();
132 velocity_ = 0.0;
133 // Node's animation update callback
134 OnUpdate(value_, velocity_);
135 NotifyUpdateListener(value_, velocity_);
136 OnEnd(value_);
137 scheduler_->Stop();
138 } else {
139 OnUpdate(value_, velocity_);
140 NotifyUpdateListener(value_, velocity_);
141 scheduler_->Start();
142 }
143 }
144
Cancel()145 void SimpleSpringNode::Cancel()
146 {
147 scheduler_->Stop();
148 isRunning_ = false;
149 velocity_ = 0.0;
150 OnEnd(value_);
151 }
152
ResetNode(double value,double velocity)153 void SimpleSpringNode::ResetNode(double value, double velocity)
154 {
155 LOGD("ResetNode. value: %{public}.3lf, velocity: %{public}.3lf", value, velocity);
156 value_ = value;
157 velocity_ = velocity;
158 OnUpdate(value_, velocity_);
159 NotifyUpdateListener(value_, velocity_);
160 }
161
TransferParams(double stiffness,double damping)162 void SimpleSpringNode::TransferParams(double stiffness, double damping)
163 {
164 if (springProperty_) {
165 springProperty_->SetStiffness(stiffness);
166 springProperty_->SetDamping(damping);
167 }
168 }
169
170 } // namespace OHOS::Ace