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 #include "js_typeface.h"
18 #include "../js_drawing_utils.h"
19 #include "native_value.h"
20
21 namespace OHOS::Rosen {
22 namespace Drawing {
23 thread_local napi_ref JsFont::constructor_ = nullptr;
24 const std::string CLASS_NAME = "Font";
Init(napi_env env,napi_value exportObj)25 napi_value JsFont::Init(napi_env env, napi_value exportObj)
26 {
27 napi_property_descriptor properties[] = {
28 DECLARE_NAPI_FUNCTION("enableSubpixel", JsFont::EnableSubpixel),
29 DECLARE_NAPI_FUNCTION("enableEmbolden", JsFont::EnableEmbolden),
30 DECLARE_NAPI_FUNCTION("enableLinearMetrics", JsFont::EnableLinearMetrics),
31 DECLARE_NAPI_FUNCTION("setSize", JsFont::SetSize),
32 DECLARE_NAPI_FUNCTION("setTypeface", JsFont::SetTypeface),
33 DECLARE_NAPI_FUNCTION("getTypeface", JsFont::GetTypeface),
34 DECLARE_NAPI_FUNCTION("getSize", JsFont::GetSize),
35 DECLARE_NAPI_FUNCTION("getMetrics", JsFont::GetMetrics),
36 DECLARE_NAPI_FUNCTION("measureText", JsFont::MeasureText),
37 };
38
39 napi_value constructor = nullptr;
40 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
41 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
42 if (status != napi_ok) {
43 ROSEN_LOGE("Failed to define Font class");
44 return nullptr;
45 }
46
47 status = napi_create_reference(env, constructor, 1, &constructor_);
48 if (status != napi_ok) {
49 ROSEN_LOGE("Failed to create reference of constructor");
50 return nullptr;
51 }
52
53 status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
54 if (status != napi_ok) {
55 ROSEN_LOGE("Failed to set constructor");
56 return nullptr;
57 }
58
59 napi_property_descriptor staticProperty[] = {
60 DECLARE_NAPI_STATIC_FUNCTION("createFont", JsFont::CreateFont),
61 };
62 status = napi_define_properties(env, exportObj, 1, staticProperty);
63 if (status != napi_ok) {
64 ROSEN_LOGE("Failed to define static function");
65 return nullptr;
66 }
67 return exportObj;
68 }
69
Constructor(napi_env env,napi_callback_info info)70 napi_value JsFont::Constructor(napi_env env, napi_callback_info info)
71 {
72 size_t argCount = 0;
73 napi_value jsThis = nullptr;
74 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
75 if (status != napi_ok) {
76 ROSEN_LOGE("failed to napi_get_cb_info");
77 return nullptr;
78 }
79
80 std::shared_ptr<Font> font = std::make_shared<Font>();
81 JsFont *jsFont = new(std::nothrow) JsFont(font);
82
83 status = napi_wrap(env, jsThis, jsFont,
84 JsFont::Destructor, nullptr, nullptr);
85 if (status != napi_ok) {
86 delete jsFont;
87 ROSEN_LOGE("Failed to wrap native instance");
88 return nullptr;
89 }
90 return jsThis;
91 }
92
Destructor(napi_env env,void * nativeObject,void * finalize)93 void JsFont::Destructor(napi_env env, void *nativeObject, void *finalize)
94 {
95 (void)finalize;
96 if (nativeObject != nullptr) {
97 JsFont *napi = reinterpret_cast<JsFont *>(nativeObject);
98 delete napi;
99 }
100 }
101
CreateFont(napi_env env,napi_callback_info info)102 napi_value JsFont::CreateFont(napi_env env, napi_callback_info info)
103 {
104 napi_value result = nullptr;
105 napi_value constructor = nullptr;
106 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
107 if (status != napi_ok) {
108 ROSEN_LOGE("Failed to get the representation of constructor object");
109 return nullptr;
110 }
111
112 status = napi_new_instance(env, constructor, 0, nullptr, &result);
113 if (status != napi_ok) {
114 ROSEN_LOGE("Failed to instantiate JavaScript font instance");
115 return nullptr;
116 }
117 return result;
118 }
119
~JsFont()120 JsFont::~JsFont()
121 {
122 m_font = nullptr;
123 }
124
EnableSubpixel(napi_env env,napi_callback_info info)125 napi_value JsFont::EnableSubpixel(napi_env env, napi_callback_info info)
126 {
127 JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
128 return (me != nullptr) ? me->OnEnableSubpixel(env, info) : nullptr;
129 }
130
EnableEmbolden(napi_env env,napi_callback_info info)131 napi_value JsFont::EnableEmbolden(napi_env env, napi_callback_info info)
132 {
133 JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
134 return (me != nullptr) ? me->OnEnableEmbolden(env, info) : nullptr;
135 }
136
EnableLinearMetrics(napi_env env,napi_callback_info info)137 napi_value JsFont::EnableLinearMetrics(napi_env env, napi_callback_info info)
138 {
139 JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
140 return (me != nullptr) ? me->OnEnableLinearMetrics(env, info) : nullptr;
141 }
142
SetSize(napi_env env,napi_callback_info info)143 napi_value JsFont::SetSize(napi_env env, napi_callback_info info)
144 {
145 JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
146 return (me != nullptr) ? me->OnSetSize(env, info) : nullptr;
147 }
148
SetTypeface(napi_env env,napi_callback_info info)149 napi_value JsFont::SetTypeface(napi_env env, napi_callback_info info)
150 {
151 JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
152 return (me != nullptr) ? me->OnSetTypeface(env, info) : nullptr;
153 }
154
GetTypeface(napi_env env,napi_callback_info info)155 napi_value JsFont::GetTypeface(napi_env env, napi_callback_info info)
156 {
157 JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
158 return (me != nullptr) ? me->OnGetTypeface(env, info) : nullptr;
159 }
160
GetSize(napi_env env,napi_callback_info info)161 napi_value JsFont::GetSize(napi_env env, napi_callback_info info)
162 {
163 JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
164 return (me != nullptr) ? me->OnGetSize(env, info) : nullptr;
165 }
166
GetMetrics(napi_env env,napi_callback_info info)167 napi_value JsFont::GetMetrics(napi_env env, napi_callback_info info)
168 {
169 JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
170 return (me != nullptr) ? me->OnGetMetrics(env, info) : nullptr;
171 }
172
MeasureText(napi_env env,napi_callback_info info)173 napi_value JsFont::MeasureText(napi_env env, napi_callback_info info)
174 {
175 JsFont* me = CheckParamsAndGetThis<JsFont>(env, info);
176 return (me != nullptr) ? me->OnMeasureText(env, info) : nullptr;
177 }
178
OnEnableSubpixel(napi_env env,napi_callback_info info)179 napi_value JsFont::OnEnableSubpixel(napi_env env, napi_callback_info info)
180 {
181 if (m_font == nullptr) {
182 ROSEN_LOGE("JsFont::OnEnableSubpixel font is nullptr");
183 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
184 }
185
186 size_t argc = ARGC_ONE;
187 napi_value argv[ARGC_ONE] = {nullptr};
188 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
189 if (status != napi_ok || argc < ARGC_ONE) {
190 ROSEN_LOGE("JsFont::OnEnableSubpixel Argc is invalid: %{public}zu", argc);
191 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
192 }
193
194 bool isSubpixel = false;
195 if (!ConvertFromJsValue(env, argv[0], isSubpixel)) {
196 ROSEN_LOGE("JsFont::OnEnableSubpixel Argv[0] is invalid");
197 return NapiGetUndefined(env);
198 }
199
200 m_font->SetSubpixel(isSubpixel);
201 return NapiGetUndefined(env);
202 }
203
OnEnableEmbolden(napi_env env,napi_callback_info info)204 napi_value JsFont::OnEnableEmbolden(napi_env env, napi_callback_info info)
205 {
206 if (m_font == nullptr) {
207 ROSEN_LOGE("JsFont::OnEnableEmbolden font is nullptr");
208 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
209 }
210
211 size_t argc = ARGC_ONE;
212 napi_value argv[ARGC_ONE] = {nullptr};
213 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
214 if (status != napi_ok || argc < ARGC_ONE) {
215 ROSEN_LOGE("JsFont::OnEnableEmbolden Argc is invalid: %{public}zu", argc);
216 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
217 }
218
219 bool isEmbolden = false;
220 if (!ConvertFromJsValue(env, argv[0], isEmbolden)) {
221 ROSEN_LOGE("JsFont::OnEnableEmbolden Argv[0] is invalid");
222 return NapiGetUndefined(env);
223 }
224
225 m_font->SetEmbolden(isEmbolden);
226 return NapiGetUndefined(env);
227 }
228
OnEnableLinearMetrics(napi_env env,napi_callback_info info)229 napi_value JsFont::OnEnableLinearMetrics(napi_env env, napi_callback_info info)
230 {
231 if (m_font == nullptr) {
232 ROSEN_LOGE("JsFont::OnEnableLinearMetrics font is nullptr");
233 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
234 }
235
236 size_t argc = ARGC_ONE;
237 napi_value argv[ARGC_ONE] = {nullptr};
238 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
239 if (status != napi_ok || argc < ARGC_ONE) {
240 ROSEN_LOGE("JsFont::OnEnableLinearMetrics Argc is invalid: %{public}zu", argc);
241 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
242 }
243
244 bool isLinearMetrics = false;
245 if (!ConvertFromJsValue(env, argv[0], isLinearMetrics)) {
246 ROSEN_LOGE("JsFont::OnEnableLinearMetrics Argv[0] is invalid");
247 return NapiGetUndefined(env);
248 }
249
250 m_font->SetLinearMetrics(isLinearMetrics);
251 return NapiGetUndefined(env);
252 }
253
OnSetSize(napi_env env,napi_callback_info info)254 napi_value JsFont::OnSetSize(napi_env env, napi_callback_info info)
255 {
256 if (m_font == nullptr) {
257 ROSEN_LOGE("JsFont::OnSetSize font is nullptr");
258 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
259 }
260
261 size_t argc = ARGC_ONE;
262 napi_value argv[ARGC_ONE] = {nullptr};
263 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
264 if (status != napi_ok || argc < ARGC_ONE) {
265 ROSEN_LOGE("JsFont::OnSetSize Argc is invalid: %{public}zu", argc);
266 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
267 }
268
269 double textSize = 0.0;
270 if (!ConvertFromJsValue(env, argv[0], textSize)) {
271 ROSEN_LOGE("JsFont::OnSetSize Argv[0] is invalid");
272 return NapiGetUndefined(env);
273 }
274
275 m_font->SetSize((float)textSize);
276 return NapiGetUndefined(env);
277 }
278
OnGetSize(napi_env env,napi_callback_info info)279 napi_value JsFont::OnGetSize(napi_env env, napi_callback_info info)
280 {
281 if (m_font == nullptr) {
282 ROSEN_LOGE("JsFont::OnGetSize font is nullptr");
283 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
284 }
285
286 double textSize = m_font->GetSize();
287 return GetDoubleAndConvertToJsValue(env, textSize);
288 }
289
OnGetMetrics(napi_env env,napi_callback_info info)290 napi_value JsFont::OnGetMetrics(napi_env env, napi_callback_info info)
291 {
292 if (m_font == nullptr) {
293 ROSEN_LOGE("JsFont::OnGetMetrics font is nullptr");
294 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
295 }
296 FontMetrics metrics;
297 m_font->GetMetrics(&metrics);
298 return GetFontMetricsAndConvertToJsValue(env, &metrics);
299 }
300
OnSetTypeface(napi_env env,napi_callback_info info)301 napi_value JsFont::OnSetTypeface(napi_env env, napi_callback_info info)
302 {
303 if (m_font == nullptr) {
304 ROSEN_LOGE("JsFont::OnSetTypeface font is nullptr");
305 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
306 }
307
308 size_t argc = ARGC_ONE;
309 napi_value argv[ARGC_ONE] = {nullptr};
310 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
311 if (status != napi_ok || argc < ARGC_ONE) {
312 ROSEN_LOGE("JsFont::OnSetTypeface Argc is invalid: %{public}zu", argc);
313 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
314 }
315 JsTypeface *jsTypeface = nullptr;
316 napi_unwrap(env, argv[0], (void **)&jsTypeface);
317 if (jsTypeface == nullptr) {
318 ROSEN_LOGE("JsFont::OnSetTypeface jsTypeface is nullptr");
319 return NapiGetUndefined(env);
320 }
321
322 m_font->SetTypeface(jsTypeface->GetTypeface());
323 return NapiGetUndefined(env);
324 }
325
OnGetTypeface(napi_env env,napi_callback_info info)326 napi_value JsFont::OnGetTypeface(napi_env env, napi_callback_info info)
327 {
328 if (m_font == nullptr) {
329 ROSEN_LOGE("JsFont::OnGetTypeface font is nullptr");
330 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
331 }
332
333 std::shared_ptr<Typeface> typeface = m_font->GetTypeface();
334 return JsTypeface::CreateJsTypeface(env, typeface);
335 }
336
OnMeasureText(napi_env env,napi_callback_info info)337 napi_value JsFont::OnMeasureText(napi_env env, napi_callback_info info)
338 {
339 if (m_font == nullptr) {
340 ROSEN_LOGE("JsFont::OnMeasureText font is nullptr");
341 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
342 }
343
344 size_t argc = ARGC_TWO;
345 napi_value argv[ARGC_TWO] = {nullptr};
346 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
347 if (status != napi_ok || argc < ARGC_TWO) {
348 ROSEN_LOGE("JsFont::OnMeasureText Argc is invalid: %{public}zu", argc);
349 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
350 }
351
352 std::string text = "";
353 if (!ConvertFromJsValue(env, argv[0], text)) {
354 ROSEN_LOGE("JsFont::OnMeasureText Argv[0] is invalid");
355 return NapiGetUndefined(env);
356 }
357
358 TextEncoding TextEncoding = TextEncoding::UTF8;
359 if (!ConvertFromJsTextEncoding(env, TextEncoding, argv[1])) {
360 ROSEN_LOGE("JsFont::OnMeasureText ConvertFromJsTextEncoding failed");
361 return NapiGetUndefined(env);
362 }
363
364 double textSize = m_font->MeasureText(text.c_str(), text.length(), TextEncoding);
365 return GetDoubleAndConvertToJsValue(env, textSize);
366 }
367
GetFont()368 std::shared_ptr<Font> JsFont::GetFont()
369 {
370 return m_font;
371 }
372 } // namespace Drawing
373 } // namespace OHOS::Rosen