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