• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "bridge/declarative_frontend/jsview/js_animator.h"
17 
18 #include "base/log/ace_scoring_log.h"
19 #include "bridge/declarative_frontend/engine/functions/js_animator_function.h"
20 #include "bridge/declarative_frontend/jsview/models/animator_model_impl.h"
21 #include "core/components_ng/pattern/animator/animator_model.h"
22 #include "core/components_ng/pattern/animator/animator_model_ng.h"
23 
24 namespace OHOS::Ace {
25 
26 std::unique_ptr<AnimatorModel> AnimatorModel::instance_ = nullptr;
27 std::mutex AnimatorModel::mutex_;
28 
GetInstance()29 AnimatorModel* AnimatorModel::GetInstance()
30 {
31     if (!instance_) {
32         std::lock_guard<std::mutex> lock(mutex_);
33         if (!instance_) {
34 #ifdef NG_BUILD
35             instance_.reset(new Framework::AnimatorModelNG());
36 #else
37             if (Container::IsCurrentUseNewPipeline()) {
38                 instance_.reset(new Framework::AnimatorModelNG());
39             } else {
40                 instance_.reset(new Framework::AnimatorModelImpl());
41             }
42 #endif
43         }
44     }
45     return instance_.get();
46 }
47 
48 } // namespace OHOS::Ace
49 
50 namespace OHOS::Ace::Framework {
51 namespace {
52 
53 constexpr int32_t FRICTION_MOTION_LENGTH = 3;
54 constexpr int32_t SPRING_MOTION_LENGTH = 4;
55 constexpr int32_t SCROLL_MOTION_LENGTH = 5;
56 
AddFrameListener(const RefPtr<AnimatorInfo> & animatorInfo,const RefPtr<KeyframeAnimation<double>> & animation)57 void AddFrameListener(const RefPtr<AnimatorInfo>& animatorInfo, const RefPtr<KeyframeAnimation<double>>& animation)
58 {
59     if (!animatorInfo || !animation) {
60         return;
61     }
62     auto frameEvent = animatorInfo->GetFrameEvent();
63     if (frameEvent) {
64         animation->AddListener([frameEvent](const float& progress) { frameEvent(progress); });
65     }
66 }
67 
HandleAnimatorInfo(const RefPtr<AnimatorInfo> & animatorInfo,const RefPtr<Animator> & animator)68 void HandleAnimatorInfo(const RefPtr<AnimatorInfo>& animatorInfo, const RefPtr<Animator>& animator)
69 {
70     if (!animatorInfo || !animator) {
71         return;
72     }
73     int32_t duration = animatorInfo->GetDuration();
74     int32_t delay = animatorInfo->GetDelay();
75     FillMode fillMode = animatorInfo->GetFillMode();
76     int32_t iteration = animatorInfo->GetIteration();
77     AnimationDirection playMode = animatorInfo->GetPlayMode();
78     animator->SetDuration(duration);
79     animator->SetStartDelay(delay);
80     animator->SetFillMode(fillMode);
81     animator->SetIteration(iteration);
82     animator->SetAnimationDirection(playMode);
83 }
84 
CreateAnimation(const RefPtr<AnimatorInfo> & animatorInfo,const RefPtr<Animator> & animator,AnimationStatus operation)85 bool CreateAnimation(
86     const RefPtr<AnimatorInfo>& animatorInfo, const RefPtr<Animator>& animator, AnimationStatus operation)
87 {
88     if (!animatorInfo || !animator) {
89         return false;
90     }
91     auto motion = animatorInfo->GetAnimatorMotion();
92     if (motion) {
93         auto frameEvent = animatorInfo->GetFrameEvent();
94         if (frameEvent) {
95             motion->AddListener([frameEvent](const float& progress) { frameEvent(progress); });
96         }
97         animator->ClearPauseListeners();
98         animator->ClearRepeatListeners();
99         animator->ClearIdleListeners();
100         if (operation == AnimationStatus::RUNNING && animator->GetStatus() != Animator::Status::RUNNING) {
101             animator->PlayMotion(motion);
102         } else if (operation == AnimationStatus::STOPPED) {
103             animator->Finish();
104         }
105         return false;
106     } else {
107         animator->ClearInterpolators();
108         auto keyframeBegin = AceType::MakeRefPtr<Keyframe<double>>(0.0, 0.0);
109         auto keyframeEnd = AceType::MakeRefPtr<Keyframe<double>>(1.0, 1.0);
110         auto keyframeAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
111         auto curve = animatorInfo->GetCurve();
112         if (curve) {
113             keyframeAnimation->SetCurve(curve);
114         }
115         keyframeAnimation->AddKeyframe(keyframeBegin);
116         keyframeAnimation->AddKeyframe(keyframeEnd);
117         AddFrameListener(animatorInfo, keyframeAnimation);
118         animator->AddInterpolator(keyframeAnimation);
119         return true;
120     }
121 }
122 
GetEventCallback(const JSCallbackInfo & info,const std::string & name)123 std::function<void()> GetEventCallback(const JSCallbackInfo& info, const std::string& name)
124 {
125     if (!info[0]->IsFunction()) {
126         return nullptr;
127     }
128     RefPtr<JsFunction> jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
129     return [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), name]() {
130         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
131         ACE_SCORING_EVENT(name);
132         func->Execute();
133     };
134 }
135 
136 } // namespace
137 
138 std::string JSAnimator::animatorId_;
139 
JSBind(BindingTarget globalObj)140 void JSAnimator::JSBind(BindingTarget globalObj)
141 {
142     JSClass<JSAnimator>::Declare("Animator");
143     MethodOptions opt = MethodOptions::NONE;
144     JSClass<JSAnimator>::StaticMethod("create", &JSAnimator::Create, opt);
145     JSClass<JSAnimator>::StaticMethod("state", &JSAnimator::SetState, opt);
146     JSClass<JSAnimator>::StaticMethod("duration", &JSAnimator::SetDuration, opt);
147     JSClass<JSAnimator>::StaticMethod("curve", &JSAnimator::SetCurve, opt);
148     JSClass<JSAnimator>::StaticMethod("delay", &JSAnimator::SetDelay, opt);
149     JSClass<JSAnimator>::StaticMethod("fillMode", &JSAnimator::SetFillMode, opt);
150     JSClass<JSAnimator>::StaticMethod("iterations", &JSAnimator::SetIteration, opt);
151     JSClass<JSAnimator>::StaticMethod("playMode", &JSAnimator::SetPlayMode, opt);
152     JSClass<JSAnimator>::StaticMethod("motion", &JSAnimator::SetMotion, opt);
153     JSClass<JSAnimator>::StaticMethod("pop", &JSAnimator::Pop, opt);
154 
155     JSClass<JSAnimator>::StaticMethod("onStart", &JSAnimator::OnStart, opt);
156     JSClass<JSAnimator>::StaticMethod("onPause", &JSAnimator::OnPause, opt);
157     JSClass<JSAnimator>::StaticMethod("onRepeat", &JSAnimator::OnRepeat, opt);
158     JSClass<JSAnimator>::StaticMethod("onCancel", &JSAnimator::OnCancel, opt);
159     JSClass<JSAnimator>::StaticMethod("onFinish", &JSAnimator::OnFinish, opt);
160     JSClass<JSAnimator>::StaticMethod("onFrame", &JSAnimator::OnFrame, opt);
161 
162     JSClass<JSAnimator>::Bind<>(globalObj);
163 
164     JSClass<JSSpringProp>::Declare("SpringProp");
165     JSClass<JSSpringProp>::Bind(globalObj, JSSpringProp::ConstructorCallback, JSSpringProp::DestructorCallback);
166 
167     JSClass<JSMotion>::Declare("SpringMotion");
168     JSClass<JSMotion>::Bind(globalObj, JSMotion::ConstructorCallback, JSMotion::DestructorCallback);
169 
170     JSClass<JSMotion>::Declare("FrictionMotion");
171     JSClass<JSMotion>::Bind(globalObj, JSMotion::ConstructorCallback, JSMotion::DestructorCallback);
172 
173     JSClass<JSMotion>::Declare("ScrollMotion");
174     JSClass<JSMotion>::Bind(globalObj, JSMotion::ConstructorCallback, JSMotion::DestructorCallback);
175 }
176 
Create(const JSCallbackInfo & info)177 void JSAnimator::Create(const JSCallbackInfo& info)
178 {
179     ContainerScope scope(Container::CurrentIdSafely());
180     if (info.Length() != 1) {
181         return;
182     }
183 
184     if (!info[0]->IsString()) {
185         return;
186     }
187     animatorId_ = info[0]->ToString();
188     AnimatorModel::GetInstance()->Create(animatorId_);
189 }
190 
Pop()191 void JSAnimator::Pop() {}
192 
SetState(int32_t state)193 void JSAnimator::SetState(int32_t state)
194 {
195     ContainerScope scope(Container::CurrentIdSafely());
196     auto animatorInfo = AnimatorModel::GetInstance()->GetAnimatorInfo(animatorId_);
197     if (!animatorInfo) {
198         TAG_LOGW(AceLogTag::ACE_ANIMATION, "animator component setState failed, id:%{public}s, state:%{public}d",
199             animatorId_.c_str(), state);
200         return;
201     }
202     auto animator = animatorInfo->GetAnimator();
203     CHECK_NULL_VOID(animator);
204     auto operation = static_cast<AnimationStatus>(state);
205     HandleAnimatorInfo(animatorInfo, animator);
206     if (!CreateAnimation(animatorInfo, animator, operation)) {
207         return;
208     }
209     switch (operation) {
210         case AnimationStatus::RUNNING:
211             TAG_LOGI(AceLogTag::ACE_ANIMATION, "animator component play, id:%{public}s", animatorId_.c_str());
212             animator->Play();
213             break;
214         case AnimationStatus::PAUSED:
215             TAG_LOGI(AceLogTag::ACE_ANIMATION, "animator component pause, id:%{public}s", animatorId_.c_str());
216             animator->Pause();
217             break;
218         case AnimationStatus::STOPPED:
219             TAG_LOGI(AceLogTag::ACE_ANIMATION, "animator component stop, id:%{public}s", animatorId_.c_str());
220             animator->Finish();
221             break;
222         case AnimationStatus::INITIAL:
223             animator->Cancel();
224             break;
225         default:
226             break;
227     }
228 }
229 
SetDuration(int32_t duration)230 void JSAnimator::SetDuration(int32_t duration)
231 {
232     ContainerScope scope(Container::CurrentIdSafely());
233     auto animatorInfo = AnimatorModel::GetInstance()->GetAnimatorInfo(animatorId_);
234     if (!animatorInfo) {
235         return;
236     }
237     animatorInfo->SetDuration(duration);
238 }
239 
SetCurve(const JSCallbackInfo & info)240 void JSAnimator::SetCurve(const JSCallbackInfo& info)
241 {
242     ContainerScope scope(Container::CurrentIdSafely());
243     if (info.Length() != 1) {
244         return;
245     }
246 
247     if (!info[0]->IsString()) {
248         return;
249     }
250     auto value = info[0]->ToString();
251     auto animatorInfo = AnimatorModel::GetInstance()->GetAnimatorInfo(animatorId_);
252     if (!animatorInfo) {
253         return;
254     }
255     auto curve = CreateCurve(value);
256     animatorInfo->SetCurve(curve);
257 }
258 
SetDelay(int32_t delay)259 void JSAnimator::SetDelay(int32_t delay)
260 {
261     ContainerScope scope(Container::CurrentIdSafely());
262     auto animatorInfo = AnimatorModel::GetInstance()->GetAnimatorInfo(animatorId_);
263     if (!animatorInfo) {
264         return;
265     }
266     animatorInfo->SetDelay(delay);
267 }
268 
SetFillMode(int32_t fillMode)269 void JSAnimator::SetFillMode(int32_t fillMode)
270 {
271     ContainerScope scope(Container::CurrentIdSafely());
272     auto animatorInfo = AnimatorModel::GetInstance()->GetAnimatorInfo(animatorId_);
273     if (!animatorInfo) {
274         return;
275     }
276     animatorInfo->SetFillMode(static_cast<FillMode>(fillMode));
277 }
278 
SetIteration(int32_t iteration)279 void JSAnimator::SetIteration(int32_t iteration)
280 {
281     ContainerScope scope(Container::CurrentIdSafely());
282     auto animatorInfo = AnimatorModel::GetInstance()->GetAnimatorInfo(animatorId_);
283     if (!animatorInfo) {
284         return;
285     }
286     animatorInfo->SetIteration(iteration);
287 }
288 
SetPlayMode(int32_t playMode)289 void JSAnimator::SetPlayMode(int32_t playMode)
290 {
291     ContainerScope scope(Container::CurrentIdSafely());
292     auto animatorInfo = AnimatorModel::GetInstance()->GetAnimatorInfo(animatorId_);
293     if (!animatorInfo) {
294         return;
295     }
296     animatorInfo->SetPlayMode(static_cast<AnimationDirection>(playMode));
297 }
298 
SetMotion(const JSCallbackInfo & info)299 void JSAnimator::SetMotion(const JSCallbackInfo& info)
300 {
301     ContainerScope scope(Container::CurrentIdSafely());
302     if (info.Length() != 1 || !info[0]->IsObject()) {
303         return;
304     }
305     JSMotion* rawMotion = JSRef<JSObject>::Cast(info[0])->Unwrap<JSMotion>();
306     if (!rawMotion) {
307         return;
308     }
309 
310     RefPtr<Motion> motion = rawMotion->GetMotion();
311     auto animatorInfo = AnimatorModel::GetInstance()->GetAnimatorInfo(animatorId_);
312     if (!animatorInfo) {
313         return;
314     }
315     animatorInfo->SetAnimatorMotion(motion);
316 }
317 
OnStart(const JSCallbackInfo & info)318 void JSAnimator::OnStart(const JSCallbackInfo& info)
319 {
320     ContainerScope scope(Container::CurrentIdSafely());
321     auto callback = GetEventCallback(info, "Animator.onStart");
322     AnimatorModel::GetInstance()->AddEventListener(std::move(callback), EventOperation::START, animatorId_);
323 }
324 
OnPause(const JSCallbackInfo & info)325 void JSAnimator::OnPause(const JSCallbackInfo& info)
326 {
327     ContainerScope scope(Container::CurrentIdSafely());
328     auto callback = GetEventCallback(info, "Animator.onPause");
329     AnimatorModel::GetInstance()->AddEventListener(std::move(callback), EventOperation::PAUSE, animatorId_);
330 }
331 
OnRepeat(const JSCallbackInfo & info)332 void JSAnimator::OnRepeat(const JSCallbackInfo& info)
333 {
334     ContainerScope scope(Container::CurrentIdSafely());
335     auto callback = GetEventCallback(info, "Animator.onRepeat");
336     AnimatorModel::GetInstance()->AddEventListener(std::move(callback), EventOperation::REPEAT, animatorId_);
337 }
338 
OnCancel(const JSCallbackInfo & info)339 void JSAnimator::OnCancel(const JSCallbackInfo& info)
340 {
341     ContainerScope scope(Container::CurrentIdSafely());
342     auto callback = GetEventCallback(info, "Animator.onCancel");
343     AnimatorModel::GetInstance()->AddEventListener(std::move(callback), EventOperation::CANCEL, animatorId_);
344 }
345 
OnFinish(const JSCallbackInfo & info)346 void JSAnimator::OnFinish(const JSCallbackInfo& info)
347 {
348     ContainerScope scope(Container::CurrentIdSafely());
349     auto callback = GetEventCallback(info, "Animator.onFinish");
350     AnimatorModel::GetInstance()->AddEventListener(std::move(callback), EventOperation::FINISH, animatorId_);
351 }
352 
OnFrame(const JSCallbackInfo & info)353 void JSAnimator::OnFrame(const JSCallbackInfo& info)
354 {
355     ContainerScope scope(Container::CurrentIdSafely());
356     if (!info[0]->IsFunction()) {
357         return;
358     }
359     RefPtr<JsAnimatorFunction> function = AceType::MakeRefPtr<JsAnimatorFunction>(JSRef<JSFunc>::Cast(info[0]));
360     auto OnFrameEvent = [execCtx = info.GetExecutionContext(), func = std::move(function)](const float& progress) {
361         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
362         ACE_SCORING_EVENT("Animator.onFrame");
363         func->Execute(progress);
364     };
365     auto animatorInfo = AnimatorModel::GetInstance()->GetAnimatorInfo(animatorId_);
366     if (!animatorInfo) {
367         return;
368     }
369     animatorInfo->SetFrameEvent(OnFrameEvent);
370 }
371 
ConstructorCallback(const JSCallbackInfo & info)372 void JSSpringProp::ConstructorCallback(const JSCallbackInfo& info)
373 {
374     ContainerScope scope(Container::CurrentIdSafely());
375     if (info.Length() != 3 || !info[0]->IsNumber() || !info[1]->IsNumber() || !info[2]->IsNumber()) {
376         return;
377     }
378     auto obj = AceType::MakeRefPtr<JSSpringProp>();
379     double mass = info[0]->ToNumber<double>();
380     double stiffness = info[1]->ToNumber<double>();
381     double damping = info[2]->ToNumber<double>();
382     auto springProp = AceType::MakeRefPtr<SpringProperty>(mass, stiffness, damping);
383     obj->SetSpringProp(springProp);
384     obj->IncRefCount();
385     info.SetReturnValue(AceType::RawPtr(obj));
386 }
387 
DestructorCallback(JSSpringProp * obj)388 void JSSpringProp::DestructorCallback(JSSpringProp* obj)
389 {
390     if (obj != nullptr) {
391         obj->DecRefCount();
392     }
393 }
394 
ConstructorCallback(const JSCallbackInfo & info)395 void JSMotion::ConstructorCallback(const JSCallbackInfo& info)
396 {
397     ContainerScope scope(Container::CurrentIdSafely());
398     int32_t len = info.Length();
399     if (len != FRICTION_MOTION_LENGTH && len != SPRING_MOTION_LENGTH && len != SCROLL_MOTION_LENGTH) {
400         return;
401     }
402     auto obj = AceType::MakeRefPtr<JSMotion>();
403     if (len == FRICTION_MOTION_LENGTH) {
404         if (!info[0]->IsNumber() || !info[1]->IsNumber() || !info[2]->IsNumber()) {
405             return;
406         }
407         double friction = info[0]->ToNumber<double>();
408         double position = info[1]->ToNumber<double>();
409         double velocity = info[2]->ToNumber<double>();
410         RefPtr<FrictionMotion> frictionMotion = AceType::MakeRefPtr<FrictionMotion>(friction, position, velocity);
411         obj->SetMotion(frictionMotion);
412     } else if (len == SPRING_MOTION_LENGTH) {
413         if (!info[0]->IsNumber() || !info[1]->IsNumber() || !info[2]->IsNumber() || !info[3]->IsObject()) {
414             return;
415         }
416         double start = info[0]->ToNumber<double>();
417         double end = info[1]->ToNumber<double>();
418         double velocity = info[2]->ToNumber<double>();
419         JSSpringProp* prop = JSRef<JSObject>::Cast(info[3])->Unwrap<JSSpringProp>();
420         if (!prop) {
421             return;
422         }
423         RefPtr<SpringProperty> springProperty = prop->GetSpringProp();
424         auto springMotion = AceType::MakeRefPtr<SpringMotion>(start, end, velocity, springProperty);
425         obj->SetMotion(springMotion);
426     } else {
427         if (!info[0]->IsNumber() || !info[1]->IsNumber() || !info[2]->IsNumber() || !info[3]->IsNumber() ||
428             !info[4]->IsObject()) {
429             return;
430         }
431         double position = info[0]->ToNumber<double>();
432         double velocity = info[1]->ToNumber<double>();
433         double min = info[2]->ToNumber<double>();
434         double max = info[3]->ToNumber<double>();
435         JSSpringProp* prop = JSRef<JSObject>::Cast(info[4])->Unwrap<JSSpringProp>();
436         if (!prop) {
437             return;
438         }
439         RefPtr<SpringProperty> springProperty = prop->GetSpringProp();
440         RefPtr<ScrollMotion> scrollMotion = AceType::MakeRefPtr<ScrollMotion>(
441             position, velocity, ExtentPair(min, min), ExtentPair(max, max), springProperty);
442         obj->SetMotion(scrollMotion);
443     }
444     obj->IncRefCount();
445     info.SetReturnValue(AceType::RawPtr(obj));
446 }
447 
DestructorCallback(JSMotion * obj)448 void JSMotion::DestructorCallback(JSMotion* obj)
449 {
450     if (obj != nullptr) {
451         obj->DecRefCount();
452     }
453 }
454 
455 } // namespace OHOS::Ace::Framework
456