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 <fstream>
17 #include "js_fontcollection.h"
18
19 #include "ability.h"
20 #include "napi_async_work.h"
21
22 namespace OHOS::Rosen {
23 namespace {
24 constexpr size_t FILE_HEAD_LENGTH = 7; // 7 is the size of "file://"
25 const std::string CLASS_NAME = "FontCollection";
26 const int32_t GLOBAL_ERROR = 10000;
27 struct FontArgumentsConcreteContext : public ContextBase {
28 std::string familyName;
29 std::string filePath;
30 ResourceInfo info;
31 };
32
ParseContextFilePath(napi_env env,napi_value * argv,sptr<FontArgumentsConcreteContext> context)33 bool ParseContextFilePath(napi_env env, napi_value* argv, sptr<FontArgumentsConcreteContext> context)
34 {
35 napi_valuetype valueType = napi_undefined;
36 napi_typeof(env, argv[ARGC_ONE], &valueType);
37
38 if (valueType == napi_object) {
39 return false;
40 } else if (valueType == napi_string) {
41 if (!ConvertFromJsValue(env, argv[ARGC_ONE], context->filePath)) {
42 std::string errMessage("Failed to convert file path:");
43 errMessage += context->filePath;
44 context->status = napi_invalid_arg;
45 context->errMessage = errMessage;
46 (context)->errCode = static_cast<int32_t>(TextErrorCode::ERROR_INVALID_PARAM);
47 TEXT_LOGE("%{public}s", errMessage.c_str());
48 }
49 }
50 return true;
51 }
52 }
53
54 std::mutex JsFontCollection::constructorMutex_;
55 thread_local napi_ref JsFontCollection::constructor_ = nullptr;
56
Constructor(napi_env env,napi_callback_info info)57 napi_value JsFontCollection::Constructor(napi_env env, napi_callback_info info)
58 {
59 size_t argCount = 0;
60 napi_value jsThis = nullptr;
61 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
62 if (status != napi_ok) {
63 TEXT_LOGE("Failed to get params");
64 return nullptr;
65 }
66
67 JsFontCollection* jsFontCollection = new(std::nothrow) JsFontCollection();
68 if (jsFontCollection == nullptr) {
69 TEXT_LOGE("Failed to new font collection");
70 return nullptr;
71 }
72 status = napi_wrap(env, jsThis, jsFontCollection,
73 JsFontCollection::Destructor, nullptr, nullptr);
74 if (status != napi_ok) {
75 delete jsFontCollection;
76 TEXT_LOGE("Failed to wrap font collection");
77 return nullptr;
78 }
79 return jsThis;
80 }
81
Init(napi_env env,napi_value exportObj)82 napi_value JsFontCollection::Init(napi_env env, napi_value exportObj)
83 {
84 if (!CreateConstructor(env)) {
85 TEXT_LOGE("Failed to create constructor");
86 return nullptr;
87 }
88 napi_value constructor = nullptr;
89 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
90 if (status != napi_ok) {
91 TEXT_LOGE("Failed to get reference, ret %{public}d", status);
92 return nullptr;
93 }
94
95 status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
96 if (status != napi_ok) {
97 TEXT_LOGE("Failed to set named property");
98 return nullptr;
99 }
100 return exportObj;
101 }
102
CreateConstructor(napi_env env)103 bool JsFontCollection::CreateConstructor(napi_env env)
104 {
105 std::lock_guard<std::mutex> lock(constructorMutex_);
106 if (constructor_) {
107 return true;
108 }
109 napi_property_descriptor properties[] = {
110 DECLARE_NAPI_STATIC_FUNCTION("getGlobalInstance", JsFontCollection::GetGlobalInstance),
111 DECLARE_NAPI_FUNCTION("loadFontSync", JsFontCollection::LoadFontSync),
112 DECLARE_NAPI_FUNCTION("clearCaches", JsFontCollection::ClearCaches),
113 DECLARE_NAPI_FUNCTION("loadFont", JsFontCollection::LoadFontAsync),
114 DECLARE_NAPI_FUNCTION("unloadFontSync", JsFontCollection::UnloadFontSync),
115 DECLARE_NAPI_FUNCTION("unloadFont", JsFontCollection::UnloadFontAsync),
116 };
117
118 napi_value constructor = nullptr;
119 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
120 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
121 if (status != napi_ok) {
122 TEXT_LOGE("Failed to define class, ret %{public}d", status);
123 return false;
124 }
125
126 status = napi_create_reference(env, constructor, 1, &constructor_);
127 if (status != napi_ok) {
128 TEXT_LOGE("Failed to create reference, ret %{public}d", status);
129 return false;
130 }
131 return true;
132 }
133
Destructor(napi_env env,void * nativeObject,void * finalize)134 void JsFontCollection::Destructor(napi_env env, void* nativeObject, void* finalize)
135 {
136 (void)finalize;
137 if (nativeObject != nullptr) {
138 JsFontCollection* napi = reinterpret_cast<JsFontCollection*>(nativeObject);
139 delete napi;
140 }
141 }
142
JsFontCollection()143 JsFontCollection::JsFontCollection()
144 {
145 fontcollection_ = OHOS::Rosen::FontCollection::From(nullptr);
146 }
147
GetFontCollection()148 std::shared_ptr<FontCollection> JsFontCollection::GetFontCollection()
149 {
150 return fontcollection_;
151 }
152
GetGlobalInstance(napi_env env,napi_callback_info info)153 napi_value JsFontCollection::GetGlobalInstance(napi_env env, napi_callback_info info)
154 {
155 if (!CreateConstructor(env)) {
156 TEXT_LOGE("Failed to create constructor");
157 return nullptr;
158 }
159 napi_value constructor = nullptr;
160 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
161 if (status != napi_ok || !constructor) {
162 TEXT_LOGE("Failed to get constructor object");
163 return nullptr;
164 }
165
166 napi_value object = nullptr;
167 status = napi_new_instance(env, constructor, 0, nullptr, &object);
168 if (status != napi_ok || !object) {
169 TEXT_LOGE("Failed to new instance");
170 return nullptr;
171 }
172
173 JsFontCollection* jsFontCollection = nullptr;
174 status = napi_unwrap(env, object, reinterpret_cast<void**>(&jsFontCollection));
175 if (status != napi_ok || !jsFontCollection) {
176 TEXT_LOGE("Failed to unwrap font collection");
177 return nullptr;
178 }
179 jsFontCollection->fontcollection_ = OHOS::Rosen::FontCollection::Create();
180
181 return object;
182 }
183
LoadFontSync(napi_env env,napi_callback_info info)184 napi_value JsFontCollection::LoadFontSync(napi_env env, napi_callback_info info)
185 {
186 JsFontCollection* me = CheckParamsAndGetThis<JsFontCollection>(env, info);
187 return (me != nullptr) ? me->OnLoadFont(env, info) : nullptr;
188 }
189
SplitAbsoluteFontPath(std::string & absolutePath)190 bool JsFontCollection::SplitAbsoluteFontPath(std::string& absolutePath)
191 {
192 auto iter = absolutePath.find_first_of(':');
193 if (iter == std::string::npos) {
194 TEXT_LOGE("Failed to find separator in path:%{public}s", absolutePath.c_str());
195 return false;
196 }
197 std::string head = absolutePath.substr(0, iter);
198 if ((head == "file" && absolutePath.size() > FILE_HEAD_LENGTH)) {
199 absolutePath = absolutePath.substr(iter + 3); // 3 means skip "://"
200 // the file format is like "file://system/fonts...",
201 return true;
202 }
203
204 return false;
205 }
206
GetResourcePartData(napi_env env,ResourceInfo & info,napi_value paramsNApi,napi_value bundleNameNApi,napi_value moduleNameNApi)207 bool JsFontCollection::GetResourcePartData(napi_env env, ResourceInfo& info, napi_value paramsNApi,
208 napi_value bundleNameNApi, napi_value moduleNameNApi)
209 {
210 napi_valuetype valueType = napi_undefined;
211 bool isArray = false;
212 if (napi_is_array(env, paramsNApi, &isArray) != napi_ok) {
213 TEXT_LOGE("Failed to get array type");
214 return false;
215 }
216 if (!isArray) {
217 TEXT_LOGE("Invalid array type");
218 return false;
219 }
220
221 uint32_t arrayLength = 0;
222 napi_get_array_length(env, paramsNApi, &arrayLength);
223 for (uint32_t i = 0; i < arrayLength; i++) {
224 size_t ret = 0;
225 napi_value indexValue = nullptr;
226 napi_get_element(env, paramsNApi, i, &indexValue);
227 napi_typeof(env, indexValue, &valueType);
228 if (valueType == napi_string) {
229 size_t strLen = GetParamLen(env, indexValue) + 1;
230 std::unique_ptr<char[]> indexStr = std::make_unique<char[]>(strLen);
231 napi_get_value_string_utf8(env, indexValue, indexStr.get(), strLen, &ret);
232 info.params.emplace_back(indexStr.get());
233 } else if (valueType == napi_number) {
234 int32_t num = 0;
235 napi_get_value_int32(env, indexValue, &num);
236 info.params.emplace_back(std::to_string(num));
237 } else {
238 TEXT_LOGE("Invalid value type %{public}d", valueType);
239 return false;
240 }
241 }
242
243 napi_typeof(env, bundleNameNApi, &valueType);
244 if (valueType == napi_string) {
245 size_t ret = 0;
246 size_t strLen = GetParamLen(env, bundleNameNApi) + 1;
247 std::unique_ptr<char[]> bundleNameStr = std::make_unique<char[]>(strLen);
248 napi_get_value_string_utf8(env, bundleNameNApi, bundleNameStr.get(), strLen, &ret);
249 info.bundleName = bundleNameStr.get();
250 }
251
252 napi_typeof(env, moduleNameNApi, &valueType);
253 if (valueType == napi_string) {
254 size_t ret = 0;
255 size_t strLen = GetParamLen(env, moduleNameNApi) + 1;
256 std::unique_ptr<char[]> moduleNameStr = std::make_unique<char[]>(strLen);
257 napi_get_value_string_utf8(env, moduleNameNApi, moduleNameStr.get(), strLen, &ret);
258 info.moduleName = moduleNameStr.get();
259 }
260
261 return true;
262 }
263
ParseResourceType(napi_env env,napi_value value,ResourceInfo & info)264 bool JsFontCollection::ParseResourceType(napi_env env, napi_value value, ResourceInfo& info)
265 {
266 napi_value idNApi = nullptr;
267 napi_value typeNApi = nullptr;
268 napi_value paramsNApi = nullptr;
269 napi_value bundleNameNApi = nullptr;
270 napi_value moduleNameNApi = nullptr;
271 napi_valuetype valueType = napi_undefined;
272 napi_typeof(env, value, &valueType);
273 if (valueType == napi_object) {
274 napi_get_named_property(env, value, "id", &idNApi);
275 napi_get_named_property(env, value, "type", &typeNApi);
276 napi_get_named_property(env, value, "params", ¶msNApi);
277 napi_get_named_property(env, value, "bundleName", &bundleNameNApi);
278 napi_get_named_property(env, value, "moduleName", &moduleNameNApi);
279 } else {
280 return false;
281 }
282
283 napi_typeof(env, idNApi, &valueType);
284 if (valueType == napi_number) {
285 napi_get_value_int32(env, idNApi, &info.resId);
286 }
287
288 napi_typeof(env, typeNApi, &valueType);
289 if (valueType == napi_number) {
290 napi_get_value_int32(env, typeNApi, &info.type);
291 }
292 if (!GetResourcePartData(env, info, paramsNApi, bundleNameNApi, moduleNameNApi)) {
293 return false;
294 }
295
296 return true;
297 }
298
GetResourceManager() const299 std::shared_ptr<Global::Resource::ResourceManager> JsFontCollection::GetResourceManager() const
300 {
301 std::shared_ptr<AbilityRuntime::ApplicationContext> context =
302 AbilityRuntime::ApplicationContext::GetApplicationContext();
303 TEXT_ERROR_CHECK(context != nullptr, return nullptr, "Failed to get application context");
304 auto resourceManager = context->GetResourceManager();
305 TEXT_ERROR_CHECK(resourceManager != nullptr, return nullptr, "Failed to get resource manager");
306 return resourceManager;
307 }
308
ParseResourcePath(const std::string familyName,ResourceInfo & info)309 bool JsFontCollection::ParseResourcePath(const std::string familyName, ResourceInfo& info)
310 {
311 int32_t state = 0;
312 auto resourceManager = GetResourceManager();
313 TEXT_ERROR_CHECK(resourceManager != nullptr, return false,
314 "Failed to get resourceManager, resourceManager is nullptr");
315
316 if (info.type == static_cast<int32_t>(ResourceType::STRING)) {
317 std::string rPath;
318 if (info.resId < 0 && !info.params.empty() && info.params[0].size() > 0) {
319 rPath = info.params[0];
320 } else {
321 state = resourceManager->GetStringById(info.resId, rPath);
322 if (state >= GLOBAL_ERROR || state < 0) {
323 return false;
324 }
325 if (!SplitAbsoluteFontPath(rPath) || !GetFontFileProperties(rPath, familyName)) {
326 return false;
327 }
328 }
329 } else if (info.type == static_cast<int32_t>(ResourceType::RAWFILE)) {
330 size_t dataLen = 0;
331 std::unique_ptr<uint8_t[]> rawData;
332
333 if (info.params.empty()) {
334 return false;
335 }
336
337 state = resourceManager->GetRawFileFromHap(info.params[0], dataLen, rawData);
338 if (state >= GLOBAL_ERROR || state < 0) {
339 return false;
340 }
341 if (!fontcollection_->LoadFont(familyName.c_str(), rawData.get(), dataLen)) {
342 return false;
343 }
344 return true;
345 } else {
346 TEXT_LOGE("Invalid resource type %{public}d", info.type);
347 return false;
348 }
349 return true;
350 }
351
GetFontFileProperties(const std::string path,const std::string familyName)352 bool JsFontCollection::GetFontFileProperties(const std::string path, const std::string familyName)
353 {
354 if (fontcollection_ == nullptr) {
355 TEXT_LOGE("Null font collection");
356 return false;
357 }
358
359 char tmpPath[PATH_MAX] = {0};
360 if (realpath(path.c_str(), tmpPath) == nullptr) {
361 TEXT_LOGE("Invalid path %{public}s", path.c_str());
362 return false;
363 }
364
365 std::ifstream f(tmpPath);
366 if (!f.good()) {
367 TEXT_LOGE("Failed to access %{public}s, %{public}s", tmpPath, strerror(errno));
368 return false;
369 }
370
371 std::ifstream ifs(tmpPath, std::ios_base::in);
372 if (!ifs.is_open()) {
373 return false;
374 }
375
376 ifs.seekg(0, ifs.end);
377 if (!ifs.good()) {
378 ifs.close();
379 return false;
380 }
381
382 size_t datalen = static_cast<size_t>(ifs.tellg());
383 if (ifs.fail()) {
384 ifs.close();
385 return false;
386 }
387
388 ifs.seekg(ifs.beg);
389 if (!ifs.good()) {
390 ifs.close();
391 return false;
392 }
393
394 std::unique_ptr<char[]> buffer = std::make_unique<char[]>(datalen);
395 ifs.read(buffer.get(), datalen);
396 if (!ifs.good()) {
397 TEXT_LOGE("Failed to read %{public}s, data len %{public}zu, %{public}s",
398 tmpPath, datalen, strerror(errno));
399 ifs.close();
400 return false;
401 }
402 ifs.close();
403 const uint8_t* rawData = reinterpret_cast<uint8_t*>(buffer.get());
404 if (!fontcollection_->LoadFont(familyName.c_str(), rawData, datalen)) {
405 TEXT_LOGE("Failed to load font %{public}s", familyName.c_str());
406 return false;
407 }
408 return true;
409 }
410
OnLoadFont(napi_env env,napi_callback_info info)411 napi_value JsFontCollection::OnLoadFont(napi_env env, napi_callback_info info)
412 {
413 size_t argc = ARGC_TWO;
414 napi_value argv[ARGC_TWO] = {nullptr};
415 if (napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr) != napi_ok ||
416 argc < ARGC_TWO) {
417 TEXT_LOGE("Failed to get argument, argc %{public}zu", argc);
418 return nullptr;
419 }
420 if (argv[0] == nullptr) {
421 TEXT_LOGE("Null argv[0]");
422 return nullptr;
423 }
424 std::string familyName;
425 std::string familySrc;
426 if (!ConvertFromJsValue(env, argv[0], familyName)) {
427 TEXT_LOGE("Failed to convert argv[0]");
428 return nullptr;
429 }
430 napi_valuetype valueType = napi_undefined;
431 if (argv[1] == nullptr) {
432 TEXT_LOGE("Null arv[1]");
433 return nullptr;
434 }
435 napi_typeof(env, argv[1], &valueType);
436 if (valueType != napi_object) {
437 if (!ConvertFromJsValue(env, argv[1], familySrc)) {
438 TEXT_LOGE("Failed to convert argv[1]");
439 return nullptr;
440 }
441 if (!SplitAbsoluteFontPath(familySrc) || !GetFontFileProperties(familySrc, familyName)) {
442 return nullptr;
443 }
444 return NapiGetUndefined(env);
445 }
446
447 ResourceInfo resourceInfo;
448 if (!ParseResourceType(env, argv[1], resourceInfo) || !ParseResourcePath(familyName, resourceInfo)) {
449 return nullptr;
450 }
451
452 return NapiGetUndefined(env);
453 }
454
ClearCaches(napi_env env,napi_callback_info info)455 napi_value JsFontCollection::ClearCaches(napi_env env, napi_callback_info info)
456 {
457 JsFontCollection* me = CheckParamsAndGetThis<JsFontCollection>(env, info);
458 return (me != nullptr) ? me->OnClearCaches(env, info) : nullptr;
459 }
460
OnClearCaches(napi_env env,napi_callback_info info)461 napi_value JsFontCollection::OnClearCaches(napi_env env, napi_callback_info info)
462 {
463 if (fontcollection_ == nullptr) {
464 TEXT_LOGE("Null font collection");
465 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM,
466 "JsFontCollection::OnClearCaches fontCollection is nullptr.");
467 }
468 fontcollection_->ClearCaches();
469 return NapiGetUndefined(env);
470 }
471
LoadFontAsync(napi_env env,napi_callback_info info)472 napi_value JsFontCollection::LoadFontAsync(napi_env env, napi_callback_info info)
473 {
474 JsFontCollection* me = CheckParamsAndGetThis<JsFontCollection>(env, info);
475 return (me != nullptr) ? me->OnLoadFontAsync(env, info) : nullptr;
476 }
477
OnLoadFontAsync(napi_env env,napi_callback_info info)478 napi_value JsFontCollection::OnLoadFontAsync(napi_env env, napi_callback_info info)
479 {
480 sptr<FontArgumentsConcreteContext> context = sptr<FontArgumentsConcreteContext>::MakeSptr();
481 NAPI_CHECK_AND_THROW_ERROR(context != nullptr, TextErrorCode::ERROR_NO_MEMORY, "Failed to make context");
482 auto inputParser = [env, context](size_t argc, napi_value* argv) {
483 TEXT_ERROR_CHECK(argv != nullptr, return, "Argv is null");
484 NAPI_CHECK_ARGS(context, context->status == napi_ok, napi_invalid_arg,
485 TextErrorCode::ERROR_INVALID_PARAM, return, "Status error, status=%d", static_cast<int>(context->status));
486 NAPI_CHECK_ARGS(context, argc >= ARGC_TWO, napi_invalid_arg, TextErrorCode::ERROR_INVALID_PARAM,
487 return, "Argc is invalid %zu", argc);
488 NAPI_CHECK_ARGS(context, ConvertFromJsValue(env, argv[0], context->familyName), napi_invalid_arg,
489 TextErrorCode::ERROR_INVALID_PARAM, return, "FamilyName is invalid %s", context->familyName.c_str());
490
491 if (!ParseContextFilePath(env, argv, context)) {
492 auto* fontCollection = reinterpret_cast<JsFontCollection*>(context->native);
493 NAPI_CHECK_ARGS(context, fontCollection != nullptr, napi_invalid_arg,
494 TextErrorCode::ERROR_INVALID_PARAM, return, "FontCollection is null");
495 NAPI_CHECK_ARGS(context, fontCollection->ParseResourceType(env, argv[ARGC_ONE], context->info),
496 napi_invalid_arg, TextErrorCode::ERROR_INVALID_PARAM, return, "Parse resource error");
497 }
498 };
499
500 context->GetCbInfo(env, info, inputParser);
501
502 auto executor = [context]() {
503 TEXT_ERROR_CHECK(context != nullptr, return, "Context is null");
504
505 auto* fontCollection = reinterpret_cast<JsFontCollection*>(context->native);
506 NAPI_CHECK_ARGS(context, fontCollection != nullptr, napi_generic_failure,
507 TextErrorCode::ERROR_INVALID_PARAM, return, "FontCollection is null");
508
509 NAPI_CHECK_ARGS(context, fontCollection->fontcollection_ != nullptr, napi_generic_failure,
510 TextErrorCode::ERROR_INVALID_PARAM, return, "Inner fontcollection is null");
511
512 if (!context->filePath.empty()) {
513 NAPI_CHECK_ARGS(context, fontCollection->SplitAbsoluteFontPath(context->filePath),
514 napi_invalid_arg, TextErrorCode::ERROR_INVALID_PARAM, return, "Failed to split absolute font path");
515
516 NAPI_CHECK_ARGS(context, fontCollection->GetFontFileProperties(context->filePath,
517 context->familyName), napi_invalid_arg, TextErrorCode::ERROR_INVALID_PARAM, return,
518 "Failed to get font file properties");
519 } else {
520 NAPI_CHECK_ARGS(context, fontCollection->ParseResourcePath(context->familyName, context->info),
521 napi_invalid_arg, TextErrorCode::ERROR_INVALID_PARAM, return,
522 "Failed to execute function, path is invalid");
523 }
524 };
525
526 auto complete = [env](napi_value& output) {
527 output = NapiGetUndefined(env);
528 };
529 return NapiAsyncWork::Enqueue(env, context, "OnLoadFontAsync", executor, complete);
530 }
531
UnloadFontAsync(napi_env env,napi_callback_info info)532 napi_value JsFontCollection::UnloadFontAsync(napi_env env, napi_callback_info info)
533 {
534 JsFontCollection* me = CheckParamsAndGetThis<JsFontCollection>(env, info);
535 return (me != nullptr) ? me->OnUnloadFontAsync(env, info) : nullptr;
536 }
537
UnloadFontSync(napi_env env,napi_callback_info info)538 napi_value JsFontCollection::UnloadFontSync(napi_env env, napi_callback_info info)
539 {
540 JsFontCollection* me = CheckParamsAndGetThis<JsFontCollection>(env, info);
541 return (me != nullptr) ? me->OnUnloadFont(env, info) : nullptr;
542 }
543
544
OnUnloadFontAsync(napi_env env,napi_callback_info info)545 napi_value JsFontCollection::OnUnloadFontAsync(napi_env env, napi_callback_info info)
546 {
547 sptr<FontArgumentsConcreteContext> context = sptr<FontArgumentsConcreteContext>::MakeSptr();
548 NAPI_CHECK_AND_THROW_ERROR(context != nullptr, TextErrorCode::ERROR_NO_MEMORY, "Failed to make context");
549 auto inputParser = [env, context](size_t argc, napi_value* argv) {
550 TEXT_ERROR_CHECK(argv != nullptr, return, "Argv is null");
551 NAPI_CHECK_ARGS(context, context->status == napi_ok, napi_invalid_arg,
552 TextErrorCode::ERROR_INVALID_PARAM, return, "Status error, status=%d", static_cast<int>(context->status));
553 NAPI_CHECK_ARGS(context, argc >= ARGC_ONE, napi_invalid_arg, TextErrorCode::ERROR_INVALID_PARAM,
554 return, "Argc is invalid %zu", argc);
555 NAPI_CHECK_ARGS(context, ConvertFromJsValue(env, argv[0], context->familyName), napi_invalid_arg,
556 TextErrorCode::ERROR_INVALID_PARAM, return, "FamilyName is invalid %s", context->familyName.c_str());
557 };
558
559 context->GetCbInfo(env, info, inputParser);
560
561 auto executor = [context]() {
562 TEXT_ERROR_CHECK(context != nullptr, return, "Context is null");
563
564 auto* fontCollection = reinterpret_cast<JsFontCollection*>(context->native);
565 NAPI_CHECK_ARGS(context, fontCollection != nullptr, napi_generic_failure, TextErrorCode::ERROR_INVALID_PARAM,
566 return, "FontCollection is null");
567
568 NAPI_CHECK_ARGS(context, fontCollection->fontcollection_ != nullptr, napi_generic_failure,
569 TextErrorCode::ERROR_INVALID_PARAM, return, "Inner fontcollection is null");
570 fontCollection->fontcollection_->UnloadFont(context->familyName);
571 };
572
573 auto complete = [env](napi_value& output) {
574 output = NapiGetUndefined(env);
575 };
576 return NapiAsyncWork::Enqueue(env, context, "OnUnloadFontAsync", executor, complete);
577 }
578
OnUnloadFont(napi_env env,napi_callback_info info)579 napi_value JsFontCollection::OnUnloadFont(napi_env env, napi_callback_info info)
580 {
581 size_t argc = ARGC_ONE;
582 napi_value argv[ARGC_ONE] = { nullptr };
583 if (napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr) != napi_ok || argc < ARGC_ONE) {
584 TEXT_LOGE("Failed to get argument, argc %{public}zu", argc);
585 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Failed to get argument");
586 }
587 if (argv[0] == nullptr) {
588 TEXT_LOGE("Null argv[0]");
589 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Failed to get argument");
590 }
591 std::string familyName;
592 if (!ConvertFromJsValue(env, argv[0], familyName)) {
593 TEXT_LOGE("Failed to convert argv[0]");
594 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Failed to get argument");
595 }
596
597 fontcollection_->UnloadFont(familyName);
598
599 return NapiGetUndefined(env);
600 }
601
602 } // namespace OHOS::Rosen
603