1 /*
2 * Copyright (c) 2022-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
17 #include "animator_option.h"
18 #include "interfaces/napi/kits/utils/napi_utils.h"
19 #include "base/thread/frame_trace_adapter.h"
20
21 namespace OHOS::Ace::Napi {
22
23 namespace {
24 constexpr size_t INTERPOLATING_SPRING_PARAMS_SIZE = 4;
25 constexpr char INTERPOLATING_SPRING[] = "interpolating-spring";
26 constexpr size_t SIMPLEANIMATOR_CONSTRUCTOR_PARAMS_SIZE = 2;
27 constexpr float ANIMATOR_DEFALUT_BEGIN = 0.0f;
28 constexpr float ANIMATOR_DEFALUT_END = 1.0f;
29 constexpr int32_t ANIMATOR_DEFALUT_DURATION = 1000;
30 const std::string ANIMATOR_DEFALUT_EASING = "ease";
31 constexpr int32_t ANIMATOR_DEFALUT_DELAY = 0;
32 constexpr int32_t ANIMATOR_DEFALUT_ITERATIONS = 1;
33 const std::string ANIMATOR_FILLMODE_FORWARDS = "forwards";
34 const std::string ANIMATOR_FILLMODE_NONE = "none";
35 const std::string ANIMATOR_FILLMODE_BACKWARDS = "backwards";
36 const std::string ANIMATOR_FILLMODE_BOTH = "both";
37 const std::string ANIMATOR_DIRECTION_NORMAL = "normal";
38 const std::string ANIMATOR_DIRECTION_ALTERNATE = "alternate";
39 const std::string ANIMATOR_DIRECTION_REVERSE = "reverse";
40 const std::string ANIMATOR_DIRECTION_ALTERNATE_REVERSE = "alternate-reverse";
41 const std::string ANIMATOR_SIMPLE_ANIMATOR_OPTIONS_NAME = "SimpleAnimatorOptions";
42 } // namespace
43
ParseString(napi_env env,napi_value propertyNapi,std::string & property)44 static void ParseString(napi_env env, napi_value propertyNapi, std::string& property)
45 {
46 if (propertyNapi != nullptr) {
47 napi_valuetype valueType = napi_undefined;
48 napi_typeof(env, propertyNapi, &valueType);
49 if (valueType == napi_undefined) {
50 NapiThrow(env, "Required input parameters are missing.", ERROR_CODE_PARAM_INVALID);
51 return;
52 } else if (valueType != napi_string) {
53 NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
54 return;
55 }
56
57 size_t buffSize = 0;
58 napi_status status = napi_get_value_string_utf8(env, propertyNapi, nullptr, 0, &buffSize);
59 if (status != napi_ok || buffSize == 0) {
60 return;
61 }
62 std::unique_ptr<char[]> propertyString = std::make_unique<char[]>(buffSize + 1);
63 size_t retLen = 0;
64 napi_get_value_string_utf8(env, propertyNapi, propertyString.get(), buffSize + 1, &retLen);
65 property = propertyString.get();
66 }
67 }
68
ParseInt(napi_env env,napi_value propertyNapi,int32_t & property)69 static void ParseInt(napi_env env, napi_value propertyNapi, int32_t& property)
70 {
71 if (propertyNapi != nullptr) {
72 napi_valuetype valueType = napi_undefined;
73 napi_typeof(env, propertyNapi, &valueType);
74 if (valueType == napi_undefined) {
75 NapiThrow(env, "Required input parameters are missing.", ERROR_CODE_PARAM_INVALID);
76 return;
77 } else if (valueType != napi_number) {
78 NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
79 return;
80 }
81 napi_get_value_int32(env, propertyNapi, &property);
82 }
83 }
84
ParseDouble(napi_env env,napi_value propertyNapi,double & property)85 static void ParseDouble(napi_env env, napi_value propertyNapi, double& property)
86 {
87 if (propertyNapi != nullptr) {
88 napi_valuetype valueType = napi_undefined;
89 napi_typeof(env, propertyNapi, &valueType);
90 if (valueType == napi_undefined) {
91 NapiThrow(env, "Required input parameters are missing.", ERROR_CODE_PARAM_INVALID);
92 return;
93 } else if (valueType != napi_number) {
94 NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
95 return;
96 }
97 napi_get_value_double(env, propertyNapi, &property);
98 }
99 }
100
StringToFillMode(const std::string & fillMode)101 static FillMode StringToFillMode(const std::string& fillMode)
102 {
103 if (fillMode.compare("forwards") == 0) {
104 return FillMode::FORWARDS;
105 } else if (fillMode.compare("backwards") == 0) {
106 return FillMode::BACKWARDS;
107 } else if (fillMode.compare("both") == 0) {
108 return FillMode::BOTH;
109 } else {
110 return FillMode::NONE;
111 }
112 }
113
StringToAnimationDirection(const std::string & direction)114 static AnimationDirection StringToAnimationDirection(const std::string& direction)
115 {
116 if (direction.compare("alternate") == 0) {
117 return AnimationDirection::ALTERNATE;
118 } else if (direction.compare("reverse") == 0) {
119 return AnimationDirection::REVERSE;
120 } else if (direction.compare("alternate-reverse") == 0) {
121 return AnimationDirection::ALTERNATE_REVERSE;
122 } else {
123 return AnimationDirection::NORMAL;
124 }
125 }
126
ParseOptionToMotion(const std::shared_ptr<AnimatorOption> & option)127 static RefPtr<Motion> ParseOptionToMotion(const std::shared_ptr<AnimatorOption>& option)
128 {
129 const auto& curveStr = option->easing;
130 if (curveStr.back() != ')') {
131 return nullptr;
132 }
133 std::string::size_type leftEmbracePosition = curveStr.find_last_of('(');
134 if (leftEmbracePosition == std::string::npos) {
135 return nullptr;
136 }
137 auto aniTimFuncName = curveStr.substr(0, leftEmbracePosition);
138 if (aniTimFuncName.compare(INTERPOLATING_SPRING)) {
139 return nullptr;
140 }
141 auto params = curveStr.substr(leftEmbracePosition + 1, curveStr.length() - leftEmbracePosition - 2);
142 std::vector<std::string> paramsVector;
143 StringUtils::StringSplitter(params, ',', paramsVector);
144 if (paramsVector.size() != INTERPOLATING_SPRING_PARAMS_SIZE) {
145 return nullptr;
146 }
147 for (auto& param : paramsVector) {
148 Framework::RemoveHeadTailSpace(param);
149 }
150 float velocity = StringUtils::StringToFloat(paramsVector[0]);
151 float mass = StringUtils::StringToFloat(paramsVector[1]);
152 float stiffness = StringUtils::StringToFloat(paramsVector[2]);
153 float damping = StringUtils::StringToFloat(paramsVector[3]);
154 // input velocity is normalized velocity, while the velocity of arkui's springMotion is absolute velocity.
155 velocity = velocity * (option->end - option->begin);
156 if (LessOrEqual(mass, 0)) {
157 mass = 1.0f;
158 }
159 if (LessOrEqual(stiffness, 0)) {
160 stiffness = 1.0f;
161 }
162 if (LessOrEqual(damping, 0)) {
163 damping = 1.0f;
164 }
165 return AceType::MakeRefPtr<SpringMotion>(
166 option->begin, option->end, velocity, AceType::MakeRefPtr<SpringProperty>(mass, stiffness, damping));
167 }
168
GetNapiCallbackInfoAndThis(napi_env env,napi_callback_info info)169 void* GetNapiCallbackInfoAndThis(napi_env env, napi_callback_info info)
170 {
171 napi_value value = nullptr;
172 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &value, nullptr);
173 if (status != napi_ok) {
174 return nullptr;
175 }
176 void* result = nullptr;
177 status = napi_unwrap(env, value, &result);
178 if (status != napi_ok) {
179 return nullptr;
180 }
181 return result;
182 }
183
FillModeToString(const FillMode & fillMode)184 std::string FillModeToString(const FillMode& fillMode)
185 {
186 if (fillMode == FillMode::NONE) {
187 return ANIMATOR_FILLMODE_NONE;
188 } else if (fillMode == FillMode::BACKWARDS) {
189 return ANIMATOR_FILLMODE_BACKWARDS;
190 } else if (fillMode == FillMode::BOTH) {
191 return ANIMATOR_FILLMODE_BOTH;
192 } else {
193 return ANIMATOR_FILLMODE_FORWARDS;
194 }
195 }
196
AnimationDirectionToString(const AnimationDirection & direction)197 std::string AnimationDirectionToString(const AnimationDirection& direction)
198 {
199 if (direction == AnimationDirection::ALTERNATE) {
200 return ANIMATOR_DIRECTION_ALTERNATE;
201 } else if (direction == AnimationDirection::REVERSE) {
202 return ANIMATOR_DIRECTION_REVERSE;
203 } else if (direction == AnimationDirection::ALTERNATE_REVERSE) {
204 return ANIMATOR_DIRECTION_ALTERNATE_REVERSE;
205 } else {
206 return ANIMATOR_DIRECTION_NORMAL;
207 }
208 }
209
IsSimpleAnimatorOptions(napi_env env,napi_value argv)210 bool IsSimpleAnimatorOptions(napi_env env, napi_value argv)
211 {
212 bool isSimpleOption = false;
213 napi_value constructorName = nullptr;
214 napi_get_named_property(env, argv, "constructor", &constructorName);
215 napi_value name = nullptr;
216 napi_get_named_property(env, constructorName, "name", &name);
217
218 napi_valuetype valueType = napi_undefined;
219 napi_typeof(env, name, &valueType);
220 if (valueType == napi_string) {
221 std::string strName = "";
222 ParseString(env, name, strName);
223 if (strName == ANIMATOR_SIMPLE_ANIMATOR_OPTIONS_NAME) {
224 isSimpleOption = true;
225 }
226 }
227 return isSimpleOption;
228 }
229
SetSimpleAnimatorOptions(napi_env env,napi_value argv,std::shared_ptr<AnimatorOption> & option)230 void SetSimpleAnimatorOptions(napi_env env, napi_value argv, std::shared_ptr<AnimatorOption>& option)
231 {
232 void* result = nullptr;
233 napi_unwrap(env, argv, &result);
234 JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(result);
235 if (me == nullptr) {
236 return;
237 }
238 option->begin = me->GetBegin();
239 option->end = me->GetEnd();
240 option->duration = me->GetDuration().has_value() ? me->GetDuration().value() : ANIMATOR_DEFALUT_DURATION;
241 option->easing = me->GetEasing().has_value() ? me->GetEasing().value() : ANIMATOR_DEFALUT_EASING;
242 option->delay = me->GetDelay().has_value() ? me->GetDelay().value() : ANIMATOR_DEFALUT_DELAY;
243 option->fill = me->GetFill().has_value() ? FillModeToString(me->GetFill().value()) : ANIMATOR_FILLMODE_FORWARDS;
244 option->direction = me->GetDirection().has_value() ? AnimationDirectionToString(me->GetDirection().value())
245 : ANIMATOR_DIRECTION_NORMAL;
246 option->iterations = me->GetIterations().has_value() ? me->GetIterations().value() : ANIMATOR_DEFALUT_ITERATIONS;
247 }
248
ParseAnimatorOption(napi_env env,napi_callback_info info,std::shared_ptr<AnimatorOption> & option)249 static void ParseAnimatorOption(napi_env env, napi_callback_info info, std::shared_ptr<AnimatorOption>& option)
250 {
251 size_t argc = 1;
252 napi_value argv;
253 napi_get_cb_info(env, info, &argc, &argv, NULL, NULL);
254 if (argc != 1) {
255 NapiThrow(env, "The number of parameters must be equal to 1.", ERROR_CODE_PARAM_INVALID);
256 return;
257 }
258 if (IsSimpleAnimatorOptions(env, argv)) {
259 SetSimpleAnimatorOptions(env, argv, option);
260 return;
261 }
262 napi_value durationNapi = nullptr;
263 napi_value easingNapi = nullptr;
264 napi_value delayNapi = nullptr;
265 napi_value fillNapi = nullptr;
266 napi_value directionNapi = nullptr;
267 napi_value iterationsNapi = nullptr;
268 napi_value beginNapi = nullptr;
269 napi_value endNapi = nullptr;
270 napi_valuetype valueType = napi_undefined;
271 napi_typeof(env, argv, &valueType);
272 if (valueType == napi_object) {
273 napi_get_named_property(env, argv, "duration", &durationNapi);
274 napi_get_named_property(env, argv, "easing", &easingNapi);
275 napi_get_named_property(env, argv, "delay", &delayNapi);
276 napi_get_named_property(env, argv, "fill", &fillNapi);
277 napi_get_named_property(env, argv, "direction", &directionNapi);
278 napi_get_named_property(env, argv, "iterations", &iterationsNapi);
279 napi_get_named_property(env, argv, "begin", &beginNapi);
280 napi_get_named_property(env, argv, "end", &endNapi);
281 } else {
282 NapiThrow(env, "The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
283 return;
284 }
285
286 int32_t duration = 0;
287 int32_t delay = 0;
288 int32_t iterations = 0;
289 double begin = 0.0;
290 double end = 0.0;
291 std::string easing = "ease";
292 std::string fill = "none";
293 std::string direction = "normal";
294 ParseString(env, easingNapi, easing);
295 ParseString(env, fillNapi, fill);
296 ParseString(env, directionNapi, direction);
297 ParseInt(env, durationNapi, duration);
298 ParseInt(env, delayNapi, delay);
299 ParseInt(env, iterationsNapi, iterations);
300 ParseDouble(env, beginNapi, begin);
301 ParseDouble(env, endNapi, end);
302 option->duration = std::max(duration, 0);
303 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
304 option->delay = delay;
305 } else {
306 option->delay = std::max(delay, 0);
307 }
308 option->iterations = iterations >= -1 ? iterations : 1;
309 option->begin = begin;
310 option->end = end;
311 option->easing = easing;
312 option->fill = fill;
313 option->direction = direction;
314 }
315
GetAnimatorResult(napi_env env,napi_callback_info info)316 static AnimatorResult* GetAnimatorResult(napi_env env, napi_callback_info info)
317 {
318 AnimatorResult* animatorResult = nullptr;
319 napi_value thisVar;
320 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
321 napi_unwrap(env, thisVar, reinterpret_cast<void**>(&animatorResult));
322 return animatorResult;
323 }
324
GetAnimatorInResult(napi_env env,napi_callback_info info)325 static RefPtr<Animator> GetAnimatorInResult(napi_env env, napi_callback_info info)
326 {
327 AnimatorResult* animatorResult = GetAnimatorResult(env, info);
328 if (!animatorResult) {
329 return nullptr;
330 }
331 return animatorResult->GetAnimator();
332 }
333
JSReset(napi_env env,napi_callback_info info)334 static napi_value JSReset(napi_env env, napi_callback_info info)
335 {
336 AnimatorResult* animatorResult = nullptr;
337 napi_value thisVar;
338 napi_get_cb_info(env, info, NULL, NULL, &thisVar, NULL);
339 napi_unwrap(env, thisVar, (void**)&animatorResult);
340 if (!animatorResult) {
341 NapiThrow(env, "Internal error. Unwrap animator result is failed.", ERROR_CODE_INTERNAL_ERROR);
342 return nullptr;
343 }
344 auto option = animatorResult->GetAnimatorOption();
345 if (!option) {
346 NapiThrow(env, "Internal error. Option is null in AnimatorResult.", ERROR_CODE_INTERNAL_ERROR);
347 return nullptr;
348 }
349 ParseAnimatorOption(env, info, option);
350 auto animator = animatorResult->GetAnimator();
351 if (!animator) {
352 NapiThrow(env, "Internal error. Animator is null in AnimatorResult.", ERROR_CODE_INTERNAL_ERROR);
353 return nullptr;
354 }
355 TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator reset, id:%{public}d", animator->GetId());
356 animator->ClearInterpolators();
357 animator->ResetIsReverse();
358 animatorResult->ApplyOption();
359 napi_ref onframeRef = animatorResult->GetOnframeRef();
360 if (onframeRef) {
361 auto onFrameCallback = [env, onframeRef, id = animator->GetId(),
362 weakOption = std::weak_ptr<AnimatorOption>(animatorResult->GetAnimatorOption())](
363 double value) {
364 napi_handle_scope scope = nullptr;
365 napi_open_handle_scope(env, &scope);
366 if (scope == nullptr) {
367 TAG_LOGW(
368 AceLogTag::ACE_ANIMATION, "ohos.animator call onFrame failed, scope is null, id:%{public}d", id);
369 return;
370 }
371 napi_value ret = nullptr;
372 napi_value valueNapi = nullptr;
373 napi_value onframe = nullptr;
374 auto result = napi_get_reference_value(env, onframeRef, &onframe);
375 auto option = weakOption.lock();
376 if (!(result == napi_ok && onframe && option)) {
377 TAG_LOGW(AceLogTag::ACE_ANIMATION,
378 "ohos.animator call onFrame failed, get reference result:%{public}d, id:%{public}d",
379 result == napi_ok, id);
380 napi_close_handle_scope(env, scope);
381 return;
382 }
383 ACE_SCOPED_TRACE(
384 "ohos.animator onframe. duration:%d, curve:%s, id:%d", option->duration, option->easing.c_str(), id);
385 napi_create_double(env, value, &valueNapi);
386 napi_call_function(env, nullptr, onframe, 1, &valueNapi, &ret);
387 napi_close_handle_scope(env, scope);
388 };
389 RefPtr<Animation<double>> animation;
390 RefPtr<Motion> motion = ParseOptionToMotion(option);
391 if (motion) {
392 motion->AddListener(onFrameCallback);
393 animatorResult->SetMotion(motion);
394 } else {
395 auto curve = Framework::CreateCurve(option->easing);
396 animation = AceType::MakeRefPtr<CurveAnimation<double>>(option->begin, option->end, curve);
397 animation->AddListener(onFrameCallback);
398 animator->AddInterpolator(animation);
399 animatorResult->SetMotion(nullptr);
400 }
401 }
402 napi_value result;
403 napi_get_null(env, &result);
404 return result;
405 }
406
407 // since API 9 deprecated
JSUpdate(napi_env env,napi_callback_info info)408 static napi_value JSUpdate(napi_env env, napi_callback_info info)
409 {
410 return JSReset(env, info);
411 }
412
JSPlay(napi_env env,napi_callback_info info)413 static napi_value JSPlay(napi_env env, napi_callback_info info)
414 {
415 FrameTraceAdapter* ft = FrameTraceAdapter::GetInstance();
416 if (ft != nullptr) {
417 ft->SetFrameTraceLimit();
418 }
419 auto animatorResult = GetAnimatorResult(env, info);
420 if (!animatorResult) {
421 TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: cannot find animator result when call play");
422 return nullptr;
423 }
424 auto animator = animatorResult->GetAnimator();
425 if (!animator) {
426 TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: no animator is created when call play");
427 return nullptr;
428 }
429 if (!animator->HasScheduler()) {
430 auto result = animator->AttachSchedulerOnContainer();
431 if (!result) {
432 TAG_LOGW(AceLogTag::ACE_ANIMATION,
433 "ohos.animator: play failed, animator is not bound to specific context, use uiContext.createAnimator "
434 "instead, id:%{public}d",
435 animator->GetId());
436 return nullptr;
437 }
438 }
439 TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator play, id:%{public}d, %{public}s",
440 animator->GetId(), animatorResult->GetAnimatorOption()->ToString().c_str());
441 if (animatorResult->GetMotion()) {
442 animator->PlayMotion(animatorResult->GetMotion());
443 } else {
444 animator->Play();
445 }
446 animator->PrintVsyncInfoIfNeed();
447 napi_value result = nullptr;
448 napi_get_null(env, &result);
449 return result;
450 }
451
JSFinish(napi_env env,napi_callback_info info)452 static napi_value JSFinish(napi_env env, napi_callback_info info)
453 {
454 auto animator = GetAnimatorInResult(env, info);
455 if (!animator) {
456 return nullptr;
457 }
458 TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator finish, id:%{public}d", animator->GetId());
459 animator->Finish();
460 napi_value result = nullptr;
461 napi_get_null(env, &result);
462 return result;
463 }
464
JSPause(napi_env env,napi_callback_info info)465 static napi_value JSPause(napi_env env, napi_callback_info info)
466 {
467 auto animator = GetAnimatorInResult(env, info);
468 if (!animator) {
469 return nullptr;
470 }
471 TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator pause, id:%{public}d", animator->GetId());
472 animator->Pause();
473 napi_value result;
474 napi_get_null(env, &result);
475 return result;
476 }
477
JSCancel(napi_env env,napi_callback_info info)478 static napi_value JSCancel(napi_env env, napi_callback_info info)
479 {
480 auto animator = GetAnimatorInResult(env, info);
481 if (!animator) {
482 return nullptr;
483 }
484 TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator cancel, id:%{public}d", animator->GetId());
485 animator->Cancel();
486 napi_value result;
487 napi_get_null(env, &result);
488 return result;
489 }
490
JSReverse(napi_env env,napi_callback_info info)491 static napi_value JSReverse(napi_env env, napi_callback_info info)
492 {
493 auto animatorResult = GetAnimatorResult(env, info);
494 if (!animatorResult) {
495 TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: cannot find animator result when call reverse");
496 return nullptr;
497 }
498 if (animatorResult->GetMotion()) {
499 TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: interpolatingSpringCurve, cannot reverse");
500 return nullptr;
501 }
502 auto animator = animatorResult->GetAnimator();
503 if (!animator) {
504 TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: no animator is created when call reverse");
505 return nullptr;
506 }
507 if (!animator->HasScheduler()) {
508 auto result = animator->AttachSchedulerOnContainer();
509 if (!result) {
510 TAG_LOGW(AceLogTag::ACE_ANIMATION,
511 "ohos.animator: reverse failed, animator is not bound to specific context, use "
512 "uiContext.createAnimator instead, id:%{public}d",
513 animator->GetId());
514 return nullptr;
515 }
516 }
517 TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator reverse, id:%{public}d", animator->GetId());
518 animator->Reverse();
519 napi_value result;
520 napi_get_null(env, &result);
521 return result;
522 }
523
ParseJsValue(napi_env env,napi_value jsObject,const std::string & name,int32_t & data)524 static bool ParseJsValue(napi_env env, napi_value jsObject, const std::string& name, int32_t& data)
525 {
526 napi_value value = nullptr;
527 napi_get_named_property(env, jsObject, name.c_str(), &value);
528 napi_valuetype type = napi_undefined;
529 napi_typeof(env, value, &type);
530 if (type == napi_number) {
531 napi_get_value_int32(env, value, &data);
532 return true;
533 } else {
534 return false;
535 }
536 return true;
537 }
538
ParseExpectedFrameRateRange(napi_env env,napi_callback_info info,FrameRateRange & frameRateRange)539 static napi_value ParseExpectedFrameRateRange(napi_env env, napi_callback_info info, FrameRateRange& frameRateRange)
540 {
541 size_t argc = 1;
542 napi_value argv[1];
543 napi_value thisVar = nullptr;
544 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
545 if (argc != 1) {
546 NapiThrow(env, "The number of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
547 return nullptr;
548 }
549
550 napi_value& nativeObj = argv[0];
551 if (nativeObj == nullptr) {
552 NapiThrow(env, "The nativeObj is nullptr.", ERROR_CODE_PARAM_INVALID);
553 return nullptr;
554 }
555
556 int32_t minFPS = 0;
557 int32_t maxFPS = 0;
558 int32_t expectedFPS = 0;
559 ParseJsValue(env, nativeObj, "min", minFPS);
560 ParseJsValue(env, nativeObj, "max", maxFPS);
561 ParseJsValue(env, nativeObj, "expected", expectedFPS);
562
563 frameRateRange.Set(minFPS, maxFPS, expectedFPS);
564 if (!frameRateRange.IsValid()) {
565 NapiThrow(env, "ExpectedFrameRateRange Error", ERROR_CODE_PARAM_INVALID);
566 return nullptr;
567 }
568 return nullptr;
569 }
570
JSSetExpectedFrameRateRange(napi_env env,napi_callback_info info)571 static napi_value JSSetExpectedFrameRateRange(napi_env env, napi_callback_info info)
572 {
573 auto animatorResult = GetAnimatorResult(env, info);
574 if (!animatorResult) {
575 TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: cannot find animator when call SetExpectedFrameRateRange");
576 return nullptr;
577 }
578 auto animator = animatorResult->GetAnimator();
579 if (!animator) {
580 TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator: no animator is created when call SetExpectedFrameRateRange");
581 return nullptr;
582 }
583 if (!animator->HasScheduler()) {
584 auto result = animator->AttachSchedulerOnContainer();
585 if (!result) {
586 TAG_LOGW(AceLogTag::ACE_ANIMATION,
587 "ohos.animator: SetExpectedFrameRateRange failed because animator is not bound to specific context, "
588 "use uiContext.createAnimator instead, id:%{public}d",
589 animator->GetId());
590 return nullptr;
591 }
592 }
593 FrameRateRange frameRateRange;
594 ParseExpectedFrameRateRange(env, info, frameRateRange);
595 animator->SetExpectedFrameRateRange(frameRateRange);
596 TAG_LOGD(AceLogTag::ACE_ANIMATION, "animator id:%{public}d SetExpectedFrameRateRange"
597 "{%{public}d, %{public}d, %{public}d}", animator->GetId(), frameRateRange.min_, frameRateRange.max_,
598 frameRateRange.preferred_);
599 return nullptr;
600 }
601
SetOnframe(napi_env env,napi_callback_info info)602 static napi_value SetOnframe(napi_env env, napi_callback_info info)
603 {
604 AnimatorResult* animatorResult = nullptr;
605 size_t argc = 1;
606 napi_value thisVar = nullptr;
607 napi_value onframe = nullptr;
608 napi_get_cb_info(env, info, &argc, &onframe, &thisVar, NULL);
609 napi_unwrap(env, thisVar, (void**)&animatorResult);
610 if (!animatorResult) {
611 return nullptr;
612 }
613 auto option = animatorResult->GetAnimatorOption();
614 if (!option) {
615 return nullptr;
616 }
617 auto animator = animatorResult->GetAnimator();
618 if (!animator) {
619 return nullptr;
620 }
621 animator->ClearInterpolators();
622 // convert onframe function to reference
623 napi_ref onframeRef = animatorResult->GetOnframeRef();
624 if (onframeRef) {
625 uint32_t count = 0;
626 napi_reference_unref(env, onframeRef, &count);
627 }
628 napi_create_reference(env, onframe, 1, &onframeRef);
629 animatorResult->SetOnframeRef(onframeRef);
630 auto onFrameCallback = [env, onframeRef, id = animator->GetId(),
631 weakOption = std::weak_ptr<AnimatorOption>(animatorResult->GetAnimatorOption())](
632 double value) {
633 napi_handle_scope scope = nullptr;
634 napi_open_handle_scope(env, &scope);
635 if (scope == nullptr) {
636 TAG_LOGW(AceLogTag::ACE_ANIMATION, "ohos.animator call onFrame failed, scope is null, id:%{public}d", id);
637 return;
638 }
639 napi_value ret = nullptr;
640 napi_value valueNapi = nullptr;
641 napi_value onframe = nullptr;
642 auto result = napi_get_reference_value(env, onframeRef, &onframe);
643 auto option = weakOption.lock();
644 if (!(result == napi_ok && onframe && option)) {
645 TAG_LOGW(AceLogTag::ACE_ANIMATION,
646 "ohos.animator call onFrame failed, get reference result:%{public}d, id:%{public}d", result == napi_ok,
647 id);
648 napi_close_handle_scope(env, scope);
649 return;
650 }
651 ACE_SCOPED_TRACE(
652 "ohos.animator onframe. duration:%d, curve:%s, id:%d", option->duration, option->easing.c_str(), id);
653 napi_create_double(env, value, &valueNapi);
654 napi_call_function(env, nullptr, onframe, 1, &valueNapi, &ret);
655 napi_close_handle_scope(env, scope);
656 };
657 RefPtr<Animation<double>> animation;
658 RefPtr<Motion> motion = ParseOptionToMotion(option);
659 if (motion) {
660 motion->AddListener(onFrameCallback);
661 animatorResult->SetMotion(motion);
662 } else {
663 auto curve = Framework::CreateCurve(option->easing);
664 animation = AceType::MakeRefPtr<CurveAnimation<double>>(option->begin, option->end, curve);
665 animation->AddListener(onFrameCallback);
666 animator->AddInterpolator(animation);
667 animatorResult->SetMotion(nullptr);
668 }
669 if (!animator->HasScheduler()) {
670 animator->AttachSchedulerOnContainer();
671 }
672 napi_value undefined;
673 napi_get_undefined(env, &undefined);
674 return undefined;
675 }
676
SetOnFrame(napi_env env,napi_callback_info info)677 static napi_value SetOnFrame(napi_env env, napi_callback_info info)
678 {
679 return SetOnframe(env, info);
680 }
681
SetOnfinish(napi_env env,napi_callback_info info)682 static napi_value SetOnfinish(napi_env env, napi_callback_info info)
683 {
684 AnimatorResult* animatorResult = nullptr;
685 size_t argc = 1;
686 napi_value thisVar = nullptr;
687 napi_value onfinish = nullptr;
688 napi_get_cb_info(env, info, &argc, &onfinish, &thisVar, NULL);
689 napi_unwrap(env, thisVar, (void**)&animatorResult);
690 if (!animatorResult) {
691 return nullptr;
692 }
693 auto option = animatorResult->GetAnimatorOption();
694 if (!option) {
695 return nullptr;
696 }
697 auto animator = animatorResult->GetAnimator();
698 if (!animator) {
699 return nullptr;
700 }
701 // convert onfinish function to reference
702 napi_ref onfinishRef = animatorResult->GetOnfinishRef();
703 if (onfinishRef) {
704 uint32_t count = 0;
705 napi_reference_unref(env, onfinishRef, &count);
706 }
707 napi_create_reference(env, onfinish, 1, &onfinishRef);
708 animatorResult->SetOnfinishRef(onfinishRef);
709 animator->ClearStopListeners();
710 TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator set finish callback, id:%{public}d", animator->GetId());
711 animator->AddStopListener([env, onfinishRef, id = animator->GetId()] {
712 napi_handle_scope scope = nullptr;
713 napi_open_handle_scope(env, &scope);
714 if (scope == nullptr) {
715 TAG_LOGW(AceLogTag::ACE_ANIMATION,
716 "ohos.animator call finish callback failed, scope is null, id:%{public}d", id);
717 return;
718 }
719 napi_value ret = nullptr;
720 napi_value onfinish = nullptr;
721 auto result = napi_get_reference_value(env, onfinishRef, &onfinish);
722 if (result != napi_ok || onfinish == nullptr) {
723 napi_close_handle_scope(env, scope);
724 TAG_LOGW(AceLogTag::ACE_ANIMATION,
725 "ohos.animator call finish callback failed, get onFinish failed, id:%{public}d", id);
726 return;
727 }
728 ACE_SCOPED_TRACE("ohos.animator finishCallback, id:%d", id);
729 TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator call finish callback, id:%{public}d", id);
730 result = napi_call_function(env, NULL, onfinish, 0, NULL, &ret);
731 if (result != napi_ok) {
732 TAG_LOGW(
733 AceLogTag::ACE_ANIMATION, "ohos.animator call finish callback failed, napi error, id:%{public}d", id);
734 }
735 napi_close_handle_scope(env, scope);
736 });
737 napi_value undefined;
738 napi_get_undefined(env, &undefined);
739 return undefined;
740 }
741
SetOnFinish(napi_env env,napi_callback_info info)742 static napi_value SetOnFinish(napi_env env, napi_callback_info info)
743 {
744 return SetOnfinish(env, info);
745 }
746
SetOncancel(napi_env env,napi_callback_info info)747 static napi_value SetOncancel(napi_env env, napi_callback_info info)
748 {
749 AnimatorResult* animatorResult = nullptr;
750 size_t argc = 1;
751 napi_value thisVar = nullptr;
752 napi_value oncancel = nullptr;
753 napi_get_cb_info(env, info, &argc, &oncancel, &thisVar, NULL);
754 napi_unwrap(env, thisVar, (void**)&animatorResult);
755 if (!animatorResult) {
756 return nullptr;
757 }
758 auto option = animatorResult->GetAnimatorOption();
759 if (!option) {
760 return nullptr;
761 }
762 auto animator = animatorResult->GetAnimator();
763 if (!animator) {
764 return nullptr;
765 }
766 // convert oncancel function to reference
767 napi_ref oncancelRef = animatorResult->GetOncancelRef();
768 if (oncancelRef) {
769 uint32_t count = 0;
770 napi_reference_unref(env, oncancelRef, &count);
771 }
772 napi_create_reference(env, oncancel, 1, &oncancelRef);
773 animatorResult->SetOncancelRef(oncancelRef);
774 animator->ClearIdleListeners();
775 animator->AddIdleListener([env, oncancelRef] {
776 napi_handle_scope scope = nullptr;
777 napi_open_handle_scope(env, &scope);
778 if (scope == nullptr) {
779 return;
780 }
781 napi_value ret = nullptr;
782 napi_value oncancel = nullptr;
783 auto result = napi_get_reference_value(env, oncancelRef, &oncancel);
784 if (result != napi_ok || oncancel == nullptr) {
785 napi_close_handle_scope(env, scope);
786 return;
787 }
788 napi_call_function(env, NULL, oncancel, 0, NULL, &ret);
789 napi_close_handle_scope(env, scope);
790 });
791 napi_value undefined;
792 napi_get_undefined(env, &undefined);
793 return undefined;
794 }
795
SetOnCancel(napi_env env,napi_callback_info info)796 static napi_value SetOnCancel(napi_env env, napi_callback_info info)
797 {
798 return SetOncancel(env, info);
799 }
800
SetOnrepeat(napi_env env,napi_callback_info info)801 static napi_value SetOnrepeat(napi_env env, napi_callback_info info)
802 {
803 AnimatorResult* animatorResult = nullptr;
804 size_t argc = 1;
805 napi_value thisVar = nullptr;
806 napi_value onrepeat = nullptr;
807 napi_get_cb_info(env, info, &argc, &onrepeat, &thisVar, NULL);
808 napi_unwrap(env, thisVar, (void**)&animatorResult);
809 if (!animatorResult) {
810 return nullptr;
811 }
812 auto option = animatorResult->GetAnimatorOption();
813 if (!option) {
814 return nullptr;
815 }
816 auto animator = animatorResult->GetAnimator();
817 if (!animator) {
818 return nullptr;
819 }
820 // convert onrepeat function to reference
821 napi_ref onrepeatRef = animatorResult->GetOnrepeatRef();
822 if (onrepeatRef) {
823 uint32_t count = 0;
824 napi_reference_unref(env, onrepeatRef, &count);
825 }
826 napi_create_reference(env, onrepeat, 1, &onrepeatRef);
827 animatorResult->SetOnrepeatRef(onrepeatRef);
828 animator->ClearRepeatListeners();
829 animator->AddRepeatListener([env, onrepeatRef] {
830 napi_handle_scope scope = nullptr;
831 napi_open_handle_scope(env, &scope);
832 if (scope == nullptr) {
833 return;
834 }
835 napi_value ret = nullptr;
836 napi_value onrepeat = nullptr;
837 auto result = napi_get_reference_value(env, onrepeatRef, &onrepeat);
838 if (result != napi_ok || onrepeat == nullptr) {
839 napi_close_handle_scope(env, scope);
840 return;
841 }
842 napi_call_function(env, NULL, onrepeat, 0, NULL, &ret);
843 napi_close_handle_scope(env, scope);
844 });
845 napi_value undefined;
846 napi_get_undefined(env, &undefined);
847 return undefined;
848 }
849
SetOnRepeat(napi_env env,napi_callback_info info)850 static napi_value SetOnRepeat(napi_env env, napi_callback_info info)
851 {
852 return SetOnrepeat(env, info);
853 }
854
JSCreate(napi_env env,napi_callback_info info)855 static napi_value JSCreate(napi_env env, napi_callback_info info)
856 {
857 auto option = std::make_shared<AnimatorOption>();
858 ParseAnimatorOption(env, info, option);
859 auto animator = CREATE_ANIMATOR("ohos.animator");
860 animator->AttachSchedulerOnContainer();
861 AnimatorResult* animatorResult = new AnimatorResult(animator, option);
862 napi_value jsAnimator = nullptr;
863 napi_create_object(env, &jsAnimator);
864 napi_wrap(
865 env, jsAnimator, animatorResult,
866 [](napi_env env, void* data, void* hint) {
867 AnimatorResult* animatorResult = (AnimatorResult*)data;
868 // release four references(onFunc) before releasing animatorResult
869 animatorResult->Destroy(env);
870 delete animatorResult;
871 },
872 nullptr, nullptr);
873 napi_property_descriptor resultFuncs[] = {
874 DECLARE_NAPI_FUNCTION("update", JSUpdate),
875 DECLARE_NAPI_FUNCTION("reset", JSReset),
876 DECLARE_NAPI_FUNCTION("play", JSPlay),
877 DECLARE_NAPI_FUNCTION("finish", JSFinish),
878 DECLARE_NAPI_FUNCTION("pause", JSPause),
879 DECLARE_NAPI_FUNCTION("cancel", JSCancel),
880 DECLARE_NAPI_FUNCTION("reverse", JSReverse),
881 DECLARE_NAPI_FUNCTION("setExpectedFrameRateRange", JSSetExpectedFrameRateRange),
882 DECLARE_NAPI_SETTER("onframe", SetOnframe),
883 DECLARE_NAPI_SETTER("onfinish", SetOnfinish),
884 DECLARE_NAPI_SETTER("oncancel", SetOncancel),
885 DECLARE_NAPI_SETTER("onrepeat", SetOnrepeat),
886 DECLARE_NAPI_SETTER("onFrame", SetOnFrame),
887 DECLARE_NAPI_SETTER("onFinish", SetOnFinish),
888 DECLARE_NAPI_SETTER("onCancel", SetOnCancel),
889 DECLARE_NAPI_SETTER("onRepeat", SetOnRepeat),
890 };
891
892 NAPI_CALL(env, napi_define_properties(env, jsAnimator, sizeof(resultFuncs) / sizeof(resultFuncs[0]), resultFuncs));
893 return jsAnimator;
894 }
895
896 // since API 9 deprecated
JSCreateAnimator(napi_env env,napi_callback_info info)897 static napi_value JSCreateAnimator(napi_env env, napi_callback_info info)
898 {
899 return JSCreate(env, info);
900 }
901
ParseIntSimpleOptions(napi_env env,napi_value propertyNapi,int32_t & property,int32_t defaultValue)902 static void ParseIntSimpleOptions(napi_env env, napi_value propertyNapi, int32_t& property, int32_t defaultValue)
903 {
904 if (propertyNapi == nullptr) {
905 return;
906 }
907 napi_valuetype valueType = napi_undefined;
908 napi_typeof(env, propertyNapi, &valueType);
909 if (valueType != napi_number) {
910 property = defaultValue;
911 return;
912 }
913 napi_get_value_int32(env, propertyNapi, &property);
914 }
915
ParseStringSimpleOptions(napi_env env,napi_value propertyNapi,std::string & property,const std::string & defaultValue)916 static void ParseStringSimpleOptions(
917 napi_env env, napi_value propertyNapi, std::string& property, const std::string& defaultValue)
918 {
919 if (propertyNapi == nullptr) {
920 return;
921 }
922 napi_valuetype valueType = napi_undefined;
923 napi_typeof(env, propertyNapi, &valueType);
924 if (valueType != napi_string) {
925 property = defaultValue;
926 return;
927 }
928 size_t buffSize = 0;
929 napi_status status = napi_get_value_string_utf8(env, propertyNapi, nullptr, 0, &buffSize);
930 if (status != napi_ok || buffSize == 0) {
931 return;
932 }
933 std::unique_ptr<char[]> propertyString = std::make_unique<char[]>(buffSize + 1);
934 size_t retLen = 0;
935 napi_get_value_string_utf8(env, propertyNapi, propertyString.get(), buffSize + 1, &retLen);
936 property = propertyString.get();
937 }
938
ParseDoubleSimpleOptions(napi_env env,napi_value propertyNapi,double & property,double defaultValue)939 static void ParseDoubleSimpleOptions(napi_env env, napi_value propertyNapi, double& property, double defaultValue)
940 {
941 if (propertyNapi == nullptr) {
942 return;
943 }
944 napi_valuetype valueType = napi_undefined;
945 napi_typeof(env, propertyNapi, &valueType);
946 if (valueType != napi_number) {
947 property = defaultValue;
948 return;
949 }
950 napi_get_value_double(env, propertyNapi, &property);
951 }
952
OnSetDuration(napi_env env,napi_callback_info info)953 napi_value JsSimpleAnimatorOption::OnSetDuration(napi_env env, napi_callback_info info)
954 {
955 size_t argc = 1;
956 napi_value argv[1] = { nullptr };
957 napi_value thisArg;
958 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
959 if (argc != 1) {
960 return nullptr;
961 }
962 int32_t duration = ANIMATOR_DEFALUT_DURATION;
963 ParseIntSimpleOptions(env, argv[0], duration, ANIMATOR_DEFALUT_DURATION);
964 duration_ = std::max(duration, 0);
965 return thisArg;
966 }
967
OnSetEasing(napi_env env,napi_callback_info info)968 napi_value JsSimpleAnimatorOption::OnSetEasing(napi_env env, napi_callback_info info)
969 {
970 size_t argc = 1;
971 napi_value argv[1] = { nullptr };
972 napi_value thisArg;
973 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
974 if (argc != 1) {
975 return nullptr;
976 }
977 std::string easing = ANIMATOR_DEFALUT_EASING;
978 ParseStringSimpleOptions(env, argv[0], easing, ANIMATOR_DEFALUT_EASING);
979 easing_ = easing;
980 return thisArg;
981 }
982
OnSetDelay(napi_env env,napi_callback_info info)983 napi_value JsSimpleAnimatorOption::OnSetDelay(napi_env env, napi_callback_info info)
984 {
985 size_t argc = 1;
986 napi_value argv[1] = { nullptr };
987 napi_value thisArg;
988 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
989 if (argc != 1) {
990 return nullptr;
991 }
992 int32_t delay = ANIMATOR_DEFALUT_DELAY;
993 ParseIntSimpleOptions(env, argv[0], delay, ANIMATOR_DEFALUT_DELAY);
994 delay_ = delay;
995 return thisArg;
996 }
997
OnSetFill(napi_env env,napi_callback_info info)998 napi_value JsSimpleAnimatorOption::OnSetFill(napi_env env, napi_callback_info info)
999 {
1000 size_t argc = 1;
1001 napi_value argv[1] = { nullptr };
1002 napi_value thisArg;
1003 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
1004 if (argc != 1) {
1005 return nullptr;
1006 }
1007 int32_t intValue = static_cast<int32_t>(FillMode::FORWARDS);
1008 ParseIntSimpleOptions(env, argv[0], intValue, static_cast<int32_t>(FillMode::FORWARDS));
1009 FillMode fillValue = FillMode::FORWARDS;
1010 if (intValue >= static_cast<int32_t>(FillMode::NONE) && intValue <= static_cast<int32_t>(FillMode::BOTH)) {
1011 fillValue = static_cast<FillMode>(intValue);
1012 }
1013 fill_ = fillValue;
1014 return thisArg;
1015 }
1016
OnSetDirection(napi_env env,napi_callback_info info)1017 napi_value JsSimpleAnimatorOption::OnSetDirection(napi_env env, napi_callback_info info)
1018 {
1019 size_t argc = 1;
1020 napi_value argv[1] = { nullptr };
1021 napi_value thisArg;
1022 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
1023 if (argc != 1) {
1024 return nullptr;
1025 }
1026 std::string direction = ANIMATOR_DIRECTION_NORMAL;
1027 ParseStringSimpleOptions(env, argv[0], direction, ANIMATOR_DIRECTION_NORMAL);
1028 AnimationDirection directionValue = StringToAnimationDirection(direction);
1029 direction_ = directionValue;
1030 return thisArg;
1031 }
1032
OnSetIterations(napi_env env,napi_callback_info info)1033 napi_value JsSimpleAnimatorOption::OnSetIterations(napi_env env, napi_callback_info info)
1034 {
1035 size_t argc = 1;
1036 napi_value argv[1] = { nullptr };
1037 napi_value thisArg;
1038 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
1039 if (argc != 1) {
1040 return nullptr;
1041 }
1042 int32_t iterations = ANIMATOR_DEFALUT_ITERATIONS;
1043 ParseIntSimpleOptions(env, argv[0], iterations, ANIMATOR_DEFALUT_ITERATIONS);
1044 iterations_ = iterations >= ANIMATION_REPEAT_INFINITE ? iterations : ANIMATOR_DEFALUT_ITERATIONS;
1045 return thisArg;
1046 }
1047
JsSetDuration(napi_env env,napi_callback_info info)1048 static napi_value JsSetDuration(napi_env env, napi_callback_info info)
1049 {
1050 JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(GetNapiCallbackInfoAndThis(env, info));
1051 if (me == nullptr) {
1052 return nullptr;
1053 }
1054 napi_value thisArg = me->OnSetDuration(env, info);
1055 return thisArg;
1056 }
1057
JsSetEasing(napi_env env,napi_callback_info info)1058 static napi_value JsSetEasing(napi_env env, napi_callback_info info)
1059 {
1060 JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(GetNapiCallbackInfoAndThis(env, info));
1061 if (me == nullptr) {
1062 return nullptr;
1063 }
1064 napi_value thisArg = me->OnSetEasing(env, info);
1065 return thisArg;
1066 }
1067
JsSetDelay(napi_env env,napi_callback_info info)1068 static napi_value JsSetDelay(napi_env env, napi_callback_info info)
1069 {
1070 JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(GetNapiCallbackInfoAndThis(env, info));
1071 if (me == nullptr) {
1072 return nullptr;
1073 }
1074 napi_value thisArg = me->OnSetDelay(env, info);
1075 return thisArg;
1076 }
1077
JsSetFill(napi_env env,napi_callback_info info)1078 static napi_value JsSetFill(napi_env env, napi_callback_info info)
1079 {
1080 JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(GetNapiCallbackInfoAndThis(env, info));
1081 if (me == nullptr) {
1082 return nullptr;
1083 }
1084 napi_value thisArg = me->OnSetFill(env, info);
1085 return thisArg;
1086 }
1087
JsSetDirection(napi_env env,napi_callback_info info)1088 static napi_value JsSetDirection(napi_env env, napi_callback_info info)
1089 {
1090 JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(GetNapiCallbackInfoAndThis(env, info));
1091 if (me == nullptr) {
1092 return nullptr;
1093 }
1094 napi_value thisArg = me->OnSetDirection(env, info);
1095 return thisArg;
1096 }
1097
JsSetIterations(napi_env env,napi_callback_info info)1098 static napi_value JsSetIterations(napi_env env, napi_callback_info info)
1099 {
1100 JsSimpleAnimatorOption* me = static_cast<JsSimpleAnimatorOption*>(GetNapiCallbackInfoAndThis(env, info));
1101 if (me == nullptr) {
1102 return nullptr;
1103 }
1104 napi_value thisArg = me->OnSetIterations(env, info);
1105 return thisArg;
1106 }
1107
SimpleOptionsConstructor(napi_env env,napi_callback_info info)1108 static napi_value SimpleOptionsConstructor(napi_env env, napi_callback_info info)
1109 {
1110 size_t argc = SIMPLEANIMATOR_CONSTRUCTOR_PARAMS_SIZE;
1111 napi_value argv[SIMPLEANIMATOR_CONSTRUCTOR_PARAMS_SIZE];
1112 napi_value thisArg;
1113 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, nullptr));
1114 if (argc != SIMPLEANIMATOR_CONSTRUCTOR_PARAMS_SIZE) {
1115 return nullptr;
1116 }
1117 double begin = ANIMATOR_DEFALUT_BEGIN;
1118 double end = ANIMATOR_DEFALUT_END;
1119 ParseDoubleSimpleOptions(env, argv[0], begin, ANIMATOR_DEFALUT_BEGIN);
1120 ParseDoubleSimpleOptions(env, argv[1], end, ANIMATOR_DEFALUT_END);
1121 auto me = new JsSimpleAnimatorOption();
1122 me->SetBegin(begin);
1123 me->SetEnd(end);
1124 napi_wrap(
1125 env, thisArg, me,
1126 [](napi_env env, void* data, void* hint) {
1127 auto me = reinterpret_cast<JsSimpleAnimatorOption*>(data);
1128 delete me;
1129 },
1130 nullptr, nullptr);
1131 return thisArg;
1132 }
1133
InitSimpleAnimatorOptions(napi_env env,napi_value exports)1134 napi_value InitSimpleAnimatorOptions(napi_env env, napi_value exports)
1135 {
1136 napi_value classSimpleOptions = nullptr;
1137 napi_property_descriptor simpleAnimatorOptionsDesc[] = {
1138 DECLARE_NAPI_FUNCTION("duration", JsSetDuration),
1139 DECLARE_NAPI_FUNCTION("easing", JsSetEasing),
1140 DECLARE_NAPI_FUNCTION("delay", JsSetDelay),
1141 DECLARE_NAPI_FUNCTION("fill", JsSetFill),
1142 DECLARE_NAPI_FUNCTION("direction", JsSetDirection),
1143 DECLARE_NAPI_FUNCTION("iterations", JsSetIterations),
1144 };
1145 napi_define_class(env, "SimpleAnimatorOptions", NAPI_AUTO_LENGTH, SimpleOptionsConstructor, nullptr,
1146 sizeof(simpleAnimatorOptionsDesc) / sizeof(*simpleAnimatorOptionsDesc), simpleAnimatorOptionsDesc,
1147 &classSimpleOptions);
1148 NAPI_CALL(env, napi_set_named_property(env, exports, "SimpleAnimatorOptions", classSimpleOptions));
1149 return exports;
1150 }
1151
AnimatorExport(napi_env env,napi_value exports)1152 static napi_value AnimatorExport(napi_env env, napi_value exports)
1153 {
1154 napi_property_descriptor animatorDesc[] = {
1155 DECLARE_NAPI_FUNCTION("create", JSCreate),
1156 DECLARE_NAPI_FUNCTION("createAnimator", JSCreateAnimator),
1157 };
1158 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(animatorDesc) / sizeof(animatorDesc[0]), animatorDesc));
1159 InitSimpleAnimatorOptions(env, exports);
1160 return exports;
1161 }
1162
1163 static napi_module animatorModule = {
1164 .nm_version = 1,
1165 .nm_flags = 0,
1166 .nm_filename = nullptr,
1167 .nm_register_func = AnimatorExport,
1168 .nm_modname = "animator",
1169 .nm_priv = ((void*)0),
1170 .reserved = { 0 },
1171 };
1172
AnimatorRegister()1173 extern "C" __attribute__((constructor)) void AnimatorRegister()
1174 {
1175 napi_module_register(&animatorModule);
1176 }
1177
ApplyOption()1178 void AnimatorResult::ApplyOption()
1179 {
1180 CHECK_NULL_VOID(animator_);
1181 CHECK_NULL_VOID(option_);
1182 if (motion_) {
1183 // duration not works. Iteration can only be 1. Direction can only be normal.
1184 animator_->SetIteration(1);
1185 animator_->SetAnimationDirection(AnimationDirection::NORMAL);
1186 } else {
1187 animator_->SetDuration(option_->duration);
1188 animator_->SetIteration(option_->iterations);
1189 animator_->SetAnimationDirection(StringToAnimationDirection(option_->direction));
1190 }
1191 animator_->SetStartDelay(option_->delay);
1192 // FillMode not works for motion in animator implementation.
1193 animator_->SetFillMode(StringToFillMode(option_->fill));
1194 }
1195
Destroy(napi_env env)1196 void AnimatorResult::Destroy(napi_env env)
1197 {
1198 if (animator_) {
1199 if (!animator_->IsStopped()) {
1200 animator_->Stop();
1201 TAG_LOGI(AceLogTag::ACE_ANIMATION, "ohos.animator force stopping done when destroying, id:%{public}d",
1202 animator_->GetId());
1203 }
1204 }
1205 if (onframe_ != nullptr) {
1206 napi_delete_reference(env, onframe_);
1207 }
1208 if (onfinish_ != nullptr) {
1209 napi_delete_reference(env, onfinish_);
1210 }
1211 if (oncancel_ != nullptr) {
1212 napi_delete_reference(env, oncancel_);
1213 }
1214 if (onrepeat_ != nullptr) {
1215 napi_delete_reference(env, onrepeat_);
1216 }
1217 }
1218
1219 } // namespace OHOS::Ace::Napi
1220