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_animation_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 
GetCurrentNodeId(shared_ptr<JsRuntime> & runtime,shared_ptr<JsValue> & value)56 inline NodeId GetCurrentNodeId(shared_ptr<JsRuntime>& runtime, shared_ptr<JsValue>& value)
57 {
58     if (!value) {
59         LOGE("Get current node id failed. value is null.");
60         return 0;
61     }
62     shared_ptr<JsValue> jsNodeId = value->GetProperty(runtime, "__nodeId");
63     if (!jsNodeId || !jsNodeId->IsInt32(runtime)) {
64         LOGE("Get current node id failed. jsNodeId is null or not a integer");
65         return 0;
66     }
67 
68     NodeId id = jsNodeId->ToInt32(runtime);
69     if (id < 0) {
70         return 0;
71     }
72     return id;
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     if (pageId < 0) {
88         return 0;
89     }
90     return pageId;
91 }
92 
HandleJsAnimationContext(const shared_ptr<JsRuntime> & runtime,int32_t pageId,int32_t nodeId,AnimationOperation operation)93 void HandleJsAnimationContext(
94     const shared_ptr<JsRuntime>& runtime, int32_t pageId, int32_t nodeId, AnimationOperation operation)
95 {
96     if (!runtime) {
97         LOGE("Handle JsAnimationContext failed, runtime is null.");
98         return;
99     }
100     auto delegate = GetFrontendDelegate(runtime);
101     if (!delegate) {
102         LOGE("Handle JsAnimationContext failed, delegate is null.");
103         return;
104     }
105     auto page = GetPageById(runtime, pageId);
106     if (!page) {
107         LOGE("no page found for nodeId: %{public}d", nodeId);
108         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
109         return;
110     }
111     auto task = AceType::MakeRefPtr<JsiAnimationBridgeTaskOperation>(operation);
112     page->PushCommand(AceType::MakeRefPtr<JsCommandAnimation>(nodeId, task));
113     if (page->CheckPageCreated()) {
114         delegate->TriggerPageUpdate(page->GetPageId());
115     }
116 }
117 
118 const std::vector<std::tuple<std::string, RegisterFunctionType, RegisterFunctionType>> JSI_ANIMATION_FUNCS = {
119     { "playState", JsiAnimationBridgeUtils::JsAnimationPlayStateGet, JsiAnimationBridgeUtils::JsAnimationPlayStateSet },
120     { "startTime", JsiAnimationBridgeUtils::JsAnimationStartTimeGet, JsiAnimationBridgeUtils::JsAnimationStartTimeSet },
121     { "pending", JsiAnimationBridgeUtils::JsAnimationPendingGet, JsiAnimationBridgeUtils::JsAnimationPendingSet }
122 };
123 
CallAnimationFinishJs(const WeakPtr<JsiAnimationBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime,const RefPtr<JsAcePage> & page)124 void CallAnimationFinishJs(const WeakPtr<JsiAnimationBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime,
125     const RefPtr<JsAcePage>& page)
126 {
127     auto bridge = bridgeWeak.Upgrade();
128     if (!bridge) {
129         LOGE("Call Animation Finish Js Failed. animation bridge is null.");
130         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
131         return;
132     }
133     if (!runtime) {
134         LOGE("Call Animation Finish Js Failed. runtime is null.");
135         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
136         return;
137     }
138     auto animationObject = bridge->GetJsObject();
139     if (!animationObject || animationObject->IsNull(runtime)) {
140         LOGE("Animation Object is null");
141         return;
142     }
143     shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onfinish");
144     if (!jsFunc || !jsFunc->IsFunction(runtime)) {
145         return;
146     }
147     jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
148 }
149 
CallAnimationCancelJs(const WeakPtr<JsiAnimationBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime,const RefPtr<JsAcePage> & page)150 void CallAnimationCancelJs(const WeakPtr<JsiAnimationBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime,
151     const RefPtr<JsAcePage>& page)
152 {
153     auto bridge = bridgeWeak.Upgrade();
154     if (!bridge) {
155         LOGE("Call Animation Cancel Js Failed. animation bridge is null.");
156         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
157         return;
158     }
159     if (!runtime) {
160         LOGE("Call Animation Cancel Js Failed. runtime is null.");
161         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
162         return;
163     }
164     auto animationObject = bridge->GetJsObject();
165     if (!animationObject || animationObject->IsNull(runtime)) {
166         LOGE("Animation Object is null");
167         return;
168     }
169     shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "oncancel");
170     if (!jsFunc || !jsFunc->IsFunction(runtime)) {
171         return;
172     }
173 
174     jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
175 }
176 
JsUpdatePlayState(shared_ptr<JsRuntime> && runtime,const WeakPtr<JsiAnimationBridge> & bridgeWeak,const char * state)177 void JsUpdatePlayState(
178     shared_ptr<JsRuntime>&& runtime, const WeakPtr<JsiAnimationBridge>& bridgeWeak, const char* state)
179 {
180     if (!runtime) {
181         LOGE("Set playState failed. runtime is null.");
182         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
183         return;
184     }
185     auto bridge = bridgeWeak.Upgrade();
186     if (!bridge) {
187         LOGW("Set playState failed. bridge is null.");
188         return;
189     }
190     auto animationContext = bridge->GetJsObject();
191     if (!animationContext) {
192         LOGW("Set playState failed. animationContext is null.");
193         return;
194     }
195     bool succ = animationContext->SetProperty(runtime, "__playState", runtime->NewString(state));
196     if (!succ) {
197         LOGW("Set playState failed.");
198     }
199 }
200 
AddListenerForEventCallback(const WeakPtr<JsiAnimationBridge> & bridgeWeak,const RefPtr<Animator> & animator,shared_ptr<JsRuntime> runtime,const RefPtr<JsAcePage> & page)201 void AddListenerForEventCallback(const WeakPtr<JsiAnimationBridge>& bridgeWeak, const RefPtr<Animator>& animator,
202     shared_ptr<JsRuntime> runtime, const RefPtr<JsAcePage>& page)
203 {
204     std::weak_ptr<JsRuntime> weakRuntime(runtime);
205     animator->AddStopListener([weakRuntime, bridgeWeak, page] {
206         auto delegate = GetFrontendDelegate(weakRuntime);
207         if (!delegate) {
208             LOGE("Handle Stop listener failed, fail to get delegate");
209             return;
210         }
211         auto jsTaskExecutor = delegate->GetAnimationJsTask();
212         jsTaskExecutor.PostTask(
213             [bridgeWeak, weakRuntime, page]() mutable {
214                 LOGI("call animation onfinish event");
215                 CallAnimationFinishJs(bridgeWeak, weakRuntime.lock(), page);
216             },
217             "ArkUIAnimationStopEvent");
218     });
219     animator->AddIdleListener([weakRuntime, bridgeWeak, page] {
220         auto delegate = GetFrontendDelegate(weakRuntime);
221         if (!delegate) {
222             LOGE("Handle Idle listener failed, fail to get delegate");
223             return;
224         }
225         auto jsTaskExecutor = delegate->GetAnimationJsTask();
226         jsTaskExecutor.PostTask(
227             [bridgeWeak, weakRuntime, page]() mutable {
228                 LOGI("call animation oncancel event");
229                 CallAnimationCancelJs(bridgeWeak, weakRuntime.lock(), page);
230             },
231             "ArkUIAnimationCancelEvent");
232     });
233 }
234 
235 } // namespace
236 
JsiAnimationBridge(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & animationContext,NodeId nodeId)237 JsiAnimationBridge::JsiAnimationBridge(
238     const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& animationContext, NodeId nodeId)
239     : animationObject_(animationContext), nodeId_(nodeId)
240 {
241     runtime_ = runtime;
242 }
243 
JsAnimationStartTimeGet(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)244 shared_ptr<JsValue> JsiAnimationBridgeUtils::JsAnimationStartTimeGet(shared_ptr<JsRuntime> runtime,
245     shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
246 {
247     if (!thisObj) {
248         LOGE("JsAnimationStartTimeGet failed. thisObj is null.");
249         return runtime->NewInt32(0);
250     }
251     int32_t nodeId = GetCurrentNodeId(runtime, thisObj);
252     int32_t pageId = GetCurrentPageId(runtime, thisObj);
253     auto page = GetPageById(runtime, pageId);
254     if (!page) {
255         LOGE("JsAnimationStartTimeGet: no page found for nodeId: %{public}d", nodeId);
256         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
257         return runtime->NewInt32(0);
258     }
259     auto domDocument = page->GetDomDocument();
260     if (!domDocument) {
261         LOGE("JsAnimationStartTimeGet failed, DomDocument is null.");
262         return runtime->NewInt32(0);
263     }
264     auto domNode = domDocument->GetDOMNodeById(nodeId);
265     if (!domNode) {
266         LOGE("JsAnimationStartTimeGet failed, DomNode is null.");
267         return runtime->NewInt32(0);
268     }
269     auto tweenComponent = domNode->GetTweenComponent();
270     if (tweenComponent) {
271         auto option = tweenComponent->GetCustomTweenOption();
272         auto startTime = option.GetDelay();
273         thisObj->SetProperty(runtime, "__startTime", runtime->NewInt32(startTime));
274     }
275     shared_ptr<JsValue> jsDelay = thisObj->GetProperty(runtime, "__startTime");
276     int32_t delay = jsDelay->IsInt32(runtime) ? jsDelay->ToInt32(runtime) : 0;
277     shared_ptr<JsValue> jsResult = runtime->NewInt32(delay);
278     return jsResult;
279 }
280 
JsAnimationStartTimeSet(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)281 shared_ptr<JsValue> JsiAnimationBridgeUtils::JsAnimationStartTimeSet(shared_ptr<JsRuntime> runtime,
282     shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
283 {
284     if (!thisObj) {
285         LOGE("JsAnimationStartTimeSet failed. thisObj is null.");
286         return runtime->NewInt32(0);
287     }
288     if (argv.size() != 1) {
289         LOGE("Not valid Length for info. length: %{public}u", (uint32_t)argv.size());
290         return runtime->NewUndefined();
291     }
292     shared_ptr<JsValue> jsStartTime = argv[0];
293     if (!jsStartTime) {
294         return runtime->NewUndefined();
295     }
296     std::string startTime = jsStartTime->ToString(runtime);
297     int32_t nodeId = GetCurrentNodeId(runtime, thisObj);
298     int32_t pageId = GetCurrentPageId(runtime, thisObj);
299     auto page = GetPageById(runtime, pageId);
300     if (!page) {
301         LOGE("JsAnimationStartTimeSet: no page found for nodeId: %{public}d", nodeId);
302         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
303         return runtime->NewUndefined();
304     }
305     auto task = AceType::MakeRefPtr<JsiAnimationBridgeTaskStartTime>(startTime);
306     page->PushCommand(AceType::MakeRefPtr<JsCommandAnimation>(nodeId, task));
307     return runtime->NewUndefined();
308 }
309 
JsAnimationPendingGet(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)310 shared_ptr<JsValue> JsiAnimationBridgeUtils::JsAnimationPendingGet(shared_ptr<JsRuntime> runtime,
311     shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
312 {
313     if (!thisObj) {
314         LOGE("JsAnimationPendingGet failed. thisObj is null.");
315         return runtime->NewBoolean(true);
316     }
317     int32_t nodeId = GetCurrentNodeId(runtime, thisObj);
318     int32_t pageId = GetCurrentPageId(runtime, thisObj);
319     auto page = GetPageById(runtime, pageId);
320     if (!page) {
321         LOGE("JsAnimationPendingGet: no page found for nodeId: %{public}d", nodeId);
322         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
323         return runtime->NewBoolean(true);
324     }
325     auto domDocument = page->GetDomDocument();
326     if (!domDocument) {
327         LOGE("JsAnimationPendingGet failed, DomDocument is null.");
328         return runtime->NewBoolean(true);
329     }
330     auto domNode = domDocument->GetDOMNodeById(nodeId);
331     if (!domNode) {
332         LOGE("JsAnimationPendingGet failed, DomNode is null.");
333         return runtime->NewBoolean(true);
334     }
335     auto tweenComponent = domNode->GetTweenComponent();
336     if (tweenComponent) {
337         auto controller = tweenComponent->GetAnimator();
338         if (controller) {
339             thisObj->SetProperty(runtime, "__pending", runtime->NewBoolean(controller->IsPending()));
340         }
341     }
342     shared_ptr<JsValue> jsPending = thisObj->GetProperty(runtime, "__pending");
343     bool pending = false;
344     if (jsPending) {
345         pending = jsPending->IsBoolean(runtime) ? jsPending->ToBoolean(runtime) : false;
346     }
347     return runtime->NewBoolean(pending);
348 }
349 
JsAnimationPendingSet(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)350 shared_ptr<JsValue> JsiAnimationBridgeUtils::JsAnimationPendingSet(shared_ptr<JsRuntime> runtime,
351     shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
352 {
353     return runtime->NewUndefined();
354 }
355 
JsAnimationPlayStateGet(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)356 shared_ptr<JsValue> JsiAnimationBridgeUtils::JsAnimationPlayStateGet(shared_ptr<JsRuntime> runtime,
357     shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
358 {
359     if (!thisObj) {
360         LOGE("JsAnimationPlayStateGet failed. thisObj is null.");
361         return runtime->NewUndefined();
362     }
363     shared_ptr<JsValue> jsPending = thisObj->GetProperty(runtime, "__playState");
364     if (!jsPending) {
365         LOGE("JsAnimationPlayStateGet: no pending find.");
366         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
367         return runtime->NewUndefined();
368     }
369     return runtime->NewString(jsPending->ToString(runtime));
370 }
371 
JsAnimationPlayStateSet(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)372 shared_ptr<JsValue> JsiAnimationBridgeUtils::JsAnimationPlayStateSet(shared_ptr<JsRuntime> runtime,
373     shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
374 {
375     if (argv.size() != 1) {
376         LOGE("Not valid Length for info. length: %{public}u", (uint32_t)argv.size());
377         return runtime->NewUndefined();
378     }
379     shared_ptr<JsValue> jsPlayState = argv[0];
380     if (!jsPlayState || !jsPlayState->IsString(runtime)) {
381         LOGE("Not valid type for value.");
382         return runtime->NewUndefined();
383     }
384     std::string playState = jsPlayState->ToString(runtime);
385     AnimationOperation operation = StringToAnimationOperation(playState);
386     int32_t nodeId = GetCurrentNodeId(runtime, thisObj);
387     int32_t pageId = GetCurrentPageId(runtime, thisObj);
388     auto page = GetPageById(runtime, pageId);
389     if (!page) {
390         LOGE("no page found for nodeId: %{public}d", nodeId);
391         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
392         return runtime->NewUndefined();
393     }
394     auto task = AceType::MakeRefPtr<JsiAnimationBridgeTaskOperation>(operation);
395     page->PushCommand(AceType::MakeRefPtr<JsCommandAnimation>(nodeId, task));
396     return runtime->NewUndefined();
397 }
398 
JsCreateAnimation(const RefPtr<JsAcePage> & page,const std::string & param)399 void JsiAnimationBridge::JsCreateAnimation(const RefPtr<JsAcePage>& page, const std::string& param)
400 {
401     std::vector<std::unordered_map<std::string, std::string>> animationFrames;
402     std::unordered_map<std::string, double> animationDoubleOptions;
403     std::unordered_map<std::string, std::string> animationStringOptions;
404     int32_t iterations = 0;
405 
406     BaseAnimationBridgeUtils::JsParseAnimationFrames(param, animationFrames);
407     BaseAnimationBridgeUtils::JsParseAnimationOptions(
408         param, iterations, animationDoubleOptions, animationStringOptions);
409     auto tweenOption = TweenOption();
410     auto iterEasing = animationStringOptions.find(DOM_ANIMATION_EASING);
411     if (iterEasing != animationStringOptions.end()) {
412         tweenOption.SetCurve(CreateCurve(iterEasing->second));
413     }
414     std::vector<Dimension> transformOrigin = BaseAnimationBridgeUtils::HandleTransformOrigin(animationFrames);
415     if (transformOrigin.size() == BaseAnimationBridgeUtils::TRANSFORM_ORIGIN_DEFAULT_SIZE) {
416         tweenOption.SetTransformOrigin(transformOrigin.front(), transformOrigin.back());
417     }
418     auto iterDuration = animationDoubleOptions.find(DOM_ANIMATION_DURATION_API);
419     if (iterDuration != animationDoubleOptions.end()) {
420         tweenOption.SetDuration(iterDuration->second);
421     }
422     auto iterFill = animationStringOptions.find(DOM_ANIMATION_FILL);
423     if (iterFill != animationStringOptions.end()) {
424         tweenOption.SetFillMode(StringToFillMode(iterFill->second));
425     }
426     auto iterDirection = animationStringOptions.find(DOM_ANIMATION_DIRECTION_API);
427     if (iterDirection != animationStringOptions.end()) {
428         tweenOption.SetAnimationDirection(StringToAnimationDirection(iterDirection->second));
429     }
430     auto iterDelay = animationDoubleOptions.find(DOM_ANIMATION_DELAY_API);
431     if (iterDelay != animationDoubleOptions.end()) {
432         tweenOption.SetDelay(iterDelay->second);
433     }
434     tweenOption.SetIteration(iterations);
435 
436     auto domDocument = page->GetDomDocument();
437     if (!domDocument) {
438         LOGE("JsCreateAnimation failed, DomDocument is null.");
439         return;
440     }
441     auto domNode = domDocument->GetDOMNodeById(nodeId_);
442     if (!domNode) {
443         LOGE("JsCreateAnimation failed, DomNode is null.");
444         return;
445     }
446     domNode->ParseAnimationStyle(animationFrames);
447     domNode->TweenOptionSetKeyframes(tweenOption);
448     if (tweenOption.IsValid()) {
449         domNode->SetCustomAnimationStyleUpdate(true);
450     }
451     RefPtr<Animator> animator = CREATE_ANIMATOR();
452     auto tweenComponent = domNode->GetTweenComponent();
453     if (!tweenComponent) {
454         tweenComponent = AceType::MakeRefPtr<TweenComponent>(
455             BaseAnimationBridgeUtils::COMPONENT_PREFIX + std::to_string(nodeId_), domNode->GetTag());
456         domNode->SetTweenComponent(tweenComponent);
457     }
458     tweenComponent->SetAnimator(animator);
459     BaseAnimationBridgeUtils::SetTweenComponentParams(nullptr, animationFrames, tweenComponent, tweenOption);
460     AddListenerForEventCallback(AceType::WeakClaim(this), animator, runtime_, page);
461     domNode->GenerateComponentNode();
462     page->PushDirtyNode(nodeId_);
463 }
464 
SetPlayStateCallbacksWithListenerId(RefPtr<Animator> & animator)465 void JsiAnimationBridge::SetPlayStateCallbacksWithListenerId(RefPtr<Animator>& animator)
466 {
467     WeakPtr<JsiAnimationBridge> bridgeWeak = AceType::WeakClaim(this);
468     animator->RemoveStopListener(finishListenerId_);
469     std::weak_ptr<JsRuntime> weakRuntime(runtime_);
470     finishListenerId_ = animator->AddStopListener([bridgeWeak, weakRuntime] {
471         auto delegate = GetFrontendDelegate(weakRuntime);
472         if (!delegate) {
473             LOGE("Handle stop callback failed. delegate is null.");
474             return;
475         }
476         auto jsTaskExecutor = delegate->GetAnimationJsTask();
477         jsTaskExecutor.PostTask(
478             [weakRuntime, bridgeWeak]() mutable {
479                 JsUpdatePlayState(weakRuntime.lock(), bridgeWeak, DOM_ANIMATION_PLAY_STATE_FINISHED);
480             },
481             "ArkUIAnimationUpdateFinishState");
482     });
483     animator->RemoveIdleListener(idleListenerId_);
484     idleListenerId_ = animator->AddIdleListener([bridgeWeak, weakRuntime] {
485         auto delegate = GetFrontendDelegate(weakRuntime);
486         if (!delegate) {
487             LOGE("Handle idle callback failed. delegate is null.");
488             return;
489         }
490         auto jsTaskExecutor = delegate->GetAnimationJsTask();
491         jsTaskExecutor.PostTask(
492             [weakRuntime, bridgeWeak]() mutable {
493                 JsUpdatePlayState(weakRuntime.lock(), bridgeWeak, DOM_ANIMATION_PLAY_STATE_IDLE);
494             },
495             "ArkUIAnimationUpdateIdleState");
496     });
497 }
498 
SetPlayStateCallbacks(RefPtr<Animator> & animator)499 void JsiAnimationBridge::SetPlayStateCallbacks(RefPtr<Animator>& animator)
500 {
501     if (!animator) {
502         LOGE("Set PlayState callbacks failed. simulation controller is null.");
503         return;
504     }
505     WeakPtr<JsiAnimationBridge> bridgeWeak = AceType::WeakClaim(this);
506     SetPlayStateCallbacksWithListenerId(animator);
507     animator->ClearPauseListeners();
508     std::weak_ptr<JsRuntime> weakRuntime(runtime_);
509     animator->AddPauseListener([bridgeWeak, weakRuntime] {
510         auto delegate = GetFrontendDelegate(weakRuntime);
511         if (!delegate) {
512             LOGE("Handle pause callback failed. delegate is null.");
513             return;
514         }
515         auto jsTaskExecutor = delegate->GetAnimationJsTask();
516         jsTaskExecutor.PostTask([weakRuntime, bridgeWeak]() mutable {
517                 JsUpdatePlayState(weakRuntime.lock(), bridgeWeak, DOM_ANIMATION_PLAY_STATE_PAUSED);
518             },
519             "ArkUIAnimationUpdatePauseState");
520     });
521     animator->ClearStartListeners();
522     animator->AddStartListener([bridgeWeak, weakRuntime] {
523         auto delegate = GetFrontendDelegate(weakRuntime);
524         if (!delegate) {
525             LOGE("Handle start callback failed. delegate is null.");
526             return;
527         }
528         auto jsTaskExecutor = delegate->GetAnimationJsTask();
529         jsTaskExecutor.PostTask([weakRuntime, bridgeWeak]() mutable {
530                 JsUpdatePlayState(weakRuntime.lock(), bridgeWeak, DOM_ANIMATION_PLAY_STATE_RUNNING);
531             },
532             "ArkUIAnimationUpdateStartState");
533     });
534     animator->ClearResumeListeners();
535     animator->AddResumeListener([bridgeWeak, weakRuntime] {
536         auto delegate = GetFrontendDelegate(weakRuntime);
537         if (!delegate) {
538             LOGE("Handle resume callback failed. delegate is null.");
539             return;
540         }
541         auto jsTaskExecutor = delegate->GetAnimationJsTask();
542         jsTaskExecutor.PostTask([weakRuntime, bridgeWeak]() mutable {
543                 JsUpdatePlayState(weakRuntime.lock(), bridgeWeak, DOM_ANIMATION_PLAY_STATE_RUNNING);
544             },
545             "ArkUIAnimationUpdateResumeState");
546     });
547 }
548 
JsAnimationPlay(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)549 shared_ptr<JsValue> JsiAnimationBridgeUtils::JsAnimationPlay(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
550     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
551 {
552     int32_t nodeId = GetCurrentNodeId(runtime, thisObj);
553     int32_t pageId = GetCurrentPageId(runtime, thisObj);
554     HandleJsAnimationContext(runtime, pageId, nodeId, AnimationOperation::PLAY);
555     return runtime->NewUndefined();
556 }
557 
JsAnimationFinish(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)558 shared_ptr<JsValue> JsiAnimationBridgeUtils::JsAnimationFinish(shared_ptr<JsRuntime> runtime,
559     shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
560 {
561     int32_t nodeId = GetCurrentNodeId(runtime, thisObj);
562     int32_t pageId = GetCurrentPageId(runtime, thisObj);
563     HandleJsAnimationContext(runtime, pageId, nodeId, AnimationOperation::FINISH);
564     return runtime->NewUndefined();
565 }
566 
JsAnimationPause(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)567 shared_ptr<JsValue> JsiAnimationBridgeUtils::JsAnimationPause(shared_ptr<JsRuntime> runtime,
568     shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
569 {
570     int32_t nodeId = GetCurrentNodeId(runtime, thisObj);
571     int32_t pageId = GetCurrentPageId(runtime, thisObj);
572     HandleJsAnimationContext(runtime, pageId, nodeId, AnimationOperation::PAUSE);
573     return runtime->NewUndefined();
574 }
575 
JsAnimationCancel(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)576 shared_ptr<JsValue> JsiAnimationBridgeUtils::JsAnimationCancel(shared_ptr<JsRuntime> runtime,
577     shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
578 {
579     int32_t nodeId = GetCurrentNodeId(runtime, thisObj);
580     int32_t pageId = GetCurrentPageId(runtime, thisObj);
581     HandleJsAnimationContext(runtime, pageId, nodeId, AnimationOperation::CANCEL);
582     return runtime->NewUndefined();
583 }
584 
JsAnimationReverse(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)585 shared_ptr<JsValue> JsiAnimationBridgeUtils::JsAnimationReverse(shared_ptr<JsRuntime> runtime,
586     shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
587 {
588     int32_t nodeId = GetCurrentNodeId(runtime, thisObj);
589     int32_t pageId = GetCurrentPageId(runtime, thisObj);
590     HandleJsAnimationContext(runtime, pageId, nodeId, AnimationOperation::REVERSE);
591     return runtime->NewUndefined();
592 }
593 
CreateAnimationContext(shared_ptr<JsRuntime> runtime,int32_t pageId,NodeId nodeId)594 shared_ptr<JsValue> JsiAnimationBridgeUtils::CreateAnimationContext(
595     shared_ptr<JsRuntime> runtime, int32_t pageId, NodeId nodeId)
596 {
597     const std::unordered_map<const char*, RegisterFunctionType> contextTable = {
598         { "play", JsAnimationPlay },
599         { "finish", JsAnimationFinish },
600         { "pause", JsAnimationPause },
601         { "cancel", JsAnimationCancel },
602         { "reverse", JsAnimationReverse },
603     };
604 
605     auto animationContext = runtime->NewObject();
606     for (const auto& iter : contextTable) {
607         animationContext->SetProperty(runtime, iter.first, runtime->NewFunction(iter.second));
608     }
609     animationContext->SetProperty(runtime, "__nodeId", runtime->NewInt32(nodeId));
610     animationContext->SetProperty(runtime, "__pageId", runtime->NewInt32(pageId));
611     animationContext->SetProperty(runtime, "__playState", runtime->NewString(DOM_ANIMATION_PLAY_STATE_IDLE));
612     animationContext->SetProperty(runtime, "finished", runtime->NewBoolean(false));
613     for (const auto& item : JSI_ANIMATION_FUNCS) {
614         auto getterTempl = runtime->NewFunction(std::get<1>(item));
615         auto setterTempl = runtime->NewFunction(std::get<2>(item));
616         bool ret = animationContext->SetAccessorProperty(runtime, std::get<0>(item), getterTempl, setterTempl);
617         if (!ret) {
618             LOGE("Animation set accessor property failed., name: %{public}s", std::get<0>(item).c_str());
619         }
620     }
621     return animationContext;
622 }
623 
JsiAnimationBridgeTaskCreate(shared_ptr<JsRuntime> runtime,const RefPtr<JsiAnimationBridge> & bridge,std::string param)624 JsiAnimationBridgeTaskCreate::JsiAnimationBridgeTaskCreate(
625     shared_ptr<JsRuntime> runtime, const RefPtr<JsiAnimationBridge>& bridge, std::string param)
626     : bridge_(bridge), runtime_(runtime), param_(std::move(param))
627 {}
628 
AnimationBridgeTaskFunc(const RefPtr<JsAcePage> & page,NodeId nodeId)629 void JsiAnimationBridgeTaskCreate::AnimationBridgeTaskFunc(const RefPtr<JsAcePage>& page, NodeId nodeId)
630 {
631     if (!page) {
632         LOGE("Create Animation Bridge failed. page is null.");
633         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
634         return;
635     }
636     if (!bridge_) {
637         LOGE("Create Animation Bridge failed. bridge is null.");
638         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
639         return;
640     }
641     auto bridgeFree = AceType::DynamicCast<JsiAnimationBridge>(page->GetAnimationBridge(nodeId));
642     auto delegate = GetFrontendDelegate(runtime_);
643     if (!delegate) {
644         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
645         LOGE("Create Animation Bridge failed. delegate is null.");
646         return;
647     }
648     auto jsTaskExecutor = delegate->GetAnimationJsTask();
649     if (bridgeFree) {
650         auto weakBridge = AceType::WeakClaim(AceType::RawPtr(bridgeFree));
651         jsTaskExecutor.PostTask(
652             [weakBridge]() mutable {
653                 auto bridgeFree = weakBridge.Upgrade();
654                 if (bridgeFree != nullptr) {
655                     bridgeFree.Reset();
656                 }
657             },
658             "ArkUIAnimationBridgeRelease");
659     }
660     bridge_->JsCreateAnimation(page, param_);
661     page->AddAnimationBridge(nodeId, bridge_);
662 }
663 
AnimationBridgeTaskFunc(const RefPtr<JsAcePage> & page,NodeId nodeId)664 void JsiAnimationBridgeTaskOperation::AnimationBridgeTaskFunc(const RefPtr<JsAcePage>& page, NodeId nodeId)
665 {
666     auto animationBridge = AceType::DynamicCast<JsiAnimationBridge>(page->GetAnimationBridge(nodeId));
667     if (!animationBridge) {
668         LOGE("no animation bridge found for nodeId: %{public}d", nodeId);
669         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
670         return;
671     }
672     auto domDocument = page->GetDomDocument();
673     if (!domDocument) {
674         LOGE("Animation operation failed, DomDocument is null.");
675         return;
676     }
677     auto domNode = domDocument->GetDOMNodeById(nodeId);
678     if (!domNode) {
679         LOGE("Animation operation failed, DomNode is null.");
680         return;
681     }
682     auto tweenComponent = domNode->GetTweenComponent();
683     if (tweenComponent) {
684         tweenComponent->SetCustomAnimationOperation(operation_);
685     }
686 
687     RefPtr<Animator> animator;
688     if (tweenComponent) {
689         animator = tweenComponent->GetAnimator();
690     }
691     if (animator) {
692         animationBridge->SetPlayStateCallbacks(animator);
693     }
694     domNode->GenerateComponentNode();
695     page->PushDirtyNode(nodeId);
696 }
697 
AnimationBridgeTaskFunc(const RefPtr<JsAcePage> & page,NodeId nodeId)698 void JsiAnimationBridgeTaskStartTime::AnimationBridgeTaskFunc(const RefPtr<JsAcePage>& page, NodeId nodeId)
699 {
700     if (!page) {
701         LOGE("JsiAnimationBridgeTaskStartTime: Get page is error");
702         return;
703     }
704     auto domDocument = page->GetDomDocument();
705     if (!domDocument) {
706         LOGE("AnimationBridgeTaskStartTime failed, DomDocument is null.");
707         return;
708     }
709     auto domNode = domDocument->GetDOMNodeById(nodeId);
710     if (!domNode) {
711         LOGE("AnimationBridgeTaskStartTime failed, DomNode is null.");
712         return;
713     }
714     auto tweenComponent = domNode->GetTweenComponent();
715     if (tweenComponent) {
716         auto option = tweenComponent->GetCustomTweenOption();
717         option.SetDelay(StringToInt(startTime_));
718         tweenComponent->SetCustomTweenOption(option);
719     }
720 }
721 
722 } // namespace OHOS::Ace::Framework
723