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 "TextNodeJS.h"
17
18 #include <font/implementation_uids.h>
19 #include <font/intf_font_manager.h>
20 #include <scene/ext/intf_ecs_context.h>
21 #include <scene/ext/intf_ecs_object_access.h>
22 #include <scene/interface/intf_node.h>
23 #include <scene/interface/intf_scene.h>
24 #include <scene/interface/intf_text.h>
25
26 #include <render/implementation_uids.h>
27
28 #include "SceneJS.h"
29
30 namespace {
PrintFontsFromNode(const SCENE_NS::INode::Ptr & someNode)31 void PrintFontsFromNode(const SCENE_NS::INode::Ptr& someNode)
32 {
33 if (auto ecsAccess = interface_pointer_cast<SCENE_NS::IEcsObjectAccess>(someNode)) {
34 if (auto engineClassRegister = ecsAccess->GetEcsObject()->
35 GetScene()->GetEcsContext().GetNativeEcs()->GetClassFactory().GetInterface<CORE_NS::IClassRegister>()) {
36 if (auto* renderClassRegister = CORE_NS::GetInstance<CORE_NS::IClassRegister>(
37 *engineClassRegister, RENDER_NS::UID_RENDER_CONTEXT)) {
38 auto fontManager =
39 CORE_NS::GetInstance<FONT_NS::IFontManager>(*renderClassRegister, FONT_NS::UID_FONT_MANAGER);
40
41 CORE_LOG_E("Fonts");
42 for (auto& face : fontManager->GetTypeFaces()) {
43 CORE_LOG_E("face: \"%s\" family: \"%s\"", BASE_NS::string(face.name).c_str(),
44 BASE_NS::string(face.styleName).c_str());
45 }
46 }
47 }
48 }
49 }
50 } // anonymous namespace
51
Init(napi_env env,napi_value exports)52 void TextNodeJS::Init(napi_env env, napi_value exports)
53 {
54 using namespace NapiApi;
55
56 BASE_NS::vector<napi_property_descriptor> node_props = {
57 GetSetProperty<BASE_NS::string, TextNodeJS, &TextNodeJS::GetText, &TextNodeJS::SetText>("text"),
58 GetSetProperty<BASE_NS::string, TextNodeJS, &TextNodeJS::GetFont, &TextNodeJS::SetFont>("font"),
59 GetSetProperty<NapiApi::Object, TextNodeJS, &TextNodeJS::GetColor, &TextNodeJS::SetColor>("color"),
60 GetSetProperty<float, TextNodeJS, &TextNodeJS::GetFontSize, &TextNodeJS::SetFontSize>("fontSize"),
61 };
62 NodeImpl::GetPropertyDescs(node_props);
63
64 napi_value func;
65 auto status = napi_define_class(env, "TextNode", NAPI_AUTO_LENGTH, BaseObject::ctor<TextNodeJS>(), nullptr,
66 node_props.size(), node_props.data(), &func);
67
68 NapiApi::MyInstanceState* mis;
69 GetInstanceData(env, (void**)&mis);
70 mis->StoreCtor("TextNode", func);
71 }
72
TextNodeJS(napi_env e,napi_callback_info i)73 TextNodeJS::TextNodeJS(napi_env e, napi_callback_info i) : BaseObject<TextNodeJS>(e, i), NodeImpl(NodeImpl::TEXT)
74 {
75 LOG_V("TextNodeJS ++");
76
77 NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object> fromJs(e, i);
78 if (!fromJs) {
79 // no arguments. so internal create.
80 // expecting caller to finish initialization
81 return;
82 }
83
84 {
85 // add the dispose hook to scene. (so that the geometry node is disposed when scene is disposed)
86 NapiApi::Object meJs(fromJs.This());
87 NapiApi::Object scene = fromJs.Arg<0>();
88 if (auto sceneJS = GetJsWrapper<SceneJS>(scene)) {
89 sceneJS->StrongDisposeHook(reinterpret_cast<uintptr_t>(&scene_), meJs);
90 }
91 }
92
93 // java script call.. with arguments
94 scene_ = fromJs.Arg<0>().valueOrDefault();
95 auto scn = GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject());
96 if (scn == nullptr) {
97 // hmm..
98 LOG_F("Invalid scene for TextNodeJS!");
99 return;
100 }
101 NapiApi::Object args = fromJs.Arg<1>();
102
103 auto obj = GetNativeObjectParam<META_NS::IObject>(args);
104 if (obj) {
105 StoreJsObj(obj, fromJs.This());
106 return;
107 }
108
109 // collect parameters
110 NapiApi::Value<BASE_NS::string> name;
111 NapiApi::Value<BASE_NS::string> path;
112 if (auto prm = args.Get("name")) {
113 name = NapiApi::Value<BASE_NS::string>(e, prm);
114 }
115 if (auto prm = args.Get("path")) {
116 path = NapiApi::Value<BASE_NS::string>(e, prm);
117 }
118
119 BASE_NS::string nodePath;
120
121 if (path.IsDefined()) {
122 // create using path
123 nodePath = path.valueOrDefault("");
124 } else if (name.IsDefined()) {
125 // use the name as path (creates under root)
126 nodePath = name.valueOrDefault("");
127 }
128
129 // Create actual node object.
130 SCENE_NS::INode::Ptr node = scn->CreateNode(nodePath, Scene::ClassId::TextNode).GetResult();
131
132 SetNativeObject(interface_pointer_cast<META_NS::IObject>(node), false);
133 node.reset();
134 NapiApi::Object meJs(fromJs.This());
135 StoreJsObj(GetNativeObject(), meJs);
136
137 if (name.IsDefined()) {
138 // set the name of the object. if we were given one
139 meJs.Set("name", name);
140 }
141 }
142
~TextNodeJS()143 TextNodeJS::~TextNodeJS()
144 {
145 LOG_V("TextNodeJS --");
146 }
147
GetInstanceImpl(uint32_t id)148 void* TextNodeJS::GetInstanceImpl(uint32_t id)
149 {
150 if (id == TextNodeJS::ID)
151 return this;
152 return NodeImpl::GetInstanceImpl(id);
153 }
154
DisposeNative(void * sc)155 void TextNodeJS::DisposeNative(void* sc)
156 {
157 if (!disposed_) {
158 LOG_V("TextNodeJS::DisposeNative");
159 disposed_ = true;
160
161 if (auto* sceneJS = static_cast<SceneJS*>(sc)) {
162 sceneJS->ReleaseStrongDispose(reinterpret_cast<uintptr_t>(&scene_));
163 }
164
165 scene_.Reset();
166 }
167 }
168
Finalize(napi_env env)169 void TextNodeJS::Finalize(napi_env env)
170 {
171 DisposeNative(GetJsWrapper<SceneJS>(scene_.GetObject()));
172 BaseObject::Finalize(env);
173 }
174
GetText(NapiApi::FunctionContext<> & ctx)175 napi_value TextNodeJS::GetText(NapiApi::FunctionContext<>& ctx)
176 {
177 if (!validateSceneRef()) {
178 return ctx.GetUndefined();
179 }
180
181 BASE_NS::string name;
182 auto native = GetThisNativeObject(ctx);
183 auto object = interface_pointer_cast<META_NS::IObject>(native);
184 auto node = interface_pointer_cast<SCENE_NS::INode>(native);
185 auto text = interface_pointer_cast<SCENE_NS::IText>(native);
186 if (!object || !node || !text) {
187 LOG_E("NodeImpl not a text node! %p %p %p %p", native.get(), object.get(), node.get(), text.get());
188 return ctx.GetUndefined();
189 }
190
191 auto result = META_NS::GetValue(text->Text());
192
193 return ctx.GetString(result);
194 }
195
SetText(NapiApi::FunctionContext<BASE_NS::string> & ctx)196 void TextNodeJS::SetText(NapiApi::FunctionContext<BASE_NS::string>& ctx)
197 {
198 if (!validateSceneRef()) {
199 return;
200 }
201
202 BASE_NS::string text = ctx.Arg<0>();
203
204 if (auto textNode = interface_pointer_cast<SCENE_NS::IText>(GetThisNativeObject(ctx))) {
205 textNode->Text()->SetValue(text);
206 if (auto node = interface_pointer_cast<SCENE_NS::INode>(textNode)) {
207 PrintFontsFromNode(node);
208 }
209 } else {
210 LOG_W("Unable to set text value to TextNode");
211 }
212 }
213
GetFont(NapiApi::FunctionContext<> & ctx)214 napi_value TextNodeJS::GetFont(NapiApi::FunctionContext<>& ctx)
215 {
216 if (!validateSceneRef()) {
217 return ctx.GetUndefined();
218 }
219
220 auto native = GetThisNativeObject(ctx);
221 auto object = interface_pointer_cast<META_NS::IObject>(native);
222 auto node = interface_pointer_cast<SCENE_NS::INode>(native);
223 auto text = interface_pointer_cast<SCENE_NS::IText>(native);
224 if (!object || !node || !text) {
225 LOG_E("NodeImpl not a text node! %p %p %p %p", native.get(), object.get(), node.get(), text.get());
226 return ctx.GetUndefined();
227 }
228
229 auto result = META_NS::GetValue(text->FontFamily());
230
231 return ctx.GetString(result);
232 }
233
SetFont(NapiApi::FunctionContext<BASE_NS::string> & ctx)234 void TextNodeJS::SetFont(NapiApi::FunctionContext<BASE_NS::string>& ctx)
235 {
236 if (!validateSceneRef()) {
237 return;
238 }
239
240 BASE_NS::string font = ctx.Arg<0>();
241
242 if (auto textNode = interface_pointer_cast<SCENE_NS::IText>(GetThisNativeObject(ctx))) {
243 textNode->FontFamily()->SetValue(font);
244 } else {
245 LOG_W("Unable to set font to TextNode");
246 }
247 }
248
GetColor(NapiApi::FunctionContext<> & ctx)249 napi_value TextNodeJS::GetColor(NapiApi::FunctionContext<>& ctx)
250 {
251 if (!validateSceneRef()) {
252 return ctx.GetUndefined();
253 }
254
255 auto native = GetThisNativeObject(ctx);
256 auto object = interface_pointer_cast<META_NS::IObject>(native);
257 auto node = interface_pointer_cast<SCENE_NS::INode>(native);
258 auto text = interface_pointer_cast<SCENE_NS::IText>(native);
259 if (!object || !node || !text) {
260 LOG_E("NodeImpl not a text node! %p %p %p %p", native.get(), object.get(), node.get(), text.get());
261 return ctx.GetUndefined();
262 }
263
264 if (!color_) {
265 color_ = BASE_NS::make_unique<ColorProxy>(ctx.Env(), text->TextColor());
266 }
267
268 return color_->Value();
269 }
270
SetColor(NapiApi::FunctionContext<NapiApi::Object> & ctx)271 void TextNodeJS::SetColor(NapiApi::FunctionContext<NapiApi::Object>& ctx)
272 {
273 if (!validateSceneRef()) {
274 return;
275 }
276
277 auto native = GetThisNativeObject(ctx);
278 auto object = interface_pointer_cast<META_NS::IObject>(native);
279 auto node = interface_pointer_cast<SCENE_NS::INode>(native);
280 auto text = interface_pointer_cast<SCENE_NS::IText>(native);
281 if (!object || !node || !text) {
282 LOG_E("NodeImpl not a text node! %p %p %p %p", native.get(), object.get(), node.get(), text.get());
283 return;
284 }
285
286 if (!color_) {
287 color_ = BASE_NS::make_unique<ColorProxy>(ctx.Env(), text->TextColor());
288 }
289
290 color_->SetValue(ctx.Arg<0>());
291 }
292
GetFontSize(NapiApi::FunctionContext<> & ctx)293 napi_value TextNodeJS::GetFontSize(NapiApi::FunctionContext<>& ctx)
294 {
295 if (!validateSceneRef()) {
296 return ctx.GetUndefined();
297 }
298
299 auto native = GetThisNativeObject(ctx);
300 auto object = interface_pointer_cast<META_NS::IObject>(native);
301 auto node = interface_pointer_cast<SCENE_NS::INode>(native);
302 auto text = interface_pointer_cast<SCENE_NS::IText>(native);
303 if (!object || !node || !text) {
304 LOG_E("NodeImpl not a text node! %p %p %p %p", native.get(), object.get(), node.get(), text.get());
305 return ctx.GetUndefined();
306 }
307
308 auto result = META_NS::GetValue(text->FontSize());
309
310 return ctx.GetNumber(result);
311 }
312
SetFontSize(NapiApi::FunctionContext<float> & ctx)313 void TextNodeJS::SetFontSize(NapiApi::FunctionContext<float>& ctx)
314 {
315 if (!validateSceneRef()) {
316 return;
317 }
318
319 float fontSize = ctx.Arg<0>();
320
321 if (auto textNode = interface_pointer_cast<SCENE_NS::IText>(GetThisNativeObject(ctx))) {
322 textNode->FontSize()->SetValue(fontSize);
323 } else {
324 LOG_W("Unable to set font size to TextNode");
325 }
326 }
327