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