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