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