• 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         return;
136     }
137     jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
138 }
139 
CallAnimationFinishJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)140 void CallAnimationFinishJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
141 {
142     auto bridge = bridgeWeak.Upgrade();
143     if (!bridge) {
144         LOGE("Call Animation Finish Js Failed. animation bridge is null.");
145         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
146         return;
147     }
148     if (!runtime) {
149         LOGE("Call Animation Finish Js Failed. runtime is null.");
150         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
151         return;
152     }
153     auto animationObject = bridge->GetJsObject();
154     if (!animationObject || animationObject->IsNull(runtime)) {
155         LOGE("Animation Object is null");
156         return;
157     }
158     shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onfinish");
159     if (!jsFunc || !jsFunc->IsFunction(runtime)) {
160         return;
161     }
162     jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
163 }
164 
CallAnimationCancelJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)165 void CallAnimationCancelJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
166 {
167     auto bridge = bridgeWeak.Upgrade();
168     if (!bridge) {
169         LOGE("Call Animation Cancel Js Failed. animation bridge is null.");
170         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
171         return;
172     }
173     if (!runtime) {
174         LOGE("Call Animation Cancel Js Failed. runtime is null.");
175         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
176         return;
177     }
178     auto animationObject = bridge->GetJsObject();
179     if (!animationObject || animationObject->IsNull(runtime)) {
180         LOGE("Animation Object is null");
181         return;
182     }
183     shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "oncancel");
184     if (!jsFunc || !jsFunc->IsFunction(runtime)) {
185         return;
186     }
187     jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
188 }
189 
CallAnimationRepeatJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)190 void CallAnimationRepeatJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
191 {
192     auto bridge = bridgeWeak.Upgrade();
193     if (!bridge) {
194         LOGE("Call Animation Repeat Js Failed. animation bridge is null.");
195         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
196         return;
197     }
198     if (!runtime) {
199         LOGE("Call Animation Repeat Js Failed. runtime is null.");
200         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
201         return;
202     }
203     auto animationObject = bridge->GetJsObject();
204     if (!animationObject || animationObject->IsNull(runtime)) {
205         LOGE("Animation Object is null");
206         return;
207     }
208     shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onrepeat");
209     if (!jsFunc || !jsFunc->IsFunction(runtime)) {
210         return;
211     }
212     jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
213 }
214 
CallAnimationFrameJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime,double value)215 void CallAnimationFrameJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime, double value)
216 {
217     auto bridge = bridgeWeak.Upgrade();
218     if (!bridge) {
219         LOGE("Call Animation Frame Js Failed. animation bridge is null.");
220         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
221         return;
222     }
223     if (!runtime) {
224         LOGE("Call Animation Frame Js Failed. runtime is null.");
225         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
226         return;
227     }
228     auto animationObject = bridge->GetJsObject();
229     if (!animationObject || animationObject->IsNull(runtime)) {
230         LOGE("Animation Object is null");
231         return;
232     }
233     shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onframe");
234     if (!jsFunc || !jsFunc->IsFunction(runtime)) {
235         return;
236     }
237     std::vector<shared_ptr<JsValue>> argv = { runtime->NewNumber(value) };
238     jsFunc->Call(runtime, runtime->GetGlobal(), argv, argv.size());
239 }
240 
AddListenerForEventCallback(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,const RefPtr<Animator> & animator,shared_ptr<JsRuntime> runtime)241 void AddListenerForEventCallback(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, const RefPtr<Animator>& animator,
242     shared_ptr<JsRuntime> runtime)
243 {
244     std::weak_ptr<JsRuntime> weakRuntime(runtime);
245     animator->AddStartListener([weakRuntime, bridgeWeak] {
246         auto delegate = GetFrontendDelegate(weakRuntime);
247         if (!delegate) {
248             LOGE("Handle Start listener failed, fail to get delegate");
249             return;
250         }
251         auto jsTaskExecutor = delegate->GetAnimationJsTask();
252         jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
253             LOGI("call animation onstart event");
254             CallAnimationStartJs(bridgeWeak, weakRuntime.lock());
255         });
256     });
257     animator->AddStopListener([weakRuntime, bridgeWeak] {
258         auto delegate = GetFrontendDelegate(weakRuntime);
259         if (!delegate) {
260             LOGE("Handle Stop listener failed, fail to get delegate");
261             return;
262         }
263         auto jsTaskExecutor = delegate->GetAnimationJsTask();
264         jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
265             LOGI("call animation onfinish event");
266             CallAnimationFinishJs(bridgeWeak, weakRuntime.lock());
267         });
268     });
269     animator->AddIdleListener([weakRuntime, bridgeWeak] {
270         auto delegate = GetFrontendDelegate(weakRuntime);
271         if (!delegate) {
272             LOGE("Handle Idle listener failed, fail to get delegate");
273             return;
274         }
275         auto jsTaskExecutor = delegate->GetAnimationJsTask();
276         jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
277             LOGI("call animation oncancel event");
278             CallAnimationCancelJs(bridgeWeak, weakRuntime.lock());
279         });
280     });
281     animator->AddRepeatListener([weakRuntime, bridgeWeak] {
282         auto delegate = GetFrontendDelegate(weakRuntime);
283         if (!delegate) {
284             LOGE("Handle Repeat listener failed, fail to get delegate");
285             return;
286         }
287         auto jsTaskExecutor = delegate->GetAnimationJsTask();
288         jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
289             LOGI("call animation onrepeat event");
290             CallAnimationRepeatJs(bridgeWeak, weakRuntime.lock());
291         });
292     });
293 }
294 
AddFrameListener(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,const RefPtr<KeyframeAnimation<double>> & animator,shared_ptr<JsRuntime> runtime)295 void AddFrameListener(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, const RefPtr<KeyframeAnimation<double>>& animator,
296     shared_ptr<JsRuntime> runtime)
297 {
298     std::weak_ptr<JsRuntime> weakRuntime(runtime);
299     animator->AddListener([weakRuntime, bridgeWeak](double value) {
300         auto delegate = GetFrontendDelegate(weakRuntime);
301         if (!delegate) {
302             LOGE("Handle Frame listener failed, fail to get delegate");
303             return;
304         }
305         auto jsTaskExecutor = delegate->GetAnimationJsTask();
306         jsTaskExecutor.PostTask([bridgeWeak, weakRuntime, value]() mutable {
307             LOGI("call animation onframe event");
308             CallAnimationFrameJs(bridgeWeak, weakRuntime.lock(), value);
309         });
310     });
311 }
312 
313 } // namespace
314 
CreateAnimatorContext(shared_ptr<JsRuntime> runtime,int32_t pageId,int32_t bridgeId)315 shared_ptr<JsValue> JsiAnimatorBridgeUtils::CreateAnimatorContext(
316     shared_ptr<JsRuntime> runtime, int32_t pageId, int32_t bridgeId)
317 {
318     const std::unordered_map<const char*, RegisterFunctionType> contextTable = {
319         { "play", JsAnimatorPlay },
320         { "finish", JsAnimatorFinish },
321         { "pause", JsAnimatorPause },
322         { "cancel", JsAnimatorCancel },
323         { "reverse", JsAnimatorReverse },
324         { "update", JsAnimatorUpdate },
325         { "reset", JsAnimatorReset },
326     };
327     auto animatorContext = runtime->NewObject();
328     for (const auto& iter : contextTable) {
329         animatorContext->SetProperty(runtime, iter.first, runtime->NewFunction(iter.second));
330     }
331     animatorContext->SetProperty(runtime, "__pageId", runtime->NewInt32(pageId));
332     animatorContext->SetProperty(runtime, "__bridgeId", runtime->NewInt32(bridgeId));
333     return animatorContext;
334 }
335 
JsAnimatorPlay(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)336 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorPlay(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
337     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
338 {
339     int32_t pageId = GetCurrentPageId(runtime, thisObj);
340     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
341     HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::PLAY);
342     return runtime->NewUndefined();
343 }
344 
JsAnimatorFinish(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)345 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorFinish(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
346     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
347 {
348     int32_t pageId = GetCurrentPageId(runtime, thisObj);
349     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
350     HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::FINISH);
351     return runtime->NewUndefined();
352 }
353 
JsAnimatorPause(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)354 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorPause(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
355     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
356 {
357     int32_t pageId = GetCurrentPageId(runtime, thisObj);
358     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
359     HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::PAUSE);
360     return runtime->NewUndefined();
361 }
362 
JsAnimatorCancel(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)363 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorCancel(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
364     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
365 {
366     int32_t pageId = GetCurrentPageId(runtime, thisObj);
367     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
368     HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::CANCEL);
369     return runtime->NewUndefined();
370 }
371 
JsAnimatorReverse(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)372 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorReverse(shared_ptr<JsRuntime> runtime,
373     shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
374 {
375     int32_t pageId = GetCurrentPageId(runtime, thisObj);
376     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
377     HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::REVERSE);
378     return runtime->NewUndefined();
379 }
380 
381 // 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)382 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorUpdate(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
383     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
384 {
385     if (argv.empty()) {
386         return runtime->NewUndefined();
387     }
388     const shared_ptr<JsValue>& paramObj = argv[0];
389     if (!paramObj || !paramObj->IsObject(runtime)) {
390         LOGE("JsAnimatorUpdate failed, first argument is not an object!");
391         return runtime->NewUndefined();
392     }
393     int32_t len = 0;
394     shared_ptr<JsValue> properties;
395     if (!paramObj->GetPropertyNames(runtime, properties, len)) {
396         LOGE("JsAnimatorUpdate failed, fail to get object property list!");
397         return runtime->NewUndefined();
398     }
399     std::unordered_map<std::string, std::string> params;
400     for (int32_t i = 0; i < len; ++i) {
401         shared_ptr<JsValue> key = properties->GetElement(runtime, i);
402         shared_ptr<JsValue> val = paramObj->GetProperty(runtime, key);
403         std::string keyStr = key->ToString(runtime);
404         std::string valStr = val->ToString(runtime);
405         params[keyStr] = valStr;
406     }
407     int32_t pageId = GetCurrentPageId(runtime, thisObj);
408     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
409     auto page = GetPageById(runtime, pageId);
410     if (!page) {
411         LOGE("no page found for pageId: %{public}d", pageId);
412         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
413         return runtime->NewUndefined();
414     }
415     auto task = AceType::MakeRefPtr<JsiAnimatorTaskUpdate>(runtime, params);
416     page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
417     return runtime->NewUndefined();
418 }
419 
JsAnimatorReset(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)420 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorReset(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
421     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
422 {
423     if (argv.empty()) {
424         runtime->ThrowError("Parameter error. The number of parameters must be greater than or equal to 1.",
425             ERROR_CODE_PARAM_INVALID);
426         return runtime->NewUndefined();
427     }
428     const shared_ptr<JsValue>& paramObj = argv[0];
429     if (!paramObj || !paramObj->IsObject(runtime)) {
430         LOGE("JsAnimatorUpdate failed, first argument is not an object!");
431         runtime->ThrowError("Parameter error. The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
432         return runtime->NewUndefined();
433     }
434     int32_t len = 0;
435     shared_ptr<JsValue> properties;
436     if (!paramObj->GetPropertyNames(runtime, properties, len)) {
437         LOGE("JsAnimatorUpdate failed, fail to get object property list!");
438         runtime->ThrowError("Internal error. Fail to get object property list.", ERROR_CODE_INTERNAL_ERROR);
439         return runtime->NewUndefined();
440     }
441     std::unordered_map<std::string, std::string> params;
442     for (int32_t i = 0; i < len; ++i) {
443         shared_ptr<JsValue> key = properties->GetElement(runtime, i);
444         shared_ptr<JsValue> val = paramObj->GetProperty(runtime, key);
445         std::string keyStr = key->ToString(runtime);
446         std::string valStr = val->ToString(runtime);
447         params[keyStr] = valStr;
448     }
449     int32_t pageId = GetCurrentPageId(runtime, thisObj);
450     int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
451     auto page = GetPageById(runtime, pageId);
452     if (!page) {
453         LOGE("no page found for pageId: %{public}d", pageId);
454         runtime->ThrowError("Internal error. Can not find the page for pageId.", ERROR_CODE_INTERNAL_ERROR);
455         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
456         return runtime->NewUndefined();
457     }
458     auto task = AceType::MakeRefPtr<JsiAnimatorTaskUpdate>(runtime, params);
459     page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
460     return runtime->NewUndefined();
461 }
462 
JsCreateBridgeId()463 int32_t JsiAnimatorBridgeUtils::JsCreateBridgeId()
464 {
465     static int32_t bridgeId = 0;
466     return bridgeId++;
467 }
468 
JsiAnimatorBridge(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & animatorContext)469 JsiAnimatorBridge::JsiAnimatorBridge(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& animatorContext)
470     : animatorObject_(animatorContext)
471 {
472     runtime_ = runtime;
473 }
474 
~JsiAnimatorBridge()475 JsiAnimatorBridge::~JsiAnimatorBridge()
476 {
477     RefPtr<Animator> animator;
478     animator.Swap(animator_);
479     auto taskExecutor = Container::CurrentTaskExecutor();
480     if (taskExecutor) {
481         taskExecutor->PostSyncTask(
482             [&animator]() {
483               LOGI("release animator on UI thread");
484               animator.Reset();
485             },
486             TaskExecutor::TaskType::UI);
487     }
488 }
489 
JsCreateAnimation(const std::string & param)490 void JsiAnimatorBridge::JsCreateAnimation(const std::string& param)
491 {
492     int32_t iterations = 0;
493     double duration = 0.0;
494     double delay = 0.0;
495     std::unordered_map<std::string, double> animationDoubleParams;
496     std::unordered_map<std::string, std::string> animationStringParams;
497     BaseAnimationBridgeUtils::JsParseAnimatorParams(param, iterations, animationDoubleParams, animationStringParams);
498     RefPtr<Curve> curve;
499     std::string curveString;
500     auto iterEasing = animationStringParams.find(DOM_ANIMATION_EASING);
501     if (iterEasing != animationStringParams.end()) {
502         curveString = iterEasing->second;
503     }
504     curve = CreateCurve(curveString);
505     auto iterDuration = animationDoubleParams.find(DOM_ANIMATION_DURATION_API);
506     if (iterDuration != animationDoubleParams.end()) {
507         duration = iterDuration->second;
508     }
509     std::string fillString;
510     auto iterFill = animationStringParams.find(DOM_ANIMATION_FILL);
511     if (iterFill != animationStringParams.end()) {
512         fillString = iterFill->second;
513     }
514     auto iterDelay = animationDoubleParams.find(DOM_ANIMATION_DELAY_API);
515     if (iterDelay != animationDoubleParams.end()) {
516         delay = iterDelay->second;
517     }
518     if (!runtime_) {
519         LOGE("runtime is null");
520         return;
521     }
522     auto keyframeAnimation = CreateDoubleAnimation(animationDoubleParams, curve);
523     if (!animator_) {
524         animator_ = CREATE_ANIMATOR();
525     }
526     if (!animator_->IsStopped()) {
527         animator_->Stop();
528     }
529     auto iterDirection = animationStringParams.find(DOM_ANIMATION_DIRECTION_API);
530     if (iterDirection != animationStringParams.end()) {
531         animator_->SetAnimationDirection(StringToAnimationDirection(iterDirection->second));
532     }
533     animator_->ClearInterpolators();
534     animator_->SetDuration(duration);
535     animator_->SetIteration(iterations);
536     animator_->SetStartDelay(delay);
537     animator_->SetFillMode(StringToFillMode(fillString));
538     animator_->AddInterpolator(keyframeAnimation);
539     AddListenerForEventCallback(AceType::WeakClaim(this), animator_, runtime_);
540 }
541 
CreateDoubleAnimation(std::unordered_map<std::string,double> & animationParams,const RefPtr<Curve> & curve)542 RefPtr<KeyframeAnimation<double>> JsiAnimatorBridge::CreateDoubleAnimation(
543     std::unordered_map<std::string, double>& animationParams, const RefPtr<Curve>& curve)
544 {
545     double begin = 0.0;
546     double end = 1.0;
547     auto animationBegin = animationParams.find(DOM_ANIMATION_BEGIN);
548     if (animationBegin != animationParams.end()) {
549         begin = animationBegin->second;
550     }
551     auto animationEnd = animationParams.find(DOM_ANIMATION_END);
552     if (animationEnd != animationParams.end()) {
553         end = animationEnd->second;
554     }
555     auto keyframeBegin = AceType::MakeRefPtr<Keyframe<double>>(0.0, begin);
556     auto keyframeEnd = AceType::MakeRefPtr<Keyframe<double>>(1.0, end);
557     auto keyframeAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
558     keyframeAnimation->AddKeyframe(keyframeBegin);
559     keyframeAnimation->AddKeyframe(keyframeEnd);
560     keyframeAnimation->SetCurve(curve);
561     AddFrameListener(AceType::WeakClaim(this), keyframeAnimation, runtime_);
562     return keyframeAnimation;
563 }
564 
JsiAnimatorTaskCreate(shared_ptr<JsRuntime> runtime,const RefPtr<JsiAnimatorBridge> & bridge,const std::string & param)565 JsiAnimatorTaskCreate::JsiAnimatorTaskCreate(
566     shared_ptr<JsRuntime> runtime, const RefPtr<JsiAnimatorBridge>& bridge, const std::string& param)
567     : bridge_(bridge), runtime_(runtime), param_(std::move(param))
568 {}
569 
AnimatorBridgeTaskFunc(const RefPtr<JsAcePage> & page,int32_t bridgeId)570 void JsiAnimatorTaskCreate::AnimatorBridgeTaskFunc(const RefPtr<JsAcePage>& page, int32_t bridgeId)
571 {
572     if (!page) {
573         LOGE("Create Animation Bridge failed. page is null.");
574         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
575         return;
576     }
577     if (!bridge_) {
578         LOGE("Create Animation Bridge failed. bridge is null.");
579         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
580         return;
581     }
582     auto bridgeFree = AceType::DynamicCast<JsiAnimatorBridge>(page->GetAnimatorBridge(bridgeId));
583     auto delegate = GetFrontendDelegate(runtime_);
584     if (!delegate) {
585         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
586         LOGE("Create Animation Bridge failed. delegate is null.");
587         return;
588     }
589     auto jsTaskExecutor = delegate->GetAnimationJsTask();
590     if (bridgeFree) {
591         auto weakBridge = AceType::WeakClaim(AceType::RawPtr(bridgeFree));
592         jsTaskExecutor.PostTask([weakBridge]() mutable {
593             auto bridgeFree = weakBridge.Upgrade();
594             if (bridgeFree != nullptr) {
595                 bridgeFree.Reset();
596             }
597         });
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