18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (C) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci#include "NodeImpl.h"
168bf80f4bSopenharmony_ci
178bf80f4bSopenharmony_ci#include <meta/api/make_callback.h>
188bf80f4bSopenharmony_ci#include <meta/interface/intf_containable.h>
198bf80f4bSopenharmony_ci#include <meta/interface/intf_container.h>
208bf80f4bSopenharmony_ci#include <meta/interface/intf_task_queue.h>
218bf80f4bSopenharmony_ci#include <meta/interface/intf_task_queue_registry.h>
228bf80f4bSopenharmony_ci#include <napi_api.h>
238bf80f4bSopenharmony_ci#include <scene_plugin/api/camera_uid.h>
248bf80f4bSopenharmony_ci#include <scene_plugin/api/light_uid.h>
258bf80f4bSopenharmony_ci#include <scene_plugin/api/node_uid.h>
268bf80f4bSopenharmony_ci#include <scene_plugin/api/scene.h>
278bf80f4bSopenharmony_ci#include <scene_plugin/interface/intf_node.h>
288bf80f4bSopenharmony_ci
298bf80f4bSopenharmony_ci#include "BaseObjectJS.h"
308bf80f4bSopenharmony_civoid NodeImpl::RegisterEnums(NapiApi::Object exports)
318bf80f4bSopenharmony_ci{
328bf80f4bSopenharmony_ci    napi_value v;
338bf80f4bSopenharmony_ci    NapiApi::Object NodeType(exports.GetEnv());
348bf80f4bSopenharmony_ci#define DECL_ENUM(enu, x)                                            \
358bf80f4bSopenharmony_ci    {                                                                \
368bf80f4bSopenharmony_ci        napi_create_uint32(enu.GetEnv(), NodeImpl::NodeType::x, &v); \
378bf80f4bSopenharmony_ci        enu.Set(#x, v);                                              \
388bf80f4bSopenharmony_ci    }
398bf80f4bSopenharmony_ci    DECL_ENUM(NodeType, NODE);
408bf80f4bSopenharmony_ci    DECL_ENUM(NodeType, GEOMETRY);
418bf80f4bSopenharmony_ci    DECL_ENUM(NodeType, CAMERA);
428bf80f4bSopenharmony_ci    DECL_ENUM(NodeType, LIGHT);
438bf80f4bSopenharmony_ci#undef DECL_ENUM
448bf80f4bSopenharmony_ci    exports.Set("NodeType", NodeType);
458bf80f4bSopenharmony_ci}
468bf80f4bSopenharmony_ciNodeImpl::NodeImpl(NodeType type) : SceneResourceImpl(SceneResourceImpl::NODE), type_(type)
478bf80f4bSopenharmony_ci{
488bf80f4bSopenharmony_ci    LOG_F("NodeImpl ++");
498bf80f4bSopenharmony_ci}
508bf80f4bSopenharmony_ciNodeImpl::~NodeImpl()
518bf80f4bSopenharmony_ci{
528bf80f4bSopenharmony_ci    LOG_F("NodeImpl --");
538bf80f4bSopenharmony_ci}
548bf80f4bSopenharmony_ci
558bf80f4bSopenharmony_civoid* NodeImpl::GetInstanceImpl(uint32_t id)
568bf80f4bSopenharmony_ci{
578bf80f4bSopenharmony_ci    if (id == NodeImpl::ID) {
588bf80f4bSopenharmony_ci        return this;
598bf80f4bSopenharmony_ci    }
608bf80f4bSopenharmony_ci    return SceneResourceImpl::GetInstanceImpl(id);
618bf80f4bSopenharmony_ci}
628bf80f4bSopenharmony_ci
638bf80f4bSopenharmony_civoid NodeImpl::GetPropertyDescs(BASE_NS::vector<napi_property_descriptor>& props)
648bf80f4bSopenharmony_ci{
658bf80f4bSopenharmony_ci    using namespace NapiApi;
668bf80f4bSopenharmony_ci    // META_NS::IContainer;
678bf80f4bSopenharmony_ci
688bf80f4bSopenharmony_ci    SceneResourceImpl::GetPropertyDescs(props);
698bf80f4bSopenharmony_ci
708bf80f4bSopenharmony_ci    // node
718bf80f4bSopenharmony_ci
728bf80f4bSopenharmony_ci    props.push_back(TROGetProperty<BASE_NS::string, NodeImpl, &NodeImpl::GetPath>("path"));
738bf80f4bSopenharmony_ci    props.push_back(TROGetSetProperty<Object, NodeImpl, &NodeImpl::GetPosition, &NodeImpl::SetPosition>("position"));
748bf80f4bSopenharmony_ci    props.push_back(TROGetSetProperty<Object, NodeImpl, &NodeImpl::GetRotation, &NodeImpl::SetRotation>("rotation"));
758bf80f4bSopenharmony_ci    props.push_back(TROGetSetProperty<Object, NodeImpl, &NodeImpl::GetScale, &NodeImpl::SetScale>("scale"));
768bf80f4bSopenharmony_ci    props.push_back(TROGetProperty<BASE_NS::string, NodeImpl, &NodeImpl::GetParent>("parent"));
778bf80f4bSopenharmony_ci    props.push_back(TROGetSetProperty<bool, NodeImpl, &NodeImpl::GetVisible, &NodeImpl::SetVisible>("visible"));
788bf80f4bSopenharmony_ci    props.push_back(TROGetSetProperty<bool, NodeImpl, &NodeImpl::GetChildContainer, &NodeImpl::SetVisible>("children"));
798bf80f4bSopenharmony_ci    props.push_back(TROGetProperty<BASE_NS::string, NodeImpl, &NodeImpl::GetNodeType>("nodeType"));
808bf80f4bSopenharmony_ci    props.push_back(TROGetProperty<BASE_NS::string, NodeImpl, &NodeImpl::GetLayerMask>("layerMask"));
818bf80f4bSopenharmony_ci
828bf80f4bSopenharmony_ci    // node methods
838bf80f4bSopenharmony_ci    props.push_back(MakeTROMethod<FunctionContext<>, NodeImpl, &NodeImpl::Dispose>("destroy"));
848bf80f4bSopenharmony_ci    props.push_back(
858bf80f4bSopenharmony_ci        MakeTROMethod<FunctionContext<BASE_NS::string>, NodeImpl, &NodeImpl::GetNodeByPath>("getNodeByPath"));
868bf80f4bSopenharmony_ci
878bf80f4bSopenharmony_ci    // layermask methods.
888bf80f4bSopenharmony_ci    props.push_back(MakeTROMethod<FunctionContext<uint32_t>, NodeImpl, &NodeImpl::GetLayerMaskEnabled>("getEnabled"));
898bf80f4bSopenharmony_ci    props.push_back(
908bf80f4bSopenharmony_ci        MakeTROMethod<FunctionContext<uint32_t, bool>, NodeImpl, &NodeImpl::SetLayerMaskEnabled>("setEnabled"));
918bf80f4bSopenharmony_ci
928bf80f4bSopenharmony_ci    // container
938bf80f4bSopenharmony_ci    props.push_back(MakeTROMethod<FunctionContext<Object>, NodeImpl, &NodeImpl::AppendChild>("append"));
948bf80f4bSopenharmony_ci    props.push_back(
958bf80f4bSopenharmony_ci        MakeTROMethod<FunctionContext<Object, Object>, NodeImpl, &NodeImpl::InsertChildAfter>("insertAfter"));
968bf80f4bSopenharmony_ci    props.push_back(MakeTROMethod<FunctionContext<Object>, NodeImpl, &NodeImpl::RemoveChild>("remove"));
978bf80f4bSopenharmony_ci    props.push_back(MakeTROMethod<FunctionContext<uint32_t>, NodeImpl, &NodeImpl::GetChild>("get"));
988bf80f4bSopenharmony_ci    props.push_back(MakeTROMethod<FunctionContext<>, NodeImpl, &NodeImpl::ClearChildren>("clear"));
998bf80f4bSopenharmony_ci    props.push_back(MakeTROMethod<FunctionContext<>, NodeImpl, &NodeImpl::GetCount>("count"));
1008bf80f4bSopenharmony_ci}
1018bf80f4bSopenharmony_cinapi_value NodeImpl::Dispose(NapiApi::FunctionContext<>& ctx)
1028bf80f4bSopenharmony_ci{
1038bf80f4bSopenharmony_ci    // Dispose of the native object. (makes the js object invalid)
1048bf80f4bSopenharmony_ci    posProxy_.reset();
1058bf80f4bSopenharmony_ci    sclProxy_.reset();
1068bf80f4bSopenharmony_ci    rotProxy_.reset();
1078bf80f4bSopenharmony_ci    if (TrueRootObject* instance = GetThisRootObject(ctx)) {
1088bf80f4bSopenharmony_ci        instance->DisposeNative();
1098bf80f4bSopenharmony_ci    }
1108bf80f4bSopenharmony_ci    scene_.Reset();
1118bf80f4bSopenharmony_ci    return ctx.GetUndefined();
1128bf80f4bSopenharmony_ci}
1138bf80f4bSopenharmony_cinapi_value NodeImpl::GetLayerMaskEnabled(NapiApi::FunctionContext<uint32_t>& ctx)
1148bf80f4bSopenharmony_ci{
1158bf80f4bSopenharmony_ci    uint32_t bit = ctx.Arg<0>();
1168bf80f4bSopenharmony_ci    bool enabled = false;
1178bf80f4bSopenharmony_ci    if (auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx))) {
1188bf80f4bSopenharmony_ci        uint64_t mask = 1ull << bit;
1198bf80f4bSopenharmony_ci    ExecSyncTask([node, mask, &enabled]() {
1208bf80f4bSopenharmony_ci            enabled = node->LayerMask()->GetValue() & mask;
1218bf80f4bSopenharmony_ci        return META_NS::IAny::Ptr {};
1228bf80f4bSopenharmony_ci        });
1238bf80f4bSopenharmony_ci    }
1248bf80f4bSopenharmony_ci    return ctx.GetBoolean(enabled);
1258bf80f4bSopenharmony_ci}
1268bf80f4bSopenharmony_cinapi_value NodeImpl::SetLayerMaskEnabled(NapiApi::FunctionContext<uint32_t, bool>& ctx)
1278bf80f4bSopenharmony_ci{
1288bf80f4bSopenharmony_ci    uint32_t bit = ctx.Arg<0>();
1298bf80f4bSopenharmony_ci    bool enabled = ctx.Arg<1>();
1308bf80f4bSopenharmony_ci    if (auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx))) {
1318bf80f4bSopenharmony_ci    uint64_t mask = 1ull << bit;
1328bf80f4bSopenharmony_ci    ExecSyncTask([node, enabled, mask]() {
1338bf80f4bSopenharmony_ci            if (enabled) {
1348bf80f4bSopenharmony_ci                node->LayerMask()->SetValue(node->LayerMask()->GetValue() | mask);
1358bf80f4bSopenharmony_ci            } else {
1368bf80f4bSopenharmony_ci                node->LayerMask()->SetValue(node->LayerMask()->GetValue() & ~mask);
1378bf80f4bSopenharmony_ci            }
1388bf80f4bSopenharmony_ci                return META_NS::IAny::Ptr {};
1398bf80f4bSopenharmony_ci        });
1408bf80f4bSopenharmony_ci    }
1418bf80f4bSopenharmony_ci    return ctx.GetUndefined();
1428bf80f4bSopenharmony_ci}
1438bf80f4bSopenharmony_ci
1448bf80f4bSopenharmony_cinapi_value NodeImpl::GetNodeType(NapiApi::FunctionContext<>& ctx)
1458bf80f4bSopenharmony_ci{
1468bf80f4bSopenharmony_ci    uint32_t type = -1; // return -1 if the object does not exist anymore
1478bf80f4bSopenharmony_ci    if (auto node = interface_cast<SCENE_NS::INode>(GetThisNativeObject(ctx))) {
1488bf80f4bSopenharmony_ci        type = type_;
1498bf80f4bSopenharmony_ci    }
1508bf80f4bSopenharmony_ci    napi_value value;
1518bf80f4bSopenharmony_ci    napi_status status = napi_create_uint32(ctx, type, &value);
1528bf80f4bSopenharmony_ci    return value;
1538bf80f4bSopenharmony_ci}
1548bf80f4bSopenharmony_ci
1558bf80f4bSopenharmony_cinapi_value NodeImpl::GetLayerMask(NapiApi::FunctionContext<>& ctx)
1568bf80f4bSopenharmony_ci{
1578bf80f4bSopenharmony_ci    if (auto node = interface_cast<SCENE_NS::INode>(GetThisNativeObject(ctx))) {
1588bf80f4bSopenharmony_ci        return ctx.This();
1598bf80f4bSopenharmony_ci    }
1608bf80f4bSopenharmony_ci    return ctx.GetUndefined();
1618bf80f4bSopenharmony_ci}
1628bf80f4bSopenharmony_ci
1638bf80f4bSopenharmony_cinapi_value NodeImpl::GetPath(NapiApi::FunctionContext<>& ctx)
1648bf80f4bSopenharmony_ci{
1658bf80f4bSopenharmony_ci    auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
1668bf80f4bSopenharmony_ci    BASE_NS::string path;
1678bf80f4bSopenharmony_ci    if (node) {
1688bf80f4bSopenharmony_ci        ExecSyncTask([node, &path]() {
1698bf80f4bSopenharmony_ci            if (interface_cast<META_NS::IContainable>(node)->GetParent()) {
1708bf80f4bSopenharmony_ci                path = node->Path()->GetValue();
1718bf80f4bSopenharmony_ci            }
1728bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
1738bf80f4bSopenharmony_ci        });
1748bf80f4bSopenharmony_ci    }
1758bf80f4bSopenharmony_ci    napi_value value;
1768bf80f4bSopenharmony_ci    napi_status status = napi_create_string_utf8(ctx, path.c_str(), path.length(), &value);
1778bf80f4bSopenharmony_ci    return value;
1788bf80f4bSopenharmony_ci}
1798bf80f4bSopenharmony_ci
1808bf80f4bSopenharmony_cinapi_value NodeImpl::GetVisible(NapiApi::FunctionContext<>& ctx)
1818bf80f4bSopenharmony_ci{
1828bf80f4bSopenharmony_ci    auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
1838bf80f4bSopenharmony_ci    bool visible = false;
1848bf80f4bSopenharmony_ci    if (node) {
1858bf80f4bSopenharmony_ci        ExecSyncTask([node, &visible]() {
1868bf80f4bSopenharmony_ci            visible = node->Visible()->GetValue();
1878bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
1888bf80f4bSopenharmony_ci        });
1898bf80f4bSopenharmony_ci    }
1908bf80f4bSopenharmony_ci    napi_value value;
1918bf80f4bSopenharmony_ci    napi_status status = napi_get_boolean(ctx, visible, &value);
1928bf80f4bSopenharmony_ci    return value;
1938bf80f4bSopenharmony_ci}
1948bf80f4bSopenharmony_civoid NodeImpl::SetVisible(NapiApi::FunctionContext<bool>& ctx)
1958bf80f4bSopenharmony_ci{
1968bf80f4bSopenharmony_ci    auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
1978bf80f4bSopenharmony_ci    if (node) {
1988bf80f4bSopenharmony_ci        bool visible = ctx.Arg<0>();
1998bf80f4bSopenharmony_ci        ExecSyncTask([node, visible]() {
2008bf80f4bSopenharmony_ci            node->Visible()->SetValue(visible);
2018bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
2028bf80f4bSopenharmony_ci        });
2038bf80f4bSopenharmony_ci    }
2048bf80f4bSopenharmony_ci}
2058bf80f4bSopenharmony_ci
2068bf80f4bSopenharmony_cinapi_value NodeImpl::GetPosition(NapiApi::FunctionContext<>& ctx)
2078bf80f4bSopenharmony_ci{
2088bf80f4bSopenharmony_ci    auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
2098bf80f4bSopenharmony_ci    if (!node) {
2108bf80f4bSopenharmony_ci        return ctx.GetUndefined();
2118bf80f4bSopenharmony_ci    }
2128bf80f4bSopenharmony_ci    if (posProxy_ == nullptr) {
2138bf80f4bSopenharmony_ci        posProxy_ = BASE_NS::make_unique<Vec3Proxy>(ctx, node->Position());
2148bf80f4bSopenharmony_ci    }
2158bf80f4bSopenharmony_ci    return posProxy_ ? posProxy_->Value() : NapiApi::Value<NapiApi::Object>();
2168bf80f4bSopenharmony_ci}
2178bf80f4bSopenharmony_ci
2188bf80f4bSopenharmony_civoid NodeImpl::SetPosition(NapiApi::FunctionContext<NapiApi::Object>& ctx)
2198bf80f4bSopenharmony_ci{
2208bf80f4bSopenharmony_ci    auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
2218bf80f4bSopenharmony_ci    if (!node) {
2228bf80f4bSopenharmony_ci        return;
2238bf80f4bSopenharmony_ci    }
2248bf80f4bSopenharmony_ci    NapiApi::Object obj = ctx.Arg<0>();
2258bf80f4bSopenharmony_ci    if (posProxy_ == nullptr) {
2268bf80f4bSopenharmony_ci        posProxy_ = BASE_NS::make_unique<Vec3Proxy>(ctx, node->Position());
2278bf80f4bSopenharmony_ci    }
2288bf80f4bSopenharmony_ci    posProxy_->SetValue(obj);
2298bf80f4bSopenharmony_ci}
2308bf80f4bSopenharmony_ci
2318bf80f4bSopenharmony_cinapi_value NodeImpl::GetScale(NapiApi::FunctionContext<>& ctx)
2328bf80f4bSopenharmony_ci{
2338bf80f4bSopenharmony_ci    auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
2348bf80f4bSopenharmony_ci    if (!node) {
2358bf80f4bSopenharmony_ci        return ctx.GetUndefined();
2368bf80f4bSopenharmony_ci    }
2378bf80f4bSopenharmony_ci    if (sclProxy_ == nullptr) {
2388bf80f4bSopenharmony_ci        sclProxy_ = BASE_NS::make_unique<Vec3Proxy>(ctx, node->Scale());
2398bf80f4bSopenharmony_ci    }
2408bf80f4bSopenharmony_ci    return sclProxy_ ? sclProxy_->Value() : NapiApi::Value<NapiApi::Object>();
2418bf80f4bSopenharmony_ci}
2428bf80f4bSopenharmony_ci
2438bf80f4bSopenharmony_civoid NodeImpl::SetScale(NapiApi::FunctionContext<NapiApi::Object>& ctx)
2448bf80f4bSopenharmony_ci{
2458bf80f4bSopenharmony_ci    auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
2468bf80f4bSopenharmony_ci    if (!node) {
2478bf80f4bSopenharmony_ci        return;
2488bf80f4bSopenharmony_ci    }
2498bf80f4bSopenharmony_ci    NapiApi::Object obj = ctx.Arg<0>();
2508bf80f4bSopenharmony_ci    if (sclProxy_ == nullptr) {
2518bf80f4bSopenharmony_ci        sclProxy_ = BASE_NS::make_unique<Vec3Proxy>(ctx, node->Scale());
2528bf80f4bSopenharmony_ci    }
2538bf80f4bSopenharmony_ci    sclProxy_->SetValue(obj);
2548bf80f4bSopenharmony_ci}
2558bf80f4bSopenharmony_ci
2568bf80f4bSopenharmony_cinapi_value NodeImpl::GetRotation(NapiApi::FunctionContext<>& ctx)
2578bf80f4bSopenharmony_ci{
2588bf80f4bSopenharmony_ci    auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
2598bf80f4bSopenharmony_ci    if (!node) {
2608bf80f4bSopenharmony_ci        return ctx.GetUndefined();
2618bf80f4bSopenharmony_ci    }
2628bf80f4bSopenharmony_ci    if (rotProxy_ == nullptr) {
2638bf80f4bSopenharmony_ci        rotProxy_ = BASE_NS::make_unique<QuatProxy>(ctx, node->Rotation());
2648bf80f4bSopenharmony_ci    }
2658bf80f4bSopenharmony_ci    return rotProxy_ ? rotProxy_->Value() : NapiApi::Value<NapiApi::Object>();
2668bf80f4bSopenharmony_ci}
2678bf80f4bSopenharmony_ci
2688bf80f4bSopenharmony_civoid NodeImpl::SetRotation(NapiApi::FunctionContext<NapiApi::Object>& ctx)
2698bf80f4bSopenharmony_ci{
2708bf80f4bSopenharmony_ci    auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
2718bf80f4bSopenharmony_ci    if (!node) {
2728bf80f4bSopenharmony_ci        return;
2738bf80f4bSopenharmony_ci    }
2748bf80f4bSopenharmony_ci    NapiApi::Object obj = ctx.Arg<0>();
2758bf80f4bSopenharmony_ci    if (rotProxy_ == nullptr) {
2768bf80f4bSopenharmony_ci        rotProxy_ = BASE_NS::make_unique<QuatProxy>(ctx, node->Rotation());
2778bf80f4bSopenharmony_ci    }
2788bf80f4bSopenharmony_ci    rotProxy_->SetValue(obj);
2798bf80f4bSopenharmony_ci}
2808bf80f4bSopenharmony_ci
2818bf80f4bSopenharmony_cinapi_value NodeImpl::GetParent(NapiApi::FunctionContext<>& ctx)
2828bf80f4bSopenharmony_ci{
2838bf80f4bSopenharmony_ci    auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
2848bf80f4bSopenharmony_ci    if (!node) {
2858bf80f4bSopenharmony_ci        return ctx.GetNull();
2868bf80f4bSopenharmony_ci    }
2878bf80f4bSopenharmony_ci    META_NS::IObject::Ptr root;
2888bf80f4bSopenharmony_ci    if (auto containable = interface_cast<META_NS::IContainable>(node)) {
2898bf80f4bSopenharmony_ci        ExecSyncTask([containable, &root]() {
2908bf80f4bSopenharmony_ci            root = interface_pointer_cast<META_NS::IObject>(containable->GetParent());
2918bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
2928bf80f4bSopenharmony_ci        });
2938bf80f4bSopenharmony_ci    }
2948bf80f4bSopenharmony_ci
2958bf80f4bSopenharmony_ci    if (!root) {
2968bf80f4bSopenharmony_ci        // no parent.
2978bf80f4bSopenharmony_ci        return ctx.GetNull();
2988bf80f4bSopenharmony_ci    }
2998bf80f4bSopenharmony_ci
3008bf80f4bSopenharmony_ci    if (auto cached = FetchJsObj(root)) {
3018bf80f4bSopenharmony_ci        // always return the same js object.
3028bf80f4bSopenharmony_ci        return cached;
3038bf80f4bSopenharmony_ci    }
3048bf80f4bSopenharmony_ci    if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) {
3058bf80f4bSopenharmony_ci        CORE_LOG_F("INVALID SCENE!");
3068bf80f4bSopenharmony_ci    }
3078bf80f4bSopenharmony_ci
3088bf80f4bSopenharmony_ci    // create new js object for the native node.
3098bf80f4bSopenharmony_ci    NapiApi::Object argJS(ctx);
3108bf80f4bSopenharmony_ci    napi_value args[] = { scene_.GetValue(), argJS };
3118bf80f4bSopenharmony_ci
3128bf80f4bSopenharmony_ci    return CreateFromNativeInstance(ctx, root, false /*these are owned by the scene*/, BASE_NS::countof(args), args);
3138bf80f4bSopenharmony_ci}
3148bf80f4bSopenharmony_ci
3158bf80f4bSopenharmony_cinapi_value NodeImpl::GetChildContainer(NapiApi::FunctionContext<>& ctx)
3168bf80f4bSopenharmony_ci{
3178bf80f4bSopenharmony_ci    // make sure the child list is up to date.
3188bf80f4bSopenharmony_ci    auto node = interface_pointer_cast<SCENE_NS::INode>(GetThisNativeObject(ctx));
3198bf80f4bSopenharmony_ci    if (node) {
3208bf80f4bSopenharmony_ci        ExecSyncTask([node]() {
3218bf80f4bSopenharmony_ci            node->BuildChildren(SCENE_NS::INode::BuildBehavior::NODE_BUILD_ONLY_DIRECT_CHILDREN);
3228bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
3238bf80f4bSopenharmony_ci        });
3248bf80f4bSopenharmony_ci    }
3258bf80f4bSopenharmony_ci
3268bf80f4bSopenharmony_ci    // Node implements Container<Node>
3278bf80f4bSopenharmony_ci    return ctx.This();
3288bf80f4bSopenharmony_ci}
3298bf80f4bSopenharmony_ci
3308bf80f4bSopenharmony_ci// container implementation
3318bf80f4bSopenharmony_cibool SkipNode(SCENE_NS::INode::Ptr node)
3328bf80f4bSopenharmony_ci{
3338bf80f4bSopenharmony_ci    auto o = interface_cast<META_NS::IObject>(node);
3348bf80f4bSopenharmony_ci    auto classid = o->GetClassId();
3358bf80f4bSopenharmony_ci    // white list of nodes that are actual nodes..
3368bf80f4bSopenharmony_ci    if ((classid == SCENE_NS::ClassId::Camera) || (classid == SCENE_NS::ClassId::Light) ||
3378bf80f4bSopenharmony_ci        (classid == SCENE_NS::ClassId::Node)) {
3388bf80f4bSopenharmony_ci        return false;
3398bf80f4bSopenharmony_ci    }
3408bf80f4bSopenharmony_ci    return true;
3418bf80f4bSopenharmony_ci}
3428bf80f4bSopenharmony_cinapi_value NodeImpl::GetChild(NapiApi::FunctionContext<uint32_t>& ctx)
3438bf80f4bSopenharmony_ci{
3448bf80f4bSopenharmony_ci    uint32_t index = ctx.Arg<0>();
3458bf80f4bSopenharmony_ci    META_NS::IObject::Ptr child;
3468bf80f4bSopenharmony_ci    auto metaobj = GetThisNativeObject(ctx);
3478bf80f4bSopenharmony_ci    if (auto container = interface_cast<META_NS::IContainer>(metaobj)) {
3488bf80f4bSopenharmony_ci        ExecSyncTask([container, index, &child]() {
3498bf80f4bSopenharmony_ci            auto data = container->GetAll<SCENE_NS::INode>();
3508bf80f4bSopenharmony_ci            int count = 0;
3518bf80f4bSopenharmony_ci            for (auto d : data) {
3528bf80f4bSopenharmony_ci                // Skip nodes that are not real "nodes"
3538bf80f4bSopenharmony_ci                if (SkipNode(d)) {
3548bf80f4bSopenharmony_ci                    continue;
3558bf80f4bSopenharmony_ci                }
3568bf80f4bSopenharmony_ci                if (count == index) {
3578bf80f4bSopenharmony_ci                    child = interface_pointer_cast<META_NS::IObject>(d);
3588bf80f4bSopenharmony_ci                    break;
3598bf80f4bSopenharmony_ci                }
3608bf80f4bSopenharmony_ci                count++;
3618bf80f4bSopenharmony_ci            }
3628bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
3638bf80f4bSopenharmony_ci        });
3648bf80f4bSopenharmony_ci    }
3658bf80f4bSopenharmony_ci    if (!child) {
3668bf80f4bSopenharmony_ci        // return null
3678bf80f4bSopenharmony_ci        napi_value value;
3688bf80f4bSopenharmony_ci        napi_get_null(ctx, &value);
3698bf80f4bSopenharmony_ci        return value;
3708bf80f4bSopenharmony_ci    }
3718bf80f4bSopenharmony_ci    auto cached = FetchJsObj(child);
3728bf80f4bSopenharmony_ci    if (!cached) {
3738bf80f4bSopenharmony_ci        // was not cached yet, so recreate.
3748bf80f4bSopenharmony_ci        NapiApi::Object argJS(ctx);
3758bf80f4bSopenharmony_ci        auto scn = scene_.GetObject();
3768bf80f4bSopenharmony_ci        if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) {
3778bf80f4bSopenharmony_ci            CORE_LOG_F("INVALID SCENE!");
3788bf80f4bSopenharmony_ci        }
3798bf80f4bSopenharmony_ci
3808bf80f4bSopenharmony_ci        napi_value args[] = { scene_.GetValue(), argJS };
3818bf80f4bSopenharmony_ci
3828bf80f4bSopenharmony_ci        cached =
3838bf80f4bSopenharmony_ci            CreateFromNativeInstance(ctx, child, false /*these are owned by the scene*/, BASE_NS::countof(args), args);
3848bf80f4bSopenharmony_ci    }
3858bf80f4bSopenharmony_ci    return cached;
3868bf80f4bSopenharmony_ci}
3878bf80f4bSopenharmony_ci
3888bf80f4bSopenharmony_cinapi_value NodeImpl::GetCount(NapiApi::FunctionContext<>& ctx)
3898bf80f4bSopenharmony_ci{
3908bf80f4bSopenharmony_ci    uint32_t count = 0;
3918bf80f4bSopenharmony_ci    auto metaobj = GetThisNativeObject(ctx);
3928bf80f4bSopenharmony_ci    if (auto container = interface_cast<META_NS::IContainer>(metaobj)) {
3938bf80f4bSopenharmony_ci        ExecSyncTask([container, &count]() {
3948bf80f4bSopenharmony_ci            auto data = container->GetAll<SCENE_NS::INode>();
3958bf80f4bSopenharmony_ci            for (auto d : data) {
3968bf80f4bSopenharmony_ci                // Skip nodes that are not real "nodes"
3978bf80f4bSopenharmony_ci                if (SkipNode(d)) {
3988bf80f4bSopenharmony_ci                    continue;
3998bf80f4bSopenharmony_ci                }
4008bf80f4bSopenharmony_ci                count++;
4018bf80f4bSopenharmony_ci            }
4028bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
4038bf80f4bSopenharmony_ci        });
4048bf80f4bSopenharmony_ci    }
4058bf80f4bSopenharmony_ci    napi_value value;
4068bf80f4bSopenharmony_ci    napi_status nstatus = napi_create_uint32(ctx, count, &value);
4078bf80f4bSopenharmony_ci    return value;
4088bf80f4bSopenharmony_ci}
4098bf80f4bSopenharmony_cinapi_value NodeImpl::AppendChild(NapiApi::FunctionContext<NapiApi::Object>& ctx)
4108bf80f4bSopenharmony_ci{
4118bf80f4bSopenharmony_ci    NapiApi::Object childJS = ctx.Arg<0>();
4128bf80f4bSopenharmony_ci    if ((napi_value)childJS == nullptr) {
4138bf80f4bSopenharmony_ci        // okay. Invalid arg error?
4148bf80f4bSopenharmony_ci        return ctx.GetUndefined();
4158bf80f4bSopenharmony_ci    }
4168bf80f4bSopenharmony_ci    auto childNode = GetNativeMeta<SCENE_NS::INode>(childJS);
4178bf80f4bSopenharmony_ci    if (!childNode) {
4188bf80f4bSopenharmony_ci        return ctx.GetUndefined();
4198bf80f4bSopenharmony_ci    }
4208bf80f4bSopenharmony_ci
4218bf80f4bSopenharmony_ci    auto metaobj = GetThisNativeObject(ctx);
4228bf80f4bSopenharmony_ci    if (auto container = interface_cast<META_NS::IContainer>(metaobj)) {
4238bf80f4bSopenharmony_ci        ExecSyncTask([container, childNode]() {
4248bf80f4bSopenharmony_ci            container->Add(childNode);
4258bf80f4bSopenharmony_ci            childNode->Visible()->SetValue(true);
4268bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
4278bf80f4bSopenharmony_ci        });
4288bf80f4bSopenharmony_ci    }
4298bf80f4bSopenharmony_ci
4308bf80f4bSopenharmony_ci    // make the js object keep a weak ref again (scene keeps the native object alive)
4318bf80f4bSopenharmony_ci    // (or move ownership back from SceneJS? and remove dispose hook?)
4328bf80f4bSopenharmony_ci    if (auto tro = GetRootObject(ctx, childJS)) {
4338bf80f4bSopenharmony_ci        if (auto native = tro->GetNativeObject()) {
4348bf80f4bSopenharmony_ci            tro->SetNativeObject(nullptr, true);
4358bf80f4bSopenharmony_ci            tro->SetNativeObject(native, false);
4368bf80f4bSopenharmony_ci            native.reset();
4378bf80f4bSopenharmony_ci        }
4388bf80f4bSopenharmony_ci    }
4398bf80f4bSopenharmony_ci
4408bf80f4bSopenharmony_ci    return ctx.GetUndefined();
4418bf80f4bSopenharmony_ci}
4428bf80f4bSopenharmony_cinapi_value NodeImpl::InsertChildAfter(NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object>& ctx)
4438bf80f4bSopenharmony_ci{
4448bf80f4bSopenharmony_ci    NapiApi::Object childJS = ctx.Arg<0>();
4458bf80f4bSopenharmony_ci    NapiApi::Object siblingJS = ctx.Arg<1>();
4468bf80f4bSopenharmony_ci
4478bf80f4bSopenharmony_ci    if ((napi_value)childJS == nullptr) {
4488bf80f4bSopenharmony_ci        // okay. Invalid arg error?
4498bf80f4bSopenharmony_ci        return ctx.GetUndefined();
4508bf80f4bSopenharmony_ci    }
4518bf80f4bSopenharmony_ci    auto childNode = GetNativeMeta<SCENE_NS::INode>(childJS);
4528bf80f4bSopenharmony_ci    if (!childNode) {
4538bf80f4bSopenharmony_ci        return ctx.GetUndefined();
4548bf80f4bSopenharmony_ci    }
4558bf80f4bSopenharmony_ci    SCENE_NS::INode::Ptr siblingNode;
4568bf80f4bSopenharmony_ci    if (siblingJS) {
4578bf80f4bSopenharmony_ci        siblingNode = GetNativeMeta<SCENE_NS::INode>(siblingJS);
4588bf80f4bSopenharmony_ci    }
4598bf80f4bSopenharmony_ci
4608bf80f4bSopenharmony_ci    auto metaobj = GetThisNativeObject(ctx);
4618bf80f4bSopenharmony_ci    if (auto container = interface_cast<META_NS::IContainer>(metaobj)) {
4628bf80f4bSopenharmony_ci        ExecSyncTask([container, childNode, siblingNode]() {
4638bf80f4bSopenharmony_ci            if (siblingNode) {
4648bf80f4bSopenharmony_ci                auto data = container->GetAll<SCENE_NS::INode>();
4658bf80f4bSopenharmony_ci                int64_t index = 0;
4668bf80f4bSopenharmony_ci                for (auto d : data) {
4678bf80f4bSopenharmony_ci                    index++;
4688bf80f4bSopenharmony_ci                    if (d == siblingNode) {
4698bf80f4bSopenharmony_ci                        // insert "after" the hit
4708bf80f4bSopenharmony_ci                        container->Insert(index, childNode);
4718bf80f4bSopenharmony_ci                        childNode->Visible()->SetValue(true);
4728bf80f4bSopenharmony_ci                        return META_NS::IAny::Ptr {};
4738bf80f4bSopenharmony_ci                    }
4748bf80f4bSopenharmony_ci                }
4758bf80f4bSopenharmony_ci                // did not find the sibling.. do nothing? add first? add last?
4768bf80f4bSopenharmony_ci                // for now add last..
4778bf80f4bSopenharmony_ci                container->Add(childNode);
4788bf80f4bSopenharmony_ci                childNode->Visible()->SetValue(true);
4798bf80f4bSopenharmony_ci                return META_NS::IAny::Ptr {};
4808bf80f4bSopenharmony_ci            }
4818bf80f4bSopenharmony_ci            // insert as first..
4828bf80f4bSopenharmony_ci            container->Insert(0, childNode);
4838bf80f4bSopenharmony_ci            childNode->Visible()->SetValue(true);
4848bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
4858bf80f4bSopenharmony_ci        });
4868bf80f4bSopenharmony_ci    }
4878bf80f4bSopenharmony_ci
4888bf80f4bSopenharmony_ci    // make the js object keep a weak ref again (scene keeps the native object alive)
4898bf80f4bSopenharmony_ci    // (or move ownership back from SceneJS? and remove dispose hook?)
4908bf80f4bSopenharmony_ci    if (auto tro = GetRootObject(ctx, childJS)) {
4918bf80f4bSopenharmony_ci        if (auto native = tro->GetNativeObject()) {
4928bf80f4bSopenharmony_ci            tro->SetNativeObject(nullptr, true);
4938bf80f4bSopenharmony_ci            tro->SetNativeObject(native, false);
4948bf80f4bSopenharmony_ci            native.reset();
4958bf80f4bSopenharmony_ci        }
4968bf80f4bSopenharmony_ci    }
4978bf80f4bSopenharmony_ci
4988bf80f4bSopenharmony_ci    return ctx.GetUndefined();
4998bf80f4bSopenharmony_ci}
5008bf80f4bSopenharmony_ci
5018bf80f4bSopenharmony_civoid NodeImpl::ResetNativeObj(NapiApi::FunctionContext<>& ctx, NapiApi::Object& obj)
5028bf80f4bSopenharmony_ci{
5038bf80f4bSopenharmony_ci    if (auto tro = GetRootObject(ctx, obj)) {
5048bf80f4bSopenharmony_ci        if (auto native = tro->GetNativeObject()) {
5058bf80f4bSopenharmony_ci            tro->SetNativeObject(nullptr, false);
5068bf80f4bSopenharmony_ci            tro->SetNativeObject(native, true);
5078bf80f4bSopenharmony_ci            native.reset();
5088bf80f4bSopenharmony_ci        }
5098bf80f4bSopenharmony_ci    }
5108bf80f4bSopenharmony_ci}
5118bf80f4bSopenharmony_ci
5128bf80f4bSopenharmony_cinapi_value NodeImpl::RemoveChild(NapiApi::FunctionContext<NapiApi::Object>& ctx)
5138bf80f4bSopenharmony_ci{
5148bf80f4bSopenharmony_ci    // okay. just detach from parent. (make parent invalid)
5158bf80f4bSopenharmony_ci    // and disable it.
5168bf80f4bSopenharmony_ci    NapiApi::Object childJS = ctx.Arg<0>();
5178bf80f4bSopenharmony_ci    if ((napi_value)childJS == nullptr) {
5188bf80f4bSopenharmony_ci        // okay. Invalid arg error?
5198bf80f4bSopenharmony_ci        return ctx.GetUndefined();
5208bf80f4bSopenharmony_ci    }
5218bf80f4bSopenharmony_ci    auto childNode = GetNativeMeta<SCENE_NS::INode>(childJS);
5228bf80f4bSopenharmony_ci    if (!childNode) {
5238bf80f4bSopenharmony_ci        return ctx.GetUndefined();
5248bf80f4bSopenharmony_ci    }
5258bf80f4bSopenharmony_ci
5268bf80f4bSopenharmony_ci    // make the js object keep a strong ref.
5278bf80f4bSopenharmony_ci    // (or give SceneJS ownership? and add dispose hook?)
5288bf80f4bSopenharmony_ci    if (auto tro = GetRootObject(ctx, childJS)) {
5298bf80f4bSopenharmony_ci        if (auto native = tro->GetNativeObject()) {
5308bf80f4bSopenharmony_ci            tro->SetNativeObject(nullptr, false);
5318bf80f4bSopenharmony_ci            tro->SetNativeObject(native, true);
5328bf80f4bSopenharmony_ci            native.reset();
5338bf80f4bSopenharmony_ci        }
5348bf80f4bSopenharmony_ci    }
5358bf80f4bSopenharmony_ci
5368bf80f4bSopenharmony_ci    auto metaobj = GetThisNativeObject(ctx);
5378bf80f4bSopenharmony_ci    if (auto container = interface_cast<META_NS::IContainer>(metaobj)) {
5388bf80f4bSopenharmony_ci        ExecSyncTask([container, childNode]() {
5398bf80f4bSopenharmony_ci            container->Remove(childNode);
5408bf80f4bSopenharmony_ci            childNode->Visible()->SetValue(false);
5418bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
5428bf80f4bSopenharmony_ci        });
5438bf80f4bSopenharmony_ci    }
5448bf80f4bSopenharmony_ci    return ctx.GetUndefined();
5458bf80f4bSopenharmony_ci}
5468bf80f4bSopenharmony_ci
5478bf80f4bSopenharmony_cinapi_value NodeImpl::ClearChildren(NapiApi::FunctionContext<>& ctx)
5488bf80f4bSopenharmony_ci{
5498bf80f4bSopenharmony_ci    auto metaobj = GetThisNativeObject(ctx);
5508bf80f4bSopenharmony_ci    BASE_NS::vector<SCENE_NS::INode::Ptr> removedNodes;
5518bf80f4bSopenharmony_ci    if (auto container = interface_cast<META_NS::IContainer>(metaobj)) {
5528bf80f4bSopenharmony_ci        ExecSyncTask([container, &removedNodes]() {
5538bf80f4bSopenharmony_ci            auto tmp = container->GetAll();
5548bf80f4bSopenharmony_ci            for (auto t : tmp) {
5558bf80f4bSopenharmony_ci                if (auto node = interface_pointer_cast<SCENE_NS::INode>(t)) {
5568bf80f4bSopenharmony_ci                    if (SkipNode(node)) {
5578bf80f4bSopenharmony_ci                        continue;
5588bf80f4bSopenharmony_ci                    }
5598bf80f4bSopenharmony_ci                    container->Remove(node);
5608bf80f4bSopenharmony_ci                    node->Visible()->SetValue(false);
5618bf80f4bSopenharmony_ci                    removedNodes.emplace_back(BASE_NS::move(node));
5628bf80f4bSopenharmony_ci                }
5638bf80f4bSopenharmony_ci            }
5648bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
5658bf80f4bSopenharmony_ci        });
5668bf80f4bSopenharmony_ci        for (auto node : removedNodes) {
5678bf80f4bSopenharmony_ci            if (auto cached = FetchJsObj(node)) {
5688bf80f4bSopenharmony_ci                ResetNativeObj(ctx, cached);
5698bf80f4bSopenharmony_ci            }
5708bf80f4bSopenharmony_ci        }
5718bf80f4bSopenharmony_ci    }
5728bf80f4bSopenharmony_ci    return ctx.GetUndefined();
5738bf80f4bSopenharmony_ci}
5748bf80f4bSopenharmony_ci
5758bf80f4bSopenharmony_ciSCENE_NS::INode::Ptr recurse_children(const SCENE_NS::INode::Ptr startNode, BASE_NS::string_view path)
5768bf80f4bSopenharmony_ci{
5778bf80f4bSopenharmony_ci    SCENE_NS::INode::Ptr node = startNode;
5788bf80f4bSopenharmony_ci    while (node != nullptr) {
5798bf80f4bSopenharmony_ci        node->BuildChildren(SCENE_NS::INode::BuildBehavior::NODE_BUILD_ONLY_DIRECT_CHILDREN);
5808bf80f4bSopenharmony_ci        // see if
5818bf80f4bSopenharmony_ci        if (auto container = interface_cast<META_NS::IContainer>(node)) {
5828bf80f4bSopenharmony_ci            auto pos = path.find('/', 0);
5838bf80f4bSopenharmony_ci            BASE_NS::string_view step = path.substr(0, pos);
5848bf80f4bSopenharmony_ci            node = interface_pointer_cast<SCENE_NS::INode>(container->FindByName(step));
5858bf80f4bSopenharmony_ci            if (node) {
5868bf80f4bSopenharmony_ci                if (pos == BASE_NS::string_view::npos) {
5878bf80f4bSopenharmony_ci                    return node;
5888bf80f4bSopenharmony_ci                }
5898bf80f4bSopenharmony_ci                path = path.substr(pos + 1);
5908bf80f4bSopenharmony_ci            }
5918bf80f4bSopenharmony_ci        }
5928bf80f4bSopenharmony_ci    }
5938bf80f4bSopenharmony_ci    return {};
5948bf80f4bSopenharmony_ci}
5958bf80f4bSopenharmony_cinapi_value NodeImpl::GetNodeByPath(NapiApi::FunctionContext<BASE_NS::string>& ctx)
5968bf80f4bSopenharmony_ci{
5978bf80f4bSopenharmony_ci    BASE_NS::string path = ctx.Arg<0>();
5988bf80f4bSopenharmony_ci    auto meta = GetThisNativeObject(ctx);
5998bf80f4bSopenharmony_ci    if (!meta) {
6008bf80f4bSopenharmony_ci        return ctx.GetNull();
6018bf80f4bSopenharmony_ci    }
6028bf80f4bSopenharmony_ci
6038bf80f4bSopenharmony_ci    META_NS::IObject::Ptr child;
6048bf80f4bSopenharmony_ci    if (auto node = interface_pointer_cast<SCENE_NS::INode>(meta)) {
6058bf80f4bSopenharmony_ci        ExecSyncTask([node, &child, path]() {
6068bf80f4bSopenharmony_ci            // make sure the child objects exist
6078bf80f4bSopenharmony_ci            child = interface_pointer_cast<META_NS::IObject>(recurse_children(node, path));
6088bf80f4bSopenharmony_ci            return META_NS::IAny::Ptr {};
6098bf80f4bSopenharmony_ci        });
6108bf80f4bSopenharmony_ci    }
6118bf80f4bSopenharmony_ci
6128bf80f4bSopenharmony_ci    if (!child) {
6138bf80f4bSopenharmony_ci        // no such child.
6148bf80f4bSopenharmony_ci        return ctx.GetNull();
6158bf80f4bSopenharmony_ci    }
6168bf80f4bSopenharmony_ci
6178bf80f4bSopenharmony_ci    if (auto cached = FetchJsObj(child)) {
6188bf80f4bSopenharmony_ci        // always return the same js object.
6198bf80f4bSopenharmony_ci        return cached;
6208bf80f4bSopenharmony_ci    }
6218bf80f4bSopenharmony_ci
6228bf80f4bSopenharmony_ci    if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) {
6238bf80f4bSopenharmony_ci        CORE_LOG_F("INVALID SCENE!");
6248bf80f4bSopenharmony_ci    }
6258bf80f4bSopenharmony_ci
6268bf80f4bSopenharmony_ci    // create new js object for the native node.
6278bf80f4bSopenharmony_ci    NapiApi::Object argJS(ctx);
6288bf80f4bSopenharmony_ci    napi_value args[] = { scene_.GetValue(), argJS };
6298bf80f4bSopenharmony_ci
6308bf80f4bSopenharmony_ci    return CreateFromNativeInstance(ctx, child, false /*these are owned by the scene*/, BASE_NS::countof(args), args);
6318bf80f4bSopenharmony_ci}
632