• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/v8/v8_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/engine/v8/v8_engine.h"
23 #include "frameworks/bridge/js_frontend/engine/v8/v8_utils.h"
24 #include "frameworks/bridge/js_frontend/js_ace_page.h"
25 
26 namespace OHOS::Ace::Framework {
27 namespace {
28 
GetPageById(v8::Isolate * isolate,int32_t pageId)29 RefPtr<JsAcePage> GetPageById(v8::Isolate* isolate, int32_t pageId)
30 {
31     LOGD("Enter GetPageById");
32     if (isolate == nullptr) {
33         LOGE("Isolate is null.");
34         return nullptr;
35     }
36     auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
37     return (*delegate)->GetPage(pageId);
38 }
39 
GetCurrentBridgeId(const v8::Local<v8::Context> & ctx,v8::Local<v8::Object> value)40 inline int32_t GetCurrentBridgeId(const v8::Local<v8::Context>& ctx, v8::Local<v8::Object> value)
41 {
42     v8::Isolate* isolate = ctx->GetIsolate();
43     v8::HandleScope handleScope(isolate);
44     int32_t id = value->Get(ctx, v8::String::NewFromUtf8(isolate, "__bridgeId").ToLocalChecked())
45         .ToLocalChecked()->Int32Value(ctx).ToChecked();
46     return id < 0 ? 0 : id;
47 }
48 
GetCurrentPageId(const v8::Local<v8::Context> & ctx,v8::Local<v8::Object> value)49 inline int32_t GetCurrentPageId(const v8::Local<v8::Context>& ctx, v8::Local<v8::Object> value)
50 {
51     v8::Isolate* isolate = ctx->GetIsolate();
52     v8::HandleScope handleScope(isolate);
53     int32_t id = value->Get(ctx, v8::String::NewFromUtf8(isolate, "__pageId").ToLocalChecked())
54         .ToLocalChecked()->Int32Value(ctx).ToChecked();
55     return id < 0 ? 0 : id;
56 }
57 
HandleJsAnimatorContext(const v8::Local<v8::Context> & ctx,int32_t pageId,int32_t bridgeId,AnimatorOperation operation)58 void HandleJsAnimatorContext(const v8::Local<v8::Context>& ctx, int32_t pageId, int32_t bridgeId,
59     AnimatorOperation operation)
60 {
61     v8::Isolate* isolate = ctx->GetIsolate();
62     auto page = GetPageById(isolate, pageId);
63     if (!page) {
64         LOGE("no page found for bridgeId: %{public}d", bridgeId);
65         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
66         return;
67     }
68     auto task = AceType::MakeRefPtr<V8AnimatorTaskOperation>(operation);
69     page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
70     if (page->CheckPageCreated()) {
71         auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
72         (*delegate)->TriggerPageUpdate(page->GetPageId());
73     }
74 }
75 
CallAnimationStartJs(const WeakPtr<V8AnimatorBridge> & bridgeWeak,v8::Isolate * isolate)76 void CallAnimationStartJs(const WeakPtr<V8AnimatorBridge>& bridgeWeak, v8::Isolate* isolate)
77 {
78     auto bridge = bridgeWeak.Upgrade();
79     if (!bridge) {
80         LOGE("Call Animation Start Js Failed. animation bridge is null.");
81         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
82         return;
83     }
84     v8::HandleScope handleScope(isolate);
85     auto animatorObject = bridge->GetJsObject();
86     if (animatorObject.IsEmpty()) {
87         LOGE("Animation Object is null");
88         return;
89     }
90     auto context = bridge->GetContext();
91     v8::Local<v8::Value> proto =
92         animatorObject->Get(context, v8::String::NewFromUtf8(isolate, "onstart").ToLocalChecked()).ToLocalChecked();
93     if (!proto->IsFunction()) {
94         LOGE("cannot find 'CallAnimationStartJs' function from animation object, maybe no callback at all.");
95         return;
96     }
97     v8::TryCatch tryCatch(isolate);
98     v8::Local<v8::Function> jsFunc = v8::Local<v8::Function>::Cast(proto);
99     v8::Local<v8::Value> funcRes;
100     v8::Local<v8::Object> global = context->Global();
101     bool succ = jsFunc->Call(context, global, 0, {}).ToLocal(&funcRes);
102     if (!succ) {
103         V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::ANIMATION_START_ERROR);
104         return;
105     }
106 }
107 
CallAnimationFinishJs(const WeakPtr<V8AnimatorBridge> & bridgeWeak,v8::Isolate * isolate)108 void CallAnimationFinishJs(const WeakPtr<V8AnimatorBridge>& bridgeWeak, v8::Isolate* isolate)
109 {
110     auto bridge = bridgeWeak.Upgrade();
111     if (!bridge) {
112         LOGE("Call Animation Finish Js Failed. animation bridge is null.");
113         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
114         return;
115     }
116     v8::HandleScope handleScope(isolate);
117     auto animatorObject = bridge->GetJsObject();
118     if (animatorObject.IsEmpty()) {
119         LOGE("Animation Object is null");
120         return;
121     }
122     auto context = bridge->GetContext();
123     v8::Local<v8::Value> proto =
124         animatorObject->Get(context, v8::String::NewFromUtf8(isolate, "onfinish").ToLocalChecked()).ToLocalChecked();
125     if (!proto->IsFunction()) {
126         LOGE("cannot find 'CallAnimationFinishJs' function from animation object, maybe no callback at all.");
127         return;
128     }
129     v8::TryCatch tryCatch(isolate);
130     v8::Local<v8::Function> jsFunc = v8::Local<v8::Function>::Cast(proto);
131     v8::Local<v8::Value> funcRes;
132     v8::Local<v8::Object> global = context->Global();
133     bool succ = jsFunc->Call(context, global, 0, {}).ToLocal(&funcRes);
134     if (!succ) {
135         V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::ANIMATION_FINISH_ERROR);
136         return;
137     }
138 }
139 
CallAnimationCancelJs(const WeakPtr<V8AnimatorBridge> & bridgeWeak,v8::Isolate * isolate)140 void CallAnimationCancelJs(const WeakPtr<V8AnimatorBridge>& bridgeWeak, v8::Isolate* isolate)
141 {
142     auto bridge = bridgeWeak.Upgrade();
143     if (!bridge) {
144         LOGE("Call Animation Cancel Js Failed. animation bridge is null.");
145         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
146         return;
147     }
148     v8::HandleScope handleScope(isolate);
149     auto animatorObject = bridge->GetJsObject();
150     if (animatorObject.IsEmpty()) {
151         LOGE("Animation Object is null");
152         return;
153     }
154     auto context = bridge->GetContext();
155     v8::Local<v8::Value> proto =
156         animatorObject->Get(context, v8::String::NewFromUtf8(isolate, "oncancel").ToLocalChecked()).ToLocalChecked();
157     if (!proto->IsFunction()) {
158         LOGE("cannot find 'CallAnimationCancelJs' function from animation object, maybe no callback at all.");
159         return;
160     }
161     LOGD("animation oncancel event call");
162     v8::TryCatch tryCatch(isolate);
163     v8::Local<v8::Function> jsFunc = v8::Local<v8::Function>::Cast(proto);
164     v8::Local<v8::Value> funcRes;
165     v8::Local<v8::Object> global = context->Global();
166     bool succ = jsFunc->Call(context, global, 0, {}).ToLocal(&funcRes);
167     if (!succ) {
168         V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::ANIMATION_CANCEL_ERROR);
169         return;
170     }
171 }
172 
CallAnimationRepeatJs(const WeakPtr<V8AnimatorBridge> & bridgeWeak,v8::Isolate * isolate)173 void CallAnimationRepeatJs(const WeakPtr<V8AnimatorBridge>& bridgeWeak, v8::Isolate* isolate)
174 {
175     auto bridge = bridgeWeak.Upgrade();
176     if (!bridge) {
177         LOGE("Call Animation Repeat Js Failed. animation bridge is null.");
178         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
179         return;
180     }
181     v8::HandleScope handleScope(isolate);
182     auto animatorObject = bridge->GetJsObject();
183     if (animatorObject.IsEmpty()) {
184         LOGE("Animation Object is null");
185         return;
186     }
187     auto context = bridge->GetContext();
188     v8::Local<v8::Value> proto =
189         animatorObject->Get(context, v8::String::NewFromUtf8(isolate, "onrepeat").ToLocalChecked()).ToLocalChecked();
190     if (!proto->IsFunction()) {
191         LOGE("cannot find 'CallAnimationRepeatJs' function from animation object, maybe no callback at all.");
192         return;
193     }
194     LOGD("animation onrepeat event call");
195     v8::TryCatch tryCatch(isolate);
196     v8::Local<v8::Function> jsFunc = v8::Local<v8::Function>::Cast(proto);
197     v8::Local<v8::Value> funcRes;
198     v8::Local<v8::Object> global = context->Global();
199     bool succ = jsFunc->Call(context, global, 0, {}).ToLocal(&funcRes);
200     if (!succ) {
201         V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::ANIMATION_REPEAT_ERROR);
202         return;
203     }
204 }
205 
CallAnimationFrameJs(const WeakPtr<V8AnimatorBridge> & bridgeWeak,v8::Isolate * isolate,double value)206 void CallAnimationFrameJs(const WeakPtr<V8AnimatorBridge>& bridgeWeak, v8::Isolate* isolate, double value)
207 {
208     auto bridge = bridgeWeak.Upgrade();
209     if (!bridge) {
210         LOGE("Call Animation Repeat Js Failed. animation bridge is null.");
211         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
212         return;
213     }
214     v8::HandleScope handleScope(isolate);
215     auto animatorObject = bridge->GetJsObject();
216     if (animatorObject.IsEmpty()) {
217         LOGE("Animation Object is null");
218         return;
219     }
220     auto context = bridge->GetContext();
221     v8::Local<v8::Value> proto =
222         animatorObject->Get(context, v8::String::NewFromUtf8(isolate, "onframe").ToLocalChecked()).ToLocalChecked();
223     if (!proto->IsFunction()) {
224         LOGE("cannot find 'CallAnimationFrameJs' function from animation object, maybe no callback at all.");
225         return;
226     }
227     v8::TryCatch tryCatch(isolate);
228     v8::Local<v8::Function> jsFunc = v8::Local<v8::Function>::Cast(proto);
229     v8::Local<v8::Value> funcRes;
230     v8::Local<v8::Object> global = context->Global();
231     v8::Local<v8::Value> args[] = {v8::Number::New(isolate, value)};
232     bool succ = jsFunc->Call(context, global, 1, args).ToLocal(&funcRes);
233     if (!succ) {
234         V8Utils::JsStdDumpErrorAce(isolate, &tryCatch, JsErrorType::ANIMATION_FRAME_ERROR);
235         return;
236     }
237 }
238 
AddListenerForEventCallback(const WeakPtr<V8AnimatorBridge> & bridgeWeak,const RefPtr<Animator> & animator,v8::Isolate * isolate)239 void AddListenerForEventCallback(const WeakPtr<V8AnimatorBridge>& bridgeWeak, const RefPtr<Animator>& animator,
240     v8::Isolate* isolate)
241 {
242     animator->AddStartListener([isolate, bridgeWeak] {
243         auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
244         auto jsTaskExecutor = (*delegate)->GetAnimationJsTask();
245         jsTaskExecutor.PostTask([bridgeWeak, isolate]() mutable {
246             LOGI("call animation onstart event");
247             CallAnimationStartJs(bridgeWeak, isolate);
248         });
249     });
250     animator->AddStopListener([isolate, bridgeWeak] {
251         auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
252         auto jsTaskExecutor = (*delegate)->GetAnimationJsTask();
253         jsTaskExecutor.PostTask([bridgeWeak, isolate]() mutable {
254             LOGI("call animation onfinish event");
255             CallAnimationFinishJs(bridgeWeak, isolate);
256         });
257     });
258     animator->AddIdleListener([isolate, bridgeWeak] {
259         auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
260         auto jsTaskExecutor = (*delegate)->GetAnimationJsTask();
261         jsTaskExecutor.PostTask([bridgeWeak, isolate]() mutable {
262             LOGI("call animation oncancel event");
263             CallAnimationCancelJs(bridgeWeak, isolate);
264         });
265     });
266     animator->AddRepeatListener([isolate, bridgeWeak] {
267         auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
268         auto jsTaskExecutor = (*delegate)->GetAnimationJsTask();
269         jsTaskExecutor.PostTask([bridgeWeak, isolate]() mutable {
270             LOGI("call animation onrepeat event");
271             CallAnimationRepeatJs(bridgeWeak, isolate);
272         });
273     });
274 }
275 
AddFrameListener(const WeakPtr<V8AnimatorBridge> & bridgeWeak,const RefPtr<KeyframeAnimation<double>> & animation,v8::Isolate * isolate)276 void AddFrameListener(const WeakPtr<V8AnimatorBridge>& bridgeWeak, const RefPtr<KeyframeAnimation<double>>& animation,
277     v8::Isolate* isolate)
278 {
279     animation->AddListener([isolate, bridgeWeak](double value) {
280         auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate->GetData(V8EngineInstance::FRONTEND_DELEGATE));
281         auto jsTaskExecutor = (*delegate)->GetAnimationJsTask();
282         jsTaskExecutor.PostTask([bridgeWeak, isolate, value]() mutable {
283             CallAnimationFrameJs(bridgeWeak, isolate, value);
284         });
285     });
286 }
287 
288 } // namespace
289 
CreateAnimatorContext(v8::Local<v8::Context> & ctx,int32_t pageId,int32_t bridgeId)290 v8::Local<v8::Object> V8AnimatorBridgeUtils::CreateAnimatorContext(v8::Local<v8::Context>& ctx, int32_t pageId,
291     int32_t bridgeId)
292 {
293     const std::unordered_map<const char*, v8::Local<v8::Function>> contextTable = {
294         { "play", v8::Function::New(ctx, JsAnimatorPlay, v8::Local<v8::Value>(), 0).ToLocalChecked() },
295         { "finish", v8::Function::New(ctx, JsAnimatorFinish, v8::Local<v8::Value>(), 0).ToLocalChecked() },
296         { "pause", v8::Function::New(ctx, JsAnimatorPause, v8::Local<v8::Value>(), 0).ToLocalChecked() },
297         { "cancel", v8::Function::New(ctx, JsAnimatorCancel, v8::Local<v8::Value>(), 0).ToLocalChecked() },
298         { "reverse", v8::Function::New(ctx, JsAnimatorReverse, v8::Local<v8::Value>(), 0).ToLocalChecked() },
299         { "update", v8::Function::New(ctx, JsAnimatorUpdate, v8::Local<v8::Value>(), 1).ToLocalChecked() },
300     };
301     auto animatorContext = v8::Object::New(ctx->GetIsolate());
302     for (const auto& iter : contextTable) {
303         animatorContext->Set(ctx, v8::String::NewFromUtf8(ctx->GetIsolate(), iter.first).ToLocalChecked(), iter.second)
304             .ToChecked();
305     }
306     animatorContext->Set(ctx, v8::String::NewFromUtf8(ctx->GetIsolate(), "__pageId").ToLocalChecked(),
307         v8::Int32::New(ctx->GetIsolate(), pageId)).ToChecked();
308     animatorContext->Set(ctx, v8::String::NewFromUtf8(ctx->GetIsolate(), "__bridgeId").ToLocalChecked(),
309         v8::Int32::New(ctx->GetIsolate(), bridgeId)).ToChecked();
310     return animatorContext;
311 }
312 
JsAnimatorPlay(const v8::FunctionCallbackInfo<v8::Value> & args)313 void V8AnimatorBridgeUtils::JsAnimatorPlay(const v8::FunctionCallbackInfo<v8::Value>& args)
314 {
315     if (args.Length() != 0) {
316         LOGE("args length error, length: %{public}d", args.Length());
317         return;
318     }
319     v8::Isolate* isolate = args.GetIsolate();
320     v8::HandleScope handleScope(isolate);
321     auto ctx = isolate->GetCurrentContext();
322     int32_t pageId = GetCurrentPageId(ctx, args.Holder());
323     int32_t bridgeId = GetCurrentBridgeId(ctx, args.Holder());
324     HandleJsAnimatorContext(ctx, pageId, bridgeId, AnimatorOperation::PLAY);
325 }
326 
JsAnimatorFinish(const v8::FunctionCallbackInfo<v8::Value> & args)327 void V8AnimatorBridgeUtils::JsAnimatorFinish(const v8::FunctionCallbackInfo<v8::Value>& args)
328 {
329     if (args.Length() != 0) {
330         LOGE("args length error, length: %{public}d", args.Length());
331         return;
332     }
333     v8::Isolate* isolate = args.GetIsolate();
334     v8::HandleScope handleScope(isolate);
335     auto ctx = isolate->GetCurrentContext();
336     int32_t pageId = GetCurrentPageId(ctx, args.Holder());
337     int32_t bridgeId = GetCurrentBridgeId(ctx, args.Holder());
338     HandleJsAnimatorContext(ctx, pageId, bridgeId, AnimatorOperation::FINISH);
339 }
340 
JsAnimatorPause(const v8::FunctionCallbackInfo<v8::Value> & args)341 void V8AnimatorBridgeUtils::JsAnimatorPause(const v8::FunctionCallbackInfo<v8::Value>& args)
342 {
343     if (args.Length() != 0) {
344         LOGE("args length error, length: %{public}d", args.Length());
345         return;
346     }
347     v8::Isolate* isolate = args.GetIsolate();
348     v8::HandleScope handleScope(isolate);
349     auto ctx = isolate->GetCurrentContext();
350     int32_t pageId = GetCurrentPageId(ctx, args.Holder());
351     int32_t bridgeId = GetCurrentBridgeId(ctx, args.Holder());
352     HandleJsAnimatorContext(ctx, pageId, bridgeId, AnimatorOperation::PAUSE);
353 }
354 
JsAnimatorCancel(const v8::FunctionCallbackInfo<v8::Value> & args)355 void V8AnimatorBridgeUtils::JsAnimatorCancel(const v8::FunctionCallbackInfo<v8::Value>& args)
356 {
357     if (args.Length() != 0) {
358         LOGE("args length error, length: %{public}d", args.Length());
359         return;
360     }
361     v8::Isolate* isolate = args.GetIsolate();
362     v8::HandleScope handleScope(isolate);
363     auto ctx = isolate->GetCurrentContext();
364     int32_t pageId = GetCurrentPageId(ctx, args.Holder());
365     int32_t bridgeId = GetCurrentBridgeId(ctx, args.Holder());
366     HandleJsAnimatorContext(ctx, pageId, bridgeId, AnimatorOperation::CANCEL);
367 }
368 
JsAnimatorReverse(const v8::FunctionCallbackInfo<v8::Value> & args)369 void V8AnimatorBridgeUtils::JsAnimatorReverse(const v8::FunctionCallbackInfo<v8::Value>& args)
370 {
371     if (args.Length() != 0) {
372         LOGE("args length error, length: %{public}d", args.Length());
373         return;
374     }
375     v8::Isolate* isolate = args.GetIsolate();
376     v8::HandleScope handleScope(isolate);
377     auto ctx = isolate->GetCurrentContext();
378     int32_t pageId = GetCurrentPageId(ctx, args.Holder());
379     int32_t bridgeId = GetCurrentBridgeId(ctx, args.Holder());
380     HandleJsAnimatorContext(ctx, pageId, bridgeId, AnimatorOperation::REVERSE);
381 }
382 
JsAnimatorUpdate(const v8::FunctionCallbackInfo<v8::Value> & args)383 void V8AnimatorBridgeUtils::JsAnimatorUpdate(const v8::FunctionCallbackInfo<v8::Value>& args)
384 {
385     if (args.Length() != 1) {
386         LOGE("args length error, length: %{public}d", args.Length());
387         return;
388     }
389     v8::Isolate* isolate = args.GetIsolate();
390     v8::HandleScope handleScope(isolate);
391     auto ctx = isolate->GetCurrentContext();
392     v8::Local<v8::Object> valObj = args[0]->ToObject(ctx).ToLocalChecked();
393     v8::Local<v8::Array> valObjProperties = valObj->GetOwnPropertyNames(ctx).ToLocalChecked();
394     uint32_t objLen = valObjProperties->Length();
395     std::unordered_map<std::string, std::string> params;
396     for (uint32_t i = 0; i < objLen; i++) {
397         v8::Local<v8::Value> valObjKey;
398         bool succ = valObjProperties->Get(ctx, i).ToLocal(&valObjKey);
399         if (!succ) {
400             LOGW("key is null. Ignoring!");
401             continue;
402         }
403         v8::String::Utf8Value valObjKeyStr(isolate, valObjKey);
404         const char* keyStr = *valObjKeyStr;
405         if (keyStr == nullptr) {
406             continue;
407         }
408         v8::Local<v8::Value> valObjVal = valObj->Get(ctx, valObjKey).ToLocalChecked();
409         if (valObjVal->IsString() || valObjVal->IsNumber()) {
410             v8::String::Utf8Value valObjValStr(isolate, valObjVal);
411             const char* valStr = *valObjValStr;
412             if (valStr == nullptr) {
413                 continue;
414             }
415             params[keyStr] = valStr;
416         } else {
417             LOGD("value of unsupported type. Ignoring!");
418         }
419     }
420     int32_t pageId = GetCurrentPageId(ctx, args.Holder());
421     int32_t bridgeId = GetCurrentBridgeId(ctx, args.Holder());
422     auto page = GetPageById(isolate, pageId);
423     if (!page) {
424         LOGE("no page found for bridgeId: %{public}d", bridgeId);
425         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_PAGE_ERR);
426         return;
427     }
428     auto task = AceType::MakeRefPtr<V8AnimatorTaskUpdate>(isolate, params);
429     page->PushCommand(Referenced::MakeRefPtr<JsCommandAnimator>(bridgeId, task));
430 }
431 
JsCreateBridgeId()432 int32_t V8AnimatorBridgeUtils::JsCreateBridgeId()
433 {
434     static int32_t bridgeId = 0;
435     return bridgeId++;
436 }
437 
V8AnimatorBridge(const v8::Local<v8::Context> & ctx,v8::Isolate * instance,v8::Local<v8::Object> animatorContext)438 V8AnimatorBridge::V8AnimatorBridge(
439     const v8::Local<v8::Context>& ctx, v8::Isolate* instance, v8::Local<v8::Object> animatorContext)
440     : instance_(instance)
441 {
442     animatorObject_.Reset(instance_, animatorContext);
443     ctx_.Reset(instance_, ctx);
444 }
445 
~V8AnimatorBridge()446 V8AnimatorBridge::~V8AnimatorBridge()
447 {
448     RefPtr<Animator> animator;
449     animator.Swap(animator_);
450     auto taskExecutor = Container::CurrentTaskExecutor();
451     if (taskExecutor) {
452         taskExecutor->PostSyncTask(
453             [&animator]() {
454                 LOGI("release animator on UI thread");
455                 animator.Reset();
456             },
457             TaskExecutor::TaskType::UI);
458     }
459 }
460 
JsCreateAnimation(const std::string & param)461 void V8AnimatorBridge::JsCreateAnimation(const std::string& param)
462 {
463     int32_t iterations = 0;
464     double duration = 0.0;
465     double delay = 0.0;
466     std::unordered_map<std::string, double> animationDoubleParams;
467     std::unordered_map<std::string, std::string> animationStringParams;
468     BaseAnimationBridgeUtils::JsParseAnimatorParams(param, iterations, animationDoubleParams, animationStringParams);
469     RefPtr<Curve> curve;
470     std::string curveString;
471     auto iterEasing = animationStringParams.find(DOM_ANIMATION_EASING);
472     if (iterEasing != animationStringParams.end()) {
473         curveString = iterEasing->second;
474     }
475     curve = CreateCurve(curveString);
476     auto iterDuration = animationDoubleParams.find(DOM_ANIMATION_DURATION_API);
477     if (iterDuration != animationDoubleParams.end()) {
478         duration = iterDuration->second;
479     }
480     std::string fillString;
481     auto iterFill = animationStringParams.find(DOM_ANIMATION_FILL);
482     if (iterFill != animationStringParams.end()) {
483         fillString = iterFill->second;
484     }
485     auto iterDelay = animationDoubleParams.find(DOM_ANIMATION_DELAY_API);
486     if (iterDelay != animationDoubleParams.end()) {
487         delay = iterDelay->second;
488     }
489     if (!instance_) {
490         LOGE("instance is null");
491         return;
492     }
493     auto keyframeAnimation = CreateDoubleAnimation(animationDoubleParams, curve);
494     if (!animator_) {
495         animator_ = AceType::MakeRefPtr<Animator>();
496     }
497     if (!animator_->IsStopped()) {
498         animator_->Stop();
499     }
500     auto iterDirection = animationStringParams.find(DOM_ANIMATION_DIRECTION_API);
501     if (iterDirection != animationStringParams.end()) {
502         animator_->SetAnimationDirection(StringToAnimationDirection(iterDirection->second));
503     }
504     animator_->ClearInterpolators();
505     animator_->SetDuration(duration);
506     animator_->SetIteration(iterations);
507     animator_->SetStartDelay(delay);
508     animator_->SetFillMode(StringToFillMode(fillString));
509     animator_->AddInterpolator(keyframeAnimation);
510     AddListenerForEventCallback(AceType::WeakClaim(this), animator_, instance_);
511 }
512 
CreateDoubleAnimation(std::unordered_map<std::string,double> & animationParams,const RefPtr<Curve> & curve)513 RefPtr<KeyframeAnimation<double>> V8AnimatorBridge::CreateDoubleAnimation(
514     std::unordered_map<std::string, double>& animationParams, const RefPtr<Curve>& curve)
515 {
516     double begin = 0.0;
517     double end = 1.0;
518     auto animationBegin = animationParams.find(DOM_ANIMATION_BEGIN);
519     if (animationBegin != animationParams.end()) {
520         begin = animationBegin->second;
521     }
522     auto animationEnd = animationParams.find(DOM_ANIMATION_END);
523     if (animationEnd != animationParams.end()) {
524         end = animationEnd->second;
525     }
526     auto keyframeBegin = AceType::MakeRefPtr<Keyframe<double>>(0.0, begin);
527     auto keyframeEnd = AceType::MakeRefPtr<Keyframe<double>>(1.0, end);
528     auto keyframeAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
529     keyframeAnimation->AddKeyframe(keyframeBegin);
530     keyframeAnimation->AddKeyframe(keyframeEnd);
531     keyframeAnimation->SetCurve(curve);
532     AddFrameListener(AceType::WeakClaim(this), keyframeAnimation, instance_);
533     return keyframeAnimation;
534 }
535 
V8AnimatorTaskCreate(v8::Isolate * isolate,const RefPtr<V8AnimatorBridge> & bridge,const std::string & param)536 V8AnimatorTaskCreate::V8AnimatorTaskCreate(
537     v8::Isolate* isolate, const RefPtr<V8AnimatorBridge>& bridge, const std::string& param)
538     : bridge_(bridge), isolate_(isolate), param_(std::move(param))
539 {}
540 
AnimatorBridgeTaskFunc(const RefPtr<JsAcePage> & page,int32_t bridgeId)541 void V8AnimatorTaskCreate::AnimatorBridgeTaskFunc(const RefPtr<JsAcePage>& page, int32_t bridgeId)
542 {
543     if (!bridge_) {
544         LOGE("Create Animation Bridge failed. bridge is null.");
545         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
546         return;
547     }
548     auto bridgeFree = AceType::DynamicCast<V8AnimatorBridge>(page->GetAnimatorBridge(bridgeId));
549     auto delegate = static_cast<RefPtr<FrontendDelegate>*>(isolate_->GetData(V8EngineInstance::FRONTEND_DELEGATE));
550     auto jsTaskExecutor = (*delegate)->GetAnimationJsTask();
551     if (bridgeFree) {
552         auto weakBridge = AceType::WeakClaim(AceType::RawPtr(bridgeFree));
553         jsTaskExecutor.PostTask([weakBridge]() mutable {
554             auto bridgeFree = weakBridge.Upgrade();
555             if (bridgeFree != nullptr) {
556                 bridgeFree.Reset();
557             }
558         });
559     }
560     page->RemoveAnimatorBridge(bridgeId);
561     bridge_->JsCreateAnimation(param_);
562     page->AddAnimatorBridge(bridgeId, bridge_);
563 }
564 
AnimatorBridgeTaskFunc(const RefPtr<JsAcePage> & page,int32_t bridgeId)565 void V8AnimatorTaskOperation::AnimatorBridgeTaskFunc(const RefPtr<JsAcePage>& page, int32_t bridgeId)
566 {
567     auto animatorBridge = AceType::DynamicCast<V8AnimatorBridge>(page->GetAnimatorBridge(bridgeId));
568     if (!animatorBridge) {
569         LOGE("no animation bridge found for bridgeId: %{public}d", bridgeId);
570         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
571         return;
572     }
573     RefPtr<Animator> animator = animatorBridge->JsGetAnimator();
574     if (!animator) {
575         LOGE("animator is null");
576         return;
577     }
578     switch (operation_) {
579         case AnimatorOperation::PLAY:
580             animator->Play();
581             break;
582         case AnimatorOperation::PAUSE:
583             animator->Pause();
584             break;
585         case AnimatorOperation::CANCEL:
586             animator->Cancel();
587             break;
588         case AnimatorOperation::FINISH:
589             animator->Finish();
590             break;
591         case AnimatorOperation::REVERSE:
592             animator->Reverse();
593             break;
594         case AnimatorOperation::NONE:
595         default:
596             break;
597     }
598 }
599 
AnimatorBridgeTaskFunc(const RefPtr<JsAcePage> & page,int32_t bridgeId)600 void V8AnimatorTaskUpdate::AnimatorBridgeTaskFunc(const RefPtr<JsAcePage>& page, int32_t bridgeId)
601 {
602     auto animatorBridge = AceType::DynamicCast<V8AnimatorBridge>(page->GetAnimatorBridge(bridgeId));
603     if (!animatorBridge) {
604         LOGE("no animation bridge found for bridgeId: %{public}d", bridgeId);
605         EventReport::SendAnimationException(AnimationExcepType::ANIMATION_BRIDGE_ERR);
606         return;
607     }
608     RefPtr<Animator> animator = animatorBridge->JsGetAnimator();
609     if (!animator) {
610         LOGE("animator is null");
611         return;
612     }
613     if (!isolate_) {
614         LOGE("isolate is null");
615         return;
616     }
617     animator->ClearInterpolators();
618     UpdateAnimator(animator, animatorBridge, isolate_, params_);
619 }
620 
UpdateAnimator(const RefPtr<Animator> & animator,const RefPtr<V8AnimatorBridge> & bridge,v8::Isolate * isolate,const std::unordered_map<std::string,std::string> & params)621 void V8AnimatorTaskUpdate::UpdateAnimator(const RefPtr<Animator>& animator, const RefPtr<V8AnimatorBridge>& bridge,
622     v8::Isolate* isolate, const std::unordered_map<std::string, std::string>& params)
623 {
624     int32_t iterations = 1;
625     double duration = 0.0;
626     double delay = 0.0;
627     double begin = 0.0;
628     double end = 1.0;
629     std::string curveString;
630     std::string fillString;
631     RefPtr<Curve> curve;
632     auto iterEasing = params_.find(DOM_ANIMATION_EASING);
633     if (iterEasing != params_.end()) {
634         curveString = iterEasing->second;
635     }
636     curve = CreateCurve(curveString);
637     auto iterIterations = params_.find(DOM_ANIMATION_ITERATIONS);
638     if (iterIterations != params_.end()) {
639         iterations = StringToInt(iterIterations->second);
640     }
641     auto iterDuration = params_.find(DOM_ANIMATION_DURATION_API);
642     if (iterDuration != params_.end()) {
643         duration = StringToDouble(iterDuration->second);
644     }
645     auto iterFill = params_.find(DOM_ANIMATION_FILL);
646     if (iterFill != params_.end()) {
647         fillString = iterFill->second;
648     }
649     auto iterDelay = params_.find(DOM_ANIMATION_DELAY_API);
650     if (iterDelay != params_.end()) {
651         delay = StringToDouble(iterDelay->second);
652     }
653     auto iterDirection = params_.find(DOM_ANIMATION_DIRECTION_API);
654     if (iterDirection != params_.end()) {
655         animator->SetAnimationDirection(StringToAnimationDirection(iterDirection->second));
656     }
657     auto animationBegin = params_.find(DOM_ANIMATION_BEGIN);
658     if (animationBegin != params_.end()) {
659         begin = StringToDouble(animationBegin->second);
660     }
661     auto animationEnd = params_.find(DOM_ANIMATION_END);
662     if (animationEnd != params_.end()) {
663         end = StringToDouble(animationEnd->second);
664     }
665     auto keyframeAnimation = CreateDoubleAnimation(begin, end, curve);
666     AddFrameListener(AceType::WeakClaim(RawPtr(bridge)), keyframeAnimation, isolate);
667     animator->SetDuration(duration);
668     animator->SetIteration(iterations);
669     animator->SetStartDelay(delay);
670     animator->SetFillMode(StringToFillMode(fillString));
671     animator->AddInterpolator(keyframeAnimation);
672 }
673 
CreateDoubleAnimation(double begin,double end,const RefPtr<Curve> & curve)674 RefPtr<KeyframeAnimation<double>> V8AnimatorTaskUpdate::CreateDoubleAnimation(double begin, double end,
675     const RefPtr<Curve>& curve)
676 {
677     auto keyframeBegin = AceType::MakeRefPtr<Keyframe<double>>(0.0, begin);
678     auto keyframeEnd = AceType::MakeRefPtr<Keyframe<double>>(1.0, end);
679     auto keyframeAnimation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
680     keyframeAnimation->AddKeyframe(keyframeBegin);
681     keyframeAnimation->AddKeyframe(keyframeEnd);
682     keyframeAnimation->SetCurve(curve);
683     return keyframeAnimation;
684 }
685 
686 } // namespace OHOS::Ace::Framework
687