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