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