1/*
2 * Copyright (c) 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 "node_model.h"
17
18
19#include "event_converter.h"
20#include "interfaces/native/event/ui_input_event_impl.h"
21#include "node_extened.h"
22#include "style_modifier.h"
23
24#include "base/error/error_code.h"
25#include "base/utils/utils.h"
26
27namespace OHOS::Ace::NodeModel {
28namespace {
29#if defined(WINDOWS_PLATFORM)
30#include <windows.h>
31// Here we need to find module where GetArkUINodeAPI()
32// function is implemented.
33void* FindModule()
34{
35    // To find from main exe
36    HMODULE result = nullptr;
37    const char libname[] = "libace_compatible.dll";
38    GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, libname, &result);
39    if (result) {
40        return result;
41    }
42    TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "Cannot find module!");
43    return nullptr;
44}
45void* FindFunction(void* library, const char* name)
46{
47    return (void*)GetProcAddress(reinterpret_cast<HMODULE>(library), name);
48}
49#else
50#include <dlfcn.h>
51void* FindModule()
52{
53    const char libname[] = "libace_compatible.z.so";
54    void* result = dlopen(libname, RTLD_LAZY | RTLD_LOCAL);
55    if (result) {
56        return result;
57    }
58    TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "Cannot load libace: %{public}s", dlerror());
59    return nullptr;
60}
61
62void* FindFunction(void* library, const char* name)
63{
64    return dlsym(library, name);
65}
66#endif
67
68ArkUIFullNodeAPI* impl = nullptr;
69
70bool InitialFullNodeImpl(int version)
71{
72    if (!impl) {
73        typedef ArkUIAnyAPI* (*GetAPI_t)(int);
74        GetAPI_t getAPI = nullptr;
75        void* module = FindModule();
76        if (module == nullptr) {
77            TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "fail to get module");
78            return false;
79        }
80        // Note, that RTLD_DEFAULT is ((void *) 0).
81        getAPI = reinterpret_cast<GetAPI_t>(FindFunction(module, "GetArkUIAnyFullNodeAPI"));
82        if (!getAPI) {
83            TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "Cannot find GetArkUIAnyFullNodeAPI()");
84            return false;
85        }
86
87        impl = reinterpret_cast<ArkUIFullNodeAPI*>((*getAPI)(version));
88        if (!impl) {
89            TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "getAPI() returned null");
90            return false;
91        }
92
93        if (impl->version != version) {
94            TAG_LOGE(AceLogTag::ACE_NATIVE_NODE,
95                "API version mismatch: expected %{public}d, but get the version %{public}d", version, impl->version);
96            return false;
97        }
98    }
99
100    impl->getBasicAPI()->registerNodeAsyncEventReceiver(OHOS::Ace::NodeModel::HandleInnerEvent);
101    impl->getExtendedAPI()->registerCustomNodeAsyncEventReceiver(OHOS::Ace::NodeModel::HandleInnerCustomEvent);
102    return true;
103}
104} // namespace
105
106ArkUIFullNodeAPI* GetFullImpl()
107{
108    return impl;
109}
110
111bool InitialFullImpl()
112{
113    return InitialFullNodeImpl(ARKUI_NODE_API_VERSION);
114}
115
116struct InnerEventExtraParam {
117    int32_t targetId;
118    ArkUI_NodeHandle nodePtr;
119    void* userData;
120};
121
122struct ExtraData {
123    std::unordered_map<int64_t, InnerEventExtraParam*> eventMap;
124};
125
126std::set<ArkUI_NodeHandle> g_nodeSet;
127
128bool IsValidArkUINode(ArkUI_NodeHandle nodePtr)
129{
130    if (!nodePtr || g_nodeSet.count(nodePtr) == 0) {
131        return false;
132    }
133    return true;
134}
135
136ArkUI_NodeHandle CreateNode(ArkUI_NodeType type)
137{
138    static const ArkUINodeType nodes[] = { ARKUI_CUSTOM, ARKUI_TEXT, ARKUI_SPAN, ARKUI_IMAGE_SPAN, ARKUI_IMAGE,
139        ARKUI_TOGGLE, ARKUI_LOADING_PROGRESS, ARKUI_TEXT_INPUT, ARKUI_TEXTAREA, ARKUI_BUTTON, ARKUI_PROGRESS,
140        ARKUI_CHECKBOX, ARKUI_XCOMPONENT, ARKUI_DATE_PICKER, ARKUI_TIME_PICKER, ARKUI_TEXT_PICKER,
141        ARKUI_CALENDAR_PICKER, ARKUI_SLIDER, ARKUI_RADIO, ARKUI_IMAGE_ANIMATOR, ARKUI_STACK, ARKUI_SWIPER,
142        ARKUI_SCROLL, ARKUI_LIST, ARKUI_LIST_ITEM, ARKUI_LIST_ITEM_GROUP, ARKUI_COLUMN, ARKUI_ROW, ARKUI_FLEX,
143        ARKUI_REFRESH, ARKUI_WATER_FLOW, ARKUI_FLOW_ITEM, ARKUI_RELATIVE_CONTAINER, ARKUI_GRID, ARKUI_GRID_ITEM,
144        ARKUI_CUSTOM_SPAN };
145    // already check in entry point.
146    uint32_t nodeType = type < MAX_NODE_SCOPE_NUM ? type : (type - MAX_NODE_SCOPE_NUM + BASIC_COMPONENT_NUM);
147    auto* impl = GetFullImpl();
148    if (nodeType >= sizeof(nodes) / sizeof(ArkUINodeType)) {
149        TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "node type: %{public}d NOT IMPLEMENT", type);
150        return nullptr;
151    }
152
153    ArkUI_Int32 id = ARKUI_AUTO_GENERATE_NODE_ID;
154    auto* uiNode = impl->getBasicAPI()->createNode(nodes[nodeType], id, ARKUI_NODE_FLAG_C);
155    if (!uiNode) {
156        TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "node type: %{public}d can not find in full impl", type);
157        return nullptr;
158    }
159    impl->getBasicAPI()->markDirty(uiNode, ARKUI_DIRTY_FLAG_ATTRIBUTE_DIFF);
160    ArkUI_Node* arkUINode = new ArkUI_Node({ type, uiNode });
161    impl->getExtendedAPI()->setAttachNodePtr(uiNode, reinterpret_cast<void*>(arkUINode));
162    g_nodeSet.emplace(arkUINode);
163    return arkUINode;
164}
165
166void DisposeNativeSource(ArkUI_NodeHandle nativePtr)
167{
168    CHECK_NULL_VOID(nativePtr);
169    if (nativePtr->customEventListeners) {
170        auto eventListenersSet = reinterpret_cast<std::set<void (*)(ArkUI_NodeCustomEvent*)>*>(
171        nativePtr->customEventListeners);
172        if (eventListenersSet) {
173            eventListenersSet->clear();
174        }
175        delete eventListenersSet;
176        nativePtr->customEventListeners = nullptr;
177    }
178    if (nativePtr->eventListeners) {
179        auto eventListenersSet = reinterpret_cast<std::set<void (*)(ArkUI_NodeEvent*)>*>(
180        nativePtr->eventListeners);
181        if (eventListenersSet) {
182            eventListenersSet->clear();
183        }
184        delete eventListenersSet;
185        nativePtr->eventListeners = nullptr;
186    }
187    if (nativePtr->areaChangeRadio) {
188        delete[] nativePtr->areaChangeRadio->value;
189        delete nativePtr->areaChangeRadio;
190        nativePtr->areaChangeRadio = nullptr;
191    }
192}
193
194void DisposeNode(ArkUI_NodeHandle nativePtr)
195{
196    CHECK_NULL_VOID(nativePtr);
197    // already check in entry point.
198    auto* impl = GetFullImpl();
199    impl->getBasicAPI()->disposeNode(nativePtr->uiNodeHandle);
200    DisposeNativeSource(nativePtr);
201    g_nodeSet.erase(nativePtr);
202    delete nativePtr;
203    nativePtr = nullptr;
204}
205
206int32_t AddChild(ArkUI_NodeHandle parentNode, ArkUI_NodeHandle childNode)
207{
208    CHECK_NULL_RETURN(parentNode, ERROR_CODE_PARAM_INVALID);
209    CHECK_NULL_RETURN(childNode, ERROR_CODE_PARAM_INVALID);
210    if (parentNode->type == -1) {
211        return ERROR_CODE_NATIVE_IMPL_BUILDER_NODE_ERROR;
212    }
213    auto* impl = GetFullImpl();
214    // already check in entry point.
215    impl->getBasicAPI()->addChild(parentNode->uiNodeHandle, childNode->uiNodeHandle);
216    impl->getBasicAPI()->markDirty(parentNode->uiNodeHandle, ARKUI_DIRTY_FLAG_MEASURE_BY_CHILD_REQUEST);
217    return ERROR_CODE_NO_ERROR;
218}
219
220int32_t RemoveChild(ArkUI_NodeHandle parentNode, ArkUI_NodeHandle childNode)
221{
222    CHECK_NULL_RETURN(parentNode, ERROR_CODE_PARAM_INVALID);
223    CHECK_NULL_RETURN(childNode, ERROR_CODE_PARAM_INVALID);
224    // already check in entry point.
225    if (parentNode->type == -1) {
226        return ERROR_CODE_NATIVE_IMPL_BUILDER_NODE_ERROR;
227    }
228    auto* impl = GetFullImpl();
229    impl->getBasicAPI()->removeChild(parentNode->uiNodeHandle, childNode->uiNodeHandle);
230    impl->getBasicAPI()->markDirty(parentNode->uiNodeHandle, ARKUI_DIRTY_FLAG_MEASURE_BY_CHILD_REQUEST);
231    return ERROR_CODE_NO_ERROR;
232}
233
234int32_t InsertChildAfter(ArkUI_NodeHandle parentNode, ArkUI_NodeHandle childNode, ArkUI_NodeHandle siblingNode)
235{
236    CHECK_NULL_RETURN(parentNode, ERROR_CODE_PARAM_INVALID);
237    CHECK_NULL_RETURN(childNode, ERROR_CODE_PARAM_INVALID);
238    // already check in entry point.
239    if (parentNode->type == -1) {
240        return ERROR_CODE_NATIVE_IMPL_BUILDER_NODE_ERROR;
241    }
242    auto* impl = GetFullImpl();
243    impl->getBasicAPI()->insertChildAfter(
244        parentNode->uiNodeHandle, childNode->uiNodeHandle, siblingNode ? siblingNode->uiNodeHandle : nullptr);
245    impl->getBasicAPI()->markDirty(parentNode->uiNodeHandle, ARKUI_DIRTY_FLAG_MEASURE_BY_CHILD_REQUEST);
246    return ERROR_CODE_NO_ERROR;
247}
248
249int32_t InsertChildBefore(ArkUI_NodeHandle parentNode, ArkUI_NodeHandle childNode, ArkUI_NodeHandle siblingNode)
250{
251    CHECK_NULL_RETURN(parentNode, ERROR_CODE_PARAM_INVALID);
252    CHECK_NULL_RETURN(childNode, ERROR_CODE_PARAM_INVALID);
253    // already check in entry point.
254    if (parentNode->type == -1) {
255        return ERROR_CODE_NATIVE_IMPL_BUILDER_NODE_ERROR;
256    }
257    auto* impl = GetFullImpl();
258    impl->getBasicAPI()->insertChildBefore(
259        parentNode->uiNodeHandle, childNode->uiNodeHandle, siblingNode ? siblingNode->uiNodeHandle : nullptr);
260    impl->getBasicAPI()->markDirty(parentNode->uiNodeHandle, ARKUI_DIRTY_FLAG_MEASURE_BY_CHILD_REQUEST);
261    return ERROR_CODE_NO_ERROR;
262}
263
264int32_t InsertChildAt(ArkUI_NodeHandle parentNode, ArkUI_NodeHandle childNode, int32_t position)
265{
266    CHECK_NULL_RETURN(parentNode, ERROR_CODE_PARAM_INVALID);
267    CHECK_NULL_RETURN(childNode, ERROR_CODE_PARAM_INVALID);
268    // already check in entry point.
269    if (parentNode->type == -1) {
270        return ERROR_CODE_NATIVE_IMPL_BUILDER_NODE_ERROR;
271    }
272    auto* impl = GetFullImpl();
273    impl->getBasicAPI()->insertChildAt(parentNode->uiNodeHandle, childNode->uiNodeHandle, position);
274    impl->getBasicAPI()->markDirty(parentNode->uiNodeHandle, ARKUI_DIRTY_FLAG_MEASURE_BY_CHILD_REQUEST);
275    return ERROR_CODE_NO_ERROR;
276}
277
278void SetAttribute(ArkUI_NodeHandle node, ArkUI_NodeAttributeType attribute, const char* value)
279{
280    SetNodeAttribute(node, attribute, value);
281}
282
283int32_t SetAttribute(ArkUI_NodeHandle node, ArkUI_NodeAttributeType attribute, const ArkUI_AttributeItem* value)
284{
285    if (node == nullptr) {
286        return ERROR_CODE_PARAM_INVALID;
287    }
288    if (node->type == -1 && attribute != NODE_LAYOUT_RECT) {
289        return ERROR_CODE_NATIVE_IMPL_BUILDER_NODE_ERROR;
290    }
291    return SetNodeAttribute(node, attribute, value);
292}
293
294int32_t ResetAttribute(ArkUI_NodeHandle node, ArkUI_NodeAttributeType attribute)
295{
296    if (node == nullptr) {
297        return ERROR_CODE_PARAM_INVALID;
298    }
299    if (node->type == -1 && attribute != NODE_LAYOUT_RECT) {
300        return ERROR_CODE_NATIVE_IMPL_BUILDER_NODE_ERROR;
301    }
302    return ResetNodeAttribute(node, attribute);
303}
304
305const ArkUI_AttributeItem* GetAttribute(ArkUI_NodeHandle node, ArkUI_NodeAttributeType attribute)
306{
307    if (node == nullptr) {
308        return nullptr;
309    }
310    return GetNodeAttribute(node, attribute);
311}
312
313int32_t RegisterNodeEvent(ArkUI_NodeHandle nodePtr, ArkUI_NodeEventType eventType, int32_t targetId)
314{
315    return RegisterNodeEvent(nodePtr, eventType, targetId, nullptr);
316}
317
318int32_t RegisterNodeEvent(ArkUI_NodeHandle nodePtr, ArkUI_NodeEventType eventType, int32_t targetId, void* userData)
319{
320    if (nodePtr == nullptr) {
321        return ERROR_CODE_PARAM_INVALID;
322    }
323    auto originEventType = ConvertOriginEventType(eventType, nodePtr->type);
324    if (originEventType < 0) {
325        TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "event is not supported %{public}d", eventType);
326        return ERROR_CODE_NATIVE_IMPL_TYPE_NOT_SUPPORTED;
327    }
328    // already check in entry point.
329    if (nodePtr->type == -1) {
330        return ERROR_CODE_NATIVE_IMPL_BUILDER_NODE_ERROR;
331    }
332    auto* impl = GetFullImpl();
333    auto* extraParam = new InnerEventExtraParam({ targetId, nodePtr, userData });
334    if (nodePtr->extraData) {
335        auto* extraData = reinterpret_cast<ExtraData*>(nodePtr->extraData);
336        auto result = extraData->eventMap.try_emplace(eventType, extraParam);
337        if (!result.second) {
338            result.first->second->targetId = targetId;
339            result.first->second->userData = userData;
340            delete extraParam;
341        }
342    } else {
343        nodePtr->extraData = new ExtraData();
344        auto* extraData = reinterpret_cast<ExtraData*>(nodePtr->extraData);
345        extraData->eventMap[eventType] = extraParam;
346    }
347    if (eventType == NODE_EVENT_ON_VISIBLE_AREA_CHANGE) {
348        ArkUI_AttributeItem* radio = nodePtr->areaChangeRadio;
349        radio = radio ? radio : static_cast<ArkUI_AttributeItem*>(userData);
350        if (!radio) {
351            return ERROR_CODE_PARAM_INVALID;
352        }
353        ArkUI_Int32 radioLength = radio->size;
354        if (radioLength <= 0) {
355            return ERROR_CODE_PARAM_INVALID;
356        }
357        ArkUI_Float32 radioList[radioLength];
358        for (int i = 0; i < radioLength; ++i) {
359            if (LessNotEqual(radio->value[i].f32, 0.0f) || GreatNotEqual(radio->value[i].f32, 1.0f)) {
360                return ERROR_CODE_PARAM_INVALID;
361            }
362            radioList[i] = radio->value[i].f32;
363        }
364        impl->getNodeModifiers()->getCommonModifier()->setOnVisibleAreaChange(
365            nodePtr->uiNodeHandle, reinterpret_cast<int64_t>(nodePtr), radioList, radioLength);
366    } else {
367        impl->getBasicAPI()->registerNodeAsyncEvent(
368            nodePtr->uiNodeHandle, static_cast<ArkUIEventSubKind>(originEventType), reinterpret_cast<int64_t>(nodePtr));
369    }
370    return ERROR_CODE_NO_ERROR;
371}
372
373void UnregisterNodeEvent(ArkUI_NodeHandle nodePtr, ArkUI_NodeEventType eventType)
374{
375    if (nodePtr == nullptr) {
376        return;
377    }
378    if (!nodePtr->extraData) {
379        return;
380    }
381    if (nodePtr->type == -1) {
382        return;
383    }
384    auto* extraData = reinterpret_cast<ExtraData*>(nodePtr->extraData);
385    auto& eventMap = extraData->eventMap;
386    auto innerEventExtraParam = eventMap.find(eventType);
387    if (innerEventExtraParam == eventMap.end()) {
388        return;
389    }
390    delete innerEventExtraParam->second;
391    eventMap.erase(innerEventExtraParam);
392    if (eventMap.empty()) {
393        delete extraData;
394        nodePtr->extraData = nullptr;
395    }
396    auto originEventType = ConvertOriginEventType(eventType, nodePtr->type);
397    if (originEventType < 0) {
398        return;
399    }
400    impl->getBasicAPI()->unRegisterNodeAsyncEvent(
401        nodePtr->uiNodeHandle, static_cast<ArkUIEventSubKind>(originEventType));
402}
403
404void (*g_compatibleEventReceiver)(ArkUI_CompatibleNodeEvent* event) = nullptr;
405void RegisterOnEvent(void (*eventReceiver)(ArkUI_CompatibleNodeEvent* event))
406{
407    g_compatibleEventReceiver = eventReceiver;
408}
409
410void (*g_eventReceiver)(ArkUI_NodeEvent* event) = nullptr;
411void RegisterOnEvent(void (*eventReceiver)(ArkUI_NodeEvent* event))
412{
413    g_eventReceiver = eventReceiver;
414}
415
416void UnregisterOnEvent()
417{
418    g_eventReceiver = nullptr;
419}
420
421void HandleInnerNodeEvent(ArkUINodeEvent* innerEvent)
422{
423    if (!innerEvent) {
424        return;
425    }
426    auto nativeNodeEventType = GetNativeNodeEventType(innerEvent);
427    if (nativeNodeEventType == -1) {
428        return;
429    }
430    auto eventType = static_cast<ArkUI_NodeEventType>(nativeNodeEventType);
431    auto* nodePtr = reinterpret_cast<ArkUI_NodeHandle>(innerEvent->extraParam);
432    auto extraData = reinterpret_cast<ExtraData*>(nodePtr->extraData);
433    if (!extraData) {
434        return;
435    }
436    auto innerEventExtraParam = extraData->eventMap.find(eventType);
437    if (innerEventExtraParam == extraData->eventMap.end()) {
438        return;
439    }
440    ArkUI_NodeEvent event;
441    event.node = nodePtr;
442    event.eventId = innerEventExtraParam->second->targetId;
443    event.userData = innerEventExtraParam->second->userData;
444    if (!g_eventReceiver && !g_compatibleEventReceiver && (!(event.node) ||
445        (event.node && !(event.node->eventListeners)))) {
446        TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "event receiver is not register");
447        return;
448    }
449    if ((g_eventReceiver || (event.node && event.node->eventListeners))  && ConvertEvent(innerEvent, &event)) {
450        event.targetId = innerEvent->nodeId;
451        ArkUI_UIInputEvent uiEvent;
452        if (eventType == NODE_TOUCH_EVENT || eventType == NODE_ON_TOUCH_INTERCEPT) {
453            uiEvent.inputType = ARKUI_UIINPUTEVENT_TYPE_TOUCH;
454            uiEvent.eventTypeId = C_TOUCH_EVENT_ID;
455            uiEvent.inputEvent = &(innerEvent->touchEvent);
456            event.origin = &uiEvent;
457        } else if (eventType == NODE_ON_MOUSE) {
458            uiEvent.inputType = ARKUI_UIINPUTEVENT_TYPE_MOUSE;
459            uiEvent.eventTypeId = C_MOUSE_EVENT_ID;
460            uiEvent.inputEvent = &(innerEvent->mouseEvent);
461            event.origin = &uiEvent;
462        } else {
463            event.origin = innerEvent;
464        }
465        HandleNodeEvent(&event);
466    }
467    if (g_compatibleEventReceiver) {
468        ArkUI_CompatibleNodeEvent event;
469        event.node = nodePtr;
470        event.eventId = innerEventExtraParam->second->targetId;
471        if (ConvertEvent(innerEvent, &event)) {
472            g_compatibleEventReceiver(&event);
473            ConvertEventResult(&event, innerEvent);
474        }
475    }
476}
477
478int32_t GetNativeNodeEventType(ArkUINodeEvent* innerEvent)
479{
480    int32_t invalidType = -1;
481    auto* nodePtr = reinterpret_cast<ArkUI_NodeHandle>(innerEvent->extraParam);
482    if (!nodePtr || g_nodeSet.count(nodePtr) == 0) {
483        return invalidType;
484    }
485    if (!nodePtr->extraData) {
486        return invalidType;
487    }
488    auto extraData = reinterpret_cast<ExtraData*>(nodePtr->extraData);
489    ArkUIEventSubKind subKind = static_cast<ArkUIEventSubKind>(-1);
490    switch (innerEvent->kind) {
491        case COMPONENT_ASYNC_EVENT:
492            subKind = static_cast<ArkUIEventSubKind>(innerEvent->componentAsyncEvent.subKind);
493            break;
494        case TEXT_INPUT:
495            subKind = static_cast<ArkUIEventSubKind>(innerEvent->textInputEvent.subKind);
496            break;
497        case TOUCH_EVENT:
498            subKind = static_cast<ArkUIEventSubKind>(innerEvent->touchEvent.subKind);
499            break;
500        case MOUSE_INPUT_EVENT:
501            subKind = static_cast<ArkUIEventSubKind>(innerEvent->mouseEvent.subKind);
502            break;
503        case MIXED_EVENT:
504            subKind = static_cast<ArkUIEventSubKind>(innerEvent->mixedEvent.subKind);
505            break;
506        case DRAG_EVENT:
507            subKind = static_cast<ArkUIEventSubKind>(innerEvent->dragEvent.subKind);
508            break;
509        default:
510            break; /* Empty */
511    }
512    ArkUI_NodeEventType eventType = static_cast<ArkUI_NodeEventType>(ConvertToNodeEventType(subKind));
513    auto innerEventExtraParam = extraData->eventMap.find(eventType);
514    if (innerEventExtraParam == extraData->eventMap.end()) {
515        TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "the event of %{public}d is not register", eventType);
516        return invalidType;
517    }
518    return static_cast<int32_t>(eventType);
519}
520
521void HandleNodeEvent(ArkUI_NodeEvent* event)
522{
523    if (!event) {
524        return;
525    }
526    if (event->node && event->node->eventListeners) {
527        auto eventListenersSet = reinterpret_cast<std::set<void (*)(ArkUI_NodeEvent*)>*>(event->node->eventListeners);
528        TriggerNodeEvent(event, eventListenersSet);
529    }
530    if (g_eventReceiver) {
531        g_eventReceiver(event);
532    }
533}
534
535void TriggerNodeEvent(ArkUI_NodeEvent* event, std::set<void (*)(ArkUI_NodeEvent*)>* eventListenersSet)
536{
537    if (!eventListenersSet) {
538        return;
539    }
540    if (eventListenersSet->size() == 1) {
541        auto eventListener = eventListenersSet->begin();
542        (*eventListener)(event);
543    } else if (eventListenersSet->size() > 1) {
544        for (const auto& eventListener : *eventListenersSet) {
545            (*eventListener)(event);
546            if (!IsValidArkUINode(event->node)) {
547                break;
548            }
549        }
550    }
551}
552
553int32_t CheckEvent(ArkUI_NodeEvent* event)
554{
555    return 0;
556}
557
558int32_t SetUserData(ArkUI_NodeHandle node, void* userData)
559{
560    if (!node) {
561        return ERROR_CODE_PARAM_INVALID;
562    }
563    if (!userData) {
564        return ERROR_CODE_PARAM_INVALID;
565    }
566    node->userData = userData;
567    return ERROR_CODE_NO_ERROR;
568}
569
570void* GetUserData(ArkUI_NodeHandle node)
571{
572    return node->userData;
573}
574
575int32_t SetLengthMetricUnit(ArkUI_NodeHandle nodePtr, ArkUI_LengthMetricUnit unit)
576{
577    if (!nodePtr) {
578        return ERROR_CODE_PARAM_INVALID;
579    }
580    if (!InRegion(static_cast<int32_t>(ARKUI_LENGTH_METRIC_UNIT_DEFAULT),
581        static_cast<int32_t>(ARKUI_LENGTH_METRIC_UNIT_FP), static_cast<int32_t>(unit))) {
582        return ERROR_CODE_PARAM_INVALID;
583    }
584    nodePtr->lengthMetricUnit = unit;
585    return ERROR_CODE_NO_ERROR;
586}
587
588void ApplyModifierFinish(ArkUI_NodeHandle nodePtr)
589{
590    // already check in entry point.
591    if (!nodePtr) {
592        return;
593    }
594    auto* impl = GetFullImpl();
595    impl->getBasicAPI()->applyModifierFinish(nodePtr->uiNodeHandle);
596}
597
598void MarkDirty(ArkUI_NodeHandle nodePtr, ArkUI_NodeDirtyFlag dirtyFlag)
599{
600    // spanNode inherited from UINode
601    if (!nodePtr) {
602        return;
603    }
604    ArkUIDirtyFlag flag = ARKUI_DIRTY_FLAG_MEASURE;
605    switch (dirtyFlag) {
606        case NODE_NEED_MEASURE: {
607            flag = ARKUI_DIRTY_FLAG_MEASURE_SELF_AND_PARENT;
608            break;
609        }
610        case NODE_NEED_LAYOUT: {
611            flag = ARKUI_DIRTY_FLAG_LAYOUT;
612            break;
613        }
614        case NODE_NEED_RENDER: {
615            flag = ARKUI_DIRTY_FLAG_RENDER;
616            break;
617        }
618        default: {
619            flag = ARKUI_DIRTY_FLAG_MEASURE;
620        }
621    }
622    // already check in entry point.
623    auto* impl = GetFullImpl();
624    impl->getBasicAPI()->markDirty(nodePtr->uiNodeHandle, flag);
625}
626
627int32_t AddNodeEventReceiver(ArkUI_NodeHandle nodePtr, void (*eventReceiver)(ArkUI_NodeEvent* event))
628{
629    if (!nodePtr || !eventReceiver) {
630        return ERROR_CODE_PARAM_INVALID;
631    }
632    if (!nodePtr->eventListeners) {
633        nodePtr->eventListeners = new std::set<void (*)(ArkUI_NodeEvent*)>();
634    }
635    auto eventListenersSet = reinterpret_cast<std::set<void (*)(ArkUI_NodeEvent*)>*>(nodePtr->eventListeners);
636    if (!eventListenersSet) {
637        return ERROR_CODE_PARAM_INVALID;
638    }
639    eventListenersSet->emplace(eventReceiver);
640    return ERROR_CODE_NO_ERROR;
641}
642
643int32_t RemoveNodeEventReceiver(ArkUI_NodeHandle nodePtr, void (*eventReceiver)(ArkUI_NodeEvent* event))
644{
645    if (!nodePtr || !eventReceiver || !nodePtr->eventListeners) {
646        return ERROR_CODE_PARAM_INVALID;
647    }
648    auto eventListenersSet = reinterpret_cast<std::set<void (*)(ArkUI_NodeEvent*)>*>(nodePtr->eventListeners);
649    if (!eventListenersSet) {
650        return ERROR_CODE_PARAM_INVALID;
651    }
652    eventListenersSet->erase(eventReceiver);
653    if (eventListenersSet->empty()) {
654        delete eventListenersSet;
655        nodePtr->eventListeners = nullptr;
656    }
657    return ERROR_CODE_NO_ERROR;
658}
659
660void* GetParseJsMedia()
661{
662    void* module = FindModule();
663    if (!module) {
664        TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "fail to get module");
665        return nullptr;
666    }
667    void (*parseJsMedia)(void* value, void* resource) = nullptr;
668    parseJsMedia = reinterpret_cast<void (*)(void*, void*)>(
669        FindFunction(module, "OHOS_ACE_ParseJsMedia"));
670    if (!parseJsMedia) {
671        TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "Cannot find OHOS_ACE_ParseJsMedia");
672        return nullptr;
673    }
674    return reinterpret_cast<void*>(parseJsMedia);
675}
676} // namespace OHOS::Ace::NodeModel
677
678#ifdef __cplusplus
679extern "C" {
680#endif
681
682int32_t OH_ArkUI_NodeContent_AddNode(ArkUI_NodeContentHandle content, ArkUI_NodeHandle node)
683{
684    auto* impl = OHOS::Ace::NodeModel::GetFullImpl();
685    CHECK_NULL_RETURN(impl, OHOS::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
686    CHECK_NULL_RETURN(node, OHOS::Ace::ERROR_CODE_PARAM_INVALID);
687    return impl->getNodeModifiers()->getNodeContentModifier()->addChild(
688        reinterpret_cast<ArkUINodeContentHandle>(content), node->uiNodeHandle);
689}
690
691int32_t OH_ArkUI_NodeContent_InsertNode(ArkUI_NodeContentHandle content, ArkUI_NodeHandle node, int32_t position)
692{
693    auto* impl = OHOS::Ace::NodeModel::GetFullImpl();
694    CHECK_NULL_RETURN(impl, OHOS::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
695    CHECK_NULL_RETURN(node, OHOS::Ace::ERROR_CODE_PARAM_INVALID);
696    return impl->getNodeModifiers()->getNodeContentModifier()->insertChild(
697        reinterpret_cast<ArkUINodeContentHandle>(content), node->uiNodeHandle, position);
698}
699
700int32_t OH_ArkUI_NodeContent_RemoveNode(ArkUI_NodeContentHandle content, ArkUI_NodeHandle node)
701{
702    auto* impl = OHOS::Ace::NodeModel::GetFullImpl();
703    CHECK_NULL_RETURN(impl, OHOS::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
704    CHECK_NULL_RETURN(node, OHOS::Ace::ERROR_CODE_PARAM_INVALID);
705    return impl->getNodeModifiers()->getNodeContentModifier()->removeChild(
706        reinterpret_cast<ArkUINodeContentHandle>(content), node->uiNodeHandle);
707}
708
709int32_t OH_ArkUI_NodeContent_RegisterCallback(ArkUI_NodeContentHandle content, ArkUI_NodeContentCallback callback)
710{
711    auto* impl = OHOS::Ace::NodeModel::GetFullImpl();
712    CHECK_NULL_RETURN(impl, OHOS::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
713    auto innerCallback = reinterpret_cast<void (*)(ArkUINodeContentEvent* event)>(callback);
714    return impl->getNodeModifiers()->getNodeContentModifier()->registerEvent(
715        reinterpret_cast<ArkUINodeContentHandle>(content), nullptr, innerCallback);
716}
717
718ArkUI_NodeContentEventType OH_ArkUI_NodeContentEvent_GetEventType(ArkUI_NodeContentEvent* event)
719{
720    CHECK_NULL_RETURN(event, static_cast<ArkUI_NodeContentEventType>(-1));
721    auto* innerEvent = reinterpret_cast<ArkUINodeContentEvent*>(event);
722    return static_cast<ArkUI_NodeContentEventType>(innerEvent->type);
723}
724
725ArkUI_NodeContentHandle OH_ArkUI_NodeContentEvent_GetNodeContentHandle(ArkUI_NodeContentEvent* event)
726{
727    CHECK_NULL_RETURN(event, nullptr);
728    auto* innerEvent = reinterpret_cast<ArkUINodeContentEvent*>(event);
729    return reinterpret_cast<ArkUI_NodeContentHandle>(innerEvent->nodeContent);
730}
731
732int32_t OH_ArkUI_NodeContent_SetUserData(ArkUI_NodeContentHandle content, void* userData)
733{
734    auto* impl = OHOS::Ace::NodeModel::GetFullImpl();
735    CHECK_NULL_RETURN(impl, OHOS::Ace::ERROR_CODE_NATIVE_IMPL_LIBRARY_NOT_FOUND);
736    return impl->getNodeModifiers()->getNodeContentModifier()->setUserData(
737        reinterpret_cast<ArkUINodeContentHandle>(content), userData);
738}
739
740void* OH_ArkUI_NodeContent_GetUserData(ArkUI_NodeContentHandle content)
741{
742    auto* impl = OHOS::Ace::NodeModel::GetFullImpl();
743    CHECK_NULL_RETURN(impl, nullptr);
744    return impl->getNodeModifiers()->getNodeContentModifier()->getUserData(
745        reinterpret_cast<ArkUINodeContentHandle>(content));
746}
747
748#ifdef __cplusplus
749};
750#endif
751