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
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_node_adapter_bridge.h"
17
18 #include "jsnapi_expo.h"
19
20 #include "base/memory/ace_type.h"
21 #include "base/memory/referenced.h"
22 #include "base/utils/utils.h"
23 #include "bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_frame_node_bridge.h"
24 #include "bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_utils_bridge.h"
25 #include "core/interfaces/arkoala/arkoala_api.h"
26 #include "frameworks/core/interfaces/native/node/node_adapter_impl.h"
27
28 namespace OHOS::Ace::NG {
29
GetNodeAdapter(ArkUIRuntimeCallInfo * runtimeCallInfo)30 UINodeAdapter* GetNodeAdapter(ArkUIRuntimeCallInfo* runtimeCallInfo)
31 {
32 EcmaVM* vm = runtimeCallInfo->GetVM();
33 CHECK_NULL_RETURN(vm, nullptr);
34 Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
35 CHECK_NULL_RETURN(!firstArg.IsNull(), nullptr);
36 auto* adapter = reinterpret_cast<UINodeAdapter*>(firstArg->ToNativePointer(vm)->Value());
37 return adapter;
38 }
39
SetAttachCallback(EcmaVM * vm,UINodeAdapter * adapter,const panda::Local<panda::JSValueRef> & argRef,const panda::Local<panda::JSValueRef> & thisRef)40 void SetAttachCallback(EcmaVM* vm, UINodeAdapter* adapter, const panda::Local<panda::JSValueRef>& argRef,
41 const panda::Local<panda::JSValueRef>& thisRef)
42 {
43 CHECK_NULL_VOID(adapter);
44 CHECK_NULL_VOID(!argRef->IsUndefined());
45 CHECK_NULL_VOID(argRef->IsFunction(vm));
46 auto attachObj = argRef->ToObject(vm);
47 panda::Local<panda::FunctionRef> attachFunc = attachObj;
48 auto onAttachToNode = [vm, func = JsWeak(panda::CopyableGlobal(vm, attachFunc)),
49 thisRef = JsWeak(panda::CopyableGlobal(vm, thisRef))](ArkUINodeHandle node) {
50 panda::LocalScope pandaScope(vm);
51 panda::TryCatch trycatch(vm);
52 auto function = func.Lock();
53 CHECK_NULL_VOID(!function.IsEmpty());
54 CHECK_NULL_VOID(function->IsFunction(vm));
55 panda::Local<panda::JSValueRef> params[1] = { FrameNodeBridge::MakeFrameNodeInfo(vm, node) };
56 function->Call(vm, thisRef.Lock().ToLocal(), params, 1);
57 };
58 adapter->SetOnAttachToNodeFunc(std::move(onAttachToNode));
59 }
60
SetDetachCallback(EcmaVM * vm,UINodeAdapter * adapter,const panda::Local<panda::JSValueRef> & argRef,const panda::Local<panda::JSValueRef> & thisRef)61 void SetDetachCallback(EcmaVM* vm, UINodeAdapter* adapter, const panda::Local<panda::JSValueRef>& argRef,
62 const panda::Local<panda::JSValueRef>& thisRef)
63 {
64 CHECK_NULL_VOID(adapter);
65 CHECK_NULL_VOID(!argRef->IsUndefined());
66 CHECK_NULL_VOID(argRef->IsFunction(vm));
67 auto detachObj = argRef->ToObject(vm);
68 panda::Local<panda::FunctionRef> detachFunc = detachObj;
69 auto onDetachFromNode = [vm, func = JsWeak(panda::CopyableGlobal(vm, detachFunc)),
70 thisRef = JsWeak(panda::CopyableGlobal(vm, thisRef))]() {
71 panda::LocalScope pandaScope(vm);
72 panda::TryCatch trycatch(vm);
73 auto function = func.Lock();
74 CHECK_NULL_VOID(!function.IsEmpty());
75 CHECK_NULL_VOID(function->IsFunction(vm));
76 function->Call(vm, thisRef.Lock().ToLocal(), {}, 0);
77 };
78 adapter->SetOnDetachFromNodeFunc(std::move(onDetachFromNode));
79 }
80
SetGetIdCallback(EcmaVM * vm,UINodeAdapter * adapter,const panda::Local<panda::JSValueRef> & argRef,const panda::Local<panda::JSValueRef> & thisRef)81 void SetGetIdCallback(EcmaVM* vm, UINodeAdapter* adapter, const panda::Local<panda::JSValueRef>& argRef,
82 const panda::Local<panda::JSValueRef>& thisRef)
83 {
84 CHECK_NULL_VOID(adapter);
85 CHECK_NULL_VOID(!argRef->IsUndefined());
86 CHECK_NULL_VOID(argRef->IsFunction(vm));
87 auto getIdObj = argRef->ToObject(vm);
88 panda::Local<panda::FunctionRef> getIdFunc = getIdObj;
89 auto onGetId = [vm, func = JsWeak(panda::CopyableGlobal(vm, getIdFunc)),
90 thisRef = JsWeak(panda::CopyableGlobal(vm, thisRef))](uint32_t index) -> int32_t {
91 panda::LocalScope pandaScope(vm);
92 panda::TryCatch trycatch(vm);
93 auto function = func.Lock();
94 CHECK_NULL_RETURN(!function.IsEmpty(), index);
95 CHECK_NULL_RETURN(function->IsFunction(vm), index);
96 panda::Local<panda::JSValueRef> params[1] = { panda::NumberRef::New(vm, index) };
97 auto result = function->Call(vm, thisRef.Lock().ToLocal(), params, 1);
98 CHECK_NULL_RETURN(result->IsNumber(), index);
99 return result->Int32Value(vm);
100 };
101 adapter->SetOnGetChildIdFunc(std::move(onGetId));
102 }
103
SetCreateNewChildCallback(EcmaVM * vm,UINodeAdapter * adapter,const panda::Local<panda::JSValueRef> & argRef,const panda::Local<panda::JSValueRef> & thisRef)104 void SetCreateNewChildCallback(EcmaVM* vm, UINodeAdapter* adapter, const panda::Local<panda::JSValueRef>& argRef,
105 const panda::Local<panda::JSValueRef>& thisRef)
106 {
107 CHECK_NULL_VOID(adapter);
108 CHECK_NULL_VOID(!argRef->IsUndefined());
109 CHECK_NULL_VOID(argRef->IsFunction(vm));
110 auto createChildObj = argRef->ToObject(vm);
111 panda::Local<panda::FunctionRef> createChildFunc = createChildObj;
112 auto onCreateChild = [vm, func = JsWeak(panda::CopyableGlobal(vm, createChildFunc)),
113 thisRef = JsWeak(panda::CopyableGlobal(vm, thisRef))](uint32_t index) -> ArkUINodeHandle {
114 panda::LocalScope pandaScope(vm);
115 panda::TryCatch trycatch(vm);
116 auto function = func.Lock();
117 CHECK_NULL_RETURN(!function.IsEmpty(), nullptr);
118 CHECK_NULL_RETURN(function->IsFunction(vm), nullptr);
119 panda::Local<panda::JSValueRef> params[1] = { panda::NumberRef::New(vm, index) };
120 auto result = function->Call(vm, thisRef.Lock().ToLocal(), params, 1);
121 CHECK_NULL_RETURN(result->IsNativePointer(vm), nullptr);
122 return nodePtr(result->ToNativePointer(vm)->Value());
123 };
124 adapter->SetOnCreateNewChild(std::move(onCreateChild));
125 }
126
SetDisposeChildCallback(EcmaVM * vm,UINodeAdapter * adapter,const panda::Local<panda::JSValueRef> & argRef,const panda::Local<panda::JSValueRef> & thisRef)127 void SetDisposeChildCallback(EcmaVM* vm, UINodeAdapter* adapter, const panda::Local<panda::JSValueRef>& argRef,
128 const panda::Local<panda::JSValueRef>& thisRef)
129 {
130 CHECK_NULL_VOID(adapter);
131 CHECK_NULL_VOID(!argRef->IsUndefined());
132 CHECK_NULL_VOID(argRef->IsFunction(vm));
133 auto disposeChildObj = argRef->ToObject(vm);
134 panda::Local<panda::FunctionRef> disposeChildFunc = disposeChildObj;
135 auto onDisposeChild = [vm, func = JsWeak(panda::CopyableGlobal(vm, disposeChildFunc)),
136 thisRef = JsWeak(panda::CopyableGlobal(vm, thisRef))](ArkUINodeHandle node, int32_t id) {
137 panda::LocalScope pandaScope(vm);
138 panda::TryCatch trycatch(vm);
139 auto function = func.Lock();
140 CHECK_NULL_VOID(!function.IsEmpty());
141 CHECK_NULL_VOID(function->IsFunction(vm));
142 panda::Local<panda::JSValueRef> params[2] = { panda::NumberRef::New(vm, id),
143 FrameNodeBridge::MakeFrameNodeInfo(vm, node) };
144 function->Call(vm, thisRef.Lock().ToLocal(), params, 2);
145 };
146 adapter->SetOnDisposeChild(std::move(onDisposeChild));
147 }
148
SetUpdateChildCallback(EcmaVM * vm,UINodeAdapter * adapter,const panda::Local<panda::JSValueRef> & argRef,const panda::Local<panda::JSValueRef> & thisRef)149 void SetUpdateChildCallback(EcmaVM* vm, UINodeAdapter* adapter, const panda::Local<panda::JSValueRef>& argRef,
150 const panda::Local<panda::JSValueRef>& thisRef)
151 {
152 CHECK_NULL_VOID(adapter);
153 CHECK_NULL_VOID(!argRef->IsUndefined());
154 CHECK_NULL_VOID(argRef->IsFunction(vm));
155 auto updateChildObj = argRef->ToObject(vm);
156 panda::Local<panda::FunctionRef> updateChildFunc = updateChildObj;
157 auto onUpdateChild = [vm, func = JsWeak(panda::CopyableGlobal(vm, updateChildFunc)),
158 thisRef = JsWeak(panda::CopyableGlobal(vm, thisRef))](ArkUINodeHandle node, int32_t id) {
159 panda::LocalScope pandaScope(vm);
160 panda::TryCatch trycatch(vm);
161 auto function = func.Lock();
162 CHECK_NULL_VOID(!function.IsEmpty());
163 CHECK_NULL_VOID(function->IsFunction(vm));
164 panda::Local<panda::JSValueRef> params[2] = { panda::NumberRef::New(vm, id),
165 FrameNodeBridge::MakeFrameNodeInfo(vm, node) };
166 function->Call(vm, thisRef.Lock().ToLocal(), params, 2);
167 };
168 adapter->SetOnUpdateChind(std::move(onUpdateChild));
169 }
170
CreateNodeAdapter(ArkUIRuntimeCallInfo * runtimeCallInfo)171 ArkUINativeModuleValue NodeAdapterBridge::CreateNodeAdapter(ArkUIRuntimeCallInfo* runtimeCallInfo)
172 {
173 EcmaVM* vm = runtimeCallInfo->GetVM();
174 auto* handle = GetArkUIFullNodeAPI()->getNodeAdapterAPI()->create();
175 CHECK_NULL_RETURN(handle, panda::JSValueRef::Undefined(vm));
176 auto ref = AceType::MakeRefPtr<UINodeAdapter>(handle);
177 auto nativeRef = NativeUtilsBridge::CreateStrongRef(vm, ref);
178 return nativeRef;
179 }
180
SetCallbacks(ArkUIRuntimeCallInfo * runtimeCallInfo)181 ArkUINativeModuleValue NodeAdapterBridge::SetCallbacks(ArkUIRuntimeCallInfo* runtimeCallInfo)
182 {
183 EcmaVM* vm = runtimeCallInfo->GetVM();
184 auto* adapter = GetNodeAdapter(runtimeCallInfo);
185 CHECK_NULL_RETURN(adapter, panda::JSValueRef::Undefined(vm));
186 auto thisRef = runtimeCallInfo->GetCallArgRef(1);
187 SetAttachCallback(vm, adapter, runtimeCallInfo->GetCallArgRef(2), thisRef);
188 SetDetachCallback(vm, adapter, runtimeCallInfo->GetCallArgRef(3), thisRef);
189 SetGetIdCallback(vm, adapter, runtimeCallInfo->GetCallArgRef(4), thisRef);
190 SetCreateNewChildCallback(vm, adapter, runtimeCallInfo->GetCallArgRef(5), thisRef);
191 SetDisposeChildCallback(vm, adapter, runtimeCallInfo->GetCallArgRef(6), thisRef);
192 SetUpdateChildCallback(vm, adapter, runtimeCallInfo->GetCallArgRef(7), thisRef);
193 return panda::JSValueRef::Undefined(vm);
194 }
195
SetTotalNodeCount(ArkUIRuntimeCallInfo * runtimeCallInfo)196 ArkUINativeModuleValue NodeAdapterBridge::SetTotalNodeCount(ArkUIRuntimeCallInfo* runtimeCallInfo)
197 {
198 EcmaVM* vm = runtimeCallInfo->GetVM();
199 auto* adapter = GetNodeAdapter(runtimeCallInfo);
200 CHECK_NULL_RETURN(adapter, panda::JSValueRef::Undefined(vm));
201 auto countArg = runtimeCallInfo->GetCallArgRef(1);
202 CHECK_NULL_RETURN(countArg->IsNumber(), panda::JSValueRef::Undefined(vm));
203 adapter->SetTotalNodeCount(countArg->Uint32Value(vm));
204 return panda::JSValueRef::Undefined(vm);
205 }
206
GetTotalNodeCount(ArkUIRuntimeCallInfo * runtimeCallInfo)207 ArkUINativeModuleValue NodeAdapterBridge::GetTotalNodeCount(ArkUIRuntimeCallInfo* runtimeCallInfo)
208 {
209 EcmaVM* vm = runtimeCallInfo->GetVM();
210 auto* adapter = GetNodeAdapter(runtimeCallInfo);
211 CHECK_NULL_RETURN(adapter, panda::JSValueRef::Undefined(vm));
212 uint32_t count = adapter->GetTotalNodeCount();
213 return panda::NumberRef::New(vm, count);
214 }
215
NotifyItemReloaded(ArkUIRuntimeCallInfo * runtimeCallInfo)216 ArkUINativeModuleValue NodeAdapterBridge::NotifyItemReloaded(ArkUIRuntimeCallInfo* runtimeCallInfo)
217 {
218 EcmaVM* vm = runtimeCallInfo->GetVM();
219 auto* adapter = GetNodeAdapter(runtimeCallInfo);
220 CHECK_NULL_RETURN(adapter, panda::JSValueRef::Undefined(vm));
221 adapter->NotifyItemReloaded();
222 return panda::JSValueRef::Undefined(vm);
223 }
224
NotifyItemChanged(ArkUIRuntimeCallInfo * runtimeCallInfo)225 ArkUINativeModuleValue NodeAdapterBridge::NotifyItemChanged(ArkUIRuntimeCallInfo* runtimeCallInfo)
226 {
227 EcmaVM* vm = runtimeCallInfo->GetVM();
228 auto* adapter = GetNodeAdapter(runtimeCallInfo);
229 CHECK_NULL_RETURN(adapter, panda::JSValueRef::Undefined(vm));
230 auto startArg = runtimeCallInfo->GetCallArgRef(1);
231 CHECK_NULL_RETURN(startArg->IsNumber(), panda::JSValueRef::Undefined(vm));
232 auto countArg = runtimeCallInfo->GetCallArgRef(2);
233 CHECK_NULL_RETURN(countArg->IsNumber(), panda::JSValueRef::Undefined(vm));
234 adapter->NotifyItemChanged(startArg->Uint32Value(vm), countArg->Uint32Value(vm));
235 return panda::JSValueRef::Undefined(vm);
236 }
237
NotifyItemRemoved(ArkUIRuntimeCallInfo * runtimeCallInfo)238 ArkUINativeModuleValue NodeAdapterBridge::NotifyItemRemoved(ArkUIRuntimeCallInfo* runtimeCallInfo)
239 {
240 EcmaVM* vm = runtimeCallInfo->GetVM();
241 auto* adapter = GetNodeAdapter(runtimeCallInfo);
242 CHECK_NULL_RETURN(adapter, panda::JSValueRef::Undefined(vm));
243 auto startArg = runtimeCallInfo->GetCallArgRef(1);
244 CHECK_NULL_RETURN(startArg->IsNumber(), panda::JSValueRef::Undefined(vm));
245 auto countArg = runtimeCallInfo->GetCallArgRef(2);
246 CHECK_NULL_RETURN(countArg->IsNumber(), panda::JSValueRef::Undefined(vm));
247 adapter->NotifyItemRemoved(startArg->Uint32Value(vm), countArg->Uint32Value(vm));
248 return panda::JSValueRef::Undefined(vm);
249 }
250
NotifyItemInserted(ArkUIRuntimeCallInfo * runtimeCallInfo)251 ArkUINativeModuleValue NodeAdapterBridge::NotifyItemInserted(ArkUIRuntimeCallInfo* runtimeCallInfo)
252 {
253 EcmaVM* vm = runtimeCallInfo->GetVM();
254 auto* adapter = GetNodeAdapter(runtimeCallInfo);
255 CHECK_NULL_RETURN(adapter, panda::JSValueRef::Undefined(vm));
256 auto startArg = runtimeCallInfo->GetCallArgRef(1);
257 CHECK_NULL_RETURN(startArg->IsNumber(), panda::JSValueRef::Undefined(vm));
258 auto countArg = runtimeCallInfo->GetCallArgRef(2);
259 CHECK_NULL_RETURN(countArg->IsNumber(), panda::JSValueRef::Undefined(vm));
260 adapter->NotifyItemInserted(startArg->Uint32Value(vm), countArg->Uint32Value(vm));
261 return panda::JSValueRef::Undefined(vm);
262 }
263
NotifyItemMoved(ArkUIRuntimeCallInfo * runtimeCallInfo)264 ArkUINativeModuleValue NodeAdapterBridge::NotifyItemMoved(ArkUIRuntimeCallInfo* runtimeCallInfo)
265 {
266 EcmaVM* vm = runtimeCallInfo->GetVM();
267 auto* adapter = GetNodeAdapter(runtimeCallInfo);
268 CHECK_NULL_RETURN(adapter, panda::JSValueRef::Undefined(vm));
269 auto fromArg = runtimeCallInfo->GetCallArgRef(1);
270 CHECK_NULL_RETURN(fromArg->IsNumber(), panda::JSValueRef::Undefined(vm));
271 auto toArg = runtimeCallInfo->GetCallArgRef(2);
272 CHECK_NULL_RETURN(toArg->IsNumber(), panda::JSValueRef::Undefined(vm));
273 adapter->NotifyItemMoved(fromArg->Uint32Value(vm), toArg->Uint32Value(vm));
274 return panda::JSValueRef::Undefined(vm);
275 }
276
GetAllItems(ArkUIRuntimeCallInfo * runtimeCallInfo)277 ArkUINativeModuleValue NodeAdapterBridge::GetAllItems(ArkUIRuntimeCallInfo* runtimeCallInfo)
278 {
279 EcmaVM* vm = runtimeCallInfo->GetVM();
280 auto* adapter = GetNodeAdapter(runtimeCallInfo);
281 CHECK_NULL_RETURN(adapter, panda::JSValueRef::Undefined(vm));
282 const auto& items = adapter->GetAllItems();
283 Local<panda::ArrayRef> array = panda::ArrayRef::New(vm, items.size());
284 for (uint32_t i = 0; i < items.size(); i++) {
285 panda::ArrayRef::SetValueAt(vm, array, i, FrameNodeBridge::MakeFrameNodeInfo(vm, items[i]));
286 }
287 return array;
288 }
289
AttachNodeAdapter(ArkUIRuntimeCallInfo * runtimeCallInfo)290 ArkUINativeModuleValue NodeAdapterBridge::AttachNodeAdapter(ArkUIRuntimeCallInfo* runtimeCallInfo)
291 {
292 EcmaVM* vm = runtimeCallInfo->GetVM();
293 auto* adapter = GetNodeAdapter(runtimeCallInfo);
294 CHECK_NULL_RETURN(adapter, panda::BooleanRef::New(vm, false));
295 Local<JSValueRef> nodeArg = runtimeCallInfo->GetCallArgRef(1);
296 CHECK_NULL_RETURN(!nodeArg.IsNull(), panda::BooleanRef::New(vm, false));
297 auto* frameNode = reinterpret_cast<FrameNode*>(nodeArg->ToNativePointer(vm)->Value());
298 CHECK_NULL_RETURN(frameNode, panda::BooleanRef::New(vm, false));
299 if (frameNode->GetFirstChild()) {
300 return panda::BooleanRef::New(vm, false);
301 }
302 auto* nativeNode = nodePtr(nodeArg->ToNativePointer(vm)->Value());
303 GetArkUIFullNodeAPI()->getNodeAdapterAPI()->attachHostNode(adapter->GetHandle(), nativeNode);
304 return panda::BooleanRef::New(vm, true);
305 }
306
DetachNodeAdapter(ArkUIRuntimeCallInfo * runtimeCallInfo)307 ArkUINativeModuleValue NodeAdapterBridge::DetachNodeAdapter(ArkUIRuntimeCallInfo* runtimeCallInfo)
308 {
309 EcmaVM* vm = runtimeCallInfo->GetVM();
310 Local<JSValueRef> nodeArg = runtimeCallInfo->GetCallArgRef(0);
311 CHECK_NULL_RETURN(!nodeArg.IsNull(), panda::JSValueRef::Undefined(vm));
312 auto* nativeNode = nodePtr(nodeArg->ToNativePointer(vm)->Value());
313 GetArkUIFullNodeAPI()->getNodeAdapterAPI()->detachHostNode(nativeNode);
314 GetArkUIFullNodeAPI()->getBasicAPI()->markDirty(nativeNode, ARKUI_DIRTY_FLAG_MEASURE_SELF_AND_PARENT);
315 return panda::JSValueRef::Undefined(vm);
316 }
317
318 } // namespace OHOS::Ace::NG
319