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