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 #include "ImageJS.h"
16
17 #include <scene/interface/intf_scene.h>
18
19 #include "ParamParsing.h"
20 #include "RenderContextJS.h"
21 #include "SceneJS.h"
22
23 using namespace SCENE_NS;
24
Init(napi_env env,napi_value exports)25 void ImageJS::Init(napi_env env, napi_value exports)
26 {
27 using namespace NapiApi;
28 // clang-format off
29 BASE_NS::vector<napi_property_descriptor> props;
30 SceneResourceImpl::GetPropertyDescs(props);
31 props.emplace_back(GetProperty<uint32_t, ImageJS, &ImageJS::GetWidth>("width"));
32 props.emplace_back(GetProperty<uint32_t, ImageJS, &ImageJS::GetHeight>("height"));
33
34 // clang-format on
35
36 napi_value func;
37 auto status = napi_define_class(
38 env, "Image", NAPI_AUTO_LENGTH, BaseObject::ctor<ImageJS>(), nullptr, props.size(), props.data(), &func);
39
40 NapiApi::MyInstanceState *mis;
41 NapiApi::MyInstanceState::GetInstance(env, (void **)&mis);
42 if (mis) {
43 mis->StoreCtor("Image", func);
44 }
45 }
46
DisposeNative(void * sc)47 void ImageJS::DisposeNative(void *sc)
48 {
49 if (!disposed_) {
50 disposed_ = true;
51 LOG_V("ImageJS::DisposeNative");
52
53 if (sc && resources_) {
54 resources_->ReleaseDispose(reinterpret_cast<uintptr_t>(&scene_));
55
56 if (BASE_NS::string uri = ExtractUri(uri_.GetObject()); !uri.empty()) {
57 ExecSyncTask([uri, resources = resources_]() -> META_NS::IAny::Ptr {
58 if (resources) {
59 resources->StoreBitmap(uri, nullptr);
60 }
61 return {};
62 });
63 }
64 }
65
66 UnsetNativeObject();
67 scene_.Reset();
68 resources_.reset();
69 }
70 }
GetInstanceImpl(uint32_t id)71 void *ImageJS::GetInstanceImpl(uint32_t id)
72 {
73 if (id == ImageJS::ID)
74 return this;
75 return SceneResourceImpl::GetInstanceImpl(id);
76 }
Finalize(napi_env env)77 void ImageJS::Finalize(napi_env env)
78 {
79 DisposeNative(scene_.GetObject().GetJsWrapper<SceneJS>());
80 BaseObject::Finalize(env);
81 }
82
ImageJS(napi_env e,napi_callback_info i)83 ImageJS::ImageJS(napi_env e, napi_callback_info i) : BaseObject(e, i), SceneResourceImpl(SceneResourceType::IMAGE)
84 {
85 NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object> fromJs(e, i);
86 NapiApi::Object meJs(fromJs.This());
87 NapiApi::Object renderContext = fromJs.Arg<0>(); // access to owning context...
88 scene_ = { renderContext };
89 if (!scene_.GetObject().GetJsWrapper<RenderContextJS>()) {
90 LOG_F("Invalid render context for ImageJS");
91 }
92
93 if (const auto renderContextJs = renderContext.GetJsWrapper<RenderContextJS>()) {
94 resources_ = renderContextJs->GetResources();
95 if (resources_) {
96 resources_->DisposeHook(reinterpret_cast<uintptr_t>(&scene_), meJs);
97 }
98 }
99
100 if (!GetNativeObject<SCENE_NS::IBitmap>()) {
101 LOG_E("Cannot finish creating an image: Native image object missing");
102 assert(false);
103 return;
104 }
105
106 NapiApi::Object args = fromJs.Arg<1>();
107 if (auto prm = args.Get("uri")) {
108 NapiApi::Object resType = args.Get<NapiApi::Object>("uri");
109 BASE_NS::string uriType = args.Get<BASE_NS::string>("uri");
110 BASE_NS::string uri = ExtractUri(uriType);
111 if (uri.empty()) {
112 uri = ExtractUri(resType);
113 }
114 if (!uri.empty()) {
115 if (!resType) {
116 // raw string then.. make it "resource" / "rawfile" if possible.
117 if (uri.find("OhosRawFile://") == 0) {
118 // we can only convert "OhosRawFile://" type uris back to "resource" objects.
119 NapiApi::Env env(e);
120 napi_value global;
121 napi_get_global(env, &global);
122 NapiApi::Object g(env, global);
123 napi_value func = g.Get("$rawfile");
124 NapiApi::Function f(env, func);
125 if (f) {
126 BASE_NS::string noschema(uri.substr(14)); // 14: length
127 napi_value arg = env.GetString(noschema);
128 napi_value res = f.Invoke(g, 1, &arg);
129 SetUri(NapiApi::StrongRef(env, res));
130 }
131 }
132 } else {
133 SetUri(NapiApi::StrongRef(resType));
134 }
135 }
136 }
137
138 if (const auto name = ExtractName(args); !name.empty()) {
139 meJs.Set("name", name);
140 }
141 }
142
~ImageJS()143 ImageJS::~ImageJS()
144 {
145 DisposeNative(nullptr);
146 }
147
GetWidth(NapiApi::FunctionContext<> & ctx)148 napi_value ImageJS::GetWidth(NapiApi::FunctionContext<> &ctx)
149 {
150 if (!validateSceneRef()) {
151 return ctx.GetUndefined();
152 }
153 uint32_t width = 0;
154 if (auto env = interface_cast<IBitmap>(GetNativeObject())) {
155 width = env->Size()->GetValue().x;
156 }
157 return ctx.GetNumber(width);
158 }
159
GetHeight(NapiApi::FunctionContext<> & ctx)160 napi_value ImageJS::GetHeight(NapiApi::FunctionContext<> &ctx)
161 {
162 if (!validateSceneRef()) {
163 return ctx.GetUndefined();
164 }
165 uint32_t height = 0;
166 if (auto env = interface_cast<IBitmap>(GetNativeObject())) {
167 height = env->Size()->GetValue().y;
168 }
169 return ctx.GetNumber(height);
170 }
171