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_animator_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
GetCurrentBridgeId(shared_ptr<JsRuntime> & runtime,shared_ptr<JsValue> & value)56 inline int32_t GetCurrentBridgeId(shared_ptr<JsRuntime>& runtime, shared_ptr<JsValue>& value)
57 {
58 if (!value) {
59 LOGE("Get current bridge id failed. value is null.");
60 return 0;
61 }
62 shared_ptr<JsValue> jsBridgeId = value->GetProperty(runtime, "__bridgeId");
63 if (!jsBridgeId || !jsBridgeId->IsInt32(runtime)) {
64 LOGE("Get current bridge id failed. jsBridgeId is null or not a integer");
65 return 0;
66 }
67 int32_t bridgeId = jsBridgeId->ToInt32(runtime);
68 return bridgeId < 0 ? 0 : bridgeId;
69 }
70
GetCurrentPageId(shared_ptr<JsRuntime> & runtime,shared_ptr<JsValue> & value)71 inline int32_t GetCurrentPageId(shared_ptr<JsRuntime>& runtime, shared_ptr<JsValue>& value)
72 {
73 if (!value) {
74 LOGE("Get current page id failed. value is null.");
75 return 0;
76 }
77 shared_ptr<JsValue> jsPageId = value->GetProperty(runtime, "__pageId");
78 if (!jsPageId || !jsPageId->IsInt32(runtime)) {
79 LOGE("Get current page id failed. jsPageId is null or not a integer");
80 return 0;
81 }
82 int32_t pageId = jsPageId->ToInt32(runtime);
83 return pageId < 0 ? 0 : pageId;
84 }
85
HandleJsAnimatorContext(const shared_ptr<JsRuntime> & runtime,int32_t pageId,int32_t bridgeId,AnimatorOperation operation)86 void HandleJsAnimatorContext(const shared_ptr<JsRuntime>& runtime, int32_t pageId, int32_t bridgeId,
87 AnimatorOperation operation)
88 {
89 if (!runtime) {
90 LOGE("Handle JsAnimationContext failed, runtime is null.");
91 return;
92 }
93 auto delegate = GetFrontendDelegate(runtime);
94 if (!delegate) {
95 LOGE("Handle JsAnimationContext failed, delegate is null.");
96 return;
97 }
98 auto page = GetPageById(runtime, pageId);
99 if (!page) {
100 LOGE("no page found for pageId: %{public}d", pageId);
101 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
102 return;
103 }
104 auto task = AceType::MakeRefPtr<JsiAnimatorTaskOperation>(operation);
105 page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
106 if (page->CheckPageCreated()) {
107 delegate->TriggerPageUpdate(page->GetPageId());
108 }
109 }
110
CallAnimationStartJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)111 void CallAnimationStartJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
112 {
113 auto bridge = bridgeWeak.Upgrade();
114 if (!bridge) {
115 LOGE("Call Animation Start Js Failed. animation bridge is null.");
116 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
117 return;
118 }
119 if (!runtime) {
120 LOGE("Call Animation Start Js Failed. runtime is null.");
121 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
122 return;
123 }
124 auto animationObject = bridge->GetJsObject();
125 if (!animationObject || animationObject->IsNull(runtime)) {
126 LOGE("Animation Object is null");
127 return;
128 }
129 shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onstart");
130 if (!jsFunc || !jsFunc->IsFunction(runtime)) {
131 return;
132 }
133 jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
134 }
135
CallAnimationFinishJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)136 void CallAnimationFinishJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
137 {
138 auto bridge = bridgeWeak.Upgrade();
139 if (!bridge) {
140 LOGE("Call Animation Finish Js Failed. animation bridge is null.");
141 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
142 return;
143 }
144 if (!runtime) {
145 LOGE("Call Animation Finish Js Failed. runtime is null.");
146 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
147 return;
148 }
149 auto animationObject = bridge->GetJsObject();
150 if (!animationObject || animationObject->IsNull(runtime)) {
151 LOGE("Animation Object is null");
152 return;
153 }
154 shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onfinish");
155 if (!jsFunc || !jsFunc->IsFunction(runtime)) {
156 return;
157 }
158 jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
159 }
160
CallAnimationCancelJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)161 void CallAnimationCancelJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
162 {
163 auto bridge = bridgeWeak.Upgrade();
164 if (!bridge) {
165 LOGE("Call Animation Cancel Js Failed. animation bridge is null.");
166 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
167 return;
168 }
169 if (!runtime) {
170 LOGE("Call Animation Cancel Js Failed. runtime is null.");
171 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
172 return;
173 }
174 auto animationObject = bridge->GetJsObject();
175 if (!animationObject || animationObject->IsNull(runtime)) {
176 LOGE("Animation Object is null");
177 return;
178 }
179 shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "oncancel");
180 if (!jsFunc || !jsFunc->IsFunction(runtime)) {
181 return;
182 }
183 jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
184 }
185
CallAnimationRepeatJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)186 void CallAnimationRepeatJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
187 {
188 auto bridge = bridgeWeak.Upgrade();
189 if (!bridge) {
190 LOGE("Call Animation Repeat Js Failed. animation bridge is null.");
191 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
192 return;
193 }
194 if (!runtime) {
195 LOGE("Call Animation Repeat Js Failed. runtime is null.");
196 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
197 return;
198 }
199 auto animationObject = bridge->GetJsObject();
200 if (!animationObject || animationObject->IsNull(runtime)) {
201 LOGE("Animation Object is null");
202 return;
203 }
204 shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onrepeat");
205 if (!jsFunc || !jsFunc->IsFunction(runtime)) {
206 return;
207 }
208 jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
209 }
210
CallAnimationFrameJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime,double value)211 void CallAnimationFrameJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime, double value)
212 {
213 auto bridge = bridgeWeak.Upgrade();
214 if (!bridge) {
215 LOGE("Call Animation Frame Js Failed. animation bridge is null.");
216 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
217 return;
218 }
219 if (!runtime) {
220 LOGE("Call Animation Frame Js Failed. runtime is null.");
221 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
222 return;
223 }
224 auto animationObject = bridge->GetJsObject();
225 if (!animationObject || animationObject->IsNull(runtime)) {
226 LOGE("Animation Object is null");
227 return;
228 }
229 shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onframe");
230 if (!jsFunc || !jsFunc->IsFunction(runtime)) {
231 return;
232 }
233 std::vector<shared_ptr<JsValue>> argv = { runtime->NewNumber(value) };
234 jsFunc->Call(runtime, runtime->GetGlobal(), argv, argv.size());
235 }
236
AddListenerForEventCallback(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,const RefPtr<Animator> & animator,shared_ptr<JsRuntime> runtime)237 void AddListenerForEventCallback(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, const RefPtr<Animator>& animator,
238 shared_ptr<JsRuntime> runtime)
239 {
240 std::weak_ptr<JsRuntime> weakRuntime(runtime);
241 animator->AddStartListener([weakRuntime, bridgeWeak] {
242 auto delegate = GetFrontendDelegate(weakRuntime);
243 if (!delegate) {
244 LOGE("Handle Start listener failed, fail to get delegate");
245 return;
246 }
247 auto jsTaskExecutor = delegate->GetAnimationJsTask();
248 jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
249 LOGI("call animation onstart event");
250 CallAnimationStartJs(bridgeWeak, weakRuntime.lock());
251 }, "ArkUIAnimationStartEvent");
252 });
253 animator->AddStopListener([weakRuntime, bridgeWeak] {
254 auto delegate = GetFrontendDelegate(weakRuntime);
255 if (!delegate) {
256 LOGE("Handle Stop listener failed, fail to get delegate");
257 return;
258 }
259 auto jsTaskExecutor = delegate->GetAnimationJsTask();
260 jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
261 LOGI("call animation onfinish event");
262 CallAnimationFinishJs(bridgeWeak, weakRuntime.lock());
263 }, "ArkUIAnimationStopEvent");
264 });
265 animator->AddIdleListener([weakRuntime, bridgeWeak] {
266 auto delegate = GetFrontendDelegate(weakRuntime);
267 if (!delegate) {
268 LOGE("Handle Idle listener failed, fail to get delegate");
269 return;
270 }
271 auto jsTaskExecutor = delegate->GetAnimationJsTask();
272 jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
273 LOGI("call animation oncancel event");
274 CallAnimationCancelJs(bridgeWeak, weakRuntime.lock());
275 }, "ArkUIAnimationCancelEvent");
276 });
277 animator->AddRepeatListener([weakRuntime, bridgeWeak] {
278 auto delegate = GetFrontendDelegate(weakRuntime);
279 if (!delegate) {
280 LOGE("Handle Repeat listener failed, fail to get delegate");
281 return;
282 }
283 auto jsTaskExecutor = delegate->GetAnimationJsTask();
284 jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
285 LOGI("call animation onrepeat event");
286 CallAnimationRepeatJs(bridgeWeak, weakRuntime.lock());
287 }, "ArkUIAnimationRepeat");
288 });
289 }
290
AddFrameListener(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,const RefPtr<KeyframeAnimation<double>> & animator,shared_ptr<JsRuntime> runtime)291 void AddFrameListener(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, const RefPtr<KeyframeAnimation<double>>& animator,
292 shared_ptr<JsRuntime> runtime)
293 {
294 std::weak_ptr<JsRuntime> weakRuntime(runtime);
295 animator->AddListener([weakRuntime, bridgeWeak](double value) {
296 auto delegate = GetFrontendDelegate(weakRuntime);
297 if (!delegate) {
298 LOGE("Handle Frame listener failed, fail to get delegate");
299 return;
300 }
301 auto jsTaskExecutor = delegate->GetAnimationJsTask();
302 jsTaskExecutor.PostTask(
303 [bridgeWeak, weakRuntime, value]() mutable {
304 LOGI("call animation onframe event");
305 CallAnimationFrameJs(bridgeWeak, weakRuntime.lock(), value);
306 },
307 "ArkUIAnimationFrame");
308 });
309 }
310
311 } // namespace
312
CreateAnimatorContext(shared_ptr<JsRuntime> runtime,int32_t pageId,int32_t bridgeId)313 shared_ptr<JsValue> JsiAnimatorBridgeUtils::CreateAnimatorContext(
314 shared_ptr<JsRuntime> runtime, int32_t pageId, int32_t bridgeId)
315 {
316 const std::unordered_map<const char*, RegisterFunctionType> contextTable = {
317 { "play", JsAnimatorPlay },
318 { "finish", JsAnimatorFinish },
319 { "pause", JsAnimatorPause },
320 { "cancel", JsAnimatorCancel },
321 { "reverse", JsAnimatorReverse },
322 { "update", JsAnimatorUpdate },
323 { "reset", JsAnimatorReset },
324 };
325 auto animatorContext = runtime->NewObject();
326 for (const auto& iter : contextTable) {
327 animatorContext->SetProperty(runtime, iter.first, runtime->NewFunction(iter.second));
328 }
329 animatorContext->SetProperty(runtime, "__pageId", runtime->NewInt32(pageId));
330 animatorContext->SetProperty(runtime, "__bridgeId", runtime->NewInt32(bridgeId));
331 return animatorContext;
332 }
333
JsAnimatorPlay(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)334 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorPlay(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
335 const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
336 {
337 int32_t pageId = GetCurrentPageId(runtime, thisObj);
338 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
339 HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::PLAY);
340 return runtime->NewUndefined();
341 }
342
JsAnimatorFinish(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)343 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorFinish(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
344 const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
345 {
346 int32_t pageId = GetCurrentPageId(runtime, thisObj);
347 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
348 HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::FINISH);
349 return runtime->NewUndefined();
350 }
351
JsAnimatorPause(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)352 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorPause(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
353 const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
354 {
355 int32_t pageId = GetCurrentPageId(runtime, thisObj);
356 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
357 HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::PAUSE);
358 return runtime->NewUndefined();
359 }
360
JsAnimatorCancel(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)361 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorCancel(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
362 const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
363 {
364 int32_t pageId = GetCurrentPageId(runtime, thisObj);
365 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
366 HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::CANCEL);
367 return runtime->NewUndefined();
368 }
369
JsAnimatorReverse(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)370 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorReverse(shared_ptr<JsRuntime> runtime,
371 shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
372 {
373 int32_t pageId = GetCurrentPageId(runtime, thisObj);
374 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
375 HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::REVERSE);
376 return runtime->NewUndefined();
377 }
378
379 // animator.update api function is deprecated since 9
JsAnimatorUpdate(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)380 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorUpdate(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
381 const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
382 {
383 if (argv.empty()) {
384 return runtime->NewUndefined();
385 }
386 const shared_ptr<JsValue>& paramObj = argv[0];
387 if (!paramObj || !paramObj->IsObject(runtime)) {
388 LOGE("JsAnimatorUpdate failed, first argument is not an object!");
389 return runtime->NewUndefined();
390 }
391 int32_t len = 0;
392 shared_ptr<JsValue> properties;
393 if (!paramObj->GetPropertyNames(runtime, properties, len)) {
394 LOGE("JsAnimatorUpdate failed, fail to get object property list!");
395 return runtime->NewUndefined();
396 }
397 std::unordered_map<std::string, std::string> params;
398 for (int32_t i = 0; i < len; ++i) {
399 shared_ptr<JsValue> key = properties->GetElement(runtime, i);
400 shared_ptr<JsValue> val = paramObj->GetProperty(runtime, key);
401 std::string keyStr = key->ToString(runtime);
402 std::string valStr = val->ToString(runtime);
403 params[keyStr] = valStr;
404 }
405 int32_t pageId = GetCurrentPageId(runtime, thisObj);
406 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
407 auto page = GetPageById(runtime, pageId);
408 if (!page) {
409 LOGE("no page found for pageId: %{public}d", pageId);
410 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
411 return runtime->NewUndefined();
412 }
413 auto task = AceType::MakeRefPtr<JsiAnimatorTaskUpdate>(runtime, params);
414 page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
415 return runtime->NewUndefined();
416 }
417
JsAnimatorReset(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)418 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorReset(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
419 const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
420 {
421 if (argv.empty()) {
422 runtime->ThrowError("Parameter error. The number of parameters must be greater than or equal to 1.",
423 ERROR_CODE_PARAM_INVALID);
424 return runtime->NewUndefined();
425 }
426 const shared_ptr<JsValue>& paramObj = argv[0];
427 if (!paramObj || !paramObj->IsObject(runtime)) {
428 LOGE("JsAnimatorUpdate failed, first argument is not an object!");
429 runtime->ThrowError("Parameter error. The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
430 return runtime->NewUndefined();
431 }
432 int32_t len = 0;
433 shared_ptr<JsValue> properties;
434 if (!paramObj->GetPropertyNames(runtime, properties, len)) {
435 LOGE("JsAnimatorUpdate failed, fail to get object property list!");
436 runtime->ThrowError("Internal error. Fail to get object property list.", ERROR_CODE_INTERNAL_ERROR);
437 return runtime->NewUndefined();
438 }
439 std::unordered_map<std::string, std::string> params;
440 for (int32_t i = 0; i < len; ++i) {
441 shared_ptr<JsValue> key = properties->GetElement(runtime, i);
442 shared_ptr<JsValue> val = paramObj->GetProperty(runtime, key);
443 std::string keyStr = key->ToString(runtime);
444 std::string valStr = val->ToString(runtime);
445 params[keyStr] = valStr;
446 }
447 int32_t pageId = GetCurrentPageId(runtime, thisObj);
448 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
449 auto page = GetPageById(runtime, pageId);
450 if (!page) {
451 LOGE("no page found for pageId: %{public}d", pageId);
452 runtime->ThrowError("Internal error. Can not find the page for pageId.", ERROR_CODE_INTERNAL_ERROR);
453 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
454 return runtime->NewUndefined();
455 }
456 auto task = AceType::MakeRefPtr<JsiAnimatorTaskUpdate>(runtime, params);
457 page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
458 return runtime->NewUndefined();
459 }
460
JsCreateBridgeId()461 int32_t JsiAnimatorBridgeUtils::JsCreateBridgeId()
462 {
463 static int32_t bridgeId = 0;
464 return bridgeId++;
465 }
466
JsiAnimatorBridge(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & animatorContext)467 JsiAnimatorBridge::JsiAnimatorBridge(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& animatorContext)
468 : animatorObject_(animatorContext)
469 {
470 runtime_ = runtime;
471 }
472
~JsiAnimatorBridge()473 JsiAnimatorBridge::~JsiAnimatorBridge()
474 {
475 RefPtr<Animator> animator;
476 animator.Swap(animator_);
477 auto taskExecutor = Container::CurrentTaskExecutor();
478 if (taskExecutor) {
479 taskExecutor->PostSyncTask(
480 [&animator]() {
481 LOGI("release animator on UI thread");
482 animator.Reset();
483 },
484 TaskExecutor::TaskType::UI, "ArkUIAnimatorRelease");
485 }
486 }
487
JsCreateAnimation(const std::string & param)488 void JsiAnimatorBridge::JsCreateAnimation(const std::string& param)
489 {
490 int32_t iterations = 0;
491 double duration = 0.0;
492 double delay = 0.0;
493 std::unordered_map<std::string, double> animationDoubleParams;
494 std::unordered_map<std::string, std::string> animationStringParams;
495 BaseAnimationBridgeUtils::JsParseAnimatorParams(param, iterations, animationDoubleParams, animationStringParams);
496 RefPtr<Curve> curve;
497 std::string curveString;
498 auto iterEasing = animationStringParams.find(DOM_ANIMATION_EASING);
499 if (iterEasing != animationStringParams.end()) {
500 curveString = iterEasing->second;
501 }
502 curve = CreateCurve(curveString);
503 auto iterDuration = animationDoubleParams.find(DOM_ANIMATION_DURATION_API);
504 if (iterDuration != animationDoubleParams.end()) {
505 duration = iterDuration->second;
506 }
507 std::string fillString;
508 auto iterFill = animationStringParams.find(DOM_ANIMATION_FILL);
509 if (iterFill != animationStringParams.end()) {
510 fillString = iterFill->second;
511 }
512 auto iterDelay = animationDoubleParams.find(DOM_ANIMATION_DELAY_API);
513 if (iterDelay != animationDoubleParams.end()) {
514 delay = iterDelay->second;
515 }
516 if (!runtime_) {
517 LOGE("runtime is null");
518 return;
519 }
520 auto keyframeAnimation = CreateDoubleAnimation(animationDoubleParams, curve);
521 if (!animator_) {
522 animator_ = CREATE_ANIMATOR();
523 }
524 if (!animator_->IsStopped()) {
525 animator_->Stop();
526 }
527 auto iterDirection = animationStringParams.find(DOM_ANIMATION_DIRECTION_API);
528 if (iterDirection != animationStringParams.end()) {
529 animator_->SetAnimationDirection(StringToAnimationDirection(iterDirection->second));
530 }
531 animator_->ClearInterpolators();
532 animator_->SetDuration(duration);
533 animator_->SetIteration(iterations);
534 animator_->SetStartDelay(delay);
535 animator_->SetFillMode(StringToFillMode(fillString));
536 animator_->AddInterpolator(keyframeAnimation);
537 AddListenerForEventCallback(AceType::WeakClaim(this), animator_, runtime_);
538 }
539
CreateDoubleAnimation(std::unordered_map<std::string,double> & animationParams,const RefPtr<Curve> & curve)540 RefPtr<KeyframeAnimation<double>> JsiAnimatorBridge::CreateDoubleAnimation(
541 std::unordered_map<std::string, double>& animationParams, const RefPtr<Curve>& curve)
542 {
543 double begin = 0.0;
544 double end = 1.0;
545 auto animationBegin = animationParams.find(DOM_ANIMATION_BEGIN);
546 if (animationBegin != animationParams.end()) {
547 begin = animationBegin->second;
548 }
549 auto animationEnd = animationParams.find(DOM_ANIMATION_END);
550 if (animationEnd != animationParams.end()) {
551 end = animationEnd->second;
552 }
553 auto keyframeBegin = AceType::MakeRefPtr<Keyframe<double>>(0.0, begin);
554 auto keyframeEnd = AceType::MakeRefPtr<Keyframe<double>>(1.0, end);
555 auto keyframeAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
556 keyframeAnimation->AddKeyframe(keyframeBegin);
557 keyframeAnimation->AddKeyframe(keyframeEnd);
558 keyframeAnimation->SetCurve(curve);
559 AddFrameListener(AceType::WeakClaim(this), keyframeAnimation, runtime_);
560 return keyframeAnimation;
561 }
562
JsiAnimatorTaskCreate(shared_ptr<JsRuntime> runtime,const RefPtr<JsiAnimatorBridge> & bridge,const std::string & param)563 JsiAnimatorTaskCreate::JsiAnimatorTaskCreate(
564 shared_ptr<JsRuntime> runtime, const RefPtr<JsiAnimatorBridge>& bridge, const std::string& param)
565 : bridge_(bridge), runtime_(runtime), param_(std::move(param))
566 {}
567
AnimatorBridgeTaskFunc(const RefPtr<JsAcePage> & page,int32_t bridgeId)568 void JsiAnimatorTaskCreate::AnimatorBridgeTaskFunc(const RefPtr<JsAcePage>& page, int32_t bridgeId)
569 {
570 if (!page) {
571 LOGE("Create Animation Bridge failed. page is null.");
572 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
573 return;
574 }
575 if (!bridge_) {
576 LOGE("Create Animation Bridge failed. bridge is null.");
577 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
578 return;
579 }
580 auto bridgeFree = AceType::DynamicCast<JsiAnimatorBridge>(page->GetAnimatorBridge(bridgeId));
581 auto delegate = GetFrontendDelegate(runtime_);
582 if (!delegate) {
583 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
584 LOGE("Create Animation Bridge failed. delegate is null.");
585 return;
586 }
587 auto jsTaskExecutor = delegate->GetAnimationJsTask();
588 if (bridgeFree) {
589 auto weakBridge = AceType::WeakClaim(AceType::RawPtr(bridgeFree));
590 jsTaskExecutor.PostTask(
591 [weakBridge]() mutable {
592 auto bridgeFree = weakBridge.Upgrade();
593 if (bridgeFree != nullptr) {
594 bridgeFree.Reset();
595 }
596 },
597 "ArkUIAnimatorBridgeRelease");
598 }
599 page->RemoveAnimatorBridge(bridgeId);
600 bridge_->JsCreateAnimation(param_);
601 page->AddAnimatorBridge(bridgeId, bridge_);
602 }
603
AnimatorBridgeTaskFunc(const RefPtr<JsAcePage> & page,int32_t bridgeId)604 void JsiAnimatorTaskOperation::AnimatorBridgeTaskFunc(const RefPtr<JsAcePage>& page, int32_t bridgeId)
605 {
606 if (!page) {
607 LOGE("AnimatorBridgeTaskFunc failed. page is null");
608 return;
609 }
610 auto animatorBridge = AceType::DynamicCast<JsiAnimatorBridge>(page->GetAnimatorBridge(bridgeId));
611 if (!animatorBridge) {
612 LOGE("no animation bridge found for bridgeId: %{public}d", bridgeId);
613 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
614 return;
615 }
616 RefPtr<Animator> animator = animatorBridge->JsGetAnimator();
617 if (!animator) {
618 LOGE("animator is null");
619 return;
620 }
621 switch (operation_) {
622 case AnimatorOperation::PLAY:
623 animator->Play();
624 break;
625 case AnimatorOperation::PAUSE:
626 animator->Pause();
627 break;
628 case AnimatorOperation::CANCEL:
629 animator->Cancel();
630 break;
631 case AnimatorOperation::FINISH:
632 animator->Finish();
633 break;
634 case AnimatorOperation::REVERSE:
635 animator->Reverse();
636 break;
637 case AnimatorOperation::NONE:
638 default:
639 break;
640 }
641 }
642
AnimatorBridgeTaskFunc(const RefPtr<JsAcePage> & page,int32_t bridgeId)643 void JsiAnimatorTaskUpdate::AnimatorBridgeTaskFunc(const RefPtr<JsAcePage>& page, int32_t bridgeId)
644 {
645 if (!page) {
646 LOGE("AnimatorBridgeTaskFunc failed. page is null");
647 return;
648 }
649 auto animatorBridge = AceType::DynamicCast<JsiAnimatorBridge>(page->GetAnimatorBridge(bridgeId));
650 if (!animatorBridge) {
651 LOGE("no animation bridge found for bridgeId: %{public}d", bridgeId);
652 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
653 return;
654 }
655 RefPtr<Animator> animator = animatorBridge->JsGetAnimator();
656 if (!animator) {
657 LOGE("animator is null");
658 return;
659 }
660 if (!runtime_) {
661 LOGE("runtime is null");
662 return;
663 }
664 animator->ClearInterpolators();
665 animator->ResetIsReverse();
666 UpdateAnimator(animator, animatorBridge, runtime_, params_);
667 }
668
UpdateAnimator(const RefPtr<Animator> & animator,const RefPtr<JsiAnimatorBridge> & bridge,shared_ptr<JsRuntime> runtime,const std::unordered_map<std::string,std::string> & params)669 void JsiAnimatorTaskUpdate::UpdateAnimator(const RefPtr<Animator>& animator, const RefPtr<JsiAnimatorBridge>& bridge,
670 shared_ptr<JsRuntime> runtime, const std::unordered_map<std::string, std::string>& params)
671 {
672 int32_t iterations = 1;
673 double duration = 0.0;
674 double delay = 0.0;
675 double begin = 0.0;
676 double end = 1.0;
677 std::string curveString;
678 std::string fillString;
679 RefPtr<Curve> curve;
680 auto iterEasing = params_.find(DOM_ANIMATION_EASING);
681 if (iterEasing != params_.end()) {
682 curveString = iterEasing->second;
683 }
684 curve = CreateCurve(curveString);
685 auto iterIterations = params_.find(DOM_ANIMATION_ITERATIONS);
686 if (iterIterations != params_.end()) {
687 iterations = StringToInt(iterIterations->second);
688 }
689 auto iterDuration = params_.find(DOM_ANIMATION_DURATION_API);
690 if (iterDuration != params_.end()) {
691 duration = StringToDouble(iterDuration->second);
692 }
693 auto iterFill = params_.find(DOM_ANIMATION_FILL);
694 if (iterFill != params_.end()) {
695 fillString = iterFill->second;
696 }
697 auto iterDelay = params_.find(DOM_ANIMATION_DELAY_API);
698 if (iterDelay != params_.end()) {
699 delay = StringToDouble(iterDelay->second);
700 }
701 auto iterDirection = params_.find(DOM_ANIMATION_DIRECTION_API);
702 if (iterDirection != params_.end()) {
703 animator->SetAnimationDirection(StringToAnimationDirection(iterDirection->second));
704 }
705 auto animationBegin = params_.find(DOM_ANIMATION_BEGIN);
706 if (animationBegin != params_.end()) {
707 begin = StringToDouble(animationBegin->second);
708 }
709 auto animationEnd = params_.find(DOM_ANIMATION_END);
710 if (animationEnd != params_.end()) {
711 end = StringToDouble(animationEnd->second);
712 }
713 auto keyframeAnimation = CreateDoubleAnimation(begin, end, curve);
714 AddFrameListener(AceType::WeakClaim(RawPtr(bridge)), keyframeAnimation, runtime);
715 animator->SetDuration(duration);
716 animator->SetIteration(iterations);
717 animator->SetStartDelay(delay);
718 animator->SetFillMode(StringToFillMode(fillString));
719 animator->AddInterpolator(keyframeAnimation);
720 }
721
CreateDoubleAnimation(double begin,double end,const RefPtr<Curve> & curve)722 RefPtr<KeyframeAnimation<double>> JsiAnimatorTaskUpdate::CreateDoubleAnimation(
723 double begin, double end, const RefPtr<Curve>& curve)
724 {
725 auto keyframeBegin = AceType::MakeRefPtr<Keyframe<double>>(0.0, begin);
726 auto keyframeEnd = AceType::MakeRefPtr<Keyframe<double>>(1.0, end);
727 auto keyframeAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
728 keyframeAnimation->AddKeyframe(keyframeBegin);
729 keyframeAnimation->AddKeyframe(keyframeEnd);
730 keyframeAnimation->SetCurve(curve);
731 return keyframeAnimation;
732 }
733
734 } // namespace OHOS::Ace::Framework
735