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 return;
136 }
137 jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
138 }
139
CallAnimationFinishJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)140 void CallAnimationFinishJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
141 {
142 auto bridge = bridgeWeak.Upgrade();
143 if (!bridge) {
144 LOGE("Call Animation Finish Js Failed. animation bridge is null.");
145 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
146 return;
147 }
148 if (!runtime) {
149 LOGE("Call Animation Finish Js Failed. runtime is null.");
150 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
151 return;
152 }
153 auto animationObject = bridge->GetJsObject();
154 if (!animationObject || animationObject->IsNull(runtime)) {
155 LOGE("Animation Object is null");
156 return;
157 }
158 shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onfinish");
159 if (!jsFunc || !jsFunc->IsFunction(runtime)) {
160 return;
161 }
162 jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
163 }
164
CallAnimationCancelJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)165 void CallAnimationCancelJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
166 {
167 auto bridge = bridgeWeak.Upgrade();
168 if (!bridge) {
169 LOGE("Call Animation Cancel Js Failed. animation bridge is null.");
170 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
171 return;
172 }
173 if (!runtime) {
174 LOGE("Call Animation Cancel Js Failed. runtime is null.");
175 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
176 return;
177 }
178 auto animationObject = bridge->GetJsObject();
179 if (!animationObject || animationObject->IsNull(runtime)) {
180 LOGE("Animation Object is null");
181 return;
182 }
183 shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "oncancel");
184 if (!jsFunc || !jsFunc->IsFunction(runtime)) {
185 return;
186 }
187 jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
188 }
189
CallAnimationRepeatJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime)190 void CallAnimationRepeatJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime)
191 {
192 auto bridge = bridgeWeak.Upgrade();
193 if (!bridge) {
194 LOGE("Call Animation Repeat Js Failed. animation bridge is null.");
195 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
196 return;
197 }
198 if (!runtime) {
199 LOGE("Call Animation Repeat Js Failed. runtime is null.");
200 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
201 return;
202 }
203 auto animationObject = bridge->GetJsObject();
204 if (!animationObject || animationObject->IsNull(runtime)) {
205 LOGE("Animation Object is null");
206 return;
207 }
208 shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onrepeat");
209 if (!jsFunc || !jsFunc->IsFunction(runtime)) {
210 return;
211 }
212 jsFunc->Call(runtime, runtime->GetGlobal(), {}, 0);
213 }
214
CallAnimationFrameJs(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,shared_ptr<JsRuntime> && runtime,double value)215 void CallAnimationFrameJs(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, shared_ptr<JsRuntime>&& runtime, double value)
216 {
217 auto bridge = bridgeWeak.Upgrade();
218 if (!bridge) {
219 LOGE("Call Animation Frame Js Failed. animation bridge is null.");
220 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
221 return;
222 }
223 if (!runtime) {
224 LOGE("Call Animation Frame Js Failed. runtime is null.");
225 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
226 return;
227 }
228 auto animationObject = bridge->GetJsObject();
229 if (!animationObject || animationObject->IsNull(runtime)) {
230 LOGE("Animation Object is null");
231 return;
232 }
233 shared_ptr<JsValue> jsFunc = animationObject->GetProperty(runtime, "onframe");
234 if (!jsFunc || !jsFunc->IsFunction(runtime)) {
235 return;
236 }
237 std::vector<shared_ptr<JsValue>> argv = { runtime->NewNumber(value) };
238 jsFunc->Call(runtime, runtime->GetGlobal(), argv, argv.size());
239 }
240
AddListenerForEventCallback(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,const RefPtr<Animator> & animator,shared_ptr<JsRuntime> runtime)241 void AddListenerForEventCallback(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, const RefPtr<Animator>& animator,
242 shared_ptr<JsRuntime> runtime)
243 {
244 std::weak_ptr<JsRuntime> weakRuntime(runtime);
245 animator->AddStartListener([weakRuntime, bridgeWeak] {
246 auto delegate = GetFrontendDelegate(weakRuntime);
247 if (!delegate) {
248 LOGE("Handle Start listener failed, fail to get delegate");
249 return;
250 }
251 auto jsTaskExecutor = delegate->GetAnimationJsTask();
252 jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
253 LOGI("call animation onstart event");
254 CallAnimationStartJs(bridgeWeak, weakRuntime.lock());
255 });
256 });
257 animator->AddStopListener([weakRuntime, bridgeWeak] {
258 auto delegate = GetFrontendDelegate(weakRuntime);
259 if (!delegate) {
260 LOGE("Handle Stop listener failed, fail to get delegate");
261 return;
262 }
263 auto jsTaskExecutor = delegate->GetAnimationJsTask();
264 jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
265 LOGI("call animation onfinish event");
266 CallAnimationFinishJs(bridgeWeak, weakRuntime.lock());
267 });
268 });
269 animator->AddIdleListener([weakRuntime, bridgeWeak] {
270 auto delegate = GetFrontendDelegate(weakRuntime);
271 if (!delegate) {
272 LOGE("Handle Idle listener failed, fail to get delegate");
273 return;
274 }
275 auto jsTaskExecutor = delegate->GetAnimationJsTask();
276 jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
277 LOGI("call animation oncancel event");
278 CallAnimationCancelJs(bridgeWeak, weakRuntime.lock());
279 });
280 });
281 animator->AddRepeatListener([weakRuntime, bridgeWeak] {
282 auto delegate = GetFrontendDelegate(weakRuntime);
283 if (!delegate) {
284 LOGE("Handle Repeat listener failed, fail to get delegate");
285 return;
286 }
287 auto jsTaskExecutor = delegate->GetAnimationJsTask();
288 jsTaskExecutor.PostTask([bridgeWeak, weakRuntime]() mutable {
289 LOGI("call animation onrepeat event");
290 CallAnimationRepeatJs(bridgeWeak, weakRuntime.lock());
291 });
292 });
293 }
294
AddFrameListener(const WeakPtr<JsiAnimatorBridge> & bridgeWeak,const RefPtr<KeyframeAnimation<double>> & animator,shared_ptr<JsRuntime> runtime)295 void AddFrameListener(const WeakPtr<JsiAnimatorBridge>& bridgeWeak, const RefPtr<KeyframeAnimation<double>>& animator,
296 shared_ptr<JsRuntime> runtime)
297 {
298 std::weak_ptr<JsRuntime> weakRuntime(runtime);
299 animator->AddListener([weakRuntime, bridgeWeak](double value) {
300 auto delegate = GetFrontendDelegate(weakRuntime);
301 if (!delegate) {
302 LOGE("Handle Frame listener failed, fail to get delegate");
303 return;
304 }
305 auto jsTaskExecutor = delegate->GetAnimationJsTask();
306 jsTaskExecutor.PostTask([bridgeWeak, weakRuntime, value]() mutable {
307 LOGI("call animation onframe event");
308 CallAnimationFrameJs(bridgeWeak, weakRuntime.lock(), value);
309 });
310 });
311 }
312
313 } // namespace
314
CreateAnimatorContext(shared_ptr<JsRuntime> runtime,int32_t pageId,int32_t bridgeId)315 shared_ptr<JsValue> JsiAnimatorBridgeUtils::CreateAnimatorContext(
316 shared_ptr<JsRuntime> runtime, int32_t pageId, int32_t bridgeId)
317 {
318 const std::unordered_map<const char*, RegisterFunctionType> contextTable = {
319 { "play", JsAnimatorPlay },
320 { "finish", JsAnimatorFinish },
321 { "pause", JsAnimatorPause },
322 { "cancel", JsAnimatorCancel },
323 { "reverse", JsAnimatorReverse },
324 { "update", JsAnimatorUpdate },
325 { "reset", JsAnimatorReset },
326 };
327 auto animatorContext = runtime->NewObject();
328 for (const auto& iter : contextTable) {
329 animatorContext->SetProperty(runtime, iter.first, runtime->NewFunction(iter.second));
330 }
331 animatorContext->SetProperty(runtime, "__pageId", runtime->NewInt32(pageId));
332 animatorContext->SetProperty(runtime, "__bridgeId", runtime->NewInt32(bridgeId));
333 return animatorContext;
334 }
335
JsAnimatorPlay(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)336 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorPlay(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
337 const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
338 {
339 int32_t pageId = GetCurrentPageId(runtime, thisObj);
340 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
341 HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::PLAY);
342 return runtime->NewUndefined();
343 }
344
JsAnimatorFinish(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)345 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorFinish(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
346 const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
347 {
348 int32_t pageId = GetCurrentPageId(runtime, thisObj);
349 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
350 HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::FINISH);
351 return runtime->NewUndefined();
352 }
353
JsAnimatorPause(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)354 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorPause(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
355 const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
356 {
357 int32_t pageId = GetCurrentPageId(runtime, thisObj);
358 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
359 HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::PAUSE);
360 return runtime->NewUndefined();
361 }
362
JsAnimatorCancel(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)363 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorCancel(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
364 const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
365 {
366 int32_t pageId = GetCurrentPageId(runtime, thisObj);
367 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
368 HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::CANCEL);
369 return runtime->NewUndefined();
370 }
371
JsAnimatorReverse(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)372 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorReverse(shared_ptr<JsRuntime> runtime,
373 shared_ptr<JsValue> thisObj, const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
374 {
375 int32_t pageId = GetCurrentPageId(runtime, thisObj);
376 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
377 HandleJsAnimatorContext(runtime, pageId, bridgeId, AnimatorOperation::REVERSE);
378 return runtime->NewUndefined();
379 }
380
381 // 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)382 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorUpdate(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
383 const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
384 {
385 if (argv.empty()) {
386 return runtime->NewUndefined();
387 }
388 const shared_ptr<JsValue>& paramObj = argv[0];
389 if (!paramObj || !paramObj->IsObject(runtime)) {
390 LOGE("JsAnimatorUpdate failed, first argument is not an object!");
391 return runtime->NewUndefined();
392 }
393 int32_t len = 0;
394 shared_ptr<JsValue> properties;
395 if (!paramObj->GetPropertyNames(runtime, properties, len)) {
396 LOGE("JsAnimatorUpdate failed, fail to get object property list!");
397 return runtime->NewUndefined();
398 }
399 std::unordered_map<std::string, std::string> params;
400 for (int32_t i = 0; i < len; ++i) {
401 shared_ptr<JsValue> key = properties->GetElement(runtime, i);
402 shared_ptr<JsValue> val = paramObj->GetProperty(runtime, key);
403 std::string keyStr = key->ToString(runtime);
404 std::string valStr = val->ToString(runtime);
405 params[keyStr] = valStr;
406 }
407 int32_t pageId = GetCurrentPageId(runtime, thisObj);
408 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
409 auto page = GetPageById(runtime, pageId);
410 if (!page) {
411 LOGE("no page found for pageId: %{public}d", pageId);
412 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
413 return runtime->NewUndefined();
414 }
415 auto task = AceType::MakeRefPtr<JsiAnimatorTaskUpdate>(runtime, params);
416 page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
417 return runtime->NewUndefined();
418 }
419
JsAnimatorReset(shared_ptr<JsRuntime> runtime,shared_ptr<JsValue> thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)420 shared_ptr<JsValue> JsiAnimatorBridgeUtils::JsAnimatorReset(shared_ptr<JsRuntime> runtime, shared_ptr<JsValue> thisObj,
421 const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
422 {
423 if (argv.empty()) {
424 runtime->ThrowError("Parameter error. The number of parameters must be greater than or equal to 1.",
425 ERROR_CODE_PARAM_INVALID);
426 return runtime->NewUndefined();
427 }
428 const shared_ptr<JsValue>& paramObj = argv[0];
429 if (!paramObj || !paramObj->IsObject(runtime)) {
430 LOGE("JsAnimatorUpdate failed, first argument is not an object!");
431 runtime->ThrowError("Parameter error. The type of parameters is incorrect.", ERROR_CODE_PARAM_INVALID);
432 return runtime->NewUndefined();
433 }
434 int32_t len = 0;
435 shared_ptr<JsValue> properties;
436 if (!paramObj->GetPropertyNames(runtime, properties, len)) {
437 LOGE("JsAnimatorUpdate failed, fail to get object property list!");
438 runtime->ThrowError("Internal error. Fail to get object property list.", ERROR_CODE_INTERNAL_ERROR);
439 return runtime->NewUndefined();
440 }
441 std::unordered_map<std::string, std::string> params;
442 for (int32_t i = 0; i < len; ++i) {
443 shared_ptr<JsValue> key = properties->GetElement(runtime, i);
444 shared_ptr<JsValue> val = paramObj->GetProperty(runtime, key);
445 std::string keyStr = key->ToString(runtime);
446 std::string valStr = val->ToString(runtime);
447 params[keyStr] = valStr;
448 }
449 int32_t pageId = GetCurrentPageId(runtime, thisObj);
450 int32_t bridgeId = GetCurrentBridgeId(runtime, thisObj);
451 auto page = GetPageById(runtime, pageId);
452 if (!page) {
453 LOGE("no page found for pageId: %{public}d", pageId);
454 runtime->ThrowError("Internal error. Can not find the page for pageId.", ERROR_CODE_INTERNAL_ERROR);
455 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
456 return runtime->NewUndefined();
457 }
458 auto task = AceType::MakeRefPtr<JsiAnimatorTaskUpdate>(runtime, params);
459 page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
460 return runtime->NewUndefined();
461 }
462
JsCreateBridgeId()463 int32_t JsiAnimatorBridgeUtils::JsCreateBridgeId()
464 {
465 static int32_t bridgeId = 0;
466 return bridgeId++;
467 }
468
JsiAnimatorBridge(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & animatorContext)469 JsiAnimatorBridge::JsiAnimatorBridge(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& animatorContext)
470 : animatorObject_(animatorContext)
471 {
472 runtime_ = runtime;
473 }
474
~JsiAnimatorBridge()475 JsiAnimatorBridge::~JsiAnimatorBridge()
476 {
477 RefPtr<Animator> animator;
478 animator.Swap(animator_);
479 auto taskExecutor = Container::CurrentTaskExecutor();
480 if (taskExecutor) {
481 taskExecutor->PostSyncTask(
482 [&animator]() {
483 LOGI("release animator on UI thread");
484 animator.Reset();
485 },
486 TaskExecutor::TaskType::UI);
487 }
488 }
489
JsCreateAnimation(const std::string & param)490 void JsiAnimatorBridge::JsCreateAnimation(const std::string& param)
491 {
492 int32_t iterations = 0;
493 double duration = 0.0;
494 double delay = 0.0;
495 std::unordered_map<std::string, double> animationDoubleParams;
496 std::unordered_map<std::string, std::string> animationStringParams;
497 BaseAnimationBridgeUtils::JsParseAnimatorParams(param, iterations, animationDoubleParams, animationStringParams);
498 RefPtr<Curve> curve;
499 std::string curveString;
500 auto iterEasing = animationStringParams.find(DOM_ANIMATION_EASING);
501 if (iterEasing != animationStringParams.end()) {
502 curveString = iterEasing->second;
503 }
504 curve = CreateCurve(curveString);
505 auto iterDuration = animationDoubleParams.find(DOM_ANIMATION_DURATION_API);
506 if (iterDuration != animationDoubleParams.end()) {
507 duration = iterDuration->second;
508 }
509 std::string fillString;
510 auto iterFill = animationStringParams.find(DOM_ANIMATION_FILL);
511 if (iterFill != animationStringParams.end()) {
512 fillString = iterFill->second;
513 }
514 auto iterDelay = animationDoubleParams.find(DOM_ANIMATION_DELAY_API);
515 if (iterDelay != animationDoubleParams.end()) {
516 delay = iterDelay->second;
517 }
518 if (!runtime_) {
519 LOGE("runtime is null");
520 return;
521 }
522 auto keyframeAnimation = CreateDoubleAnimation(animationDoubleParams, curve);
523 if (!animator_) {
524 animator_ = CREATE_ANIMATOR();
525 }
526 if (!animator_->IsStopped()) {
527 animator_->Stop();
528 }
529 auto iterDirection = animationStringParams.find(DOM_ANIMATION_DIRECTION_API);
530 if (iterDirection != animationStringParams.end()) {
531 animator_->SetAnimationDirection(StringToAnimationDirection(iterDirection->second));
532 }
533 animator_->ClearInterpolators();
534 animator_->SetDuration(duration);
535 animator_->SetIteration(iterations);
536 animator_->SetStartDelay(delay);
537 animator_->SetFillMode(StringToFillMode(fillString));
538 animator_->AddInterpolator(keyframeAnimation);
539 AddListenerForEventCallback(AceType::WeakClaim(this), animator_, runtime_);
540 }
541
CreateDoubleAnimation(std::unordered_map<std::string,double> & animationParams,const RefPtr<Curve> & curve)542 RefPtr<KeyframeAnimation<double>> JsiAnimatorBridge::CreateDoubleAnimation(
543 std::unordered_map<std::string, double>& animationParams, const RefPtr<Curve>& curve)
544 {
545 double begin = 0.0;
546 double end = 1.0;
547 auto animationBegin = animationParams.find(DOM_ANIMATION_BEGIN);
548 if (animationBegin != animationParams.end()) {
549 begin = animationBegin->second;
550 }
551 auto animationEnd = animationParams.find(DOM_ANIMATION_END);
552 if (animationEnd != animationParams.end()) {
553 end = animationEnd->second;
554 }
555 auto keyframeBegin = AceType::MakeRefPtr<Keyframe<double>>(0.0, begin);
556 auto keyframeEnd = AceType::MakeRefPtr<Keyframe<double>>(1.0, end);
557 auto keyframeAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
558 keyframeAnimation->AddKeyframe(keyframeBegin);
559 keyframeAnimation->AddKeyframe(keyframeEnd);
560 keyframeAnimation->SetCurve(curve);
561 AddFrameListener(AceType::WeakClaim(this), keyframeAnimation, runtime_);
562 return keyframeAnimation;
563 }
564
JsiAnimatorTaskCreate(shared_ptr<JsRuntime> runtime,const RefPtr<JsiAnimatorBridge> & bridge,const std::string & param)565 JsiAnimatorTaskCreate::JsiAnimatorTaskCreate(
566 shared_ptr<JsRuntime> runtime, const RefPtr<JsiAnimatorBridge>& bridge, const std::string& param)
567 : bridge_(bridge), runtime_(runtime), param_(std::move(param))
568 {}
569
AnimatorBridgeTaskFunc(const RefPtr<JsAcePage> & page,int32_t bridgeId)570 void JsiAnimatorTaskCreate::AnimatorBridgeTaskFunc(const RefPtr<JsAcePage>& page, int32_t bridgeId)
571 {
572 if (!page) {
573 LOGE("Create Animation Bridge failed. page is null.");
574 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
575 return;
576 }
577 if (!bridge_) {
578 LOGE("Create Animation Bridge failed. bridge is null.");
579 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
580 return;
581 }
582 auto bridgeFree = AceType::DynamicCast<JsiAnimatorBridge>(page->GetAnimatorBridge(bridgeId));
583 auto delegate = GetFrontendDelegate(runtime_);
584 if (!delegate) {
585 EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
586 LOGE("Create Animation Bridge failed. delegate is null.");
587 return;
588 }
589 auto jsTaskExecutor = delegate->GetAnimationJsTask();
590 if (bridgeFree) {
591 auto weakBridge = AceType::WeakClaim(AceType::RawPtr(bridgeFree));
592 jsTaskExecutor.PostTask([weakBridge]() mutable {
593 auto bridgeFree = weakBridge.Upgrade();
594 if (bridgeFree != nullptr) {
595 bridgeFree.Reset();
596 }
597 });
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