1 /*
2  * Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development 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 <string>
17 
18 #include "interfaces/napi/kits/utils/napi_utils.h"
19 #include "napi/native_api.h"
20 #include "napi/native_engine/native_value.h"
21 #include "napi/native_node_api.h"
22 
23 #include "bridge/common/utils/engine_helper.h"
24 #include "bridge/js_frontend/engine/common/js_engine.h"
25 #include "core/common/font_manager.h"
26 
27 namespace OHOS::Ace::Napi {
28 namespace {
29 constexpr size_t STR_BUFFER_SIZE = 1024;
30 constexpr int32_t FONT_INFO_INDEX_PATH = 0;
31 constexpr int32_t FONT_INFO_INDEX_POST_SCRIPT_NAME = 1;
32 constexpr int32_t FONT_INFO_INDEX_FULL_NAME = 2;
33 constexpr int32_t FONT_INFO_INDEX_FAMILY = 3;
34 constexpr int32_t FONT_INFO_INDEX_SUB_FAMILY = 4;
35 constexpr int32_t FONT_INFO_INDEX_WEIGHT = 5;
36 constexpr int32_t FONT_INFO_INDEX_WIDTH = 6;
37 constexpr int32_t FONT_INFO_INDEX_ITALIC = 7;
38 constexpr int32_t FONT_INFO_INDEX_MONOSPACE = 8;
39 constexpr int32_t FONT_INFO_INDEX_SYMBOLIC = 9;
40 constexpr int32_t FONT_INFO_INDEX_MAX = 10;
41 }
42 
ParseFamilyNameOrSrc(napi_env env,napi_value familyNameOrSrcNApi,std::string & familyNameOrSrc,napi_valuetype valueType,ResourceInfo & info)43 static bool ParseFamilyNameOrSrc(napi_env env, napi_value familyNameOrSrcNApi, std::string& familyNameOrSrc,
44     napi_valuetype valueType, ResourceInfo& info)
45 {
46     napi_typeof(env, familyNameOrSrcNApi, &valueType);
47     if (valueType == napi_string) {
48         size_t nameLen = 0;
49         napi_get_value_string_utf8(env, familyNameOrSrcNApi, nullptr, 0, &nameLen);
50         std::unique_ptr<char[]> name = std::make_unique<char[]>(nameLen + 1);
51         napi_get_value_string_utf8(env, familyNameOrSrcNApi, name.get(), nameLen + 1, &nameLen);
52         familyNameOrSrc = name.get();
53     } else if (valueType == napi_object) {
54         if (!ParseResourceParam(env, familyNameOrSrcNApi, info)) {
55             return false;
56         }
57         if (!ParseString(info, familyNameOrSrc)) {
58             return false;
59         }
60     } else {
61         return false;
62     }
63     return true;
64 }
65 
JSRegisterFont(napi_env env,napi_callback_info info)66 static napi_value JSRegisterFont(napi_env env, napi_callback_info info)
67 {
68     size_t argc = 1;
69     napi_value argv = nullptr;
70     napi_value thisVar = nullptr;
71     void* data = nullptr;
72     napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
73 
74     napi_value familyNameNApi = nullptr;
75     napi_value familySrcNApi = nullptr;
76     std::string familyName;
77     std::string familySrc;
78 
79     napi_valuetype valueType = napi_undefined;
80     napi_typeof(env, argv, &valueType);
81     if (valueType == napi_object) {
82         napi_get_named_property(env, argv, "familyName", &familyNameNApi);
83         napi_get_named_property(env, argv, "familySrc", &familySrcNApi);
84     } else {
85         return nullptr;
86     }
87 
88     ResourceInfo resourceInfo;
89     if (!ParseFamilyNameOrSrc(env, familyNameNApi, familyName, valueType, resourceInfo)) {
90         return nullptr;
91     }
92     if (!ParseFamilyNameOrSrc(env, familySrcNApi, familySrc, valueType, resourceInfo)) {
93         return nullptr;
94     }
95 
96     std::string bundleName = resourceInfo.bundleName.has_value() ? resourceInfo.bundleName.value() : "";
97     std::string moduleName = resourceInfo.moduleName.has_value() ? resourceInfo.moduleName.value() : "";
98     auto container = Container::CurrentSafely();
99     if (bundleName.empty() && container) {
100         bundleName = container->GetBundleName();
101     }
102     if (moduleName.empty() && container) {
103         moduleName = container->GetModuleName();
104     }
105     auto delegate = EngineHelper::GetCurrentDelegateSafely();
106     if (!delegate) {
107         return nullptr;
108     }
109     TAG_LOGI(AceLogTag::ACE_FONT, "begin to register font.");
110     delegate->RegisterFont(familyName, familySrc, bundleName, moduleName);
111     return nullptr;
112 }
113 
JSgetSystemFontList(napi_env env,napi_callback_info info)114 static napi_value JSgetSystemFontList(napi_env env, napi_callback_info info)
115 {
116     napi_value arrayResult = nullptr;
117     napi_create_array(env, &arrayResult);
118     bool isArray = false;
119     if (napi_is_array(env, arrayResult, &isArray) != napi_ok || !isArray) {
120         return arrayResult;
121     }
122     std::vector<std::string> fontList;
123     auto delegate = EngineHelper::GetCurrentDelegateSafely();
124     if (!delegate) {
125         return nullptr;
126     }
127     delegate->GetSystemFontList(fontList);
128 
129     int32_t index = 0;
130     for (const std::string& font : fontList) {
131         napi_value result = nullptr;
132         napi_create_string_utf8(env, font.c_str(), font.length(), &result);
133         napi_set_element(env, arrayResult, index++, result);
134     }
135     return arrayResult;
136 }
137 
JSgetFontByName(napi_env env,napi_callback_info info)138 static napi_value JSgetFontByName(napi_env env, napi_callback_info info)
139 {
140     size_t argc = 1;
141     napi_value argv = nullptr;
142     napi_value thisVar = nullptr;
143     void* data = nullptr;
144     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data));
145     NAPI_ASSERT(env, argc == 1, "requires 1 parameter");
146 
147     napi_valuetype type;
148     NAPI_CALL(env, napi_typeof(env, argv, &type));
149     NAPI_ASSERT(env, type == napi_string, "type mismatch");
150     char fontName[STR_BUFFER_SIZE] = { 0 };
151     size_t len = 0;
152     napi_get_value_string_utf8(env, argv, fontName, STR_BUFFER_SIZE, &len);
153     NAPI_ASSERT(env, len < STR_BUFFER_SIZE, "condition string too long");
154     std::string fontNameStr(fontName, len);
155 
156     FontInfo fontInfo;
157     auto delegate = EngineHelper::GetCurrentDelegateSafely();
158     if (!delegate) {
159         return nullptr;
160     }
161     if (!delegate->GetSystemFont(fontNameStr, fontInfo)) {
162         return nullptr;
163     }
164 
165     napi_value resultArray[FONT_INFO_INDEX_MAX] = { 0 };
166     napi_create_string_utf8(env, fontInfo.path.c_str(), NAPI_AUTO_LENGTH, &resultArray[FONT_INFO_INDEX_PATH]);
167     napi_create_string_utf8(env, fontInfo.postScriptName.c_str(), NAPI_AUTO_LENGTH,
168         &resultArray[FONT_INFO_INDEX_POST_SCRIPT_NAME]);
169     napi_create_string_utf8(env, fontInfo.fullName.c_str(), NAPI_AUTO_LENGTH, &resultArray[FONT_INFO_INDEX_FULL_NAME]);
170     napi_create_string_utf8(env, fontInfo.family.c_str(), NAPI_AUTO_LENGTH, &resultArray[FONT_INFO_INDEX_FAMILY]);
171     napi_create_string_utf8(env, fontInfo.subfamily.c_str(), NAPI_AUTO_LENGTH,
172         &resultArray[FONT_INFO_INDEX_SUB_FAMILY]);
173     napi_create_int32(env, fontInfo.weight, &resultArray[FONT_INFO_INDEX_WEIGHT]);
174     napi_create_int32(env, fontInfo.width, &resultArray[FONT_INFO_INDEX_WIDTH]);
175     napi_get_boolean(env, fontInfo.italic, &resultArray[FONT_INFO_INDEX_ITALIC]);
176     napi_get_boolean(env, fontInfo.monoSpace, &resultArray[FONT_INFO_INDEX_MONOSPACE]);
177     napi_get_boolean(env, fontInfo.symbolic, &resultArray[FONT_INFO_INDEX_SYMBOLIC]);
178 
179     napi_value result = nullptr;
180     napi_create_object(env, &result);
181     napi_set_named_property(env, result, "path", resultArray[FONT_INFO_INDEX_PATH]);
182     napi_set_named_property(env, result, "postScriptName", resultArray[FONT_INFO_INDEX_POST_SCRIPT_NAME]);
183     napi_set_named_property(env, result, "fullName", resultArray[FONT_INFO_INDEX_FULL_NAME]);
184     napi_set_named_property(env, result, "family", resultArray[FONT_INFO_INDEX_FAMILY]);
185     napi_set_named_property(env, result, "subfamily", resultArray[FONT_INFO_INDEX_SUB_FAMILY]);
186     napi_set_named_property(env, result, "weight", resultArray[FONT_INFO_INDEX_WEIGHT]);
187     napi_set_named_property(env, result, "width", resultArray[FONT_INFO_INDEX_WIDTH]);
188     napi_set_named_property(env, result, "italic", resultArray[FONT_INFO_INDEX_ITALIC]);
189     napi_set_named_property(env, result, "monoSpace", resultArray[FONT_INFO_INDEX_MONOSPACE]);
190     napi_set_named_property(env, result, "symbolic", resultArray[FONT_INFO_INDEX_SYMBOLIC]);
191 
192     return result;
193 }
194 
GetUIFontGenericInfo(napi_env env,const FontConfigJsonInfo & fontConfigJsonInfo)195 static napi_value GetUIFontGenericInfo(napi_env env, const FontConfigJsonInfo& fontConfigJsonInfo)
196 {
197     napi_value genericSetResult = nullptr;
198     napi_create_array(env, &genericSetResult);
199     int32_t index = 0;
200     for (const FontGenericInfo& generic: fontConfigJsonInfo.genericSet) {
201         napi_value genericResult = nullptr;
202         napi_create_object(env, &genericResult);
203         napi_value familyResult = nullptr;
204         napi_create_string_utf8(env, generic.familyName.c_str(), generic.familyName.length(), &familyResult);
205         napi_value aliasSetResult = nullptr;
206         napi_create_array(env, &aliasSetResult);
207         int32_t index2 = 0;
208         for (const AliasInfo& alias: generic.aliasSet) {
209             napi_value aliasResult = nullptr;
210             napi_create_object(env, &aliasResult);
211             napi_value familyNameResult = nullptr;
212             napi_create_string_utf8(env, alias.familyName.c_str(), alias.familyName.length(), &familyNameResult);
213             napi_value weightResult = nullptr;
214             napi_create_int32(env, alias.weight, &weightResult);
215             napi_set_named_property(env, aliasResult, "name", familyNameResult);
216             napi_set_named_property(env, aliasResult, "weight", weightResult);
217             napi_set_element(env, aliasSetResult, index2++, aliasResult);
218         }
219         index2 = 0;
220         napi_value adjustSetResult = nullptr;
221         napi_create_array(env, &adjustSetResult);
222         for (const AdjustInfo& adjust: generic.adjustSet) {
223             napi_value adjustResult = nullptr;
224             napi_create_object(env, &adjustResult);
225             napi_value weightResult = nullptr;
226             napi_create_int32(env, adjust.origValue, &weightResult);
227             napi_value toResult = nullptr;
228             napi_create_int32(env, adjust.newValue, &toResult);
229             napi_set_named_property(env, adjustResult, "weight", weightResult);
230             napi_set_named_property(env, adjustResult, "to", toResult);
231             napi_set_element(env, adjustSetResult, index2++, adjustResult);
232         }
233         napi_set_named_property(env, genericResult, "family", familyResult);
234         napi_set_named_property(env, genericResult, "alias", aliasSetResult);
235         napi_set_named_property(env, genericResult, "adjust", adjustSetResult);
236         napi_set_element(env, genericSetResult, index++, genericResult);
237     }
238     return genericSetResult;
239 }
240 
GetUIFontFallbackInfo(napi_env env,const FontConfigJsonInfo & fontConfigJsonInfo)241 static napi_value GetUIFontFallbackInfo(napi_env env, const FontConfigJsonInfo& fontConfigJsonInfo)
242 {
243     napi_value fallbackGroupSetResult = nullptr;
244     napi_create_array(env, &fallbackGroupSetResult);
245     int32_t index = 0;
246     for (const FallbackGroup& fallbackGroup: fontConfigJsonInfo.fallbackGroupSet) {
247         napi_value fallbackGroupResult = nullptr;
248         napi_create_object(env, &fallbackGroupResult);
249         napi_value fontSetNameResult = nullptr;
250         napi_create_string_utf8(env, fallbackGroup.groupName.c_str(),
251             fallbackGroup.groupName.length(), &fontSetNameResult);
252         napi_value fallbackListResult = nullptr;
253         napi_create_array(env, &fallbackListResult);
254         int32_t index2 = 0;
255         for (const FallbackInfo& fallback: fallbackGroup.fallbackInfoSet) {
256             napi_value fallbackResult = nullptr;
257             napi_create_object(env, &fallbackResult);
258             napi_value familyResult = nullptr;
259             napi_create_string_utf8(env, fallback.familyName.c_str(), fallback.familyName.length(), &familyResult);
260             napi_value languageResult = nullptr;
261             napi_create_string_utf8(env, fallback.font.c_str(), fallback.font.length(), &languageResult);
262 
263             napi_set_named_property(env, fallbackResult, "language", languageResult);
264             napi_set_named_property(env, fallbackResult, "family", familyResult);
265             napi_set_element(env, fallbackListResult, index2++, fallbackResult);
266         }
267         napi_set_named_property(env, fallbackGroupResult, "fontSetName", fontSetNameResult);
268         napi_set_named_property(env, fallbackGroupResult, "fallback", fallbackListResult);
269         napi_set_element(env, fallbackGroupSetResult, index++, fallbackGroupResult);
270     }
271     return fallbackGroupSetResult;
272 }
273 
JsGetUIFontConfig(napi_env env,napi_callback_info info)274 static napi_value JsGetUIFontConfig(napi_env env, napi_callback_info info)
275 {
276     FontConfigJsonInfo fontConfigJsonInfo;
277     auto delegate = EngineHelper::GetCurrentDelegateSafely();
278     if (!delegate) {
279         return nullptr;
280     }
281     delegate->GetUIFontConfig(fontConfigJsonInfo);
282     napi_value result = nullptr;
283     napi_create_object(env, &result);
284     napi_value fontDirSetResult = nullptr;
285     napi_create_array(env, &fontDirSetResult);
286     int32_t index = 0;
287     for (const std::string& fontDir : fontConfigJsonInfo.fontDirSet) {
288         napi_value fontDirResult = nullptr;
289         napi_create_string_utf8(env, fontDir.c_str(), fontDir.length(), &fontDirResult);
290         napi_set_element(env, fontDirSetResult, index++, fontDirResult);
291     }
292     napi_value genericSetResult = GetUIFontGenericInfo(env, fontConfigJsonInfo);
293     napi_value fallbackGroupSetResult = GetUIFontFallbackInfo(env, fontConfigJsonInfo);
294 
295     napi_set_named_property(env, result, "fontDir", fontDirSetResult);
296     napi_set_named_property(env, result, "generic", genericSetResult);
297     napi_set_named_property(env, result, "fallbackGroups", fallbackGroupSetResult);
298     return result;
299 }
300 
FontExport(napi_env env,napi_value exports)301 static napi_value FontExport(napi_env env, napi_value exports)
302 {
303     napi_property_descriptor fontDesc[] = {
304         DECLARE_NAPI_FUNCTION("registerFont", JSRegisterFont),
305         DECLARE_NAPI_FUNCTION("getSystemFontList", JSgetSystemFontList),
306         DECLARE_NAPI_FUNCTION("getFontByName", JSgetFontByName),
307         DECLARE_NAPI_FUNCTION("getUIFontConfig", JsGetUIFontConfig)
308     };
309     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(fontDesc) / sizeof(fontDesc[0]), fontDesc));
310     return exports;
311 }
312 
313 static napi_module fontModule = {
314     .nm_version = 1,
315     .nm_flags = 0,
316     .nm_filename = nullptr,
317     .nm_register_func = FontExport,
318     .nm_modname = "font",
319     .nm_priv = ((void*)0),
320     .reserved = { 0 },
321 };
322 
FontRegister()323 extern "C" __attribute__((constructor)) void FontRegister()
324 {
325     napi_module_register(&fontModule);
326 }
327 } // namespace OHOS::Ace::Napi
328