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