1 /*
2 * Copyright (c) 2022-2023 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 "common-interop.h"
17 #include "common-redrawer.h"
18
19 #include "ark-interop.h"
20 #include "oh_sk_log.h"
21
22 #include "platform-api.h"
23
24 static napi_ref gPlatformApiRef = nullptr;
25
Node_skoala_setPlatformAPI(const Napi::CallbackInfo & info)26 Napi::Value Node_skoala_setPlatformAPI(const Napi::CallbackInfo& info) {
27 if (static_cast<size_t>(0) >= info.Length()) {
28 Napi::Error::New(info.Env(), "No such element")
29 .ThrowAsJavaScriptException();
30 return info.Env().Undefined();
31 }
32 if (info[0].IsNull()) {
33 return info.Env().Undefined();
34 }
35
36 napi_value platformApi = (napi_value)info[0];
37 napi_create_reference(info.Env(), platformApi, 1, &gPlatformApiRef);
38
39 return info.Env().Undefined();
40 }
MAKE_INTEROP_NODE_EXPORT(skoala_setPlatformAPI)41 MAKE_INTEROP_NODE_EXPORT(skoala_setPlatformAPI)
42
43 Napi::Value Node_skoala_createRedrawerPeer(const Napi::CallbackInfo& info) {
44 if (static_cast<size_t>(0) >= info.Length()) {
45 Napi::Error::New(info.Env(), "No such element")
46 .ThrowAsJavaScriptException();
47 return info.Env().Undefined();
48 }
49 if (info[0].IsNull()) {
50 return info.Env().Undefined();
51 }
52 napi_value redrawer = (napi_value)info[0];
53
54 napi_value platformApi = nullptr;
55 napi_get_reference_value(info.Env(), gPlatformApiRef, &platformApi);
56
57 auto* peer = reinterpret_cast<RedrawerPeer *>(GetPeerFactory()(reinterpret_cast<void*>(&const_cast<Napi::CallbackInfo&>(info)),
58 GetEngine(), platformApi, redrawer, Engine::RuntimeKind::JS));
59 Napi::Value result = makePointer(info, peer);
60 peer->callOnInitEnv(info);
61 return result;
62 }
MAKE_INTEROP_NODE_EXPORT(skoala_createRedrawerPeer)63 MAKE_INTEROP_NODE_EXPORT(skoala_createRedrawerPeer)
64
65 Napi::Value Node_skoala_checkEvents(const Napi::CallbackInfo& info) {
66 if (static_cast<size_t>(0) >= info.Length()) {
67 Napi::Error::New(info.Env(), "No such element")
68 .ThrowAsJavaScriptException();
69 return info.Env().Undefined();
70 }
71 if (info[0].IsNull()) {
72 return info.Env().Undefined();
73 }
74 RedrawerData* data = reinterpret_cast<RedrawerData*>(getPointer(info, 0));
75 return makeBoolean(info, data->peer->checkEvents(data->peer->engine, reinterpret_cast<void*>(&const_cast<Napi::CallbackInfo&>(info))));
76 }
MAKE_INTEROP_NODE_EXPORT(skoala_checkEvents)77 MAKE_INTEROP_NODE_EXPORT(skoala_checkEvents)
78
79 Napi::Value Node_skoala_drawPicture(const Napi::CallbackInfo& info) {
80 if (static_cast<size_t>(3) >= info.Length()) {
81 Napi::Error::New(info.Env(), "No such element")
82 .ThrowAsJavaScriptException();
83 return info.Env().Undefined();
84 }
85
86 SkPicture* picture = reinterpret_cast<SkPicture*>(getPointer(info, 0));
87 RedrawerData* data = reinterpret_cast<RedrawerData*>(getPointer(info, 1));
88 Napi::Function completer = Napi::Function(info.Env(), (napi_value)info[2]);
89 KBoolean sync = getBoolean(info, 3);
90
91 performDrawOperation(completer, data, picture, sync);
92
93 return info.Env().Undefined();
94 }
MAKE_INTEROP_NODE_EXPORT(skoala_drawPicture)95 MAKE_INTEROP_NODE_EXPORT(skoala_drawPicture)
96
97 void doDisposeCallback(KNativePointer cb) {
98 NodeCallback* callback = reinterpret_cast<NodeCallback*>(cb);
99 delete callback;
100 }
101
callCallback(KNativePointer cb)102 napi_value callCallback(KNativePointer cb) {
103 NodeCallback* callback = reinterpret_cast<NodeCallback*>(cb);
104 return callback->callCallback();
105 }
106
getEnv(KNativePointer cb)107 Napi::Env getEnv(KNativePointer cb) {
108 NodeCallback* callback = reinterpret_cast<NodeCallback*>(cb);
109 return callback->getEnv();
110 }
111
doCallBooleanCallback(KNativePointer cb)112 KBoolean doCallBooleanCallback(KNativePointer cb) {
113 napi_value value = callCallback(cb);
114 Napi::Env env = getEnv(cb);
115
116 return getBoolean(env, Napi::Value(env, value));
117 }
118
doCallIntCallback(KNativePointer cb)119 KInt doCallIntCallback(KNativePointer cb) {
120 napi_value value = callCallback(cb);
121 Napi::Env env = getEnv(cb);
122
123 return getInt32(env, Napi::Value(env, value));
124 }
125
doCallNativePointerCallback(KNativePointer cb)126 KNativePointer doCallNativePointerCallback(KNativePointer cb) {
127 napi_value value = callCallback(cb);
128 Napi::Env env = getEnv(cb);
129
130 return getPointer(env, Napi::Value(env, value));
131 }
132
doCallVoidCallback(KNativePointer cb)133 void doCallVoidCallback(KNativePointer cb) {
134 callCallback(cb);
135 }
136
Node_skoala_registerCallback(const Napi::CallbackInfo & info)137 Napi::Value Node_skoala_registerCallback(const Napi::CallbackInfo& info) {
138 static std::once_flag flag;
139 std::call_once(flag, []() {
140 initCallbacks(
141 &doCallBooleanCallback,
142 &doCallIntCallback,
143 &doCallNativePointerCallback,
144 &doCallVoidCallback,
145 &doDisposeCallback);
146 });
147
148 if (static_cast<size_t>(1) >= info.Length()) {
149 Napi::Error::New(info.Env(), "No such element").ThrowAsJavaScriptException();
150 return info.Env().Undefined();
151 }
152
153 Napi::Value arg0 = info[0];
154
155 if (arg0.IsNull() || arg0.IsUndefined() || !arg0.IsFunction()) {
156 Napi::Error::New(info.Env(), "Wrong callback").ThrowAsJavaScriptException();
157 return info.Env().Undefined();
158 }
159
160 Napi::Value arg1 = info[1];
161 if (!arg0.IsObject()) {
162 Napi::Error::New(info.Env(), "Not an object").ThrowAsJavaScriptException();
163 return info.Env().Undefined();
164 }
165 NodeCallback* callback = new NodeCallback(info, arg1, arg0);
166
167 return makePointer(info, callback);
168 }
MAKE_INTEROP_NODE_EXPORT(skoala_registerCallback)169 MAKE_INTEROP_NODE_EXPORT(skoala_registerCallback)
170
171 static inline void OnAsyncWorkExecute(napi_env env, void* asyncworker) {}
OnAsyncWorkComplete(napi_env env,napi_status status,void * asyncworker)172 static inline void OnAsyncWorkComplete(napi_env env,
173 napi_status status,
174 void* asyncworker) {
175 napi_value platformApi = nullptr;
176 napi_value runCallback = nullptr;
177 napi_get_reference_value(env, gPlatformApiRef, &platformApi);
178 napi_get_named_property(env, platformApi, "run", &runCallback);
179 Napi::Function cb = Napi::Function(env, runCallback);
180 cb.Call(runCallback, {});
181 }
182 static napi_async_work gWork = nullptr;
Node_skoala_enqueue_run(const Napi::CallbackInfo & info)183 Napi::Value Node_skoala_enqueue_run(const Napi::CallbackInfo& info) {
184 const char* resource_name = "generic";
185 napi_env env = info.Env();
186 const Napi::Object resource = Napi::Object::New(env);
187 napi_value resource_id;
188 napi_status status = napi_create_string_latin1(
189 env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
190 NAPI_THROW_IF_FAILED_VOID(env, status);
191
192 // napi_async_work work;
193 if (gWork != nullptr) {
194 napi_delete_async_work(env, gWork);
195 gWork = nullptr;
196 }
197 status = napi_create_async_work(env, resource, resource_id, OnAsyncWorkExecute,
198 OnAsyncWorkComplete, nullptr, &gWork);
199 NAPI_THROW_IF_FAILED_VOID(env, status);
200 status = napi_queue_async_work(env, gWork);
201 NAPI_THROW_IF_FAILED_VOID(env, status);
202
203 return info.Env().Undefined();
204 }
205 MAKE_INTEROP_NODE_EXPORT(skoala_enqueue_run)
206