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