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