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