1 /*
2 * Copyright (c) 2025 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 <ani.h>
17 #include <array>
18 #include <iostream>
19 #include <memory>
20 #include <string>
21 #include <vector>
22
23 #include "base/memory/referenced.h"
24 #include "base/utils/string_utils.h"
25 #include "bridge/common/utils/utils.h"
26 #include "core/animation/animation.h"
27 #include "core/animation/animator.h"
28 #include "core/animation/curve.h"
29 #include "core/animation/spring_motion.h"
30 namespace OHOS::Ace::Ani {
31 constexpr size_t INTERPOLATING_SPRING_PARAMS_SIZE = 4;
32 constexpr char INTERPOLATING_SPRING[] = "interpolating-spring";
33
34 struct AnimatorOption {
35 int32_t duration = 0;
36 int32_t delay = 0;
37 int32_t iterations = 0;
38 double begin = 0.0;
39 double end = 0.0;
40 std::string easing = "ease";
41 std::string fill = "none";
42 std::string direction = "normal";
43
ToStringOHOS::Ace::Ani::AnimatorOption44 std::string ToString() const
45 {
46 return "AnimatorOption:[" + std::to_string(duration) + "," + std::to_string(delay) + "," +
47 std::to_string(iterations) + "," + std::to_string(begin) + "," + std::to_string(end) + "," + easing +
48 "," + fill + "," + direction + "]";
49 }
50 };
51
StringToAnimationDirection(const std::string & direction)52 static AnimationDirection StringToAnimationDirection(const std::string &direction)
53 {
54 if (direction.compare("alternate") == 0) {
55 return AnimationDirection::ALTERNATE;
56 } else if (direction.compare("reverse") == 0) {
57 return AnimationDirection::REVERSE;
58 } else if (direction.compare("alternate-reverse") == 0) {
59 return AnimationDirection::ALTERNATE_REVERSE;
60 } else {
61 return AnimationDirection::NORMAL;
62 }
63 }
64
StringToFillMode(const std::string & fillMode)65 static FillMode StringToFillMode(const std::string &fillMode)
66 {
67 if (fillMode.compare("forwards") == 0) {
68 return FillMode::FORWARDS;
69 } else if (fillMode.compare("backwards") == 0) {
70 return FillMode::BACKWARDS;
71 } else if (fillMode.compare("both") == 0) {
72 return FillMode::BOTH;
73 } else {
74 return FillMode::NONE;
75 }
76 }
77
78 class AnimatorResult final {
79 public:
80 AnimatorResult() = default;
AnimatorResult(RefPtr<Animator> & animator,std::shared_ptr<AnimatorOption> & option)81 AnimatorResult(RefPtr<Animator> &animator, std::shared_ptr<AnimatorOption> &option)
82 : animator_(animator), option_(option)
83 {
84 ApplyOption();
85 }
86 ~AnimatorResult() = default;
87
GetAnimator() const88 RefPtr<Animator> GetAnimator() const
89 {
90 return animator_;
91 }
92
GetAnimatorOption() const93 std::shared_ptr<AnimatorOption> GetAnimatorOption() const
94 {
95 return option_;
96 }
97
GetOnframeRef() const98 ani_ref GetOnframeRef() const
99 {
100 return onframe_;
101 }
102
SetOnframeRef(const ani_ref & onframe)103 void SetOnframeRef(const ani_ref &onframe)
104 {
105 onframe_ = onframe;
106 }
107
GetOnfinishRef() const108 ani_ref GetOnfinishRef() const
109 {
110 return onfinish_;
111 }
112
SetOnfinishRef(const ani_ref & onfinish)113 void SetOnfinishRef(const ani_ref &onfinish)
114 {
115 onfinish_ = onfinish;
116 }
117
GetOncancelRef() const118 ani_ref GetOncancelRef() const
119 {
120 return oncancel_;
121 }
122
SetOncancelRef(const ani_ref & oncancel)123 void SetOncancelRef(const ani_ref &oncancel)
124 {
125 oncancel_ = oncancel;
126 }
127
GetOnrepeatRef() const128 ani_ref GetOnrepeatRef() const
129 {
130 return onrepeat_;
131 }
132
SetOnrepeatRef(const ani_ref & onrepeat)133 void SetOnrepeatRef(const ani_ref &onrepeat)
134 {
135 onrepeat_ = onrepeat;
136 }
137
GetMotion() const138 const RefPtr<Motion> &GetMotion() const
139 {
140 return motion_;
141 }
142
SetMotion(const RefPtr<Motion> & motion)143 void SetMotion(const RefPtr<Motion> &motion)
144 {
145 motion_ = motion;
146 }
147
ApplyOption()148 void ApplyOption()
149 {
150 CHECK_NULL_VOID(animator_);
151 CHECK_NULL_VOID(option_);
152 if (motion_) {
153 // duration not works. Iteration can only be 1. Direction can only be normal.
154 animator_->SetIteration(1);
155 animator_->SetAnimationDirection(AnimationDirection::NORMAL);
156 } else {
157 animator_->SetDuration(option_->duration);
158 animator_->SetIteration(option_->iterations);
159 animator_->SetAnimationDirection(StringToAnimationDirection(option_->direction));
160 }
161 animator_->SetStartDelay(option_->delay);
162 // FillMode not works for motion in animator implementation.
163 animator_->SetFillMode(StringToFillMode(option_->fill));
164 }
165
166 private:
167 RefPtr<Animator> animator_;
168 RefPtr<Motion> motion_;
169 std::shared_ptr<AnimatorOption> option_;
170 ani_ref onframe_ = nullptr;
171 ani_ref onfinish_ = nullptr;
172 ani_ref oncancel_ = nullptr;
173 ani_ref onrepeat_ = nullptr;
174 };
175
ANIUtils_ANIStringToStdString(ani_env * env,ani_string ani_str)176 std::string ANIUtils_ANIStringToStdString(ani_env *env, ani_string ani_str)
177 {
178 ani_size strSize;
179 env->String_GetUTF8Size(ani_str, &strSize);
180
181 std::vector<char> buffer(strSize + 1);
182 char *utf8_buffer = buffer.data();
183
184 // String_GetUTF8 Supportted by https://gitee.com/openharmony/arkcompiler_runtime_core/pulls/3416
185 ani_size bytes_written = 0;
186 env->String_GetUTF8(ani_str, utf8_buffer, strSize + 1, &bytes_written);
187 utf8_buffer[bytes_written] = '\0';
188 std::string content = std::string(utf8_buffer);
189 return content;
190 }
191
GetAnimatorResult(ani_env * env,ani_object obj)192 static AnimatorResult *GetAnimatorResult(ani_env *env, ani_object obj)
193 {
194 ani_long animatorResultForAni;
195 if (ANI_OK != env->Object_GetFieldByName_Long(obj, "animatorResult", &animatorResultForAni)) {
196 return nullptr;
197 }
198 return reinterpret_cast<AnimatorResult *>(animatorResultForAni);
199 }
200
201 // ani
JSReverse(ani_env * env,ani_object obj)202 static void JSReverse(ani_env *env, ani_object obj)
203 {
204 auto animatorResult = GetAnimatorResult(env, obj);
205 if (animatorResult == nullptr) {
206 return;
207 }
208 // GetMotion
209 if (animatorResult->GetMotion()) {
210 return;
211 }
212 auto animator = animatorResult->GetAnimator();
213 if (!animator) {
214 return;
215 }
216 if (!animator->HasScheduler()) {
217 // AttachSchedulerOnContainer
218 auto result = animator->AttachSchedulerOnContainer();
219 if (!result) {
220 return;
221 }
222 }
223 animator->Reverse();
224 }
225
226 // ani
JSCancel(ani_env * env,ani_object obj)227 static void JSCancel(ani_env *env, ani_object obj)
228 {
229 auto animatorResult = GetAnimatorResult(env, obj);
230 if (animatorResult == nullptr) {
231 return;
232 }
233 auto animator = animatorResult->GetAnimator();
234 if (animator == nullptr) {
235 return;
236 }
237 animator->Cancel();
238 }
239
240 // ani
JSPause(ani_env * env,ani_object obj)241 static void JSPause(ani_env *env, ani_object obj)
242 {
243 auto animatorResult = GetAnimatorResult(env, obj);
244 if (animatorResult == nullptr) {
245 return;
246 }
247 auto animator = animatorResult->GetAnimator();
248 if (animator == nullptr) {
249 return;
250 }
251 animator->Pause();
252 }
253
254 // ani
JSFinish(ani_env * env,ani_object obj)255 static void JSFinish(ani_env *env, ani_object obj)
256 {
257 auto animatorResult = GetAnimatorResult(env, obj);
258 if (animatorResult == nullptr) {
259 return;
260 }
261 auto animator = animatorResult->GetAnimator();
262 if (animator == nullptr) {
263 return;
264 }
265 animator->Finish();
266 }
267
268 // ani
JSPlay(ani_env * env,ani_object obj)269 static void JSPlay(ani_env *env, ani_object obj)
270 {
271 auto animatorResult = GetAnimatorResult(env, obj);
272 if (animatorResult == nullptr) {
273 return;
274 }
275 auto animator = animatorResult->GetAnimator();
276 if (!animator) {
277 return;
278 }
279 if (!animator->HasScheduler()) {
280 auto result = animator->AttachSchedulerOnContainer();
281 if (!result) {
282 return;
283 }
284 }
285 if (animatorResult->GetMotion()) {
286 animator->PlayMotion(animatorResult->GetMotion());
287 } else {
288 animator->Play();
289 }
290 animator->PrintVsyncInfoIfNeed();
291 }
292
ParseAnimatorOption(ani_env * env,ani_object obj,std::shared_ptr<AnimatorOption> option)293 static void ParseAnimatorOption(ani_env *env, ani_object obj, std::shared_ptr<AnimatorOption> option)
294 {
295 ani_double durationAni;
296 ani_double iterationsAni;
297 ani_double delayAni;
298 ani_ref easingAni;
299 ani_ref fillAni;
300 ani_ref directionAni;
301 ani_double beginAni;
302 ani_double endAni;
303
304 env->Object_GetPropertyByName_Double(obj, "duration", &durationAni);
305 env->Object_GetPropertyByName_Double(obj, "iterations", &iterationsAni);
306 env->Object_GetPropertyByName_Double(obj, "delay", &delayAni);
307 env->Object_GetPropertyByName_Double(obj, "begin", &beginAni);
308 env->Object_GetPropertyByName_Double(obj, "end", &endAni);
309 env->Object_GetPropertyByName_Ref(obj, "easing", &easingAni);
310 env->Object_GetPropertyByName_Ref(obj, "fill", &fillAni);
311 env->Object_GetPropertyByName_Ref(obj, "direction", &directionAni);
312 std::string easing = "ease";
313 std::string fill = "none";
314 std::string direction = "normal";
315 easing = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(easingAni));
316 fill = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(fillAni));
317 direction = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(directionAni));
318
319 option->duration = durationAni > 0 ? durationAni : 0;
320 option->iterations = iterationsAni >= -1 ? iterationsAni : 1;
321 option->begin = beginAni;
322 option->delay = delayAni;
323 option->end = endAni;
324 option->easing = easing;
325 option->fill = fill;
326 option->direction = direction;
327 }
328
SetOnfinish(ani_env * env,ani_object object,ani_object callbackObj)329 static void SetOnfinish([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object, ani_object callbackObj)
330 {
331 AnimatorResult *animatorResult = nullptr;
332 animatorResult = GetAnimatorResult(env, object);
333 if (!animatorResult) {
334 return;
335 }
336 auto option = animatorResult->GetAnimatorOption();
337 if (!option) {
338 return;
339 }
340 auto animator = animatorResult->GetAnimator();
341 if (!animator) {
342 return;
343 }
344 ani_ref onfinishRef = reinterpret_cast<ani_ref>(callbackObj);
345 ani_ref onfinishGlobalRef;
346 env->GlobalReference_Create(onfinishRef, &onfinishGlobalRef);
347 animatorResult->SetOnfinishRef(onfinishGlobalRef);
348 animator->ClearStopListeners();
349 animator->AddStopListener([env, onfinishGlobalRef, id = animator->GetId()] {
350 auto fnObj = reinterpret_cast<ani_fn_object>(onfinishGlobalRef);
351 ani_ref result;
352 env->FunctionalObject_Call(fnObj, 0, NULL, &result);
353 });
354 return;
355 }
356
ParseOptionToMotion(const std::shared_ptr<AnimatorOption> & option)357 static RefPtr<Motion> ParseOptionToMotion(const std::shared_ptr<AnimatorOption> &option)
358 {
359 const auto &curveStr = option->easing;
360 if (curveStr.back() != ')') {
361 return nullptr;
362 }
363 std::string::size_type leftEmbracePosition = curveStr.find_last_of('(');
364 if (leftEmbracePosition == std::string::npos) {
365 return nullptr;
366 }
367 auto aniTimFuncName = curveStr.substr(0, leftEmbracePosition);
368 if (aniTimFuncName.compare(INTERPOLATING_SPRING)) {
369 return nullptr;
370 }
371 auto params = curveStr.substr(leftEmbracePosition + 1, curveStr.length() - leftEmbracePosition - 2);
372 std::vector<std::string> paramsVector;
373 StringUtils::StringSplitter(params, ',', paramsVector);
374 if (paramsVector.size() != INTERPOLATING_SPRING_PARAMS_SIZE) {
375 return nullptr;
376 }
377 for (auto ¶m : paramsVector) {
378 OHOS::Ace::Framework::RemoveHeadTailSpace(param);
379 }
380 float velocity = StringUtils::StringToFloat(paramsVector[0]);
381 float mass = StringUtils::StringToFloat(paramsVector[1]);
382 float stiffness = StringUtils::StringToFloat(paramsVector[2]);
383 float damping = StringUtils::StringToFloat(paramsVector[3]);
384
385 // input velocity is normalized velocity, while the velocity of arkui's springMotion is absolute velocity.
386 velocity = velocity * (option->end - option->begin);
387 if (LessOrEqual(mass, 0)) {
388 mass = 1.0f;
389 }
390 if (LessOrEqual(stiffness, 0)) {
391 stiffness = 1.0f;
392 }
393 if (LessOrEqual(damping, 0)) {
394 damping = 1.0f;
395 }
396 return AceType::MakeRefPtr<SpringMotion>(
397 option->begin, option->end, velocity, AceType::MakeRefPtr<SpringProperty>(mass, stiffness, damping));
398 }
399
createDouble(ani_env * env,double value)400 static ani_object createDouble(ani_env *env, double value)
401 {
402 static const char *className = "Lstd/core/Double;";
403 ani_class persion_cls;
404 if (ANI_OK != env->FindClass(className, &persion_cls)) {
405 return nullptr;
406 }
407 ani_method personInfoCtor;
408 if (ANI_OK != env->Class_FindMethod(persion_cls, "<ctor>", "D:V", &personInfoCtor)) {
409 return nullptr;
410 }
411 ani_object personInfoObj;
412 if (ANI_OK != env->Object_New(persion_cls, personInfoCtor, &personInfoObj, ani_double(value))) {
413 return nullptr;
414 }
415 return personInfoObj;
416 }
417
SetOnframe(ani_env * env,ani_object object,ani_object callbackObj)418 static void SetOnframe([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object, ani_object callbackObj)
419 {
420 AnimatorResult *animatorResult = nullptr;
421 animatorResult = GetAnimatorResult(env, object);
422 if (!animatorResult) {
423 return;
424 }
425 auto option = animatorResult->GetAnimatorOption();
426 if (!option) {
427 return;
428 }
429 auto animator = animatorResult->GetAnimator();
430 if (!animator) {
431 return;
432 }
433 animator->ClearInterpolators();
434 ani_ref onframeRef = reinterpret_cast<ani_ref>(callbackObj);
435 ani_ref onframeGlobalRef;
436 env->GlobalReference_Create(onframeRef, &onframeGlobalRef);
437 animatorResult->SetOnframeRef(onframeGlobalRef);
438 auto onFrameCallback = [env,
439 onframeGlobalRef,
440 id = animator->GetId(),
441 weakOption = std::weak_ptr<AnimatorOption>(animatorResult->GetAnimatorOption())](
442 double value) {
443 auto fnObj = reinterpret_cast<ani_fn_object>(onframeGlobalRef);
444 auto option = weakOption.lock();
445 auto args = createDouble(env, value);
446 if (args == nullptr) {
447 return;
448 }
449 ani_ref result;
450 auto obj = reinterpret_cast<ani_ref>(args);
451 std::vector<ani_ref> tmp = {reinterpret_cast<ani_ref>(obj)};
452 env->FunctionalObject_Call(fnObj, tmp.size(), tmp.data(), &result);
453 };
454 RefPtr<Animation<double>> animation;
455 RefPtr<Motion> motion = ParseOptionToMotion(option);
456 if (motion) {
457 motion->AddListener(onFrameCallback);
458 animatorResult->SetMotion(motion);
459 } else {
460 auto curve = OHOS::Ace::Framework::CreateCurve(option->easing);
461 animation = AceType::MakeRefPtr<CurveAnimation<double>>(option->begin, option->end, curve);
462 animation->AddListener(onFrameCallback);
463 animator->AddInterpolator(animation);
464 animatorResult->SetMotion(nullptr);
465 }
466 if (!animator->HasScheduler()) {
467 animator->AttachSchedulerOnContainer();
468 }
469 return;
470 }
471
SetOncancel(ani_env * env,ani_object object,ani_object callbackObj)472 static void SetOncancel([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object, ani_object callbackObj)
473 {
474 AnimatorResult *animatorResult = nullptr;
475 animatorResult = GetAnimatorResult(env, object);
476 if (!animatorResult) {
477 return;
478 }
479 auto option = animatorResult->GetAnimatorOption();
480 if (!option) {
481 return;
482 }
483 auto animator = animatorResult->GetAnimator();
484 if (!animator) {
485 return;
486 }
487 ani_ref oncancelRef = reinterpret_cast<ani_ref>(callbackObj);
488 ani_ref oncancelGlobalRef;
489 env->GlobalReference_Create(oncancelRef, &oncancelGlobalRef);
490 animatorResult->SetOncancelRef(oncancelGlobalRef);
491 animator->ClearIdleListeners();
492 animator->AddIdleListener([env, oncancelGlobalRef] {
493 auto fnObj = reinterpret_cast<ani_fn_object>(oncancelGlobalRef);
494 ani_ref result;
495 env->FunctionalObject_Call(fnObj, 0, NULL, &result);
496 });
497 return;
498 }
499
SetOnrepeat(ani_env * env,ani_object object,ani_object callbackObj)500 static void SetOnrepeat([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object, ani_object callbackObj)
501 {
502 AnimatorResult *animatorResult = nullptr;
503 animatorResult = GetAnimatorResult(env, object);
504 if (!animatorResult) {
505 return;
506 }
507 auto option = animatorResult->GetAnimatorOption();
508 if (!option) {
509 return;
510 }
511 auto animator = animatorResult->GetAnimator();
512 if (!animator) {
513 return;
514 }
515
516 ani_ref onrepeatRef = reinterpret_cast<ani_ref>(callbackObj);
517 ani_ref onrepeatGlobalRef;
518 env->GlobalReference_Create(onrepeatRef, &onrepeatGlobalRef);
519 animatorResult->SetOnrepeatRef(onrepeatGlobalRef);
520 animator->ClearRepeatListeners();
521 animator->AddRepeatListener([env, onrepeatGlobalRef] {
522 auto fnObj = reinterpret_cast<ani_fn_object>(onrepeatGlobalRef);
523 ani_ref result;
524 env->FunctionalObject_Call(fnObj, 0, NULL, &result);
525 });
526 return;
527 }
528
ParseExpectedFrameRateRange(ani_env * env,ani_object objOption,FrameRateRange & frameRateRange)529 void ParseExpectedFrameRateRange(ani_env *env, ani_object objOption,
530 FrameRateRange& frameRateRange)
531 {
532 static const char *className = "L@ohos/arkui/component/Common/ExpectedFrameRateRange;";
533 ani_class cls;
534 if (ANI_OK != env->FindClass(className, &cls)) {
535 return;
536 }
537
538 ani_boolean isInstance;
539 if (ANI_OK != env->Object_InstanceOf(objOption, cls, &isInstance)) {
540 return;
541 }
542
543 int32_t minFPS = 0;
544 int32_t maxFPS = 0;
545 int32_t expectedFPS = 0;
546
547 ani_double minAni;
548 ani_double maxAni;
549 ani_double expectedAni;
550 env->Object_GetPropertyByName_Double(objOption, "min", &minAni);
551 env->Object_GetPropertyByName_Double(objOption, "max", &maxAni);
552 env->Object_GetPropertyByName_Double(objOption, "expected", &expectedAni);
553
554 minFPS = static_cast<int32_t>(minAni);
555 maxFPS = static_cast<int32_t>(maxAni);
556 expectedFPS = static_cast<int32_t>(expectedAni);
557 frameRateRange.Set(minFPS, maxFPS, expectedFPS);
558 }
559
560 // ani
JSSetExpectedFrameRateRange(ani_env * env,ani_object obj,ani_object objOption)561 static void JSSetExpectedFrameRateRange(ani_env *env, ani_object obj, ani_object objOption)
562 {
563 auto animatorResult = GetAnimatorResult(env, obj);
564 if (animatorResult == nullptr) {
565 return;
566 }
567 auto animator = animatorResult->GetAnimator();
568 if (!animator) {
569 return;
570 }
571 if (!animator->HasScheduler()) {
572 auto result = animator->AttachSchedulerOnContainer();
573 if (!result) {
574 return;
575 }
576 }
577 FrameRateRange frameRateRange;
578 ParseExpectedFrameRateRange(env, objOption, frameRateRange);
579 animator->SetExpectedFrameRateRange(frameRateRange);
580 }
581
ANICreate(ani_env * env,ani_object object,ani_object aniOption)582 ani_object ANICreate(ani_env *env, [[maybe_unused]] ani_object object, [[maybe_unused]] ani_object aniOption)
583 {
584 ani_object animator_obj = {};
585 static const char *className = "L@ohos/animator/AnimatorResultInner;";
586 ani_class cls;
587 if (ANI_OK != env->FindClass(className, &cls)) {
588 TAG_LOGI(AceLogTag::ACE_ANIMATION, "[ANI] find class fail");
589 return animator_obj;
590 }
591
592 ani_method ctor;
593 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
594 TAG_LOGI(AceLogTag::ACE_ANIMATION, "[ANI] find method fail");
595 return animator_obj;
596 }
597
598 // create animatot and construct animatorResult
599 auto option = std::make_shared<AnimatorOption>();
600 ParseAnimatorOption(env, aniOption, option);
601 TAG_LOGI(AceLogTag::ACE_ANIMATION, "[ANI] option is %{public}s", option->ToString().c_str());
602 auto animator = CREATE_ANIMATOR("ohos.animator");
603 animator->AttachSchedulerOnContainer();
604 auto animatorResult = new AnimatorResult(animator, option);
605
606 // bind end with front object
607 if (ANI_OK != env->Object_New(cls, ctor, &animator_obj, reinterpret_cast<ani_long>(animatorResult))) {
608 TAG_LOGI(AceLogTag::ACE_ANIMATION, "[ANI] create animatorResult fail");
609 return animator_obj;
610 }
611
612 return animator_obj;
613 }
614
ANIReset(ani_env * env,ani_object object,ani_object options)615 static void ANIReset(ani_env *env, [[maybe_unused]] ani_object object, [[maybe_unused]] ani_object options)
616 {
617 AnimatorResult *animatorResult = nullptr;
618 animatorResult = GetAnimatorResult(env, object);
619 if (!animatorResult) {
620 return;
621 }
622 auto option = std::make_shared<AnimatorOption>();
623 ParseAnimatorOption(env, options, option);
624 auto animator = animatorResult->GetAnimator();
625 if (!animator) {
626 return;
627 }
628 animator->ClearInterpolators();
629 animator->ResetIsReverse();
630 animatorResult->ApplyOption();
631 ani_ref onframeRef = animatorResult->GetOnframeRef();
632 if (onframeRef) {
633 auto onFrameCallback = [env, onframeRef, id = animator->GetId()](double value) {
634 auto fnObj = reinterpret_cast<ani_fn_object>(onframeRef);
635 auto args = createDouble(env, value);
636 if (args == nullptr) {
637 return;
638 }
639 ani_ref result;
640 auto obj = reinterpret_cast<ani_ref>(args);
641 std::vector<ani_ref> tmp = {reinterpret_cast<ani_ref>(obj)};
642 env->FunctionalObject_Call(fnObj, tmp.size(), tmp.data(), &result);
643 };
644 RefPtr<Animation<double>> animation;
645 RefPtr<Motion> motion = ParseOptionToMotion(option);
646 if (motion) {
647 motion->AddListener(onFrameCallback);
648 animatorResult->SetMotion(motion);
649 } else {
650 auto curve = Framework::CreateCurve(option->easing);
651 animation = AceType::MakeRefPtr<CurveAnimation<double>>(option->begin, option->end, curve);
652 animation->AddListener(onFrameCallback);
653 animator->AddInterpolator(animation);
654 animatorResult->SetMotion(nullptr);
655 }
656 }
657 return;
658 }
659
ANIUpdate(ani_env * env,ani_object object,ani_object options)660 static void ANIUpdate(ani_env *env, [[maybe_unused]] ani_object object, [[maybe_unused]] ani_object options)
661 {
662 ANIReset(env, object, options);
663 }
664
BindAnimator(ani_env * env)665 ani_status BindAnimator(ani_env *env)
666 {
667 static const char *className = "L@ohos/animator/Animator;";
668 ani_class cls;
669 if (ANI_OK != env->FindClass(className, &cls)) {
670 TAG_LOGI(AceLogTag::ACE_ANIMATION, "[ANI] Bind Animator fail");
671 return ANI_ERROR;
672 }
673
674 std::array methods = {
675 ani_native_function{"create",
676 "L@ohos/animator/AnimatorOptions;:L@ohos/animator/AnimatorResult;",
677 reinterpret_cast<void *>(ANICreate)},
678 };
679
680 if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) {
681 TAG_LOGI(AceLogTag::ACE_ANIMATION, "[ANI] Bind Animator method fail");
682 return ANI_ERROR;
683 };
684 return ANI_OK;
685 }
686
BindAnimatorResult(ani_env * env)687 ani_status BindAnimatorResult(ani_env *env)
688 {
689 static const char *className = "L@ohos/animator/AnimatorResultInner;";
690 ani_class cls;
691 if (ANI_OK != env->FindClass(className, &cls)) {
692 TAG_LOGI(AceLogTag::ACE_ANIMATION, "[ANI] bind animator result fail");
693 return ANI_ERROR;
694 }
695
696 std::array methods = {
697 ani_native_function{"play", ":V", reinterpret_cast<void *>(JSPlay)},
698 ani_native_function{"reverse", ":V", reinterpret_cast<void *>(JSReverse)},
699 ani_native_function{"cancel", ":V", reinterpret_cast<void *>(JSCancel)},
700 ani_native_function{"pause", ":V", reinterpret_cast<void *>(JSPause)},
701 ani_native_function{"finish", ":V", reinterpret_cast<void *>(JSFinish)},
702 ani_native_function{"setOnFinish", nullptr, reinterpret_cast<void *>(SetOnfinish)},
703 ani_native_function{"setOnCancel", nullptr, reinterpret_cast<void *>(SetOncancel)},
704 ani_native_function{"setOnRepeat", nullptr, reinterpret_cast<void *>(SetOnrepeat)},
705 ani_native_function{"setOnFrame", nullptr, reinterpret_cast<void *>(SetOnframe)},
706 ani_native_function{"update", "L@ohos/animator/AnimatorOptions;:V", reinterpret_cast<void *>(ANIUpdate)},
707 ani_native_function{"reset", "L@ohos/animator/AnimatorOptions;:V", reinterpret_cast<void *>(ANIReset)},
708 ani_native_function{"setExpectedFrameRateRange", nullptr,
709 reinterpret_cast<void *>(JSSetExpectedFrameRateRange)},
710 };
711
712 if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) {
713 TAG_LOGI(AceLogTag::ACE_ANIMATION, "[ANI] bind native method fail");
714 return ANI_ERROR;
715 };
716 return ANI_OK;
717 }
718 } // namespace OHOS::Ace::Ani
719
ANI_Constructor(ani_vm * vm,uint32_t * result)720 ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
721 {
722 ani_env *env;
723 if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
724 return ANI_ERROR;
725 }
726
727 // bind Animator class.
728 ani_status retBindAnimator = OHOS::Ace::Ani::BindAnimator(env);
729 if (retBindAnimator != ANI_OK) {
730 TAG_LOGI(OHOS::Ace::AceLogTag::ACE_ANIMATION, "[ANI] BindAnimator fail");
731 return retBindAnimator;
732 }
733 ani_status retBindResult = OHOS::Ace::Ani::BindAnimatorResult(env);
734 if (retBindResult != ANI_OK) {
735 TAG_LOGI(OHOS::Ace::AceLogTag::ACE_ANIMATION, "[ANI] BindAnimatorResult fail");
736 return retBindResult;
737 }
738
739 *result = ANI_VERSION_1;
740 return ANI_OK;
741 }
742