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