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