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 "js_font.h"
17 
18 #include "src/utils/SkUTF.h"
19 
20 #include "native_value.h"
21 
22 #include "js_drawing_utils.h"
23 #include "js_typeface.h"
24 
25 namespace OHOS::Rosen {
26 namespace Drawing {
27 thread_local napi_ref JsFont::constructor_ = nullptr;
28 const std::string CLASS_NAME = "Font";
29 
30 static napi_property_descriptor properties[] = {
31     DECLARE_NAPI_FUNCTION("enableSubpixel", JsFont::EnableSubpixel),
32     DECLARE_NAPI_FUNCTION("enableEmbolden", JsFont::EnableEmbolden),
33     DECLARE_NAPI_FUNCTION("enableLinearMetrics", JsFont::EnableLinearMetrics),
34     DECLARE_NAPI_FUNCTION("setBaselineSnap", JsFont::SetBaselineSnap),
35     DECLARE_NAPI_FUNCTION("setEmbeddedBitmaps", JsFont::SetEmbeddedBitmaps),
36     DECLARE_NAPI_FUNCTION("setForceAutoHinting", JsFont::SetForceAutoHinting),
37     DECLARE_NAPI_FUNCTION("setSize", JsFont::SetSize),
38     DECLARE_NAPI_FUNCTION("setTypeface", JsFont::SetTypeface),
39     DECLARE_NAPI_FUNCTION("getTypeface", JsFont::GetTypeface),
40     DECLARE_NAPI_FUNCTION("getSize", JsFont::GetSize),
41     DECLARE_NAPI_FUNCTION("getMetrics", JsFont::GetMetrics),
42     DECLARE_NAPI_FUNCTION("getWidths", JsFont::GetWidths),
43     DECLARE_NAPI_FUNCTION("measureSingleCharacter", JsFont::MeasureSingleCharacter),
44     DECLARE_NAPI_FUNCTION("measureText", JsFont::MeasureText),
45     DECLARE_NAPI_FUNCTION("setScaleX", JsFont::SetScaleX),
46     DECLARE_NAPI_FUNCTION("setSkewX", JsFont::SetSkewX),
47     DECLARE_NAPI_FUNCTION("setEdging", JsFont::SetEdging),
48     DECLARE_NAPI_FUNCTION("setHinting", JsFont::SetHinting),
49     DECLARE_NAPI_FUNCTION("countText", JsFont::CountText),
50     DECLARE_NAPI_FUNCTION("isBaselineSnap", JsFont::IsBaselineSnap),
51     DECLARE_NAPI_FUNCTION("isEmbeddedBitmaps", JsFont::IsEmbeddedBitmaps),
52     DECLARE_NAPI_FUNCTION("isForceAutoHinting", JsFont::IsForceAutoHinting),
53     DECLARE_NAPI_FUNCTION("isSubpixel", JsFont::IsSubpixel),
54     DECLARE_NAPI_FUNCTION("isLinearMetrics", JsFont::IsLinearMetrics),
55     DECLARE_NAPI_FUNCTION("getSkewX", JsFont::GetSkewX),
56     DECLARE_NAPI_FUNCTION("isEmbolden", JsFont::IsEmbolden),
57     DECLARE_NAPI_FUNCTION("getScaleX", JsFont::GetScaleX),
58     DECLARE_NAPI_FUNCTION("getHinting", JsFont::GetHinting),
59     DECLARE_NAPI_FUNCTION("getEdging", JsFont::GetEdging),
60     DECLARE_NAPI_FUNCTION("textToGlyphs", JsFont::TextToGlyphs),
61 };
62 
Init(napi_env env,napi_value exportObj)63 napi_value JsFont::Init(napi_env env, napi_value exportObj)
64 {
65     napi_value constructor = nullptr;
66     napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
67                                            sizeof(properties) / sizeof(properties[0]), properties, &constructor);
68     if (status != napi_ok) {
69         ROSEN_LOGE("Failed to define Font class");
70         return nullptr;
71     }
72 
73     status = napi_create_reference(env, constructor, 1, &constructor_);
74     if (status != napi_ok) {
75         ROSEN_LOGE("Failed to create reference of constructor");
76         return nullptr;
77     }
78 
79     status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
80     if (status != napi_ok) {
81         ROSEN_LOGE("Failed to set constructor");
82         return nullptr;
83     }
84 
85     napi_property_descriptor staticProperty[] = {
86         DECLARE_NAPI_STATIC_FUNCTION("createFont", JsFont::CreateFont),
87     };
88     status = napi_define_properties(env, exportObj, 1, staticProperty);
89     if (status != napi_ok) {
90         ROSEN_LOGE("Failed to define static function");
91         return nullptr;
92     }
93     return exportObj;
94 }
95 
Constructor(napi_env env,napi_callback_info info)96 napi_value JsFont::Constructor(napi_env env, napi_callback_info info)
97 {
98     size_t argCount = 0;
99     napi_value jsThis = nullptr;
100     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
101     if (status != napi_ok) {
102         ROSEN_LOGE("failed to napi_get_cb_info");
103         return nullptr;
104     }
105 
106     std::shared_ptr<Font> font = std::make_shared<Font>();
107     font->SetTypeface(JsTypeface::LoadZhCnTypeface());
108     JsFont *jsFont = new JsFont(font);
109 
110     status = napi_wrap_async_finalizer(env, jsThis, jsFont, JsFont::Destructor, nullptr, nullptr, 0);
111     if (status != napi_ok) {
112         delete jsFont;
113         ROSEN_LOGE("Failed to wrap native instance");
114         return nullptr;
115     }
116     return jsThis;
117 }
118 
Destructor(napi_env env,void * nativeObject,void * finalize)119 void JsFont::Destructor(napi_env env, void *nativeObject, void *finalize)
120 {
121     (void)finalize;
122     if (nativeObject != nullptr) {
123         JsFont *napi = reinterpret_cast<JsFont *>(nativeObject);
124         delete napi;
125     }
126 }
127 
CreateFont(napi_env env,napi_callback_info info)128 napi_value JsFont::CreateFont(napi_env env, napi_callback_info info)
129 {
130     napi_value result = nullptr;
131     napi_value constructor = nullptr;
132     napi_status status = napi_get_reference_value(env, constructor_, &constructor);
133     if (status != napi_ok) {
134         ROSEN_LOGE("Failed to get the representation of constructor object");
135         return nullptr;
136     }
137 
138     status = napi_new_instance(env, constructor, 0, nullptr, &result);
139     if (status != napi_ok) {
140         ROSEN_LOGE("Failed to instantiate JavaScript font instance");
141         return nullptr;
142     }
143     return result;
144 }
145 
~JsFont()146 JsFont::~JsFont()
147 {
148     m_font = nullptr;
149 }
150 
EnableSubpixel(napi_env env,napi_callback_info info)151 napi_value JsFont::EnableSubpixel(napi_env env, napi_callback_info info)
152 {
153     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
154     return (me != nullptr) ? me->OnEnableSubpixel(env, info) : nullptr;
155 }
156 
EnableEmbolden(napi_env env,napi_callback_info info)157 napi_value JsFont::EnableEmbolden(napi_env env, napi_callback_info info)
158 {
159     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
160     return (me != nullptr) ? me->OnEnableEmbolden(env, info) : nullptr;
161 }
162 
EnableLinearMetrics(napi_env env,napi_callback_info info)163 napi_value JsFont::EnableLinearMetrics(napi_env env, napi_callback_info info)
164 {
165     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
166     return (me != nullptr) ? me->OnEnableLinearMetrics(env, info) : nullptr;
167 }
168 
SetBaselineSnap(napi_env env,napi_callback_info info)169 napi_value JsFont::SetBaselineSnap(napi_env env, napi_callback_info info)
170 {
171     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
172     return (me != nullptr) ? me->OnSetBaselineSnap(env, info) : nullptr;
173 }
174 
SetEmbeddedBitmaps(napi_env env,napi_callback_info info)175 napi_value JsFont::SetEmbeddedBitmaps(napi_env env, napi_callback_info info)
176 {
177     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
178     return (me != nullptr) ? me->OnSetEmbeddedBitmaps(env, info) : nullptr;
179 }
180 
SetForceAutoHinting(napi_env env,napi_callback_info info)181 napi_value JsFont::SetForceAutoHinting(napi_env env, napi_callback_info info)
182 {
183     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
184     return (me != nullptr) ? me->OnSetForceAutoHinting(env, info) : nullptr;
185 }
186 
SetSize(napi_env env,napi_callback_info info)187 napi_value JsFont::SetSize(napi_env env, napi_callback_info info)
188 {
189     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
190     return (me != nullptr) ? me->OnSetSize(env, info) : nullptr;
191 }
192 
SetTypeface(napi_env env,napi_callback_info info)193 napi_value JsFont::SetTypeface(napi_env env, napi_callback_info info)
194 {
195     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
196     return (me != nullptr) ? me->OnSetTypeface(env, info) : nullptr;
197 }
198 
GetTypeface(napi_env env,napi_callback_info info)199 napi_value JsFont::GetTypeface(napi_env env, napi_callback_info info)
200 {
201     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
202     return (me != nullptr) ? me->OnGetTypeface(env, info) : nullptr;
203 }
204 
GetSize(napi_env env,napi_callback_info info)205 napi_value JsFont::GetSize(napi_env env, napi_callback_info info)
206 {
207     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
208     return (me != nullptr) ? me->OnGetSize(env, info) : nullptr;
209 }
210 
GetMetrics(napi_env env,napi_callback_info info)211 napi_value JsFont::GetMetrics(napi_env env, napi_callback_info info)
212 {
213     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
214     return (me != nullptr) ? me->OnGetMetrics(env, info) : nullptr;
215 }
216 
GetWidths(napi_env env,napi_callback_info info)217 napi_value JsFont::GetWidths(napi_env env, napi_callback_info info)
218 {
219     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
220     return (me != nullptr) ? me->OnGetWidths(env, info) : nullptr;
221 }
222 
IsBaselineSnap(napi_env env,napi_callback_info info)223 napi_value JsFont::IsBaselineSnap(napi_env env, napi_callback_info info)
224 {
225     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
226     return (me != nullptr) ? me->OnIsBaselineSnap(env, info) : nullptr;
227 }
228 
IsEmbeddedBitmaps(napi_env env,napi_callback_info info)229 napi_value JsFont::IsEmbeddedBitmaps(napi_env env, napi_callback_info info)
230 {
231     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
232     return (me != nullptr) ? me->OnIsEmbeddedBitmaps(env, info) : nullptr;
233 }
234 
IsForceAutoHinting(napi_env env,napi_callback_info info)235 napi_value JsFont::IsForceAutoHinting(napi_env env, napi_callback_info info)
236 {
237     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
238     return (me != nullptr) ? me->OnIsForceAutoHinting(env, info) : nullptr;
239 }
240 
MeasureSingleCharacter(napi_env env,napi_callback_info info)241 napi_value JsFont::MeasureSingleCharacter(napi_env env, napi_callback_info info)
242 {
243     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
244     return (me != nullptr) ? me->OnMeasureSingleCharacter(env, info) : nullptr;
245 }
246 
MeasureText(napi_env env,napi_callback_info info)247 napi_value JsFont::MeasureText(napi_env env, napi_callback_info info)
248 {
249     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
250     return (me != nullptr) ? me->OnMeasureText(env, info) : nullptr;
251 }
252 
SetScaleX(napi_env env,napi_callback_info info)253 napi_value JsFont::SetScaleX(napi_env env, napi_callback_info info)
254 {
255     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
256     return (me != nullptr) ? me->OnSetScaleX(env, info) : nullptr;
257 }
258 
SetSkewX(napi_env env,napi_callback_info info)259 napi_value JsFont::SetSkewX(napi_env env, napi_callback_info info)
260 {
261     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
262     return (me != nullptr) ? me->OnSetSkewX(env, info) : nullptr;
263 }
264 
SetEdging(napi_env env,napi_callback_info info)265 napi_value JsFont::SetEdging(napi_env env, napi_callback_info info)
266 {
267     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
268     return (me != nullptr) ? me->OnSetEdging(env, info) : nullptr;
269 }
270 
SetHinting(napi_env env,napi_callback_info info)271 napi_value JsFont::SetHinting(napi_env env, napi_callback_info info)
272 {
273     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
274     return (me != nullptr) ? me->OnSetHinting(env, info) : nullptr;
275 }
276 
CountText(napi_env env,napi_callback_info info)277 napi_value JsFont::CountText(napi_env env, napi_callback_info info)
278 {
279     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
280     return (me != nullptr) ? me->OnCountText(env, info) : nullptr;
281 }
282 
IsSubpixel(napi_env env,napi_callback_info info)283 napi_value JsFont::IsSubpixel(napi_env env, napi_callback_info info)
284 {
285     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
286     return (me != nullptr) ? me->OnIsSubpixel(env, info) : nullptr;
287 }
288 
IsLinearMetrics(napi_env env,napi_callback_info info)289 napi_value JsFont::IsLinearMetrics(napi_env env, napi_callback_info info)
290 {
291     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
292     return (me != nullptr) ? me->OnIsLinearMetrics(env, info) : nullptr;
293 }
294 
GetSkewX(napi_env env,napi_callback_info info)295 napi_value JsFont::GetSkewX(napi_env env, napi_callback_info info)
296 {
297     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
298     return (me != nullptr) ? me->OnGetSkewX(env, info) : nullptr;
299 }
300 
IsEmbolden(napi_env env,napi_callback_info info)301 napi_value JsFont::IsEmbolden(napi_env env, napi_callback_info info)
302 {
303     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
304     return (me != nullptr) ? me->OnIsEmbolden(env, info) : nullptr;
305 }
306 
GetScaleX(napi_env env,napi_callback_info info)307 napi_value JsFont::GetScaleX(napi_env env, napi_callback_info info)
308 {
309     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
310     return (me != nullptr) ? me->OnGetScaleX(env, info) : nullptr;
311 }
312 
GetHinting(napi_env env,napi_callback_info info)313 napi_value JsFont::GetHinting(napi_env env, napi_callback_info info)
314 {
315     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
316     return (me != nullptr) ? me->OnGetHinting(env, info) : nullptr;
317 }
318 
GetEdging(napi_env env,napi_callback_info info)319 napi_value JsFont::GetEdging(napi_env env, napi_callback_info info)
320 {
321     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
322     return (me != nullptr) ? me->OnGetEdging(env, info) : nullptr;
323 }
324 
TextToGlyphs(napi_env env,napi_callback_info info)325 napi_value JsFont::TextToGlyphs(napi_env env, napi_callback_info info)
326 {
327     JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
328     return (me != nullptr) ? me->OnTextToGlyphs(env, info) : nullptr;
329 }
330 
OnEnableSubpixel(napi_env env,napi_callback_info info)331 napi_value JsFont::OnEnableSubpixel(napi_env env, napi_callback_info info)
332 {
333     if (m_font == nullptr) {
334         ROSEN_LOGE("JsFont::OnEnableSubpixel font is nullptr");
335         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
336     }
337 
338     napi_value argv[ARGC_ONE] = {nullptr};
339     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
340 
341     bool isSubpixel = false;
342     GET_BOOLEAN_PARAM(ARGC_ZERO, isSubpixel);
343 
344     m_font->SetSubpixel(isSubpixel);
345     return nullptr;
346 }
347 
OnEnableEmbolden(napi_env env,napi_callback_info info)348 napi_value JsFont::OnEnableEmbolden(napi_env env, napi_callback_info info)
349 {
350     if (m_font == nullptr) {
351         ROSEN_LOGE("JsFont::OnEnableEmbolden font is nullptr");
352         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
353     }
354 
355     napi_value argv[ARGC_ONE] = {nullptr};
356     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
357 
358     bool isEmbolden = false;
359     GET_BOOLEAN_PARAM(ARGC_ZERO, isEmbolden);
360 
361     m_font->SetEmbolden(isEmbolden);
362     return nullptr;
363 }
364 
OnEnableLinearMetrics(napi_env env,napi_callback_info info)365 napi_value JsFont::OnEnableLinearMetrics(napi_env env, napi_callback_info info)
366 {
367     if (m_font == nullptr) {
368         ROSEN_LOGE("JsFont::OnEnableLinearMetrics font is nullptr");
369         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
370     }
371 
372     napi_value argv[ARGC_ONE] = {nullptr};
373     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
374 
375     bool isLinearMetrics = false;
376     GET_BOOLEAN_PARAM(ARGC_ZERO, isLinearMetrics);
377 
378     m_font->SetLinearMetrics(isLinearMetrics);
379     return nullptr;
380 }
381 
OnSetBaselineSnap(napi_env env,napi_callback_info info)382 napi_value JsFont::OnSetBaselineSnap(napi_env env, napi_callback_info info)
383 {
384     if (m_font == nullptr) {
385         ROSEN_LOGE("JsFont::OnSetBaselineSnap font is nullptr");
386         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
387     }
388 
389     napi_value argv[ARGC_ONE] = {nullptr};
390     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
391 
392     bool baselineSnap = false;
393     GET_BOOLEAN_PARAM(ARGC_ZERO, baselineSnap);
394 
395     m_font->SetBaselineSnap(baselineSnap);
396     return nullptr;
397 }
398 
OnIsBaselineSnap(napi_env env,napi_callback_info info)399 napi_value JsFont::OnIsBaselineSnap(napi_env env, napi_callback_info info)
400 {
401     if (m_font == nullptr) {
402         ROSEN_LOGE("JsFont::OnIsBaselineSnap font is nullptr");
403         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
404     }
405 
406     bool baselineSnap = m_font->IsBaselineSnap();
407     return CreateJsValue(env, baselineSnap);
408 }
409 
OnSetEmbeddedBitmaps(napi_env env,napi_callback_info info)410 napi_value JsFont::OnSetEmbeddedBitmaps(napi_env env, napi_callback_info info)
411 {
412     if (m_font == nullptr) {
413         ROSEN_LOGE("JsFont::OnSetEmbeddedBitmaps font is nullptr");
414         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
415     }
416 
417     napi_value argv[ARGC_ONE] = {nullptr};
418     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
419 
420     bool embeddedBitmaps = false;
421     GET_BOOLEAN_PARAM(ARGC_ZERO, embeddedBitmaps);
422 
423     m_font->SetEmbeddedBitmaps(embeddedBitmaps);
424     return nullptr;
425 }
426 
OnIsEmbeddedBitmaps(napi_env env,napi_callback_info info)427 napi_value JsFont::OnIsEmbeddedBitmaps(napi_env env, napi_callback_info info)
428 {
429     if (m_font == nullptr) {
430         ROSEN_LOGE("JsFont::OnIsEmbeddedBitmaps font is nullptr");
431         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
432     }
433 
434     bool embeddedBitmaps = m_font->IsEmbeddedBitmaps();
435     return CreateJsValue(env, embeddedBitmaps);
436 }
437 
OnSetForceAutoHinting(napi_env env,napi_callback_info info)438 napi_value JsFont::OnSetForceAutoHinting(napi_env env, napi_callback_info info)
439 {
440     if (m_font == nullptr) {
441         ROSEN_LOGE("JsFont::OnSetForceAutoHinting font is nullptr");
442         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
443     }
444 
445     napi_value argv[ARGC_ONE] = {nullptr};
446     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
447 
448     bool isForceAutoHinting = false;
449     GET_BOOLEAN_PARAM(ARGC_ZERO, isForceAutoHinting);
450 
451     m_font->SetForceAutoHinting(isForceAutoHinting);
452     return nullptr;
453 }
454 
OnIsForceAutoHinting(napi_env env,napi_callback_info info)455 napi_value JsFont::OnIsForceAutoHinting(napi_env env, napi_callback_info info)
456 {
457     if (m_font == nullptr) {
458         ROSEN_LOGE("JsFont::OnIsForceAutoHinting font is nullptr");
459         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
460     }
461 
462     bool isForceAutoHinting = m_font->IsForceAutoHinting();
463     return CreateJsValue(env, isForceAutoHinting);
464 }
465 
OnGetWidths(napi_env env,napi_callback_info info)466 napi_value JsFont::OnGetWidths(napi_env env, napi_callback_info info)
467 {
468     if (m_font == nullptr) {
469         ROSEN_LOGE("JsFont::OnGetWidths font is nullptr");
470         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
471     }
472 
473     napi_value argv[ARGC_ONE] = { nullptr };
474     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
475 
476     uint32_t fontSize = 0;
477     napi_get_array_length(env, argv[ARGC_ZERO], &fontSize);
478     if (fontSize == 0) {
479         return nullptr;
480     }
481 
482     std::unique_ptr<uint16_t[]> glyphPtr = std::make_unique<uint16_t[]>(fontSize);
483     for (uint32_t i = 0; i < fontSize; i++) {
484         napi_value tempglyph = nullptr;
485         napi_get_element(env, argv[ARGC_ZERO], i, &tempglyph);
486         uint32_t glyph_t = 0;
487         bool isColorOk = ConvertFromJsValue(env, tempglyph, glyph_t);
488         if (!isColorOk) {
489             ROSEN_LOGE("JsFont::OnGetWidths Argv[ARGC_ZERO] is invalid");
490             return nullptr;
491         }
492         glyphPtr[i] = glyph_t;
493     }
494 
495     std::unique_ptr<float[]> widthPtr = std::make_unique<float[]>(fontSize);
496     m_font->GetWidths(glyphPtr.get(), fontSize, widthPtr.get());
497     napi_value widthJsArray;
498     napi_status status = napi_create_array(env, &widthJsArray);
499     if (status != napi_ok) {
500         ROSEN_LOGE("failed to napi_create_array");
501         return nullptr;
502     }
503     for (size_t i = 0; i < fontSize; i++) {
504         napi_value element = CreateJsValue(env, widthPtr[i]);
505         napi_set_element(env, widthJsArray, i, element);
506     }
507     return widthJsArray;
508 }
509 
OnSetSize(napi_env env,napi_callback_info info)510 napi_value JsFont::OnSetSize(napi_env env, napi_callback_info info)
511 {
512     if (m_font == nullptr) {
513         ROSEN_LOGE("JsFont::OnSetSize font is nullptr");
514         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
515     }
516 
517     napi_value argv[ARGC_ONE] = {nullptr};
518     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
519 
520     double textSize = 0.0;
521     GET_DOUBLE_PARAM(ARGC_ZERO, textSize);
522 
523     m_font->SetSize((float)textSize);
524     return nullptr;
525 }
526 
OnGetSize(napi_env env,napi_callback_info info)527 napi_value JsFont::OnGetSize(napi_env env, napi_callback_info info)
528 {
529     if (m_font == nullptr) {
530         ROSEN_LOGE("JsFont::OnGetSize font is nullptr");
531         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
532     }
533 
534     double textSize = m_font->GetSize();
535     return GetDoubleAndConvertToJsValue(env, textSize);
536 }
537 
OnGetMetrics(napi_env env,napi_callback_info info)538 napi_value JsFont::OnGetMetrics(napi_env env, napi_callback_info info)
539 {
540     if (m_font == nullptr) {
541         ROSEN_LOGE("JsFont::OnGetMetrics font is nullptr");
542         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
543     }
544     FontMetrics metrics;
545     m_font->GetMetrics(&metrics);
546     return GetFontMetricsAndConvertToJsValue(env, &metrics);
547 }
548 
OnSetTypeface(napi_env env,napi_callback_info info)549 napi_value JsFont::OnSetTypeface(napi_env env, napi_callback_info info)
550 {
551     if (m_font == nullptr) {
552         ROSEN_LOGE("JsFont::OnSetTypeface font is nullptr");
553         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
554     }
555 
556     napi_value argv[ARGC_ONE] = {nullptr};
557     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
558 
559     JsTypeface *jsTypeface = nullptr;
560     GET_UNWRAP_PARAM(ARGC_ZERO, jsTypeface);
561 
562     m_font->SetTypeface(jsTypeface->GetTypeface());
563     return nullptr;
564 }
565 
OnGetTypeface(napi_env env,napi_callback_info info)566 napi_value JsFont::OnGetTypeface(napi_env env, napi_callback_info info)
567 {
568     if (m_font == nullptr) {
569         ROSEN_LOGE("JsFont::OnGetTypeface font is nullptr");
570         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
571     }
572 
573     std::shared_ptr<Typeface> typeface = m_font->GetTypeface();
574     return JsTypeface::CreateJsTypeface(env, typeface);
575 }
576 
OnMeasureSingleCharacter(napi_env env,napi_callback_info info)577 napi_value JsFont::OnMeasureSingleCharacter(napi_env env, napi_callback_info info)
578 {
579     if (m_font == nullptr) {
580         ROSEN_LOGE("JsFont::OnMeasureSingleCharacter font is nullptr");
581         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
582     }
583 
584     napi_value argv[ARGC_ONE] = {nullptr};
585     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
586 
587     size_t len = 0;
588     if (napi_get_value_string_utf8(env, argv[ARGC_ZERO], nullptr, 0, &len) != napi_ok) {
589         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Incorrect parameter0 type.");
590     }
591     if (len == 0 || len > 4) { // 4 is the maximum length of a character encoded in UTF8.
592         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM,
593             "Parameter verification failed. Input parameter0 should be single character.");
594     }
595     char str[len + 1];
596     if (napi_get_value_string_utf8(env, argv[ARGC_ZERO], str, len + 1, &len) != napi_ok) {
597         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Incorrect parameter0 type.");
598     }
599 
600     const char* currentStr = str;
601     int32_t unicode = SkUTF::NextUTF8(&currentStr, currentStr + len);
602     size_t byteLen = currentStr - str;
603     if (byteLen != len) {
604         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM,
605             "Parameter verification failed. Input parameter0 should be single character.");
606     }
607     return GetDoubleAndConvertToJsValue(env, m_font->MeasureSingleCharacter(unicode));
608 }
609 
OnMeasureText(napi_env env,napi_callback_info info)610 napi_value JsFont::OnMeasureText(napi_env env, napi_callback_info info)
611 {
612     if (m_font == nullptr) {
613         ROSEN_LOGE("JsFont::OnMeasureText font is nullptr");
614         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
615     }
616 
617     napi_value argv[ARGC_TWO] = {nullptr};
618     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_TWO);
619 
620     std::string text = "";
621     if (!ConvertFromJsValue(env, argv[ARGC_ZERO], text)) {
622         ROSEN_LOGE("JsFont::OnMeasureText Argv[0] is invalid");
623         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM,
624             "Parameter verification failed. The text input must be string.");
625     }
626 
627     TextEncoding TextEncoding = TextEncoding::UTF8;
628     if (!ConvertFromJsTextEncoding(env, TextEncoding, argv[1])) {
629         ROSEN_LOGE("JsFont::OnMeasureText ConvertFromJsTextEncoding failed");
630         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM,
631             "Parameter verification failed. The TextEncoding input must be valid.");
632     }
633 
634     double textSize = m_font->MeasureText(text.c_str(), text.length(), TextEncoding);
635     return GetDoubleAndConvertToJsValue(env, textSize);
636 }
637 
OnSetScaleX(napi_env env,napi_callback_info info)638 napi_value JsFont::OnSetScaleX(napi_env env, napi_callback_info info)
639 {
640     if (m_font == nullptr) {
641         ROSEN_LOGE("JsFont::OnSetScaleX font is nullptr");
642         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
643     }
644 
645     napi_value argv[ARGC_ONE] = {nullptr};
646     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
647 
648     double scaleX = 0.0;
649     GET_DOUBLE_PARAM(ARGC_ZERO, scaleX);
650 
651     JS_CALL_DRAWING_FUNC(m_font->SetScaleX(scaleX));
652     return nullptr;
653 }
654 
OnSetSkewX(napi_env env,napi_callback_info info)655 napi_value JsFont::OnSetSkewX(napi_env env, napi_callback_info info)
656 {
657     if (m_font == nullptr) {
658         ROSEN_LOGE("JsFont::OnSetSkewX font is nullptr");
659         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
660     }
661 
662     napi_value argv[ARGC_ONE] = {nullptr};
663     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
664 
665     double skewX = 0.0;
666     GET_DOUBLE_PARAM(ARGC_ZERO, skewX);
667 
668     JS_CALL_DRAWING_FUNC(m_font->SetSkewX(skewX));
669     return nullptr;
670 }
671 
OnSetEdging(napi_env env,napi_callback_info info)672 napi_value JsFont::OnSetEdging(napi_env env, napi_callback_info info)
673 {
674     if (m_font == nullptr) {
675         ROSEN_LOGE("JsFont::OnSetEdging font is nullptr");
676         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
677     }
678 
679     napi_value argv[ARGC_ONE] = {nullptr};
680     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
681 
682     int32_t fontEdging = 0;
683     GET_ENUM_PARAM(ARGC_ZERO, fontEdging, 0, static_cast<int32_t>(FontEdging::SUBPIXEL_ANTI_ALIAS));
684 
685     JS_CALL_DRAWING_FUNC(m_font->SetEdging(static_cast<FontEdging>(fontEdging)));
686     return nullptr;
687 }
688 
OnSetHinting(napi_env env,napi_callback_info info)689 napi_value JsFont::OnSetHinting(napi_env env, napi_callback_info info)
690 {
691     if (m_font == nullptr) {
692         ROSEN_LOGE("JsFont::OnSetHinting font is nullptr");
693         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
694     }
695 
696     napi_value argv[ARGC_ONE] = {nullptr};
697     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
698 
699     int32_t fontHinting = 0;
700     GET_ENUM_PARAM(ARGC_ZERO, fontHinting, 0, static_cast<int32_t>(FontHinting::FULL));
701 
702     JS_CALL_DRAWING_FUNC(m_font->SetHinting(static_cast<FontHinting>(fontHinting)));
703     return nullptr;
704 }
705 
OnCountText(napi_env env,napi_callback_info info)706 napi_value JsFont::OnCountText(napi_env env, napi_callback_info info)
707 {
708     if (m_font == nullptr) {
709         ROSEN_LOGE("JsFont::OnCountText font is nullptr");
710         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
711     }
712 
713     napi_value argv[ARGC_ONE] = {nullptr};
714     CHECK_PARAM_NUMBER_WITHOUT_OPTIONAL_PARAMS(argv, ARGC_ONE);
715 
716     std::string text = "";
717     if (!ConvertFromJsValue(env, argv[ARGC_ZERO], text)) {
718         ROSEN_LOGE("JsFont::OnCountText Argv[ARGC_ZERO] is invalid");
719         return nullptr;
720     }
721 
722     int32_t textSize = m_font->CountText(text.c_str(), text.length(), TextEncoding::UTF8);
723     return CreateJsNumber(env, textSize);
724 }
725 
OnIsSubpixel(napi_env env,napi_callback_info info)726 napi_value JsFont::OnIsSubpixel(napi_env env, napi_callback_info info)
727 {
728     if (m_font == nullptr) {
729         ROSEN_LOGE("JsFont::OnIsSubpixel font is nullptr");
730         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
731     }
732 
733     bool subpixel = m_font->IsSubpixel();
734     return CreateJsValue(env, subpixel);
735 }
736 
OnIsLinearMetrics(napi_env env,napi_callback_info info)737 napi_value JsFont::OnIsLinearMetrics(napi_env env, napi_callback_info info)
738 {
739     if (m_font == nullptr) {
740         ROSEN_LOGE("JsFont::OnIsLinearMetrics font is nullptr");
741         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
742     }
743 
744     bool linear = m_font->IsLinearMetrics();
745     return CreateJsValue(env, linear);
746 }
747 
OnGetSkewX(napi_env env,napi_callback_info info)748 napi_value JsFont::OnGetSkewX(napi_env env, napi_callback_info info)
749 {
750     if (m_font == nullptr) {
751         ROSEN_LOGE("JsFont::OnGetSkewX font is nullptr");
752         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
753     }
754 
755     double skewX = m_font->GetSkewX();
756     return GetDoubleAndConvertToJsValue(env, skewX);
757 }
758 
OnIsEmbolden(napi_env env,napi_callback_info info)759 napi_value JsFont::OnIsEmbolden(napi_env env, napi_callback_info info)
760 {
761     if (m_font == nullptr) {
762         ROSEN_LOGE("JsFont::OnIsEmbolden font is nullptr");
763         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
764     }
765 
766     bool fakeBoldText = m_font->IsEmbolden();
767     return CreateJsValue(env, fakeBoldText);
768 }
769 
OnGetScaleX(napi_env env,napi_callback_info info)770 napi_value JsFont::OnGetScaleX(napi_env env, napi_callback_info info)
771 {
772     if (m_font == nullptr) {
773         ROSEN_LOGE("JsFont::OnGetScaleX font is nullptr");
774         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
775     }
776 
777     double scaleX = m_font->GetScaleX();
778     return GetDoubleAndConvertToJsValue(env, scaleX);
779 }
780 
OnGetHinting(napi_env env,napi_callback_info info)781 napi_value JsFont::OnGetHinting(napi_env env, napi_callback_info info)
782 {
783     if (m_font == nullptr) {
784         ROSEN_LOGE("JsFont::OnGetHinting font is nullptr");
785         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
786     }
787 
788     FontHinting hinting = m_font->GetHinting();
789     return CreateJsNumber(env, static_cast<uint32_t>(hinting));
790 }
791 
OnGetEdging(napi_env env,napi_callback_info info)792 napi_value JsFont::OnGetEdging(napi_env env, napi_callback_info info)
793 {
794     if (m_font == nullptr) {
795         ROSEN_LOGE("JsFont::OnGetEdging font is nullptr");
796         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
797     }
798 
799     FontEdging edging = m_font->GetEdging();
800     return CreateJsNumber(env, static_cast<uint32_t>(edging));
801 }
802 
OnTextToGlyphs(napi_env env,napi_callback_info info)803 napi_value JsFont::OnTextToGlyphs(napi_env env, napi_callback_info info)
804 {
805     if (m_font == nullptr) {
806         ROSEN_LOGE("JsFont::OnTextToGlyphs font is nullptr");
807         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
808     }
809 
810     size_t argc = ARGC_TWO;
811     napi_value argv[ARGC_TWO] = { nullptr };
812     CHECK_PARAM_NUMBER_WITH_OPTIONAL_PARAMS(argv, argc, ARGC_ONE, ARGC_TWO);
813 
814     std::string text = "";
815     if (!ConvertFromJsValue(env, argv[ARGC_ZERO], text)) {
816         ROSEN_LOGE("JsFont::OnTextToGlyphs Argv[ARGC_ZERO] is invalid");
817         return nullptr;
818     }
819 
820     uint32_t glyphCount = static_cast<uint32_t>(m_font->CountText(text.c_str(), text.length(), TextEncoding::UTF8));
821     if (argc == ARGC_TWO) {
822         uint32_t inputCount = 0;
823         GET_UINT32_PARAM(ARGC_ONE, inputCount);
824         if (glyphCount != inputCount) {
825             return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
826         }
827     }
828 
829     std::unique_ptr<uint16_t[]> glyphPtr = std::make_unique<uint16_t[]>(glyphCount);
830     m_font->TextToGlyphs(text.c_str(), text.length(), TextEncoding::UTF8, glyphPtr.get(), glyphCount);
831 
832     napi_value glyphJsArray;
833     napi_status status = napi_create_array(env, &glyphJsArray);
834     if (status != napi_ok) {
835         ROSEN_LOGE("failed to napi_create_array");
836         return nullptr;
837     }
838     for (size_t i = 0; i < glyphCount; i++) {
839         napi_value element = CreateJsValue(env, glyphPtr[i]);
840         napi_set_element(env, glyphJsArray, i, element);
841     }
842     return glyphJsArray;
843 }
844 
GetFont()845 std::shared_ptr<Font> JsFont::GetFont()
846 {
847     return m_font;
848 }
849 
SetFont(std::shared_ptr<Font> font)850 void JsFont::SetFont(std::shared_ptr<Font> font)
851 {
852     m_font = font;
853 }
854 } // namespace Drawing
855 } // namespace OHOS::Rosen