• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 #include "AnimationJS.h"
16 
17 #include <meta/api/make_callback.h>
18 #include <meta/interface/animation/intf_animation.h>
19 #include <meta/interface/animation/builtin_animations.h>
20 #include <meta/interface/intf_attach.h>
21 #include <scene/interface/intf_scene.h>
22 
23 #include "SceneJS.h"
24 
25 class OnCallJS : public ThreadSafeCallback {
26     NapiApi::StrongRef jsThis_;
27     NapiApi::StrongRef ref_;
28 
29 public:
OnCallJS(const char * name,NapiApi::Object jsThis,NapiApi::Function toCall)30     OnCallJS(const char* name, NapiApi::Object jsThis, NapiApi::Function toCall)
31         : ThreadSafeCallback(toCall.GetEnv(), name), jsThis_(jsThis), ref_(toCall.GetEnv(), toCall)
32     {}
~OnCallJS()33     ~OnCallJS()
34     {
35         jsThis_.Reset();
36         ref_.Reset();
37         Release();
38     }
Finalize(napi_env env)39     void Finalize(napi_env env)
40     {
41         jsThis_.Reset();
42         ref_.Reset();
43     }
Invoked(napi_env env)44     void Invoked(napi_env env)
45     {
46         napi_value res;
47         napi_call_function(env, jsThis_.GetValue(), ref_.GetValue(), 0, nullptr, &res);
48     }
49 };
50 
Init(napi_env env,napi_value exports)51 void AnimationJS::Init(napi_env env, napi_value exports)
52 {
53     BASE_NS::vector<napi_property_descriptor> node_props;
54     SceneResourceImpl::GetPropertyDescs(node_props);
55 // Try out the helper macros.
56 // Declare NAPI_API_JS_NAME to simplify the registering.
57 #define NAPI_API_JS_NAME Animation
58 
59     DeclareGetSet(bool, "enabled", GetEnabled, SetEnabled);
60     DeclareGetSet(float, "speed", GetSpeed, SetSpeed);
61     DeclareGet(float, "duration", GetDuration);
62     DeclareGet(bool, "running", GetRunning);
63     DeclareGet(float, "progress", GetProgress);
64     DeclareMethod("pause", Pause);
65     DeclareMethod("restart", Restart);
66     DeclareMethod("seek", Seek, float);
67     DeclareMethod("start", Start);
68     DeclareMethod("stop", Stop);
69     DeclareMethod("finish", Finish);
70     DeclareMethod("onFinished", OnFinished, NapiApi::Function);
71     DeclareMethod("onStarted", OnStarted, NapiApi::Function);
72 
73     DeclareClass();
74 #undef NAPI_API_JS_NAME
75 }
76 
AnimationJS(napi_env e,napi_callback_info i)77 AnimationJS::AnimationJS(napi_env e, napi_callback_info i)
78     : BaseObject<AnimationJS>(e, i), SceneResourceImpl(SceneResourceImpl::ANIMATION)
79 {
80     NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object> fromJs(e, i);
81     NapiApi::Object meJs(fromJs.This());
82     NapiApi::Object scene = fromJs.Arg<0>(); // access to owning scene...
83     NapiApi::Object args = fromJs.Arg<1>();  // access to params.
84     scene_ = { scene };
85     if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) {
86         LOG_F("INVALID SCENE!");
87     }
88 
89     auto* tro = scene.Native<TrueRootObject>();
90     if (tro) {
91         auto* sceneJS = static_cast<SceneJS*>(tro->GetInstanceImpl(SceneJS::ID));
92         if (sceneJS) {
93             sceneJS->DisposeHook(reinterpret_cast<uintptr_t>(&scene_), meJs);
94         }
95     }
96 
97     if (args) {
98         using namespace META_NS;
99         auto obj = GetNativeObjectParam<IObject>(args);
100         if (auto a = interface_cast<IAnimation>(obj)) {
101             // linking to an existing object.
102             SetNativeObject(obj, false);
103             StoreJsObj(obj, meJs);
104 
105             // check if there is a speed controller already.(and use that)
106             auto attachments = interface_cast<META_NS::IAttach>(a)->GetAttachments();
107             for (auto at : attachments) {
108                 if (interface_cast<AnimationModifiers::ISpeed>(at)) {
109                     // yes.. (expect at most one)
110                     speedModifier_ = interface_pointer_cast<AnimationModifiers::ISpeed>(at);
111                     break;
112                 }
113             }
114         }
115     }
116 }
GetInstanceImpl(uint32_t id)117 void* AnimationJS::GetInstanceImpl(uint32_t id)
118 {
119     if (id == AnimationJS::ID)
120         return this;
121     return SceneResourceImpl::GetInstanceImpl(id);
122 }
123 
Finalize(napi_env env)124 void AnimationJS::Finalize(napi_env env)
125 {
126     DisposeNative(nullptr);
127     BaseObject<AnimationJS>::Finalize(env);
128 }
~AnimationJS()129 AnimationJS::~AnimationJS()
130 {
131     LOG_V("AnimationJS -- ");
132     DisposeNative(nullptr);
133 }
134 
DisposeNative(void *)135 void AnimationJS::DisposeNative(void*)
136 {
137     // do nothing for now..
138     if (!disposed_) {
139         disposed_ = true;
140 
141         LOG_V("AnimationJS::DisposeNative");
142         NapiApi::Object obj = scene_.GetObject();
143         auto* tro = obj.Native<TrueRootObject>();
144         if (tro) {
145             SceneJS* sceneJS = static_cast<SceneJS*>(tro->GetInstanceImpl(SceneJS::ID));
146             if (sceneJS) {
147                 sceneJS->ReleaseDispose(reinterpret_cast<uintptr_t>(&scene_));
148             }
149         }
150         scene_.Reset();
151 
152         // make sure we release postProc settings
153         if (auto anim = interface_pointer_cast<META_NS::IAnimation>(GetNativeObject())) {
154             // reset the native object refs
155             SetNativeObject(nullptr, false);
156             SetNativeObject(nullptr, true);
157             // remove listeners.
158             if (OnStartedToken_) {
159                 anim->OnStarted()->RemoveHandler(OnStartedToken_);
160             }
161             if (OnFinishedToken_) {
162                 anim->OnFinished()->RemoveHandler(OnFinishedToken_);
163             }
164             if (speedModifier_) {
165                 auto attach = interface_cast<META_NS::IAttach>(anim);
166                 if (attach) {
167                     attach->Detach(speedModifier_);
168                 }
169                 speedModifier_.reset();
170             }
171             if (OnStartedCB_) {
172                 // does a delayed delete
173                 OnStartedCB_->Release();
174                 OnStartedCB_ = nullptr;
175             }
176             if (OnFinishedCB_) {
177                 // does a delayed delete
178                 OnFinishedCB_->Release();
179                 OnFinishedCB_ = nullptr;
180             }
181         }
182     }
183 }
GetSpeed(NapiApi::FunctionContext<> & ctx)184 napi_value AnimationJS::GetSpeed(NapiApi::FunctionContext<>& ctx)
185 {
186     if (!validateSceneRef()) {
187         return ctx.GetUndefined();
188     }
189 
190     float speed = 1.0;
191     if (speedModifier_) {
192         speed = speedModifier_->SpeedFactor()->GetValue();
193     }
194 
195     return ctx.GetNumber(speed);
196 }
197 
SetSpeed(NapiApi::FunctionContext<float> & ctx)198 void AnimationJS::SetSpeed(NapiApi::FunctionContext<float>& ctx)
199 {
200     if (!validateSceneRef()) {
201         return;
202     }
203     float speed = ctx.Arg<0>();
204     if (auto a = interface_cast<META_NS::IAnimation>(GetNativeObject())) {
205         using namespace META_NS;
206         if (!speedModifier_) {
207             speedModifier_ =
208                 GetObjectRegistry().Create<AnimationModifiers::ISpeed>(ClassId::SpeedAnimationModifier);
209             interface_cast<IAttach>(a)->Attach(speedModifier_);
210         }
211         speedModifier_->SpeedFactor()->SetValue(speed);
212     }
213 }
214 
GetEnabled(NapiApi::FunctionContext<> & ctx)215 napi_value AnimationJS::GetEnabled(NapiApi::FunctionContext<>& ctx)
216 {
217     if (!validateSceneRef()) {
218         return ctx.GetUndefined();
219     }
220 
221     bool enabled { false };
222     if (auto a = interface_cast<META_NS::IAnimation>(GetNativeObject())) {
223         enabled = a->Enabled()->GetValue();
224     }
225     return ctx.GetBoolean(enabled);
226 }
SetEnabled(NapiApi::FunctionContext<bool> & ctx)227 void AnimationJS::SetEnabled(NapiApi::FunctionContext<bool>& ctx)
228 {
229     if (!validateSceneRef()) {
230         return;
231     }
232     bool enabled = ctx.Arg<0>();
233     if (auto a = interface_cast<META_NS::IAnimation>(GetNativeObject())) {
234         a->Enabled()->SetValue(enabled);
235     }
236 }
GetDuration(NapiApi::FunctionContext<> & ctx)237 napi_value AnimationJS::GetDuration(NapiApi::FunctionContext<>& ctx)
238 {
239     if (!validateSceneRef()) {
240         return ctx.GetUndefined();
241     }
242     float duration = 0.0;
243     if (auto a = interface_cast<META_NS::IAnimation>(GetNativeObject())) {
244         duration = a->TotalDuration()->GetValue().ToSecondsFloat();
245     }
246 
247     return ctx.GetNumber(duration);
248 }
249 
GetRunning(NapiApi::FunctionContext<> & ctx)250 napi_value AnimationJS::GetRunning(NapiApi::FunctionContext<>& ctx)
251 {
252     if (!validateSceneRef()) {
253         return ctx.GetUndefined();
254     }
255     bool running { false };
256     if (auto a = interface_cast<META_NS::IAnimation>(GetNativeObject())) {
257         running = a->Running()->GetValue();
258     }
259     return ctx.GetBoolean(running);
260 }
GetProgress(NapiApi::FunctionContext<> & ctx)261 napi_value AnimationJS::GetProgress(NapiApi::FunctionContext<>& ctx)
262 {
263     if (!validateSceneRef()) {
264         return ctx.GetUndefined();
265     }
266     float progress = 0.0;
267     if (auto a = interface_cast<META_NS::IAnimation>(GetNativeObject())) {
268         progress = a->Progress()->GetValue();
269     }
270     return ctx.GetNumber(progress);
271 }
272 
OnFinished(NapiApi::FunctionContext<NapiApi::Function> & ctx)273 napi_value AnimationJS::OnFinished(NapiApi::FunctionContext<NapiApi::Function>& ctx)
274 {
275     auto func = ctx.Arg<0>();
276     // do we have existing callback?
277     if (OnFinishedCB_) {
278         // stop listening ...
279         if (auto a = interface_cast<META_NS::IAnimation>(GetNativeObject())) {
280             a->OnFinished()->RemoveHandler(OnFinishedToken_);
281             OnFinishedToken_ = 0;
282         }
283         // ... and release it
284         OnFinishedCB_->Release();
285     }
286     if (!validateSceneRef()) {
287         return ctx.GetUndefined();
288     }
289 
290     // do we have a new callback?
291     if (func.IsDefinedAndNotNull()) {
292         // create handler...
293         OnFinishedCB_ = new OnCallJS("OnFinished", ctx.This(), func);
294         // ... and start listening
295         if (auto a = interface_cast<META_NS::IAnimation>(GetNativeObject())) {
296             OnFinishedToken_ = a->OnFinished()->AddHandler(
297                 META_NS::MakeCallback<META_NS::IOnChanged>(OnFinishedCB_, &OnCallJS::Trigger));
298         }
299     }
300     return ctx.GetUndefined();
301 }
302 
OnStarted(NapiApi::FunctionContext<NapiApi::Function> & ctx)303 napi_value AnimationJS::OnStarted(NapiApi::FunctionContext<NapiApi::Function>& ctx)
304 {
305     auto func = ctx.Arg<0>();
306     // do we have existing callback?
307     if (OnStartedCB_) {
308         // stop listening ...
309         if (auto a = interface_cast<META_NS::IAnimation>(GetNativeObject())) {
310             a->OnStarted()->RemoveHandler(OnStartedToken_);
311             OnStartedToken_ = 0;
312         }
313         // ... and release it
314         OnStartedCB_->Release();
315     }
316     if (!validateSceneRef()) {
317         return ctx.GetUndefined();
318     }
319     // do we have a new callback?
320     if (func.IsDefinedAndNotNull()) {
321         // create handler...
322         OnStartedCB_ = new OnCallJS("OnStart", ctx.This(), func);
323         // ... and start listening
324         if (auto a = interface_cast<META_NS::IAnimation>(GetNativeObject())) {
325             OnStartedToken_ = a->OnStarted()->AddHandler(
326                 META_NS::MakeCallback<META_NS::IOnChanged>(OnStartedCB_, &OnCallJS::Trigger));
327         }
328     }
329     return ctx.GetUndefined();
330 }
331 
Pause(NapiApi::FunctionContext<> & ctx)332 napi_value AnimationJS::Pause(NapiApi::FunctionContext<>& ctx)
333 {
334     if (!validateSceneRef()) {
335         return ctx.GetUndefined();
336     }
337 
338     if (auto a = interface_cast<META_NS::IStartableAnimation>(GetNativeObject())) {
339         a->Pause();
340     }
341     return ctx.GetUndefined();
342 }
Restart(NapiApi::FunctionContext<> & ctx)343 napi_value AnimationJS::Restart(NapiApi::FunctionContext<>& ctx)
344 {
345     if (!validateSceneRef()) {
346         return ctx.GetUndefined();
347     }
348     if (auto a = interface_cast<META_NS::IStartableAnimation>(GetNativeObject())) {
349         a->Restart();
350     }
351     return ctx.GetUndefined();
352 }
Seek(NapiApi::FunctionContext<float> & ctx)353 napi_value AnimationJS::Seek(NapiApi::FunctionContext<float>& ctx)
354 {
355     if (!validateSceneRef()) {
356         return ctx.GetUndefined();
357     }
358     float pos = ctx.Arg<0>();
359     if (auto a = interface_cast<META_NS::IStartableAnimation>(GetNativeObject())) {
360         a->Seek(pos);
361     }
362     return ctx.GetUndefined();
363 }
Start(NapiApi::FunctionContext<> & ctx)364 napi_value AnimationJS::Start(NapiApi::FunctionContext<>& ctx)
365 {
366     if (!validateSceneRef()) {
367         return ctx.GetUndefined();
368     }
369     if (auto a = interface_cast<META_NS::IStartableAnimation>(GetNativeObject())) {
370         a->Start();
371     }
372     return ctx.GetUndefined();
373 }
374 
Stop(NapiApi::FunctionContext<> & ctx)375 napi_value AnimationJS::Stop(NapiApi::FunctionContext<>& ctx)
376 {
377     if (!validateSceneRef()) {
378         return ctx.GetUndefined();
379     }
380     if (auto a = interface_cast<META_NS::IStartableAnimation>(GetNativeObject())) {
381         a->Stop();
382     }
383     return ctx.GetUndefined();
384 }
Finish(NapiApi::FunctionContext<> & ctx)385 napi_value AnimationJS::Finish(NapiApi::FunctionContext<>& ctx)
386 {
387     if (!validateSceneRef()) {
388         return ctx.GetUndefined();
389     }
390     if (auto a = interface_cast<META_NS::IStartableAnimation>(GetNativeObject())) {
391         a->Seek(1.0);
392     }
393     return ctx.GetUndefined();
394 }
395