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