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