1 /*
2  * Copyright (c) 2021 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 "frameworks/bridge/js_frontend/engine/jsi/jsi_animator_bridge.h"
17 
18 #include "base/log/event_report.h"
19 
20 namespace OHOS::Ace::Framework {
21 namespace {
22 
GetFrontendDelegate(shared_ptr<JsRuntime> && runtime)23 RefPtr<FrontendDelegate> GetFrontendDelegate(shared_ptr<JsRuntime>&& runtime)
24 {
25     if (!runtime) {
26         LOGE("Get front delegate failed. runtime is null.");
27         return nullptr;
28     }
29     auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
30     if (engine == nullptr) {
31         LOGE("Get front delegate failed. engin is null");
32         return nullptr;
33     }
34     return engine->GetFrontendDelegate();
35 }
36 
GetFrontendDelegate(std::weak_ptr<JsRuntime> weakRuntime)37 RefPtr<FrontendDelegate> GetFrontendDelegate(std::weak_ptr<JsRuntime> weakRuntime)
38 {
39     return GetFrontendDelegate(weakRuntime.lock());
40 }
41 
GetPageById(const shared_ptr<JsRuntime> & runtime,int32_t pageId)42 RefPtr<JsAcePage> GetPageById(const shared_ptr<JsRuntime>& runtime, int32_t pageId)
43 {
44     if (!runtime) {
45         LOGE("Get page by id failed, runtime is null");
46         return nullptr;
47     }
48     auto delegate = GetFrontendDelegate(runtime);
49     if (!delegate) {
50         LOGE("Get page by id failed, delegate is null");
51         return nullptr;
52     }
53     return delegate->GetPage(pageId);
54 }
55 
GetCurrentBridgeId(shared_ptr<JsRuntime> & runtime,shared_ptr<JsValue> & value)56 inline int32_t GetCurrentBridgeId(shared_ptr<JsRuntime>& runtime, shared_ptr<JsValue>& value)
57 {
58     if (!value) {
59         LOGE("Get current bridge id failed. value is null.");
60         return 0;
61     }
62     shared_ptr<JsValue> jsBridgeId = value->GetProperty(runtime, "__bridgeId");
63     if (!jsBridgeId || !jsBridgeId->IsInt32(runtime)) {
64         LOGE("Get current bridge id failed. jsBridgeId is null or not a integer");
65         return 0;
66     }
67     int32_t bridgeId = jsBridgeId->ToInt32(runtime);
68     return bridgeId < 0 ? 0 : bridgeId;
69 }
70 
GetCurrentPageId(shared_ptr<JsRuntime> & runtime,shared_ptr<JsValue> & value)71 inline int32_t GetCurrentPageId(shared_ptr<JsRuntime>& runtime, shared_ptr<JsValue>& value)
72 {
73     if (!value) {
74         LOGE("Get current page id failed. value is null.");
75         return 0;
76     }
77     shared_ptr<JsValue> jsPageId = value->GetProperty(runtime, "__pageId");
78     if (!jsPageId || !jsPageId->IsInt32(runtime)) {
79         LOGE("Get current page id failed. jsPageId is null or not a integer");
80         return 0;
81     }
82     int32_t pageId = jsPageId->ToInt32(runtime);
83     return pageId < 0 ? 0 : pageId;
84 }
85 
HandleJsAnimatorContext(const shared_ptr<JsRuntime> & runtime,int32_t pageId,int32_t bridgeId,AnimatorOperation operation)86 void HandleJsAnimatorContext(const shared_ptr<JsRuntime>& runtime, int32_t pageId, int32_t bridgeId,
87     AnimatorOperation operation)
88 {
89     if (!runtime) {
90         LOGE("Handle JsAnimationContext failed, runtime is null.");
91         return;
92     }
93     auto delegate = GetFrontendDelegate(runtime);
94     if (!delegate) {
95         LOGE("Handle JsAnimationContext failed, delegate is null.");
96         return;
97     }
98     auto page = GetPageById(runtime, pageId);
99     if (!page) {
100         LOGE("no page found for pageId: %{public}d", pageId);
101         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
102         return;
103     }
104     auto task = AceType::MakeRefPtr<JsiAnimatorTaskOperation>(operation);
105     page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
106     if (page->CheckPageCreated()) {
107         delegate->TriggerPageUpdate(page->GetPageId());
108     }
109 }
110 
CallAnimationStartJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)111 void CallAnimationStartJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
112 {
113     auto bridge = bridgeWeak.Upgrade();
114     if (!bridge) {
115         LOGE("Call Animation Start Js Failed. animation bridge is null.");
116         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
117         return;
118     }
119     if (!runtime) {
120         LOGE("Call Animation Start Js Failed. runtime is null.");
121         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
122         return;
123     }
124     auto animationObject = bridge->GetJsObject();
125     if (!animationObject || animationObject->IsNull(runtime)) {
126         LOGE("Animation Object is null");
127         return;
128     }
129     shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onstart");
130     if (!jsFunc || !jsFunc->IsFunction(runtime)) {
131         return;
132     }
133     jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
134 }
135 
CallAnimationFinishJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)136 void CallAnimationFinishJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
137 {
138     auto bridge = bridgeWeak.Upgrade();
139     if (!bridge) {
140         LOGE("Call Animation Finish Js Failed. animation bridge is null.");
141         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
142         return;
143     }
144     if (!runtime) {
145         LOGE("Call Animation Finish Js Failed. runtime is null.");
146         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
147         return;
148     }
149     auto animationObject = bridge->GetJsObject();
150     if (!animationObject || animationObject->IsNull(runtime)) {
151         LOGE("Animation Object is null");
152         return;
153     }
154     shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onfinish");
155     if (!jsFunc || !jsFunc->IsFunction(runtime)) {
156         return;
157     }
158     jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
159 }
160 
CallAnimationCancelJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)161 void CallAnimationCancelJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
162 {
163     auto bridge = bridgeWeak.Upgrade();
164     if (!bridge) {
165         LOGE("Call Animation Cancel Js Failed. animation bridge is null.");
166         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
167         return;
168     }
169     if (!runtime) {
170         LOGE("Call Animation Cancel Js Failed. runtime is null.");
171         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
172         return;
173     }
174     auto animationObject = bridge->GetJsObject();
175     if (!animationObject || animationObject->IsNull(runtime)) {
176         LOGE("Animation Object is null");
177         return;
178     }
179     shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "oncancel");
180     if (!jsFunc || !jsFunc->IsFunction(runtime)) {
181         return;
182     }
183     jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
184 }
185 
CallAnimationRepeatJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)186 void CallAnimationRepeatJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
187 {
188     auto bridge = bridgeWeak.Upgrade();
189     if (!bridge) {
190         LOGE("Call Animation Repeat Js Failed. animation bridge is null.");
191         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
192         return;
193     }
194     if (!runtime) {
195         LOGE("Call Animation Repeat Js Failed. runtime is null.");
196         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
197         return;
198     }
199     auto animationObject = bridge->GetJsObject();
200     if (!animationObject || animationObject->IsNull(runtime)) {
201         LOGE("Animation Object is null");
202         return;
203     }
204     shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onrepeat");
205     if (!jsFunc || !jsFunc->IsFunction(runtime)) {
206         return;
207     }
208     jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
209 }
210 
CallAnimationFrameJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime,double value)211 void CallAnimationFrameJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime, double value)
212 {
213     auto bridge = bridgeWeak.Upgrade();
214     if (!bridge) {
215         LOGE("Call Animation Frame Js Failed. animation bridge is null.");
216         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
217         return;
218     }
219     if (!runtime) {
220         LOGE("Call Animation Frame Js Failed. runtime is null.");
221         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
222         return;
223     }
224     auto animationObject = bridge->GetJsObject();
225     if (!animationObject || animationObject->IsNull(runtime)) {
226         LOGE("Animation Object is null");
227         return;
228     }
229     shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onframe");
230     if (!jsFunc || !jsFunc->IsFunction(runtime)) {
231         return;
232     }
233     std::vector<shared_ptr<JsValue>> argv = { runtime->NewNumber(value) };
234     jsFunc->Call(runtime, runtime->GetGlobal(), argv, argv.size());
235 }
236 
AddListenerForEventCallback(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,const RefPtr<Animator> & animator,shared_ptr<JsRuntime> runtime)237 void AddListenerForEventCallback(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, const RefPtr<Animator>& animator,
238     shared_ptr<JsRuntime> runtime)
239 {
240     std::weak_ptr<JsRuntime> weakRuntime(runtime);
241     animator->AddStartListener([weakRuntime, bridgeWeak] {
242         auto delegate = GetFrontendDelegate(weakRuntime);
243         if (!delegate) {
244             LOGE("Handle Start listener failed, fail to get delegate");
245             return;
246         }
247         auto jsTaskExecutor = delegate->GetAnimationJsTask();
248         jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
249             LOGI("call animation onstart event");
250             CallAnimationStartJs(bridgeWeak, weakRuntime.lock());
251         }, "ArkUIAnimationStartEvent");
252     });
253     animator->AddStopListener([weakRuntime, bridgeWeak] {
254         auto delegate = GetFrontendDelegate(weakRuntime);
255         if (!delegate) {
256             LOGE("Handle Stop listener failed, fail to get delegate");
257             return;
258         }
259         auto jsTaskExecutor = delegate->GetAnimationJsTask();
260         jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
261             LOGI("call animation onfinish event");
262             CallAnimationFinishJs(bridgeWeak, weakRuntime.lock());
263         }, "ArkUIAnimationStopEvent");
264     });
265     animator->AddIdleListener([weakRuntime, bridgeWeak] {
266         auto delegate = GetFrontendDelegate(weakRuntime);
267         if (!delegate) {
268             LOGE("Handle Idle listener failed, fail to get delegate");
269             return;
270         }
271         auto jsTaskExecutor = delegate->GetAnimationJsTask();
272         jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
273             LOGI("call animation oncancel event");
274             CallAnimationCancelJs(bridgeWeak, weakRuntime.lock());
275         }, "ArkUIAnimationCancelEvent");
276     });
277     animator->AddRepeatListener([weakRuntime, bridgeWeak] {
278         auto delegate = GetFrontendDelegate(weakRuntime);
279         if (!delegate) {
280             LOGE("Handle Repeat listener failed, fail to get delegate");
281             return;
282         }
283         auto jsTaskExecutor = delegate->GetAnimationJsTask();
284         jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
285             LOGI("call animation onrepeat event");
286             CallAnimationRepeatJs(bridgeWeak, weakRuntime.lock());
287         }, "ArkUIAnimationRepeat");
288     });
289 }
290 
AddFrameListener(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,const RefPtr<KeyframeAnimation<double>> & animator,shared_ptr<JsRuntime> runtime)291 void AddFrameListener(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, const RefPtr<KeyframeAnimation<double>>& animator,
292     shared_ptr<JsRuntime> runtime)
293 {
294     std::weak_ptr<JsRuntime> weakRuntime(runtime);
295     animator->AddListener([weakRuntime, bridgeWeak](double value) {
296         auto delegate = GetFrontendDelegate(weakRuntime);
297         if (!delegate) {
298             LOGE("Handle Frame listener failed, fail to get delegate");
299             return;
300         }
301         auto jsTaskExecutor = delegate->GetAnimationJsTask();
302         jsTaskExecutor.PostTask(
303             [bridgeWeak, weakRuntime, value]() mutable {
304                 LOGI("call animation onframe event");
305                 CallAnimationFrameJs(bridgeWeak, weakRuntime.lock(), value);
306             },
307             "ArkUIAnimationFrame");
308     });
309 }
310 
311 } // namespace
312 
CreateAnimatorContext(shared_ptr<JsRuntime> runtime,int32_t pageId,int32_t bridgeId)313 shared_ptr<JsValue> JsiAnimatorBridgeUtils::CreateAnimatorContext(
314     shared_ptr<JsRuntime> runtime, int32_t pageId, int32_t bridgeId)
315 {
316     const std::unordered_map<const char*, RegisterFunctionType> contextTable = {
317         { "play", JsAnimatorPlay },
318         { "finish", JsAnimatorFinish },
319         { "pause", JsAnimatorPause },
320         { "cancel", JsAnimatorCancel },
321         { "reverse", JsAnimatorReverse },
322         { "update", JsAnimatorUpdate },
323         { "reset", JsAnimatorReset },
324     };
325     auto animatorContext = runtime->NewObject();
326     for (const auto& iter : contextTable) {
327         animatorContext->SetProperty(runtime, iter.first, runtime->NewFunction(iter.second));
328     }
329     animatorContext->SetProperty(runtime, "__pageId", runtime->NewInt32(pageId));
330     animatorContext->SetProperty(runtime, "__bridgeId", runtime->NewInt32(bridgeId));
331     return animatorContext;
332 }
333 
JsAnimatorPlay(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)334 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorPlay(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
335     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
336 {
337     int32_t pageId = GetCurrentPageId(runtime, thisObj);
338     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
339     HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::PLAY);
340     return runtime->NewUndefined();
341 }
342 
JsAnimatorFinish(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)343 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorFinish(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
344     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
345 {
346     int32_t pageId = GetCurrentPageId(runtime, thisObj);
347     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
348     HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::FINISH);
349     return runtime->NewUndefined();
350 }
351 
JsAnimatorPause(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)352 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorPause(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
353     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
354 {
355     int32_t pageId = GetCurrentPageId(runtime, thisObj);
356     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
357     HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::PAUSE);
358     return runtime->NewUndefined();
359 }
360 
JsAnimatorCancel(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)361 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorCancel(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
362     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
363 {
364     int32_t pageId = GetCurrentPageId(runtime, thisObj);
365     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
366     HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::CANCEL);
367     return runtime->NewUndefined();
368 }
369 
JsAnimatorReverse(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)370 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorReverse(shared_ptr<JsRuntime> runtime,
371     shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
372 {
373     int32_t pageId = GetCurrentPageId(runtime, thisObj);
374     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
375     HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::REVERSE);
376     return runtime->NewUndefined();
377 }
378 
379 // animator.update api function is deprecated since 9
JsAnimatorUpdate(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)380 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorUpdate(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
381     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
382 {
383     if (argv.empty()) {
384         return runtime->NewUndefined();
385     }
386     const shared_ptr<JsValue>& paramObj = argv[0];
387     if (!paramObj || !paramObj->IsObject(runtime)) {
388         LOGE("JsAnimatorUpdate failed, first argument is not an object!");
389         return runtime->NewUndefined();
390     }
391     int32_t len = 0;
392     shared_ptr<JsValue> properties;
393     if (!paramObj->GetPropertyNames(runtime, properties, len)) {
394         LOGE("JsAnimatorUpdate failed, fail to get object property list!");
395         return runtime->NewUndefined();
396     }
397     std::unordered_map<std::string, std::string> params;
398     for (int32_t i = 0; i < len; ++i) {
399         shared_ptr<JsValue> key = properties->GetElement(runtime, i);
400         shared_ptr<JsValue> val = paramObj->GetProperty(runtime, key);
401         std::string keyStr = key->ToString(runtime);
402         std::string valStr = val->ToString(runtime);
403         params[keyStr] = valStr;
404     }
405     int32_t pageId = GetCurrentPageId(runtime, thisObj);
406     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
407     auto page = GetPageById(runtime, pageId);
408     if (!page) {
409         LOGE("no page found for pageId: %{public}d", pageId);
410         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
411         return runtime->NewUndefined();
412     }
413     auto task = AceType::MakeRefPtr<JsiAnimatorTaskUpdate>(runtime, params);
414     page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
415     return runtime->NewUndefined();
416 }
417 
JsAnimatorReset(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)418 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorReset(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
419     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
420 {
421     if (argv.empty()) {
422         runtime->ThrowError("Parameter error. The number of parameters must be greater than or equal to 1.",
423             ERROR_CODE_PARAM_INVALID);
424         return runtime->NewUndefined();
425     }
426     const shared_ptr<JsValue>& paramObj = argv[0];
427     if (!paramObj || !paramObj->IsObject(runtime)) {
428         LOGE("JsAnimatorUpdate failed, first argument is not an object!");
429         runtime->ThrowError("Parameter error. The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
430         return runtime->NewUndefined();
431     }
432     int32_t len = 0;
433     shared_ptr<JsValue> properties;
434     if (!paramObj->GetPropertyNames(runtime, properties, len)) {
435         LOGE("JsAnimatorUpdate failed, fail to get object property list!");
436         runtime->ThrowError("Internal error. Fail to get object property list.", ERROR_CODE_INTERNAL_ERROR);
437         return runtime->NewUndefined();
438     }
439     std::unordered_map<std::string, std::string> params;
440     for (int32_t i = 0; i < len; ++i) {
441         shared_ptr<JsValue> key = properties->GetElement(runtime, i);
442         shared_ptr<JsValue> val = paramObj->GetProperty(runtime, key);
443         std::string keyStr = key->ToString(runtime);
444         std::string valStr = val->ToString(runtime);
445         params[keyStr] = valStr;
446     }
447     int32_t pageId = GetCurrentPageId(runtime, thisObj);
448     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
449     auto page = GetPageById(runtime, pageId);
450     if (!page) {
451         LOGE("no page found for pageId: %{public}d", pageId);
452         runtime->ThrowError("Internal error. Can not find the page for pageId.", ERROR_CODE_INTERNAL_ERROR);
453         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
454         return runtime->NewUndefined();
455     }
456     auto task = AceType::MakeRefPtr<JsiAnimatorTaskUpdate>(runtime, params);
457     page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
458     return runtime->NewUndefined();
459 }
460 
JsCreateBridgeId()461 int32_t JsiAnimatorBridgeUtils::JsCreateBridgeId()
462 {
463     static int32_t bridgeId = 0;
464     return bridgeId++;
465 }
466 
JsiAnimatorBridge(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & animatorContext)467 JsiAnimatorBridge::JsiAnimatorBridge(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& animatorContext)
468     : animatorObject_(animatorContext)
469 {
470     runtime_ = runtime;
471 }
472 
~JsiAnimatorBridge()473 JsiAnimatorBridge::~JsiAnimatorBridge()
474 {
475     RefPtr<Animator> animator;
476     animator.Swap(animator_);
477     auto taskExecutor = Container::CurrentTaskExecutor();
478     if (taskExecutor) {
479         taskExecutor->PostSyncTask(
480             [&animator]() {
481               LOGI("release animator on UI thread");
482               animator.Reset();
483             },
484             TaskExecutor::TaskType::UI, "ArkUIAnimatorRelease");
485     }
486 }
487 
JsCreateAnimation(const std::string & param)488 void JsiAnimatorBridge::JsCreateAnimation(const std::string& param)
489 {
490     int32_t iterations = 0;
491     double duration = 0.0;
492     double delay = 0.0;
493     std::unordered_map<std::string, double> animationDoubleParams;
494     std::unordered_map<std::string, std::string> animationStringParams;
495     BaseAnimationBridgeUtils::JsParseAnimatorParams(param, iterations, animationDoubleParams, animationStringParams);
496     RefPtr<Curve> curve;
497     std::string curveString;
498     auto iterEasing = animationStringParams.find(DOM_ANIMATION_EASING);
499     if (iterEasing != animationStringParams.end()) {
500         curveString = iterEasing->second;
501     }
502     curve = CreateCurve(curveString);
503     auto iterDuration = animationDoubleParams.find(DOM_ANIMATION_DURATION_API);
504     if (iterDuration != animationDoubleParams.end()) {
505         duration = iterDuration->second;
506     }
507     std::string fillString;
508     auto iterFill = animationStringParams.find(DOM_ANIMATION_FILL);
509     if (iterFill != animationStringParams.end()) {
510         fillString = iterFill->second;
511     }
512     auto iterDelay = animationDoubleParams.find(DOM_ANIMATION_DELAY_API);
513     if (iterDelay != animationDoubleParams.end()) {
514         delay = iterDelay->second;
515     }
516     if (!runtime_) {
517         LOGE("runtime is null");
518         return;
519     }
520     auto keyframeAnimation = CreateDoubleAnimation(animationDoubleParams, curve);
521     if (!animator_) {
522         animator_ = CREATE_ANIMATOR();
523     }
524     if (!animator_->IsStopped()) {
525         animator_->Stop();
526     }
527     auto iterDirection = animationStringParams.find(DOM_ANIMATION_DIRECTION_API);
528     if (iterDirection != animationStringParams.end()) {
529         animator_->SetAnimationDirection(StringToAnimationDirection(iterDirection->second));
530     }
531     animator_->ClearInterpolators();
532     animator_->SetDuration(duration);
533     animator_->SetIteration(iterations);
534     animator_->SetStartDelay(delay);
535     animator_->SetFillMode(StringToFillMode(fillString));
536     animator_->AddInterpolator(keyframeAnimation);
537     AddListenerForEventCallback(AceType::WeakClaim(this), animator_, runtime_);
538 }
539 
CreateDoubleAnimation(std::unordered_map<std::string,double> & animationParams,const RefPtr<Curve> & curve)540 RefPtr<KeyframeAnimation<double>> JsiAnimatorBridge::CreateDoubleAnimation(
541     std::unordered_map<std::string, double>& animationParams, const RefPtr<Curve>& curve)
542 {
543     double begin = 0.0;
544     double end = 1.0;
545     auto animationBegin = animationParams.find(DOM_ANIMATION_BEGIN);
546     if (animationBegin != animationParams.end()) {
547         begin = animationBegin->second;
548     }
549     auto animationEnd = animationParams.find(DOM_ANIMATION_END);
550     if (animationEnd != animationParams.end()) {
551         end = animationEnd->second;
552     }
553     auto keyframeBegin = AceType::MakeRefPtr<Keyframe<double>>(0.0, begin);
554     auto keyframeEnd = AceType::MakeRefPtr<Keyframe<double>>(1.0, end);
555     auto keyframeAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
556     keyframeAnimation->AddKeyframe(keyframeBegin);
557     keyframeAnimation->AddKeyframe(keyframeEnd);
558     keyframeAnimation->SetCurve(curve);
559     AddFrameListener(AceType::WeakClaim(this), keyframeAnimation, runtime_);
560     return keyframeAnimation;
561 }
562 
JsiAnimatorTaskCreate(shared_ptr<JsRuntime> runtime,const RefPtr<JsiAnimatorBridge> & bridge,const std::string & param)563 JsiAnimatorTaskCreate::JsiAnimatorTaskCreate(
564     shared_ptr<JsRuntime> runtime, const RefPtr<JsiAnimatorBridge>& bridge, const std::string& param)
565     : bridge_(bridge), runtime_(runtime), param_(std::move(param))
566 {}
567 
AnimatorBridgeTaskFunc(const RefPtr<JsAcePage> & page,int32_t bridgeId)568 void JsiAnimatorTaskCreate::AnimatorBridgeTaskFunc(const RefPtr<JsAcePage>& page, int32_t bridgeId)
569 {
570     if (!page) {
571         LOGE("Create Animation Bridge failed. page is null.");
572         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
573         return;
574     }
575     if (!bridge_) {
576         LOGE("Create Animation Bridge failed. bridge is null.");
577         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
578         return;
579     }
580     auto bridgeFree = AceType::DynamicCast<JsiAnimatorBridge>(page->GetAnimatorBridge(bridgeId));
581     auto delegate = GetFrontendDelegate(runtime_);
582     if (!delegate) {
583         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
584         LOGE("Create Animation Bridge failed. delegate is null.");
585         return;
586     }
587     auto jsTaskExecutor = delegate->GetAnimationJsTask();
588     if (bridgeFree) {
589         auto weakBridge = AceType::WeakClaim(AceType::RawPtr(bridgeFree));
590         jsTaskExecutor.PostTask(
591             [weakBridge]() mutable {
592                 auto bridgeFree = weakBridge.Upgrade();
593                 if (bridgeFree != nullptr) {
594                     bridgeFree.Reset();
595                 }
596             },
597             "ArkUIAnimatorBridgeRelease");
598     }
599     page->RemoveAnimatorBridge(bridgeId);
600     bridge_->JsCreateAnimation(param_);
601     page->AddAnimatorBridge(bridgeId, bridge_);
602 }
603 
AnimatorBridgeTaskFunc(const RefPtr<JsAcePage> & page,int32_t bridgeId)604 void JsiAnimatorTaskOperation::AnimatorBridgeTaskFunc(const RefPtr<JsAcePage>& page, int32_t bridgeId)
605 {
606     if (!page) {
607         LOGE("AnimatorBridgeTaskFunc failed. page is null");
608         return;
609     }
610     auto animatorBridge = AceType::DynamicCast<JsiAnimatorBridge>(page->GetAnimatorBridge(bridgeId));
611     if (!animatorBridge) {
612         LOGE("no animation bridge found for bridgeId: %{public}d", bridgeId);
613         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
614         return;
615     }
616     RefPtr<Animator> animator = animatorBridge->JsGetAnimator();
617     if (!animator) {
618         LOGE("animator is null");
619         return;
620     }
621     switch (operation_) {
622         case AnimatorOperation::PLAY:
623             animator->Play();
624             break;
625         case AnimatorOperation::PAUSE:
626             animator->Pause();
627             break;
628         case AnimatorOperation::CANCEL:
629             animator->Cancel();
630             break;
631         case AnimatorOperation::FINISH:
632             animator->Finish();
633             break;
634         case AnimatorOperation::REVERSE:
635             animator->Reverse();
636             break;
637         case AnimatorOperation::NONE:
638         default:
639             break;
640     }
641 }
642 
AnimatorBridgeTaskFunc(const RefPtr<JsAcePage> & page,int32_t bridgeId)643 void JsiAnimatorTaskUpdate::AnimatorBridgeTaskFunc(const RefPtr<JsAcePage>& page, int32_t bridgeId)
644 {
645     if (!page) {
646         LOGE("AnimatorBridgeTaskFunc failed. page is null");
647         return;
648     }
649     auto animatorBridge = AceType::DynamicCast<JsiAnimatorBridge>(page->GetAnimatorBridge(bridgeId));
650     if (!animatorBridge) {
651         LOGE("no animation bridge found for bridgeId: %{public}d", bridgeId);
652         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
653         return;
654     }
655     RefPtr<Animator> animator = animatorBridge->JsGetAnimator();
656     if (!animator) {
657         LOGE("animator is null");
658         return;
659     }
660     if (!runtime_) {
661         LOGE("runtime is null");
662         return;
663     }
664     animator->ClearInterpolators();
665     animator->ResetIsReverse();
666     UpdateAnimator(animator, animatorBridge, runtime_, params_);
667 }
668 
UpdateAnimator(const RefPtr<Animator> & animator,const RefPtr<JsiAnimatorBridge> & bridge,shared_ptr<JsRuntime> runtime,const std::unordered_map<std::string,std::string> & params)669 void JsiAnimatorTaskUpdate::UpdateAnimator(const RefPtr<Animator>& animator, const RefPtr<JsiAnimatorBridge>& bridge,
670     shared_ptr<JsRuntime> runtime, const std::unordered_map<std::string, std::string>& params)
671 {
672     int32_t iterations = 1;
673     double duration = 0.0;
674     double delay = 0.0;
675     double begin = 0.0;
676     double end = 1.0;
677     std::string curveString;
678     std::string fillString;
679     RefPtr<Curve> curve;
680     auto iterEasing = params_.find(DOM_ANIMATION_EASING);
681     if (iterEasing != params_.end()) {
682         curveString = iterEasing->second;
683     }
684     curve = CreateCurve(curveString);
685     auto iterIterations = params_.find(DOM_ANIMATION_ITERATIONS);
686     if (iterIterations != params_.end()) {
687         iterations = StringToInt(iterIterations->second);
688     }
689     auto iterDuration = params_.find(DOM_ANIMATION_DURATION_API);
690     if (iterDuration != params_.end()) {
691         duration = StringToDouble(iterDuration->second);
692     }
693     auto iterFill = params_.find(DOM_ANIMATION_FILL);
694     if (iterFill != params_.end()) {
695         fillString = iterFill->second;
696     }
697     auto iterDelay = params_.find(DOM_ANIMATION_DELAY_API);
698     if (iterDelay != params_.end()) {
699         delay = StringToDouble(iterDelay->second);
700     }
701     auto iterDirection = params_.find(DOM_ANIMATION_DIRECTION_API);
702     if (iterDirection != params_.end()) {
703         animator->SetAnimationDirection(StringToAnimationDirection(iterDirection->second));
704     }
705     auto animationBegin = params_.find(DOM_ANIMATION_BEGIN);
706     if (animationBegin != params_.end()) {
707         begin = StringToDouble(animationBegin->second);
708     }
709     auto animationEnd = params_.find(DOM_ANIMATION_END);
710     if (animationEnd != params_.end()) {
711         end = StringToDouble(animationEnd->second);
712     }
713     auto keyframeAnimation = CreateDoubleAnimation(begin, end, curve);
714     AddFrameListener(AceType::WeakClaim(RawPtr(bridge)), keyframeAnimation, runtime);
715     animator->SetDuration(duration);
716     animator->SetIteration(iterations);
717     animator->SetStartDelay(delay);
718     animator->SetFillMode(StringToFillMode(fillString));
719     animator->AddInterpolator(keyframeAnimation);
720 }
721 
CreateDoubleAnimation(double begin,double end,const RefPtr<Curve> & curve)722 RefPtr<KeyframeAnimation<double>> JsiAnimatorTaskUpdate::CreateDoubleAnimation(
723     double begin, double end, const RefPtr<Curve>& curve)
724 {
725     auto keyframeBegin = AceType::MakeRefPtr<Keyframe<double>>(0.0, begin);
726     auto keyframeEnd = AceType::MakeRefPtr<Keyframe<double>>(1.0, end);
727     auto keyframeAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
728     keyframeAnimation->AddKeyframe(keyframeBegin);
729     keyframeAnimation->AddKeyframe(keyframeEnd);
730     keyframeAnimation->SetCurve(curve);
731     return keyframeAnimation;
732 }
733 
734 } // namespace OHOS::Ace::Framework
735