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 
16 #include "core/interfaces/native/node/node_adapter_impl.h"
17 
18 #include <cstdint>
19 #include <string>
20 #include <vector>
21 
22 #include "base/error/error_code.h"
23 #include "base/memory/ace_type.h"
24 #include "base/memory/referenced.h"
25 #include "base/utils/utils.h"
26 #include "core/components_ng/base/ui_node.h"
27 #include "core/components_ng/syntax/lazy_for_each_builder.h"
28 #include "core/components_ng/syntax/lazy_for_each_node.h"
29 #include "core/interfaces/arkoala/arkoala_api.h"
30 #include "core/pipeline/base/element_register.h"
31 
32 struct _ArkUINodeAdapter {
33     OHOS::Ace::RefPtr<OHOS::Ace::NG::NativeLazyForEachBuilder> builder;
34     OHOS::Ace::RefPtr<OHOS::Ace::NG::LazyForEachNode> node;
35 };
36 
37 namespace OHOS::Ace::NG {
38 
RegisterDataChangeListener(const RefPtr<V2::DataChangeListener> & listener)39 void NativeLazyForEachBuilder::RegisterDataChangeListener(const RefPtr<V2::DataChangeListener>& listener)
40 {
41     listener_ = RawPtr(listener);
42     if (!receiver_) {
43         return;
44     }
45     ArkUINodeAdapterEvent event { .type = ON_ATTACH_TO_NODE };
46     event.extraParam = reinterpret_cast<intptr_t>(userData_);
47     auto lazyForEachNode = DynamicCast<LazyForEachNode>(listener);
48     if (lazyForEachNode) {
49         auto parent = lazyForEachNode->GetParent();
50         if (parent) {
51             event.handle = reinterpret_cast<ArkUINodeHandle>(RawPtr(parent));
52         }
53     }
54     receiver_(&event);
55 }
56 
UnregisterDataChangeListener(V2::DataChangeListener * listener)57 void NativeLazyForEachBuilder::UnregisterDataChangeListener(V2::DataChangeListener* listener)
58 {
59     listener_ = nullptr;
60     if (!receiver_) {
61         return;
62     }
63     ArkUINodeAdapterEvent event { .type = ON_DETACH_FROM_NODE };
64     event.extraParam = reinterpret_cast<intptr_t>(userData_);
65     receiver_(&event);
66 }
67 
OnGetTotalCount()68 int32_t NativeLazyForEachBuilder::OnGetTotalCount()
69 {
70     return totalCount_;
71 }
72 
OnGetChildByIndex(int32_t index,std::unordered_map<std::string,LazyForEachCacheChild> & cachedItems)73 LazyForEachChild NativeLazyForEachBuilder::OnGetChildByIndex(
74     int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cachedItems)
75 {
76     LazyForEachChild child;
77     if (!receiver_) {
78         return child;
79     }
80     ArkUINodeAdapterEvent getIdevent { .index = index, .idSet = false, .type = ON_GET_NODE_ID, .nodeSet = false };
81     getIdevent.extraParam = reinterpret_cast<intptr_t>(userData_);
82     receiver_(&getIdevent);
83     std::string idStr;
84     if (getIdevent.idSet) {
85         idStr = std::to_string(getIdevent.id);
86     } else {
87         idStr = std::to_string(index);
88     }
89     child.first = idStr;
90     const auto& itemIter = cachedItems.find(idStr);
91     if (itemIter != cachedItems.end()) {
92         child.second = itemIter->second.second;
93         cachedItems.erase(itemIter);
94         // For not change C-API receiver
95         if (needUpdateEvent_) {
96             getIdevent.type = ON_UPDATE_NODE;
97             getIdevent.handle = reinterpret_cast<ArkUINodeHandle>(AceType::RawPtr(child.second));
98             if (!getIdevent.idSet) {
99                 getIdevent.id = index;
100             }
101             receiver_(&getIdevent);
102         }
103         FlushDirtyPropertyNodes(child.second);
104         return child;
105     }
106     ArkUINodeAdapterEvent getChildEvent {
107         .index = index, .id = getIdevent.id, .idSet = false, .type = ON_ADD_NODE_TO_ADAPTER, .nodeSet = false
108     };
109     getChildEvent.extraParam = reinterpret_cast<intptr_t>(userData_);
110     receiver_(&getChildEvent);
111     if (getChildEvent.nodeSet) {
112         child.second = Claim(reinterpret_cast<UINode*>(getChildEvent.handle));
113     }
114     FlushDirtyPropertyNodes(child.second);
115     return child;
116 }
117 
FlushDirtyPropertyNodes(const RefPtr<UINode> & node)118 void NativeLazyForEachBuilder::FlushDirtyPropertyNodes(const RefPtr<UINode>& node)
119 {
120     CHECK_NULL_VOID(node);
121     auto context = node->GetContext();
122     CHECK_NULL_VOID(context);
123     context->FlushDirtyPropertyNodes();
124 }
125 
OnItemDeleted(UINode * node,const std::string & key)126 void NativeLazyForEachBuilder::OnItemDeleted(UINode* node, const std::string& key)
127 {
128     if (!receiver_) {
129         return;
130     }
131     ArkUINodeAdapterEvent event {
132         .id = std::stoi(key), .idSet = false, .type = ON_REMOVE_NODE_FROM_ADAPTER, .nodeSet = false
133     };
134     event.extraParam = reinterpret_cast<intptr_t>(userData_);
135     event.handle = reinterpret_cast<ArkUINodeHandle>(node);
136     receiver_(&event);
137 }
138 
GetAllItem(ArkUINodeHandle ** items,ArkUI_Uint32 * size)139 ArkUI_Int32 NativeLazyForEachBuilder::GetAllItem(ArkUINodeHandle** items, ArkUI_Uint32* size)
140 {
141     std::vector<UINode*> childList;
142     GetAllItems(childList);
143     *size = childList.size();
144     *items = new ArkUINodeHandle[*size];
145     for (uint32_t i = 0; i < *size; i++) {
146         (*items)[i] = reinterpret_cast<ArkUINodeHandle>(childList[i]);
147     }
148     return ERROR_CODE_NO_ERROR;
149 }
150 
UINodeAdapter(ArkUINodeAdapterHandle handle)151 UINodeAdapter::UINodeAdapter(ArkUINodeAdapterHandle handle) : handle_(handle)
152 {
153     CHECK_NULL_VOID(handle_);
154     CHECK_NULL_VOID(handle_->builder);
155     handle_->builder->SetUserData(this);
156     handle_->builder->SetReceiver([](ArkUINodeAdapterEvent* event) {
157         CHECK_NULL_VOID(event);
158         auto adapter = reinterpret_cast<UINodeAdapter*>(event->extraParam);
159         if (adapter != nullptr) {
160             adapter->OnEventReceived(event);
161         }
162     });
163     handle_->builder->SetNeedUpdateEvent(true);
164 }
165 
~UINodeAdapter()166 UINodeAdapter::~UINodeAdapter()
167 {
168     if (handle_ != nullptr) {
169         delete handle_;
170         handle_ = nullptr;
171     }
172 }
173 
OnEventReceived(ArkUINodeAdapterEvent * event)174 void UINodeAdapter::OnEventReceived(ArkUINodeAdapterEvent* event)
175 {
176     switch (event->type) {
177         case ON_ATTACH_TO_NODE:
178             if (attachToNodeFunc_) {
179                 attachToNodeFunc_(event->handle);
180             }
181             break;
182         case ON_DETACH_FROM_NODE:
183             if (detachFromNodeFunc_) {
184                 detachFromNodeFunc_();
185             }
186             break;
187         case ON_GET_NODE_ID:
188             if (getChildIdFunc_) {
189                 auto id = getChildIdFunc_(event->index);
190                 event->idSet = true;
191                 event->id = id;
192             }
193             break;
194         case ON_ADD_NODE_TO_ADAPTER:
195             if (createNewChildFunc_) {
196                 auto handle = createNewChildFunc_(event->index);
197                 event->nodeSet = true;
198                 event->handle = handle;
199             }
200             break;
201         case ON_REMOVE_NODE_FROM_ADAPTER:
202             if (disposeChildFunc_) {
203                 disposeChildFunc_(event->handle, event->id);
204             }
205             break;
206         case ON_UPDATE_NODE:
207             if (updateChildFunc_) {
208                 updateChildFunc_(event->handle, event->id);
209             }
210             break;
211         default:
212             break;
213     }
214 }
215 
SetTotalNodeCount(uint32_t count)216 void UINodeAdapter::SetTotalNodeCount(uint32_t count)
217 {
218     CHECK_NULL_VOID(handle_);
219     CHECK_NULL_VOID(handle_->builder);
220     handle_->builder->SetNodeTotalCount(count);
221 }
222 
GetTotalNodeCount() const223 uint32_t UINodeAdapter::GetTotalNodeCount() const
224 {
225     CHECK_NULL_RETURN(handle_, 0);
226     CHECK_NULL_RETURN(handle_->builder, 0);
227     return handle_->builder->GetNodeTotalCount();
228 }
229 
NotifyItemReloaded()230 void UINodeAdapter::NotifyItemReloaded()
231 {
232     CHECK_NULL_VOID(handle_);
233     CHECK_NULL_VOID(handle_->builder);
234     handle_->builder->NotifyItemReloaded();
235 }
236 
NotifyItemChanged(uint32_t start,uint32_t count)237 void UINodeAdapter::NotifyItemChanged(uint32_t start, uint32_t count)
238 {
239     CHECK_NULL_VOID(handle_);
240     CHECK_NULL_VOID(handle_->builder);
241     handle_->builder->NotifyItemChanged(start, count);
242 }
243 
NotifyItemInserted(uint32_t start,uint32_t count)244 void UINodeAdapter::NotifyItemInserted(uint32_t start, uint32_t count)
245 {
246     CHECK_NULL_VOID(handle_);
247     CHECK_NULL_VOID(handle_->builder);
248     handle_->builder->NotifyItemInserted(start, count);
249 }
250 
NotifyItemMoved(uint32_t from,uint32_t to)251 void UINodeAdapter::NotifyItemMoved(uint32_t from, uint32_t to)
252 {
253     CHECK_NULL_VOID(handle_);
254     CHECK_NULL_VOID(handle_->builder);
255     handle_->builder->NotifyItemMoved(from, to);
256 }
257 
NotifyItemRemoved(uint32_t start,uint32_t count)258 void UINodeAdapter::NotifyItemRemoved(uint32_t start, uint32_t count)
259 {
260     CHECK_NULL_VOID(handle_);
261     CHECK_NULL_VOID(handle_->builder);
262     handle_->builder->NotifyItemRemoved(start, count);
263 }
264 
GetAllItems()265 std::vector<ArkUINodeHandle> UINodeAdapter::GetAllItems()
266 {
267     std::vector<ArkUINodeHandle> items;
268     CHECK_NULL_RETURN(handle_, items);
269     CHECK_NULL_RETURN(handle_->builder, items);
270 
271     ArkUINodeHandle* itemArray = nullptr;
272     uint32_t size = 0;
273     handle_->builder->GetAllItem(&itemArray, &size);
274     for (uint32_t i = 0; i < size; i++) {
275         items.push_back(itemArray[i]);
276     }
277     if (itemArray != nullptr) {
278         delete[] itemArray;
279     }
280     return items;
281 }
282 
283 } // namespace OHOS::Ace::NG
284 
285 namespace OHOS::Ace::NodeAdapter {
286 namespace {
287 
Create()288 ArkUINodeAdapterHandle Create()
289 {
290     auto* adapter = new _ArkUINodeAdapter { .builder = AceType::MakeRefPtr<NG::NativeLazyForEachBuilder>() };
291     adapter->builder->SetHostHandle(adapter);
292     return adapter;
293 }
294 
Dispose(ArkUINodeAdapterHandle handle)295 void Dispose(ArkUINodeAdapterHandle handle)
296 {
297     if (!handle) {
298         return;
299     }
300     if (handle->node) {
301         const auto& parent = handle->node->GetParent();
302         if (parent) {
303             parent->RemoveChild(handle->node);
304         }
305     }
306     if (handle->builder) {
307         handle->builder->SetHostHandle(nullptr);
308     }
309     delete handle;
310 }
311 
SetTotalNodeCount(ArkUINodeAdapterHandle handle,ArkUI_Uint32 size)312 ArkUI_Int32 SetTotalNodeCount(ArkUINodeAdapterHandle handle, ArkUI_Uint32 size)
313 {
314     if (handle) {
315         handle->builder->SetNodeTotalCount(size);
316         return ERROR_CODE_NO_ERROR;
317     }
318     return ERROR_CODE_PARAM_INVALID;
319 }
320 
GetTotalNodeCount(ArkUINodeAdapterHandle handle)321 ArkUI_Uint32 GetTotalNodeCount(ArkUINodeAdapterHandle handle)
322 {
323     if (handle) {
324         return handle->builder->GetNodeTotalCount();
325     }
326     return 0;
327 }
328 
RegisterEventReceiver(ArkUINodeAdapterHandle handle,void * userData,void (* receiver)(ArkUINodeAdapterEvent * event))329 ArkUI_Int32 RegisterEventReceiver(
330     ArkUINodeAdapterHandle handle, void* userData, void (*receiver)(ArkUINodeAdapterEvent* event))
331 {
332     if (!handle) {
333         return ERROR_CODE_PARAM_INVALID;
334     }
335     handle->builder->SetUserData(userData);
336     handle->builder->SetReceiver(receiver);
337     return ERROR_CODE_NO_ERROR;
338 }
339 
UnregisterEventReceiver(ArkUINodeAdapterHandle handle)340 void UnregisterEventReceiver(ArkUINodeAdapterHandle handle)
341 {
342     if (!handle) {
343         return;
344     }
345     handle->builder->SetUserData(nullptr);
346     handle->builder->SetReceiver(nullptr);
347 }
348 
NotifyItemReloaded(ArkUINodeAdapterHandle handle)349 ArkUI_Int32 NotifyItemReloaded(ArkUINodeAdapterHandle handle)
350 {
351     if (!handle) {
352         return ERROR_CODE_PARAM_INVALID;
353     }
354     return handle->builder->NotifyItemReloaded();
355 }
356 
NotifyItemChanged(ArkUINodeAdapterHandle handle,ArkUI_Uint32 startPosition,ArkUI_Uint32 itemCount)357 ArkUI_Int32 NotifyItemChanged(ArkUINodeAdapterHandle handle, ArkUI_Uint32 startPosition, ArkUI_Uint32 itemCount)
358 {
359     if (!handle) {
360         return ERROR_CODE_PARAM_INVALID;
361     }
362     return handle->builder->NotifyItemChanged(startPosition, itemCount);
363 }
364 
NotifyItemRemoved(ArkUINodeAdapterHandle handle,ArkUI_Uint32 startPosition,ArkUI_Uint32 itemCount)365 ArkUI_Int32 NotifyItemRemoved(ArkUINodeAdapterHandle handle, ArkUI_Uint32 startPosition, ArkUI_Uint32 itemCount)
366 {
367     if (!handle) {
368         return ERROR_CODE_PARAM_INVALID;
369     }
370     return handle->builder->NotifyItemRemoved(startPosition, itemCount);
371 }
372 
NotifyItemInserted(ArkUINodeAdapterHandle handle,ArkUI_Uint32 startPosition,ArkUI_Uint32 itemCount)373 ArkUI_Int32 NotifyItemInserted(ArkUINodeAdapterHandle handle, ArkUI_Uint32 startPosition, ArkUI_Uint32 itemCount)
374 {
375     if (!handle) {
376         return ERROR_CODE_PARAM_INVALID;
377     }
378     return handle->builder->NotifyItemInserted(startPosition, itemCount);
379 }
380 
NotifyItemMoved(ArkUINodeAdapterHandle handle,ArkUI_Uint32 from,ArkUI_Uint32 to)381 ArkUI_Int32 NotifyItemMoved(ArkUINodeAdapterHandle handle, ArkUI_Uint32 from, ArkUI_Uint32 to)
382 {
383     if (!handle) {
384         return ERROR_CODE_PARAM_INVALID;
385     }
386     return handle->builder->NotifyItemMoved(from, to);
387 }
388 
GetAllItem(ArkUINodeAdapterHandle handle,ArkUINodeHandle ** items,ArkUI_Uint32 * size)389 ArkUI_Int32 GetAllItem(ArkUINodeAdapterHandle handle, ArkUINodeHandle** items, ArkUI_Uint32* size)
390 {
391     if (!handle) {
392         return ERROR_CODE_PARAM_INVALID;
393     }
394     return handle->builder->GetAllItem(items, size);
395 }
396 
AttachHostNode(ArkUINodeAdapterHandle handle,ArkUINodeHandle host)397 void AttachHostNode(ArkUINodeAdapterHandle handle, ArkUINodeHandle host)
398 {
399     CHECK_NULL_VOID(handle);
400     CHECK_NULL_VOID(host);
401     if (!handle->node) {
402         handle->node =
403             NG::LazyForEachNode::CreateLazyForEachNode(ElementRegister::GetInstance()->MakeUniqueId(), handle->builder);
404     }
405     auto* uiNode = reinterpret_cast<NG::UINode*>(host);
406     uiNode->AddChild(handle->node);
407 }
408 
DetachHostNode(ArkUINodeHandle host)409 void DetachHostNode(ArkUINodeHandle host)
410 {
411     CHECK_NULL_VOID(host);
412     auto* uiNode = reinterpret_cast<NG::UINode*>(host);
413     const auto& child = AceType::DynamicCast<NG::LazyForEachNode>(uiNode->GetChildAtIndex(0));
414     CHECK_NULL_VOID(child);
415     uiNode->RemoveChild(child);
416     const auto& builder = AceType::DynamicCast<NG::NativeLazyForEachBuilder>(child->GetBuilder());
417     CHECK_NULL_VOID(builder);
418     auto handle = builder->GetHostHandle();
419     CHECK_NULL_VOID(handle);
420     handle->node = nullptr;
421 }
422 
GetNodeAdapter(ArkUINodeHandle host)423 ArkUINodeAdapterHandle GetNodeAdapter(ArkUINodeHandle host)
424 {
425     CHECK_NULL_RETURN(host, nullptr);
426     auto* uiNode = reinterpret_cast<NG::UINode*>(host);
427     const auto& child = AceType::DynamicCast<NG::LazyForEachNode>(uiNode->GetChildAtIndex(0));
428     CHECK_NULL_RETURN(child, nullptr);
429     const auto& builder = AceType::DynamicCast<NG::NativeLazyForEachBuilder>(child->GetBuilder());
430     CHECK_NULL_RETURN(builder, nullptr);
431     return builder->GetHostHandle();
432 }
433 
434 } // namespace
435 
GetNodeAdapterAPI()436 const ArkUINodeAdapterAPI* GetNodeAdapterAPI()
437 {
438     static const ArkUINodeAdapterAPI impl { Create, Dispose, SetTotalNodeCount, GetTotalNodeCount,
439         RegisterEventReceiver, UnregisterEventReceiver, NotifyItemReloaded, NotifyItemChanged, NotifyItemRemoved,
440         NotifyItemInserted, NotifyItemMoved, GetAllItem, AttachHostNode, DetachHostNode, GetNodeAdapter };
441     return &impl;
442 }
443 
GetCJUINodeAdapterAPI()444 const CJUINodeAdapterAPI* GetCJUINodeAdapterAPI()
445 {
446     static const CJUINodeAdapterAPI impl { Create, Dispose, SetTotalNodeCount, GetTotalNodeCount,
447         RegisterEventReceiver, UnregisterEventReceiver, NotifyItemReloaded, NotifyItemChanged, NotifyItemRemoved,
448         NotifyItemInserted, NotifyItemMoved, GetAllItem, AttachHostNode, DetachHostNode, GetNodeAdapter };
449     return &impl;
450 }
451 
452 } // namespace OHOS::Ace::NodeAdapter
453