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