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