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_typeface.h"
17
18 #include "native_value.h"
19
20 #include "js_drawing_utils.h"
21
22 namespace OHOS::Rosen {
23 namespace Drawing {
24 thread_local napi_ref JsTypeface::constructor_ = nullptr;
25 const std::string CLASS_NAME = "Typeface";
26 const std::string G_SYSTEM_FONT_DIR = "/system/fonts";
Init(napi_env env,napi_value exportObj)27 napi_value JsTypeface::Init(napi_env env, napi_value exportObj)
28 {
29 napi_property_descriptor properties[] = {
30 DECLARE_NAPI_FUNCTION("getFamilyName", JsTypeface::GetFamilyName),
31 DECLARE_NAPI_STATIC_FUNCTION("makeFromFile", JsTypeface::MakeFromFile),
32 };
33
34 napi_value constructor = nullptr;
35 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
36 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
37 if (status != napi_ok) {
38 ROSEN_LOGE("Failed to define Typeface class");
39 return nullptr;
40 }
41
42 status = napi_create_reference(env, constructor, 1, &constructor_);
43 if (status != napi_ok) {
44 ROSEN_LOGE("Failed to create reference of constructor");
45 return nullptr;
46 }
47
48 status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
49 if (status != napi_ok) {
50 ROSEN_LOGE("Failed to set constructor");
51 return nullptr;
52 }
53
54 return exportObj;
55 }
56
Constructor(napi_env env,napi_callback_info info)57 napi_value JsTypeface::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 ROSEN_LOGE("failed to napi_get_cb_info");
64 return nullptr;
65 }
66
67 JsTypeface *jsTypeface = new JsTypeface(JsTypeface::LoadZhCnTypeface());
68
69 status = napi_wrap(env, jsThis, jsTypeface, JsTypeface::Destructor, nullptr, nullptr);
70 if (status != napi_ok) {
71 delete jsTypeface;
72 ROSEN_LOGE("Failed to wrap native instance");
73 return nullptr;
74 }
75 return jsThis;
76 }
77
Destructor(napi_env env,void * nativeObject,void * finalize)78 void JsTypeface::Destructor(napi_env env, void *nativeObject, void *finalize)
79 {
80 (void)finalize;
81 if (nativeObject != nullptr) {
82 JsTypeface *napi = reinterpret_cast<JsTypeface *>(nativeObject);
83 delete napi;
84 }
85 }
86
~JsTypeface()87 JsTypeface::~JsTypeface()
88 {
89 m_typeface = nullptr;
90 }
91
CreateJsTypeface(napi_env env,const std::shared_ptr<Typeface> typeface)92 napi_value JsTypeface::CreateJsTypeface(napi_env env, const std::shared_ptr<Typeface> typeface)
93 {
94 napi_value constructor = nullptr;
95 napi_value result = nullptr;
96 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
97 if (status == napi_ok) {
98 auto jsTypeface = new JsTypeface(typeface);
99 napi_create_object(env, &result);
100 if (result == nullptr) {
101 delete jsTypeface;
102 ROSEN_LOGE("JsTypeface::MakeFromFile Create Typeface failed!");
103 return nullptr;
104 }
105 status = napi_wrap(env, result, jsTypeface, JsTypeface::Destructor, nullptr, nullptr);
106 if (status != napi_ok) {
107 delete jsTypeface;
108 ROSEN_LOGE("JsTypeface::MakeFromFile failed to wrap native instance");
109 return nullptr;
110 }
111 napi_property_descriptor resultFuncs[] = {
112 DECLARE_NAPI_FUNCTION("getFamilyName", JsTypeface::GetFamilyName),
113 };
114 napi_define_properties(env, result, sizeof(resultFuncs) / sizeof(resultFuncs[0]), resultFuncs);
115 return result;
116 }
117 return result;
118 }
119
LoadZhCnTypeface()120 std::shared_ptr<Typeface> JsTypeface::LoadZhCnTypeface()
121 {
122 std::shared_ptr<Typeface> typeface = Typeface::MakeFromFile(ZH_CN_TTF);
123 if (typeface == nullptr) {
124 typeface = Typeface::MakeDefault();
125 }
126 return typeface;
127 }
128
GetTypeface()129 std::shared_ptr<Typeface> JsTypeface::GetTypeface()
130 {
131 return m_typeface;
132 }
133
GetFamilyName(napi_env env,napi_callback_info info)134 napi_value JsTypeface::GetFamilyName(napi_env env, napi_callback_info info)
135 {
136 JsTypeface* me = CheckParamsAndGetThis<JsTypeface>(env, info);
137 return (me != nullptr) ? me->OnGetFamilyName(env, info) : nullptr;
138 }
139
OnGetFamilyName(napi_env env,napi_callback_info info)140 napi_value JsTypeface::OnGetFamilyName(napi_env env, napi_callback_info info)
141 {
142 if (m_typeface == nullptr) {
143 ROSEN_LOGE("[NAPI]typeface is null");
144 return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
145 }
146
147 auto name = m_typeface->GetFamilyName();
148 return GetStringAndConvertToJsValue(env, name);
149 }
150
MakeFromFile(napi_env env,napi_callback_info info)151 napi_value JsTypeface::MakeFromFile(napi_env env, napi_callback_info info)
152 {
153 size_t argc = ARGC_ONE;
154 napi_value argv[ARGC_ONE] = {nullptr};
155 CHECK_PARAM_NUMBER_WITH_OPTIONAL_PARAMS(argv, argc, ARGC_ONE, ARGC_ONE);
156
157 std::string text = "";
158 GET_JSVALUE_PARAM(ARGC_ZERO, text);
159
160 auto rawTypeface = Typeface::MakeFromFile(text.c_str());
161 if (rawTypeface == nullptr) {
162 ROSEN_LOGE("JsTypeface::MakeFromFile create rawTypeface failed!");
163 return nullptr;
164 }
165 auto typeface = new JsTypeface(rawTypeface);
166 std::string pathStr(text);
167 if (pathStr.substr(0, G_SYSTEM_FONT_DIR.length()) != G_SYSTEM_FONT_DIR &&
168 Drawing::Typeface::GetTypefaceRegisterCallBack() != nullptr) {
169 bool ret = Drawing::Typeface::GetTypefaceRegisterCallBack()(rawTypeface);
170 if (!ret) {
171 delete typeface;
172 ROSEN_LOGE("JsTypeface::MakeFromFile MakeRegister Typeface failed!");
173 return nullptr;
174 }
175 }
176
177 napi_value jsObj = nullptr;
178 napi_create_object(env, &jsObj);
179 if (jsObj == nullptr) {
180 delete typeface;
181 ROSEN_LOGE("JsTypeface::MakeFromFile Create Typeface failed!");
182 return nullptr;
183 }
184 napi_status status = napi_wrap(env, jsObj, typeface, JsTypeface::Destructor, nullptr, nullptr);
185 if (status != napi_ok) {
186 delete typeface;
187 ROSEN_LOGE("JsTypeface::MakeFromFile failed to wrap native instance");
188 return nullptr;
189 }
190 napi_property_descriptor resultFuncs[] = {
191 DECLARE_NAPI_FUNCTION("getFamilyName", JsTypeface::GetFamilyName),
192 };
193 napi_define_properties(env, jsObj, sizeof(resultFuncs) / sizeof(resultFuncs[0]), resultFuncs);
194 return jsObj;
195 }
196
197 } // namespace Drawing
198 } // namespace OHOS::Rosen