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 "ImageJS.h"
17
18#include <scene_plugin/interface/intf_scene.h>
19#include "SceneJS.h"
20
21using namespace SCENE_NS;
22
23void ImageJS::Init(napi_env env, napi_value exports)
24{
25    using namespace NapiApi;
26    // clang-format off
27    BASE_NS::vector<napi_property_descriptor> props;
28    SceneResourceImpl::GetPropertyDescs(props);
29    props.emplace_back(GetProperty<uint32_t, ImageJS, &ImageJS::GetWidth>("width"));
30    props.emplace_back(GetProperty<uint32_t, ImageJS, &ImageJS::GetHeight>("height"));
31
32    // clang-format on
33
34    napi_value func;
35    auto status = napi_define_class(
36        env, "Image", NAPI_AUTO_LENGTH, BaseObject::ctor<ImageJS>(), nullptr, props.size(), props.data(), &func);
37
38    NapiApi::MyInstanceState* mis;
39    napi_get_instance_data(env, (void**)&mis);
40    mis->StoreCtor("Image", func);
41}
42
43void ImageJS::DisposeNative()
44{
45    if (!disposed_) {
46        disposed_ = true;
47        LOG_F("ImageJS::DisposeNative");
48        NapiApi::Object obj = scene_.GetObject();
49        auto* tro = obj.Native<TrueRootObject>();
50        SceneJS* sceneJS;
51        if (tro) {
52            sceneJS = ((SceneJS*)tro->GetInstanceImpl(SceneJS::ID));
53            sceneJS->ReleaseDispose((uintptr_t)&scene_);
54        }
55        // reset the native object refs
56        if (auto bitmap = interface_pointer_cast<IBitmap>(GetNativeObject())) {
57            SetNativeObject(nullptr, false);
58            SetNativeObject(nullptr, true);
59            if (obj) {
60                BASE_NS::string uri = FetchResourceOrUri(obj.GetEnv(), uriRef_.GetObject());
61                ExecSyncTask([uri, sceneJS]() -> META_NS::IAny::Ptr {
62                    sceneJS->StoreBitmap(uri, nullptr);
63                    return {};
64                });
65            }
66        } else {
67            SetNativeObject(nullptr, false);
68        }
69        scene_.Reset();
70    }
71}
72void* ImageJS::GetInstanceImpl(uint32_t id)
73{
74    if (id == ImageJS::ID) {
75        return this;
76    }
77    return SceneResourceImpl::GetInstanceImpl(id);
78}
79void ImageJS::Finalize(napi_env env)
80{
81    DisposeNative();
82    BaseObject<ImageJS>::Finalize(env);
83}
84
85ImageJS::ImageJS(napi_env e, napi_callback_info i)
86    : BaseObject<ImageJS>(e, i), SceneResourceImpl(SceneResourceType::IMAGE)
87{
88    NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object> fromJs(e, i);
89    NapiApi::Object meJs(e, fromJs.This());
90    NapiApi::Object scene = fromJs.Arg<0>(); // access to owning scene...
91    scene_ = { scene };
92    if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) {
93        CORE_LOG_F("INVALID SCENE!");
94    }
95
96    auto* tro = scene.Native<TrueRootObject>();
97    auto* sceneJS = ((SceneJS*)tro->GetInstanceImpl(SceneJS::ID));
98    NapiApi::Object args = fromJs.Arg<1>();
99
100    SCENE_NS::IBitmap::Ptr bitmap;
101
102    // check if we got the NativeObject as parameter.
103    bitmap = GetNativeObjectParam<SCENE_NS::IBitmap>(args);
104
105    if (auto prm = args.Get("uri")) {
106        uriRef_ = { e, prm };
107        BASE_NS::string uri = FetchResourceOrUri(e, prm);
108        if (!uri.empty()) {
109            SetUri(uriRef_);
110        }
111        if (!bitmap) {
112            // if we did not receive it already...
113            bitmap = sceneJS->FetchBitmap(uri);
114        }
115    }
116    sceneJS->DisposeHook((uintptr_t)&scene_, meJs);
117    auto obj = interface_pointer_cast<META_NS::IObject>(bitmap);
118    SetNativeObject(obj, false);
119    StoreJsObj(obj, meJs);
120
121    BASE_NS::string name;
122    if (auto prm = args.Get<BASE_NS::string>("name")) {
123        name = prm;
124    } else {
125        if (auto named = interface_cast<META_NS::INamed>(obj)) {
126            name = named->Name()->GetValue();
127        }
128    }
129    meJs.Set("name", name);
130}
131
132ImageJS::~ImageJS()
133{
134    DisposeNative();
135}
136
137napi_value ImageJS::GetWidth(NapiApi::FunctionContext<>& ctx)
138{
139    uint32_t width = 0;
140    if (auto env = interface_cast<IBitmap>(GetNativeObject())) {
141        ExecSyncTask([env, &width]() {
142            width = env->Size()->GetValue().x;
143            return META_NS::IAny::Ptr {};
144        });
145    }
146    napi_value value;
147    napi_create_uint32(ctx, width, &value);
148    return value;
149}
150
151napi_value ImageJS::GetHeight(NapiApi::FunctionContext<>& ctx)
152{
153    uint32_t height = 0;
154    if (auto env = interface_cast<IBitmap>(GetNativeObject())) {
155        ExecSyncTask([env, &height]() {
156            height = env->Size()->GetValue().y;
157            return META_NS::IAny::Ptr {};
158        });
159    }
160    napi_value value;
161    napi_create_uint32(ctx, height, &value);
162    return value;
163}
164