• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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