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