• 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/quickjs/animation_bridge.h"
17 
18 #include <utility>
19 
20 #include "base/utils/string_utils.h"
21 #include "frameworks/bridge/common/utils/utils.h"
22 #include "frameworks/bridge/js_frontend/engine/quickjs/qjs_engine.h"
23 #include "frameworks/bridge/js_frontend/engine/quickjs/qjs_group_js_bridge.h"
24 
25 namespace OHOS::Ace::Framework {
26 
27 namespace {
28 
GetPageById(QjsEngineInstance * instance,int32_t pageId)29 RefPtr<JsAcePage> GetPageById(QjsEngineInstance* instance, int32_t pageId)
30 {
31     LOGD("Enter GetPageById");
32     if (instance == nullptr) {
33         LOGE("instance is null.");
34         return nullptr;
35     }
36     auto delegate = instance->GetDelegate();
37     if (delegate == nullptr) {
38         LOGE("delegate is null.");
39         return nullptr;
40     }
41     return delegate->GetPage(pageId);
42 }
43 
GetJsInt32Val(JSContext * ctx,JSValueConst value)44 inline int32_t GetJsInt32Val(JSContext* ctx, JSValueConst value)
45 {
46     int32_t val = 0;
47     if (JS_IsNumber(value) && (JS_ToInt32(ctx, &val, value)) < 0) {
48         val = 0;
49     }
50     return val;
51 }
52 
HandleJsAnimationContext(JSContext * ctx,int32_t pageId,int32_t nodeId,AnimationOperation operation)53 void HandleJsAnimationContext(JSContext* ctx, int32_t pageId, int32_t nodeId, AnimationOperation operation)
54 {
55     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
56     auto page = GetPageById(instance, pageId);
57     if (page == nullptr) {
58         LOGE("no page found for nodeId: %{public}d", nodeId);
59         return;
60     }
61     auto task = AceType::MakeRefPtr<AnimationBridgeTaskOperation>(operation);
62     page->PushCommand(AceType::MakeRefPtr<JsCommandAnimation>(nodeId, task));
63     if (page->CheckPageCreated()) {
64         instance->GetDelegate()->TriggerPageUpdate(page->GetPageId());
65     }
66 }
67 
68 const JSCFunctionListEntry JS_ANIMATION_FUNCS[] = {
69     JS_CGETSET_DEF(
70         "playState", AnimationBridgeUtils::JsAnimationPlayStateGet, AnimationBridgeUtils::JsAnimationPlayStateSet),
71     JS_CGETSET_DEF(
72         "startTime", AnimationBridgeUtils::JsAnimationStartTimeGet, AnimationBridgeUtils::JsAnimationStartTimeSet),
73     JS_CGETSET_DEF("pending", AnimationBridgeUtils::JsAnimationPendingGet, AnimationBridgeUtils::JsAnimationPendingSet),
74 };
75 
AddListenerForEventCallback(const WeakPtr<AnimationBridge> & bridgeWeak,const RefPtr<Animator> & animator,JSContext * ctx)76 void AddListenerForEventCallback(const WeakPtr<AnimationBridge>& bridgeWeak,
77     const RefPtr<Animator>& animator, JSContext* ctx)
78 {
79     animator->AddStopListener([ctx, bridgeWeak] {
80         auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
81         auto jsTaskExecutor = instance->GetDelegate()->GetAnimationJsTask();
82         jsTaskExecutor.PostTask([bridgeWeak, instance]() mutable {
83             auto bridge = bridgeWeak.Upgrade();
84             if (!bridge) {
85                 return;
86             }
87             LOGI("call animation onfinish event");
88             instance->CallAnimationFinishJs(bridge->GetJsObject());
89         });
90     });
91     animator->AddIdleListener([ctx, bridgeWeak] {
92         auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
93         auto jsTaskExecutor = instance->GetDelegate()->GetAnimationJsTask();
94         jsTaskExecutor.PostTask([bridgeWeak, instance]() mutable {
95             auto bridge = bridgeWeak.Upgrade();
96             if (!bridge) {
97                 return;
98             }
99             LOGI("call animation oncancel event");
100             instance->CallAnimationCancelJs(bridge->GetJsObject());
101         });
102     });
103     animator->AddRepeatListener([ctx, bridgeWeak] {
104         auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
105         auto jsTaskExecutor = instance->GetDelegate()->GetAnimationJsTask();
106         jsTaskExecutor.PostTask([bridgeWeak, instance]() mutable {
107             auto bridge = bridgeWeak.Upgrade();
108             if (!bridge) {
109                 return;
110             }
111             LOGI("call animation onrepeat event");
112             instance->CallAnimationRepeatJs(bridge->GetJsObject());
113         });
114     });
115 }
116 
117 } // namespace
118 
AnimationBridge(JSContext * ctx,JSValue animationContext,NodeId nodeId)119 AnimationBridge::AnimationBridge(JSContext* ctx, JSValue animationContext, NodeId nodeId)
120     : ctx_(ctx), animationContext_(JS_DupValue(ctx, animationContext)), nodeId_(nodeId)
121 {
122     if (ctx_ == nullptr) {
123         return;
124     }
125     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx_));
126     if (instance == nullptr) {
127         return;
128     }
129 }
130 
~AnimationBridge()131 AnimationBridge::~AnimationBridge()
132 {
133     // when last page exit, js engine will destruct first, so do not free JSObject again.
134     if (ctx_ != nullptr) {
135         JS_FreeValue(ctx_, animationContext_);
136         ctx_ = nullptr;
137     }
138 }
139 
OnJsEngineDestroy()140 void AnimationBridge::OnJsEngineDestroy()
141 {
142     LOGI("Destruct OnJsEngineDestroy, nodeId: %{public}d", nodeId_);
143     if (ctx_ != nullptr) {
144         JS_FreeValue(ctx_, animationContext_);
145         ctx_ = nullptr;
146     }
147 }
148 
JsAnimationStartTimeGet(JSContext * ctx,JSValueConst value)149 JSValue AnimationBridgeUtils::JsAnimationStartTimeGet(JSContext* ctx, JSValueConst value)
150 {
151     QJSHandleScope handleScope(ctx);
152     int32_t nodeId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__nodeId"));
153     int32_t pageId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__pageId"));
154     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
155     if (instance == nullptr) {
156         LOGE("QjsEngineInstance is null. nodeId is: %{public}d", nodeId);
157         return JS_NULL;
158     }
159     auto page = GetPageById(instance, pageId);
160     if (page == nullptr) {
161         LOGE("no page found for nodeId: %{public}d", nodeId);
162         return JS_NULL;
163     }
164     auto domDocument = page->GetDomDocument();
165     if (domDocument == nullptr) {
166         LOGE("JsAnimationStartTimeGet failed, DomDocument is null.");
167         return JS_NULL;
168     }
169     auto domNode = domDocument->GetDOMNodeById(nodeId);
170     if (domNode == nullptr) {
171         LOGE("JsAnimationStartTimeGet failed, DomNode is null.");
172         return JS_NULL;
173     }
174     auto tweenComponent = domNode->GetTweenComponent();
175     if (tweenComponent) {
176         auto option = tweenComponent->GetCustomTweenOption();
177         auto startTime = option.GetDelay();
178         JS_SetPropertyStr(ctx, value, "__startTime", JS_NewInt32(ctx, startTime));
179     }
180     return JS_GetPropertyStr(ctx, value, "__startTime");
181 }
182 
JsAnimationStartTimeSet(JSContext * ctx,JSValueConst value,JSValueConst startTime)183 JSValue AnimationBridgeUtils::JsAnimationStartTimeSet(JSContext* ctx, JSValueConst value, JSValueConst startTime)
184 {
185     QJSHandleScope handleScope(ctx);
186     int32_t startDelay = 0;
187     JS_ToInt32(ctx, &startDelay, startTime);
188     int32_t nodeId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__nodeId"));
189     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
190     if (instance == nullptr) {
191         LOGE("QjsEngineInstance is null. nodeID is: %{public}d", nodeId);
192         return JS_NULL;
193     }
194     int32_t pageId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__pageId"));
195     auto page = GetPageById(instance, pageId);
196     if (page == nullptr) {
197         LOGE("no page found for nodeId: %{public}d", nodeId);
198         return JS_NULL;
199     }
200     auto task = AceType::MakeRefPtr<AnimationBridgeTaskStartTime>(startDelay);
201     page->PushCommand(AceType::MakeRefPtr<JsCommandAnimation>(nodeId, task));
202     return JS_NULL;
203 }
204 
JsAnimationPendingGet(JSContext * ctx,JSValueConst value)205 JSValue AnimationBridgeUtils::JsAnimationPendingGet(JSContext* ctx, JSValueConst value)
206 {
207     QJSHandleScope handleScope(ctx);
208     int32_t nodeId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__nodeId"));
209     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
210     if (instance == nullptr) {
211         LOGE("QjsEngineInstance is null. nodeID is: %{public}d", nodeId);
212         return JS_NULL;
213     }
214     int32_t pageId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__pageId"));
215     auto page = GetPageById(instance, pageId);
216     if (page == nullptr) {
217         LOGE("no page found for nodeId: %{public}d", nodeId);
218         return JS_NULL;
219     }
220     auto domDocument = page->GetDomDocument();
221     if (domDocument == nullptr) {
222         LOGE("JsAnimationPendingGet failed, DomDocument is null.");
223         return JS_NULL;
224     }
225     auto domNode = domDocument->GetDOMNodeById(nodeId);
226     if (domNode == nullptr) {
227         LOGE("JsAnimationPendingGet failed, DomNode is null.");
228         return JS_NULL;
229     }
230     auto tweenComponent = domNode->GetTweenComponent();
231     RefPtr<Animator> animator;
232     if (tweenComponent) {
233         animator = tweenComponent->GetAnimator();
234     }
235     if (animator) {
236         JS_SetPropertyStr(ctx, value, "__pending", JS_NewBool(ctx, animator->IsPending()));
237     }
238     return JS_GetPropertyStr(ctx, value, "__pending");
239 }
240 
JsAnimationPendingSet(JSContext * ctx,JSValueConst value,JSValueConst pending)241 JSValue AnimationBridgeUtils::JsAnimationPendingSet(JSContext* ctx, JSValueConst value, JSValueConst pending)
242 {
243     return JS_NULL;
244 }
245 
JsAnimationPlayStateGet(JSContext * ctx,JSValueConst value)246 JSValue AnimationBridgeUtils::JsAnimationPlayStateGet(JSContext* ctx, JSValueConst value)
247 {
248     return JS_GetPropertyStr(ctx, value, "__playState");
249 }
250 
JsAnimationPlayStateSet(JSContext * ctx,JSValueConst value,JSValueConst proto)251 JSValue AnimationBridgeUtils::JsAnimationPlayStateSet(JSContext* ctx, JSValueConst value, JSValueConst proto)
252 {
253     ScopedString playState(ctx, proto);
254     AnimationOperation operation = AnimationOperation::NONE;
255     if (std::strcmp(playState.get(), DOM_ANIMATION_PLAY_STATE_IDLE) == 0) {
256         operation = AnimationOperation::CANCEL;
257     } else if (strlen(playState.get()) >= strlen(DOM_ANIMATION_PLAY_STATE_RUNNING) &&
258                std::strcmp(playState.get(), DOM_ANIMATION_PLAY_STATE_RUNNING) == 0) {
259         operation = AnimationOperation::PLAY;
260     } else if (strlen(playState.get()) >= strlen(DOM_ANIMATION_PLAY_STATE_PAUSED) &&
261                std::strcmp(playState.get(), DOM_ANIMATION_PLAY_STATE_PAUSED) == 0) {
262         operation = AnimationOperation::PAUSE;
263     } else if (strlen(playState.get()) >= strlen(DOM_ANIMATION_PLAY_STATE_FINISHED) &&
264                std::strcmp(playState.get(), DOM_ANIMATION_PLAY_STATE_FINISHED) == 0) {
265         operation = AnimationOperation::FINISH;
266     } else {
267         operation = AnimationOperation::NONE;
268     }
269 
270     QJSHandleScope handleScope(ctx);
271     int32_t nodeId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__nodeId"));
272     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx));
273     int32_t pageId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__pageId"));
274     auto page = GetPageById(instance, pageId);
275     if (page == nullptr) {
276         LOGE("no page found for nodeId: %{public}d", nodeId);
277         return JS_NULL;
278     }
279     auto task = AceType::MakeRefPtr<AnimationBridgeTaskOperation>(operation);
280     page->PushCommand(AceType::MakeRefPtr<JsCommandAnimation>(nodeId, task));
281     return JS_NULL;
282 }
283 
JsCreateAnimation(const RefPtr<JsAcePage> & page,const std::string & param)284 void AnimationBridge::JsCreateAnimation(const RefPtr<JsAcePage>& page, const std::string& param)
285 {
286     std::vector<std::unordered_map<std::string, std::string>> animationFrames;
287     std::unordered_map<std::string, double> animationDoubleOptions;
288     std::unordered_map<std::string, std::string> animationStringOptions;
289     int32_t iterations = 0;
290     BaseAnimationBridgeUtils::JsParseAnimationFrames(param, animationFrames);
291     BaseAnimationBridgeUtils::JsParseAnimationOptions(
292         param, iterations, animationDoubleOptions, animationStringOptions);
293     auto tweenOption = TweenOption();
294     auto iterEasing = animationStringOptions.find(DOM_ANIMATION_EASING);
295     if (iterEasing != animationStringOptions.end()) {
296         tweenOption.SetCurve(CreateCurve(iterEasing->second));
297     }
298     std::vector<Dimension> transformOrigin = BaseAnimationBridgeUtils::HandleTransformOrigin(animationFrames);
299     if (transformOrigin.size() == BaseAnimationBridgeUtils::TRANSFORM_ORIGIN_DEFAULT_SIZE) {
300         tweenOption.SetTransformOrigin(transformOrigin.front(), transformOrigin.back());
301     }
302     auto iterDuration = animationDoubleOptions.find(DOM_ANIMATION_DURATION_API);
303     if (iterDuration != animationDoubleOptions.end()) {
304         tweenOption.SetDuration(iterDuration->second);
305     }
306     auto iterFill = animationStringOptions.find(DOM_ANIMATION_FILL);
307     if (iterFill != animationStringOptions.end()) {
308         tweenOption.SetFillMode(StringToFillMode(iterFill->second));
309     }
310     auto iterDirection = animationStringOptions.find(DOM_ANIMATION_DIRECTION_API);
311     if (iterDirection != animationStringOptions.end()) {
312         tweenOption.SetAnimationDirection(StringToAnimationDirection(iterDirection->second));
313     }
314     auto iterDelay = animationDoubleOptions.find(DOM_ANIMATION_DELAY_API);
315     if (iterDelay != animationDoubleOptions.end()) {
316         tweenOption.SetDelay(iterDelay->second);
317     }
318     tweenOption.SetIteration(iterations);
319     if (page == nullptr) {
320         LOGE("JsCreateAnimation failed, Page is null.");
321         return;
322     }
323     auto domDocument = page->GetDomDocument();
324     if (domDocument == nullptr) {
325         LOGE("JsCreateAnimation failed, DomDocument is null.");
326         return;
327     }
328     auto domNode = domDocument->GetDOMNodeById(nodeId_);
329     if (domNode == nullptr) {
330         LOGE("JsCreateAnimation failed, DomNode is null.");
331         return;
332     }
333     domNode->ParseAnimationStyle(animationFrames);
334     domNode->TweenOptionSetKeyframes(tweenOption);
335     if (tweenOption.IsValid()) {
336         domNode->SetCustomAnimationStyleUpdate(true);
337     }
338     RefPtr<Animator> animator = AceType::MakeRefPtr<Animator>();
339     auto tweenComponent = domNode->GetTweenComponent();
340     if (!tweenComponent) {
341         tweenComponent = AceType::MakeRefPtr<TweenComponent>(
342             BaseAnimationBridgeUtils::COMPONENT_PREFIX + std::to_string(nodeId_), domNode->GetTag());
343         domNode->SetTweenComponent(tweenComponent);
344     }
345     LOGD("parse animate parameters for nodeId: %d", nodeId_);
346     tweenComponent->SetAnimator(animator);
347     BaseAnimationBridgeUtils::SetTweenComponentParams(nullptr, animationFrames, tweenComponent, tweenOption);
348     AddListenerForEventCallback(AceType::WeakClaim(this), animator, ctx_);
349     domNode->GenerateComponentNode();
350     page->PushDirtyNode(nodeId_);
351 }
352 
SetPlayStateCallbacksWithListenerId(RefPtr<Animator> & animator)353 void AnimationBridge::SetPlayStateCallbacksWithListenerId(RefPtr<Animator>& animator)
354 {
355     if (animator == nullptr) {
356         LOGE("Set PlayState callbacks failed. animator is null.");
357         return;
358     }
359     WeakPtr<AnimationBridge> bridgeWeak = AceType::WeakClaim(this);
360     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx_));
361     animator->RemoveStopListener(finishListenerId_);
362     finishListenerId_ = animator->AddStopListener([ctx = ctx_, bridgeWeak, instance] {
363         auto jsTaskExecutor = instance->GetDelegate()->GetAnimationJsTask();
364         jsTaskExecutor.PostTask([ctx, bridgeWeak, instance]() mutable {
365             auto bridge = bridgeWeak.Upgrade();
366             if (!bridge) {
367                 return;
368             }
369             JS_SetPropertyStr(ctx, bridge->GetJsObject(), "__playState",
370                 JS_NewString(ctx, DOM_ANIMATION_PLAY_STATE_FINISHED));
371         });
372     });
373     animator->RemoveIdleListener(idleListenerId_);
374     idleListenerId_ = animator->AddIdleListener([ctx = ctx_, bridgeWeak, instance] {
375         auto jsTaskExecutor = instance->GetDelegate()->GetAnimationJsTask();
376         jsTaskExecutor.PostTask([ctx, bridgeWeak, instance]() mutable {
377             auto bridge = bridgeWeak.Upgrade();
378             if (!bridge) {
379                 return;
380             }
381             JS_SetPropertyStr(
382                 ctx, bridge->GetJsObject(), "__playState", JS_NewString(ctx, DOM_ANIMATION_PLAY_STATE_IDLE));
383         });
384     });
385 }
386 
SetPlayStateCallbacks(RefPtr<Animator> & animator)387 void AnimationBridge::SetPlayStateCallbacks(RefPtr<Animator>& animator)
388 {
389     if (animator == nullptr) {
390         LOGE("Set PlayState callbacks failed. animator is null.");
391         return;
392     }
393     WeakPtr<AnimationBridge> bridgeWeak = AceType::WeakClaim(this);
394     auto instance = static_cast<QjsEngineInstance*>(JS_GetContextOpaque(ctx_));
395     SetPlayStateCallbacksWithListenerId(animator);
396     animator->ClearPauseListeners();
397     animator->AddPauseListener([ctx = ctx_, bridgeWeak, instance] {
398         auto jsTaskExecutor = instance->GetDelegate()->GetAnimationJsTask();
399         jsTaskExecutor.PostTask([ctx, bridgeWeak, instance]() mutable {
400             auto bridge = bridgeWeak.Upgrade();
401             if (!bridge) {
402                 return;
403             }
404             JS_SetPropertyStr(ctx, bridge->GetJsObject(), "__playState",
405                 JS_NewString(ctx, DOM_ANIMATION_PLAY_STATE_PAUSED));
406         });
407     });
408     animator->ClearStartListeners();
409     animator->AddStartListener([ctx = ctx_, bridgeWeak, instance] {
410         auto jsTaskExecutor = instance->GetDelegate()->GetAnimationJsTask();
411         jsTaskExecutor.PostTask([ctx, bridgeWeak, instance]() mutable {
412             auto bridge = bridgeWeak.Upgrade();
413             if (!bridge) {
414                 return;
415             }
416             instance->CallAnimationStartJs(bridge->GetJsObject());
417             JS_SetPropertyStr(ctx, bridge->GetJsObject(), "__playState",
418                 JS_NewString(ctx, DOM_ANIMATION_PLAY_STATE_RUNNING));
419         });
420     });
421     animator->ClearResumeListeners();
422     animator->AddResumeListener([ctx = ctx_, bridgeWeak, instance] {
423         auto jsTaskExecutor = instance->GetDelegate()->GetAnimationJsTask();
424         jsTaskExecutor.PostTask([ctx, bridgeWeak, instance]() mutable {
425             auto bridge = bridgeWeak.Upgrade();
426             if (!bridge) {
427                 return;
428             }
429             JS_SetPropertyStr(ctx, bridge->GetJsObject(), "__playState",
430                 JS_NewString(ctx, DOM_ANIMATION_PLAY_STATE_RUNNING));
431         });
432     });
433 }
434 
JsAnimationPlay(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)435 JSValue AnimationBridgeUtils::JsAnimationPlay(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
436 {
437     if ((!argv) || (argc != 0)) {
438         LOGE("argc error, argc = %{private}d", argc);
439         return JS_NULL;
440     }
441 
442     QJSHandleScope handleScope(ctx);
443     int32_t nodeId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__nodeId"));
444     int32_t pageId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__pageId"));
445     HandleJsAnimationContext(ctx, pageId, nodeId, AnimationOperation::PLAY);
446     return JS_NULL;
447 }
448 
JsAnimationFinish(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)449 JSValue AnimationBridgeUtils::JsAnimationFinish(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
450 {
451     if ((!argv) || (argc != 0)) {
452         LOGE("argc error, argc = %{private}d", argc);
453         return JS_NULL;
454     }
455 
456     QJSHandleScope handleScope(ctx);
457     int32_t nodeId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__nodeId"));
458     int32_t pageId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__pageId"));
459     HandleJsAnimationContext(ctx, pageId, nodeId, AnimationOperation::FINISH);
460     return JS_NULL;
461 }
462 
JsAnimationPause(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)463 JSValue AnimationBridgeUtils::JsAnimationPause(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
464 {
465     if ((!argv) || (argc != 0)) {
466         LOGE("argc error, argc = %{private}d", argc);
467         return JS_NULL;
468     }
469 
470     QJSHandleScope handleScope(ctx);
471     int32_t nodeId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__nodeId"));
472     int32_t pageId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__pageId"));
473     HandleJsAnimationContext(ctx, pageId, nodeId, AnimationOperation::PAUSE);
474     return JS_NULL;
475 }
476 
JsAnimationCancel(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)477 JSValue AnimationBridgeUtils::JsAnimationCancel(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
478 {
479     if ((!argv) || (argc != 0)) {
480         LOGE("argc error, argc = %{private}d", argc);
481         return JS_NULL;
482     }
483 
484     QJSHandleScope handleScope(ctx);
485     int32_t nodeId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__nodeId"));
486     int32_t pageId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__pageId"));
487     HandleJsAnimationContext(ctx, pageId, nodeId, AnimationOperation::CANCEL);
488     return JS_NULL;
489 }
490 
JsAnimationReverse(JSContext * ctx,JSValueConst value,int32_t argc,JSValueConst * argv)491 JSValue AnimationBridgeUtils::JsAnimationReverse(JSContext* ctx, JSValueConst value, int32_t argc, JSValueConst* argv)
492 {
493     if ((!argv) || (argc != 0)) {
494         LOGE("argc error, argc = %{private}d", argc);
495         return JS_NULL;
496     }
497 
498     QJSHandleScope handleScope(ctx);
499     int32_t nodeId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__nodeId"));
500     int32_t pageId = GetJsInt32Val(ctx, QJSUtils::GetPropertyStr(ctx, value, "__pageId"));
501     HandleJsAnimationContext(ctx, pageId, nodeId, AnimationOperation::REVERSE);
502     return JS_NULL;
503 }
504 
CreateAnimationContext(JSContext * ctx,int32_t pageId,NodeId nodeId)505 JSValue AnimationBridgeUtils::CreateAnimationContext(JSContext* ctx, int32_t pageId, NodeId nodeId)
506 {
507     auto animationContext = JS_NewObject(ctx);
508     JS_SetPropertyStr(ctx, animationContext, "play", JS_NewCFunction(ctx, JsAnimationPlay, "play", 0));
509     JS_SetPropertyStr(ctx, animationContext, "finish", JS_NewCFunction(ctx, JsAnimationFinish, "finish", 0));
510     JS_SetPropertyStr(ctx, animationContext, "pause", JS_NewCFunction(ctx, JsAnimationPause, "pause", 0));
511     JS_SetPropertyStr(ctx, animationContext, "cancel", JS_NewCFunction(ctx, JsAnimationCancel, "cancel", 0));
512     JS_SetPropertyStr(ctx, animationContext, "reverse", JS_NewCFunction(ctx, JsAnimationReverse, "reverse", 0));
513     JS_SetPropertyStr(ctx, animationContext, "__pageId", JS_NewInt32(ctx, pageId));
514     JS_SetPropertyStr(ctx, animationContext, "__nodeId", JS_NewInt32(ctx, nodeId));
515     JS_SetPropertyStr(
516         ctx, animationContext, "__playState", JS_NewString(ctx, DOM_ANIMATION_PLAY_STATE_IDLE));
517     JS_SetPropertyStr(ctx, animationContext, "finished", JS_NewBool(ctx, 0));
518     JS_SetPropertyFunctionList(ctx, animationContext, JS_ANIMATION_FUNCS, countof(JS_ANIMATION_FUNCS));
519     return animationContext;
520 }
521 
AnimationBridgeTaskCreate(const RefPtr<AnimationBridge> & animationBridge,std::string param)522 AnimationBridgeTaskCreate::AnimationBridgeTaskCreate(const RefPtr<AnimationBridge>& animationBridge, std::string param)
523     : animationBridge_(animationBridge), param_(std::move(param))
524 {}
525 
AnimationBridgeTaskFunc(const RefPtr<JsAcePage> & page,NodeId nodeId)526 void AnimationBridgeTaskCreate::AnimationBridgeTaskFunc(const RefPtr<JsAcePage>& page, NodeId nodeId)
527 {
528     if (page == nullptr) {
529         LOGE("the page is nullptr");
530         return;
531     }
532     page->RemoveAnimationBridge(nodeId);
533     animationBridge_->JsCreateAnimation(page, param_);
534     page->AddAnimationBridge(nodeId, animationBridge_);
535 }
536 
AnimationBridgeTaskFunc(const RefPtr<JsAcePage> & page,NodeId nodeId)537 void AnimationBridgeTaskOperation::AnimationBridgeTaskFunc(const RefPtr<JsAcePage>& page, NodeId nodeId)
538 {
539     if (page == nullptr) {
540         LOGE("the page is nullptr");
541         return;
542     }
543     auto animationBridge = AceType::DynamicCast<AnimationBridge>(page->GetAnimationBridge(nodeId));
544     if (!animationBridge) {
545         LOGE("no animation bridge found for nodeId: %{public}d", nodeId);
546         return;
547     }
548     auto domDocument = page->GetDomDocument();
549     if (domDocument == nullptr) {
550         LOGE("Animation operation failed, DomDocument is null.");
551         return;
552     }
553     auto domNode = domDocument->GetDOMNodeById(nodeId);
554     if (domNode == nullptr) {
555         LOGE("Animation operation failed, DomNode is null.");
556         return;
557     }
558     auto tweenComponent = domNode->GetTweenComponent();
559     if (tweenComponent) {
560         tweenComponent->SetCustomAnimationOperation(operation_);
561     }
562 
563     RefPtr<Animator> animator;
564     if (tweenComponent) {
565         animator = tweenComponent->GetAnimator();
566     }
567     if (animator) {
568         animationBridge->SetPlayStateCallbacks(animator);
569     }
570     domNode->GenerateComponentNode();
571     page->PushDirtyNode(nodeId);
572 }
573 
AnimationBridgeTaskFunc(const RefPtr<JsAcePage> & page,NodeId nodeId)574 void AnimationBridgeTaskStartTime::AnimationBridgeTaskFunc(const RefPtr<JsAcePage>& page, NodeId nodeId)
575 {
576     if (page == nullptr) {
577         LOGE("Get page is error");
578         return;
579     }
580     auto domDocument = page->GetDomDocument();
581     if (domDocument == nullptr) {
582         LOGE("AnimationBridgeTaskStartTime failed, DomDocument is null.");
583         return;
584     }
585     auto domNode = domDocument->GetDOMNodeById(nodeId);
586     if (domNode == nullptr) {
587         LOGE("AnimationBridgeTaskStartTime failed, DomNode is null.");
588         return;
589     }
590     auto tweenComponent = domNode->GetTweenComponent();
591     if (tweenComponent) {
592         auto option = tweenComponent->GetCustomTweenOption();
593         option.SetDelay(startTime_);
594         tweenComponent->SetCustomTweenOption(option);
595     }
596 }
597 
598 } // namespace OHOS::Ace::Framework
599