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